🎯 A Thai Jev is here! OpenThai-SystemOne
Announced 20 September 2026

0.8B parameters61.9 public benchFree, Apache-2.0Thai + English
Text + questions in → answers with a confidence score out, in a single pass.
Five days after TypeSafe launched Jev (a "System One model" that generates no text but answers decisions with probabilities in one pass), the OpenThai team has released an open-source version for Thai + English, named OpenThai-SystemOne.
- 0.8B parameters, runs on a laptop
- Qwen3.5-0.8B base, continued-pretrained on ~5B Thai tokens, with the 248k-word LM head replaced by a "256-slot decision head"
- Feed it a state (text/JSON) + choice / score / yes-no questions → every question answered with confidence in one forward pass
- On the same 13-subset public benchmark as Bespoke-Nimble-9B: ours 61.9 / Nimble-9B 74.8 / Jev 76.0 / raw Qwen3.5-0.8B 45.4 (ahead of the 9B on 4 of 13 subsets). Thai tasks: intent 86.4%, news topic 97.7%, XNLI-th 76.5%
- Use it for: Text Classification, Sentiment Analysis, Agentic Computer Use (picking the action for an AI agent)
- Apache-2.0, all of it open: weights, training scripts, configs and synthetic data
The API contract mirrors TypeSafe AI's POST /v1/systemone (Jev), so existing code can point at this model unchanged.
Try it in your browser
Play with OpenThai-SystemOne in your browser + API docsiapp.co.th/docs/llm/openthai-systemone
Download and install
Code, configs and every training script — GitHubgithub.com/iapp-technology/openthai-systemone
pip install "git+https://github.com/iapp-technology/openthai-systemone"
Try it
A real exchange with the model: one customer ticket, two questions, both answered in a single forward pass (91 input tokens, 0 output tokens).
curl -s https://api.iapp.co.th/v3/store/openthai/systemone -H "apikey: $IAPP_API_KEY" -H "content-type: application/json" -d '{
"state": {"ticket": "โดนหักเงินซ้ำสองครั้ง ขอเงินคืนด่วน"},
"questions": {
"department": {"type": "choice", "instructions": "ทีมใดควรรับผิดชอบ",
"criteria": {"billing": "การเงิน/คืนเงิน", "technical": "ระบบใช้งานไม่ได้", "sales": null}},
"refund": {"type": "noul", "instructions": "ลูกค้าขอเงินคืนหรือไม่"}
}}'
{"answers": {"department": {"choice": "billing", "probabilities": {"billing": 0.972, "technical": 0.009, "sales": 0.018}, "confidence": 0.87},
"refund": {"noul": 0.954}}, "usage": {"input_tokens": 91, "output_tokens": 0}}
🔑 Public API
The endpoint https://api.iapp.co.th/v3/store/openthai/systemone on the iApp AI Marketplace takes a free iApp API key. Details and a playground are at iapp.co.th/docs/llm/openthai-systemone, or run the model on your own machine as shown below.
Run it locally (CUDA, Apple MPS or CPU):
from openthai_systemone import SystemOneClient, Choice, Score, Noul
c = SystemOneClient("iapp/OpenThai-SystemOne")
r = c.system_one(
state={"ticket": "โดนหักเงินซ้ำสองครั้ง ขอเงินคืนด่วน โทรไปสามรอบแล้วไม่มีใครรับ"},
questions={
"department": Choice(instructions="ทีมใดควรรับผิดชอบ", criteria={"billing": "การเงิน/คืนเงิน", "technical": "ระบบใช้งานไม่ได้", "sales": None}),
"frustration": Score(instructions="ลูกค้าหงุดหงิดแค่ไหน", criteria=["ใจเย็น", "หงุดหงิดแต่สุภาพ", "โกรธมาก"]),
"refund": Noul(instructions="ลูกค้าขอเงินคืนอย่างชัดเจนหรือไม่"),
},
)
print(r.answers["department"].choice, r.answers["department"].probabilities)
print(r.answers["frustration"].score, r.answers["refund"].noul)
Serve it over HTTP with the same contract as POST /v1/systemone:
OPENTHAI_SYSTEMONE_MODEL=iapp/OpenThai-SystemOne uvicorn openthai_systemone.server:app --port 8000
Or load it with plain transformers (the remote code ships in the model repo):
from transformers import AutoModel
model = AutoModel.from_pretrained("iapp/OpenThai-SystemOne", trust_remote_code=True)
Three question types
| Type | You give | You get |
|---|---|---|
choice | instructions + up to 255 options (name → description or null) | choice, probabilities for every option, confidence |
score | instructions + 2–10 ordered level descriptions | score (probability-weighted, can be fractional), probabilities, confidence |
noul | a yes/no question | noul = p(yes) |
Every question in a request is answered together in one forward pass. confidence is 1 − normalised entropy, and abstain is the probability that none of the offered options fits.
📊 Numbers
All numbers are zero-shot: the model sees only the state, the instructions and the option names and descriptions. They are for the calibrated v0.1 release.
Bespoke Labs' 13-subset public benchmark (same sources, splits, instructions and sampler used to compare against Jev), macro average:
| Model | Size | Average |
|---|---|---|
| OpenThai-SystemOne | 0.8B | 61.9 |
| Bespoke-Nimble-9B | 9B | 74.8 |
| Jev (TypeSafe AI, closed) | – | 76.0 |
| Raw Qwen3.5-0.8B | 0.8B | 45.4 |
Honest reading: the 0.8B model is ahead of the 9B on 4 of 13 subsets (MultiNLI 85.6, SummEval-consistency 84.0, HelpSteer2 42.8, Civil Comments 78.0) and clearly behind on reading-comprehension style yes/no tasks (squad2 at chance, boolq, pubmedqa) and on summary relevance scoring, the one subset where the score head is badly miscalibrated (ECE 0.79). Nimble-9B and Jev numbers are as published by Bespoke Labs (18 September 2026); ours are measured with scripts/06_eval.py on scripts/06b_public_benchmarks.py rebuilds of the same subsets. The per-dataset table with ECE is in the model card.
Thai held-out sets (full eval sets; sets marked * were held out as whole datasets; lower ECE means confidence is more trustworthy):
| Set | Task | Accuracy | ECE |
|---|---|---|---|
| Prachathai67k | news topic (choice) | 97.7 | 0.005 |
| Prachathai67k | per-topic yes/no (noul) | 94.1 | 0.008 |
| MASSIVE-th | 60-way intent (choice) | 86.4 | 0.048 |
| XNLI-th | natural language inference (choice) | 76.5 | 0.028 |
| XNLI-th | entailment yes/no (noul) | 84.3 | 0.042 |
| SIB-200 Thai* | 7-way topic (choice) | 77.5 | 0.074 |
| Thai contrastive pairs (one-fact flips) | choice / noul / score | 78.7 / 82.3 / 73.2 | 0.105 / 0.088 / 0.133 |
| Wongnai | review stars 1–5 (score) | 63.3 exact (MAE 0.44) | 0.010 |
| xLAM tool selection (English) | tool choice (choice) | 99.4 | 0.007 |
| Wisesight* | 4-class social sentiment (choice) | 38.7 (known weak spot, v0.2 targets it) | 0.341 |
| banking77* (English) | 77-way intent (choice) | 32.7 (weak) | 0.165 |
Calibration helps where the model is already competent (Thai topic and NLI, Wongnai scoring, MultiNLI: ECE at or below 0.05) and does not rescue sets where accuracy itself is low, because a temperature cannot fix a wrong ranking. On the English public bench the median ECE is 0.15, so treat confidence as reliable on the Thai sets and on NLI and topic tasks, and route low-confidence English yes/no decisions to a bigger model.
Latency — a 3-question request takes about 40 ms on an H100 and 154 ms on a MacBook M3 Max (Apple GPU via MPS). A 255-option question takes 44 ms on an H100 and 1.5 s on the MacBook. Pure CPU is still slow (about 4.6 s), so use a GPU or MPS.
⚙️ How it works
- Backbone — the text tower of Qwen3.5-0.8B-Base (24 layers, hybrid Gated-DeltaNet / attention, 262k context) with the vision encoder removed, then continued-pretrained on ~5B tokens of Thai (web, Wikipedia, parallel Thai↔English, and machine-state text such as accessibility trees and JSON).
- Decision head — the 248k-token LM head is replaced by a 256-way slot head. Options are introduced by control tokens
<|ts_opt_0|> … <|ts_opt_254|>; the hidden state at each question's<|ts_answer|>token is projected to 256 logits, slots beyond the number of options are masked, and a softmax gives the distribution. Slot 255 is abstain (none of the options fits). - Reading the answer —
choice= argmax,score= Σ pᵢ·i over the ordered levels,noul= p(yes). - No position bias — option order is shuffled in training and abstain examples are mixed in, so this is an architecture, not a trick of reading logprobs over the letters A/B/C.
🔬 Training recipe
Every stage is in the GitHub repo, one script per stage, reproducible on a single H100.
scripts/00_prepare_base.py— drop Qwen3.5-0.8B's vision encoder, keep the text tower (752M parameters).scripts/01_cpt_data.py+scripts/02_cpt_train.py— Thai-heavy continued pretraining (filtered FineWeb-2 Thai, Thai Wikipedia, Thai instruction and summary text, OPUS Thai↔English, FineWeb-Edu replay, synthetic accessibility trees and JSON). One H100, about 40 hours. Held-out perplexity 31.4 → 5.38.scripts/03_decision_data.py— 1.81M decision records converted from 21 public datasets (Thai: wisesight*, wongnai, prachathai, XNLI-th, MASSIVE-th, SIB-200*, ThaiExam, iapp_wiki_qa, Thai toxicity; English: MNLI, MMLU, ARC, HelpSteer2, AG News, DBpedia, CLINC, banking77*, Mind2Web, xLAM tools). Sets marked * were held out entirely for evaluation.scripts/03b_synth_generate.py— about 100k synthetic Thai/English decision tasks generated with Qwen3.6-35B-A3B, each blind-relabelled and filtered for answer leakage (datasetiapp/openthai2.0-systemone-synth).scripts/04_decision_train.py— head swap + 12k-step SFT, then a calibration stage (Brier loss + per-type temperature) so that higher confidence really means higher accuracy.scripts/06b_public_benchmarks.py— rebuilds Bespoke Nimble's 13-subset public benchmark for a like-for-like comparison.
👨👩👧 The OpenThai 2.0 family
| Model | What | Size | Status |
|---|---|---|---|
| OpenThai 2.0 | Thai chat and reasoning LLM, reads images | 27B | released |
| OpenThai 2.0 Legal | Thai law model for RAG | 30B-A3B | released |
| OpenThai-SystemOne | Thai + English decision model (no text generation) | 0.8B | released |
| OpenThai-SystemOne CPT | the Thai-pretrained base underneath (research use) | 0.8B | private for now |
⚠️ Limits
- Version 0.1 — a 0.8B model is not a reasoning model. It will not do multi-step verification or arithmetic.
- It can only answer with the options you give, but it can still be wrong — it cannot emit an invalid option, but it can pick the wrong one. Use the
confidencefield and route low-confidence cases to a bigger model or a human. - Text only — no images. Up to 255 options per question (bucket into groups for more) and 64k tokens per request.
- Pure CPU is still slow — use a GPU or Apple MPS.
- Known v0.1 weak spots — Thai social-media sentiment (Wisesight 38.7), fine-grained 77-way English intents (banking77 32.7), extractive-QA style yes/no (squad2 at chance), and summary relevance scoring. v0.2 adds a synthetic Thai sentiment set and a second SFT round; expect the first to move, not the others.
- English calibration is weaker than Thai — median ECE 0.15 versus 0.05 or below, because the training mix is Thai-heavy by design.
🤝 Help us build it
- More Thai test sets — especially tasks with many options and UI/agent tasks. Open an issue on GitHub.
- GGUF / ONNX / MLX — the head is a plain Linear layer, so conversions are straightforward if you know the toolchain.
- Domain LoRA adapters — share yours; the plan is "one base, N adapters".
- Talk to us on the OpenThaiGPT Discord and the Facebook group.
📄 Licence and credits
Apache-2.0. Built by iApp Technology / OpenThaiGPT on Qwen3.5-0.8B-Base (Apache-2.0). Inspired by TypeSafe AI's System One models (Jev); this is an independent open re-implementation and is not affiliated with TypeSafe AI.
🙏 Thank you, Siam AI
The Thai continued pretraining, SFT and every evaluation ran on NVIDIA H100 GPUs generously provided by Siam AI Corporation. Thank you for your continued support of open Thai AI.
