| --- |
| license: apache-2.0 |
| base_model: Qwen/Qwen3.5-9B |
| tags: [accounting, thai, bookkeeping, structured-output, qwen3.5, image-text-to-text, rag] |
| language: [th, en] |
| pipeline_tag: image-text-to-text |
| extra_gated_heading: "Accept the terms before using TAI-1 (Thai Account Assistant)" |
| extra_gated_prompt: | |
| TAI-1 produces DRAFT accounting entries. Its tax rules and account mappings have NOT been |
| reviewed by a licensed Thai accountant or auditor, and its outputs may be wrong. By requesting |
| access you agree that: |
| (1) You will have every output REVIEWED by a licensed bookkeeper (ผู้ทำบัญชี) or auditor |
| (ผู้สอบบัญชี) before it is posted to a ledger, filed with the Revenue Department, or used |
| in any financial statement. |
| (2) You will not treat the model's outputs as tax or legal advice, and will not present them to |
| any third party as the opinion of a licensed professional. |
| (3) You will supply the applicable tax rules through the prompt (retrieval) rather than relying |
| on rates memorised in the weights — Thai tax rates and filing forms change by law. |
| (4) You understand that I C Develop Co., Ltd. accepts no liability for use that violates these |
| terms. |
| |
| TAI-1 สร้าง "ร่าง" การลงบัญชี เกณฑ์ภาษีและการจับคู่ผังบัญชียังไม่ผ่านการตรวจสอบโดยผู้ทำบัญชี |
| หรือผู้สอบบัญชีที่มีใบอนุญาต ผลลัพธ์อาจผิดได้ การขอสิทธิ์เข้าใช้งานถือว่าท่านยอมรับว่า |
| (1) จะให้ผู้ทำบัญชีหรือผู้สอบบัญชีตรวจสอบทุกผลลัพธ์ก่อนบันทึกลงสมุดบัญชี ยื่นต่อกรมสรรพากร |
| หรือนำไปใช้ในงบการเงิน |
| (2) จะไม่ถือว่าผลลัพธ์เป็นความเห็นทางภาษีหรือกฎหมาย และจะไม่นำเสนอต่อบุคคลอื่นในลักษณะที่ |
| ทำให้เข้าใจว่าเป็นความเห็นของผู้มีวิชาชีพ |
| (3) จะส่งเกณฑ์ภาษีที่ใช้บังคับเข้ามาทาง prompt แทนการพึ่งอัตราที่ฝังอยู่ใน weights เพราะอัตรา |
| ภาษีและแบบยื่นของไทยเปลี่ยนตามกฎหมาย |
| (4) บริษัท ไอ ซี ดีเวลลอป จำกัด ไม่รับผิดชอบต่อการใช้งานที่ขัดกับเงื่อนไขข้างต้น |
| extra_gated_fields: |
| I accept all 4 terms and will have a licensed accountant review every output: checkbox |
| Organization / intended use: text |
| --- |
| |
| # TAI-1 — Thai Account Assistant (Qwen3.5 9B) · build v2b-coa (2026-08-04) |
|
|
| **Draft-grade by design: every output must be reviewed by a licensed Thai bookkeeper or auditor |
| before it is used — accepting that condition is what the access gate asks of you.** The team's |
| reading of the underlying tax texts has itself not been signed off by a licensed professional. |
|
|
| A bookkeeping assistant for Thai accounting firms, fine-tuned from |
| [`Qwen/Qwen3.5-9B`](https://huggingface.co/Qwen/Qwen3.5-9B) (Apache-2.0). |
|
|
| ## 1. What it does |
|
|
| TAI-1 does **not** write debit/credit lines. It reads a document and returns a |
| **posting template code plus parameters**; the ICD-ACC posting engine renders the journal |
| entry. The answer space is closed — 61 templates, 218 accounts — so every axis is scored in |
| code. No LLM judge is used anywhere in this evaluation. |
|
|
| ## NEW in this build — firm chart-of-accounts mapping (`coa_mapping_draft`) |
|
|
| Maps an accounting firm's **own account names** (their phrasing, abbreviations, even typos) to |
| the standard chart. Ground truth: **102 pairs individually verified by a licensed bookkeeper** |
| on a signed review form; 6 further pairs the reviewer rejected are excluded everywhere. |
|
|
| Measured head-to-head on those 102 pairs — this capability is why the build exists, and the |
| previous build simply does not have it: |
|
|
| | prompt setup | this build | previous build (no CoA training) | |
| |---|---:|---:| |
| | account catalog in prompt (bare) | **99.0%** (101/102) | **32.4%** (33/102) | |
| | + 8 similar verified examples | **82.4%** (84/102) | **52.0%** (53/102) | |
|
|
| **Integration rules (measured, not stylistic) — full guide in `INTEGRATION-ICD-ACC.md` in this |
| repo:** |
|
|
| 1. Names an accountant already confirmed → **exact lookup, no model call.** |
| 2. Unseen names → call the model **bare** with the account block, exactly in its trained format. |
| **Do not add few-shot examples on top of this build** — it scores *lower* with them (the |
| table above is the measurement). |
| 3. Schema-validate: the answer must be a code from the catalog; reject anything else. |
| 4. The 99% column is on vocabulary this build was trained on (two firms). A new firm's unseen |
| phrasings will score between the two columns until its own verified store grows — the |
| lookup-first loop in the integration guide is how accuracy climbs **without retraining**. |
|
|
|
|
| ## 2. Getting the most out of it |
|
|
| ### 2.1 You must put the law in the prompt. This is not optional. |
|
|
| Measured on the tax axis: **100% with the rules supplied, 36.7% without.** The model was |
| deliberately trained to *apply rules it is given* rather than recall them, because Thai tax |
| rates and filing forms change by statute. A model that remembers them is wrong the day the |
| law changes and nobody notices. |
|
|
| The knowledge base is at [`icdevelop/tai1-kb`](https://huggingface.co/datasets/icdevelop/tai1-kb) (separate |
| access request). Without it you get answers worse than the numbers below, and confidently wrong. |
|
|
| ### 2.2 Retrieve the way the training data was built |
|
|
| This build was trained with legal context in **every** record, assembled by a specific rule. |
| Serving a differently-shaped context puts the prompt outside the distribution the model saw — |
| that cost the previous build 14 points (100% to 86%). |
|
|
| | Question about | Send | |
| |---|---| |
| | Input VAT | ประกาศอธิบดีฯ ฉ.17 + ฉ.42 — **whole documents** (~17k chars) | |
| | Withholding tax | ท.ป.4/2528 — **whole document** (~34k chars) | |
| | Prohibited expenses / add-back | ประมวลรัษฎากร ม.65 ตรี — **the whole (1)–(20) list** | |
| | Financial-statement line items | ประกาศ DBD 2566 — **top-4 chunks** (~11k chars) | |
|
|
| **Send whole documents for the tax questions.** Chunk-level retrieval scored 13 points worse |
| even when it retrieved the correct clause, because most of these questions are answered by a |
| rule's *absence*: "not prohibited" is only knowable if you can see the entire prohibition list. |
| Partial retrieval cannot tell "not on the list" from "not sent to me". |
|
|
| The DBD axis is the exception and proves the principle — there the candidate answers are already |
| in the prompt, so chunk retrieval is fine. **The question type decides the retrieval mode, not |
| the document size.** `kb_retrieve.py` ships with the KB; use it as-is. |
|
|
| ### 2.3 Settings that must match training |
|
|
| | | Value | If you deviate | |
| |---|---|---| |
| | chat template | `qwen3_nothink` | thinking mode measured **18.0%** — tokens go to reasoning and the JSON never arrives | |
| | context window | **at least 24,576 tokens** | longest prompt measured 21,175 tokens; shorter truncates the statute silently | |
| | temperature | 0 or near 0 | output is JSON checked by code | |
|
|
| ### 2.4 Supply business type as its own fact |
|
|
| The passenger-car input VAT exception turns on **the taxpayer's own line of business** (dealers, |
| rental firms and motor insurers may claim). Leaving it inside prose is not enough: |
|
|
| ``` |
| ประเภทธุรกิจของกิจการผู้เสียภาษี: ให้เช่ารถยนต์ |
| ``` |
|
|
| ### 2.5 Ask for the clause, not just the answer |
|
|
| On the add-back axis, requiring the sub-section alongside the answer raised accuracy from 67.9% |
| to 75.0%. More importantly, **wrong answers become visibly wrong** — a reviewer sees |
| "audit fee → 65ตรี(4) entertainment" and rejects it instantly, rather than a bare `true` that |
| reads as authoritative. When the item genuinely is on the list, the cited sub-section is right |
| 16 times out of 17. |
|
|
| ``` |
| ตอบ: {"add_back": true หรือ false, "clause": "<เช่น 65ตรี(6)>" หรือ null} |
| ``` |
|
|
| ## 2.6 Optional documents — what each one buys, and how to add it |
|
|
| The model degrades gracefully: with no reference documents at all it still answers, just far |
| worse and with misplaced confidence. Each document you install lifts a specific axis by a |
| measured amount. **You do not need all of them.** Install what matches the work you do. |
|
|
| | Document | Lifts | Measured effect | Ships with the KB? | |
| |---|---|---|---| |
| | ประกาศอธิบดีฯ ฉ.17 + ฉ.42 | input VAT | tax axis **36.7% → 100%** | ✅ yes | |
| | ท.ป.4/2528 | withholding rates and forms | same axis, same lift | ✅ yes | |
| | คู่มือเอกสารประกอบการลงบัญชี (RD) | required supporting documents | evidence axis **0/60 → 10/60** exact, recall 0.47 → 0.77 | ✅ yes | |
| | ประกาศ DBD 2566 | financial-statement line items | statement axis **85.3% → 97.1%** | ✅ yes | |
| | ประมวลรัษฎากร ม.65 ตรี | prohibited expenses / add-back | add-back axis **53.6% → 75.0%** | ✅ yes | |
| | **TFRS for NPAEs** | recognition, measurement, provisions | ⚠️ **not measured — see below** | ❌ **you must supply it** | |
|
|
| ### Adding a document we cannot ship |
|
|
| **TFRS for NPAEs** belongs to TFAC and we have no right to redistribute it. Most Thai accounting |
| firms already hold a licensed copy. To add yours: |
|
|
| ```bash |
| # 1. extract, with the Thai-character sentinel check |
| python3 extract_reference.py --pdf /your/path/tfrs-npaes.pdf --out reference-docs/tfrs-npaes.txt |
| |
| # 2. chunk it into the KB (the config entry already exists) |
| python3 build_reference_kb.py |
| ``` |
|
|
| Then make the retriever aware of it — it is deliberately **not** wired up, so that a missing |
| document can never silently shorten anyone's context: |
|
|
| ```python |
| KIND_DOCS["recognition"] = ("tfrs-npaes",) |
| ``` |
|
|
| ⚠️ **Do not trust the extraction without checking.** Thai PDFs lose characters several ways and |
| one of them is unrecoverable. Ours measured 8.3% tone marks, 9.3% vowel signs, zero |
| private-use-area characters. If yours differs a lot, the extraction is broken — do not load it. |
|
|
| ⚠️ **We publish no number for TFRS because we have never used it.** It has never been placed in |
| any prompt, so claiming a lift would be an invention. Measure it on your own data before relying |
| on it. Everything needed to do that ships with the KB. |
|
|
| ## 2.7 The model tells you what it is missing — and this makes it better, not worse |
|
|
| When a question needs a document that is not installed, the serving code states that fact and |
| the model reports it back alongside its answer: |
|
|
| ``` |
| ตอบ: {"add_back": true หรือ false, "clause": "<เช่น 65ตรี(6)>" หรือ null, |
| "missing_reference": ["<ชื่อเอกสารที่ขาด>"] หรือ []} |
| ``` |
|
|
| `kb_retrieve.missing_docs()` computes the gap by comparing what a question type needs against |
| what is loaded, so it fires only when something is genuinely absent. |
|
|
| Measured on the add-back axis with ม.65 ตรี removed from the KB: |
|
|
| | | accuracy | flags the gap | |
| |---|---:|---:| |
| | document missing, model not told | 53.6% | 0 / 28 | |
| | document missing, told **"answer with what you have"** | **32.1%** | 26 / 28 | |
| | document missing, told **as a plain fact** | **60.7%** | 23 / 28 | |
| | document present | 75.0% | — | |
|
|
| ⚠️ **The wording is the whole thing.** Phrasing the notice as an instruction to hold back cost |
| **21 points** — the model reported the gap correctly and then stopped trying. Stating the absence |
| as a fact and asking it to answer as well as it can, noting what would confirm the answer, beats |
| saying nothing at all by **7 points** while still flagging 23 of 28 cases. |
|
|
| So an installation missing an optional document is not merely tolerated — as long as the serving |
| layer declares the gap plainly, the model does better than if it had never been told. Do not |
| rewrite that notice into a hedge. |
|
|
| ## 3. Cautions |
|
|
| 1. **Output is a draft. A licensed bookkeeper or auditor must review it** before anything is |
| posted, filed, or placed in a financial statement. It is not tax or legal advice. |
| 2. **Tax criteria come from Revenue Department texts, but our reading of them is not signed |
| off.** Clause citations exist so a reviewer can check the reading instead of trusting it. |
| 3. ⚠️ **Known bias: showing the model a prohibition list makes it over-apply that list.** |
| Observed on three separate axes. On add-back, ordinary deductible costs — office rent, |
| factory electricity, raw materials, audit fees — are flagged for add-back 7 times in 10. |
| **Treat any "prohibited" answer as a candidate for review, never as a conclusion.** |
| 4. **The add-back and statement axes have never been trained.** They are measurements of base |
| behaviour published for transparency, not capabilities. Do not build on them yet. |
| 5. **The pnd3/pnd53 form mapping has no cited source.** It appears in none of the fetched |
| documents; it is a team convention, labelled as uncited inside the prompt, and needs sign-off. |
| 6. **Rates have a time dimension.** The 1.0% e-withholding rate expired 31 December 2025. |
| Back-dated documents need the text in force on their own date. |
| 7. **Do not rely on rates baked into the weights.** The model recalls roughly 37% of tax |
| knowledge unaided, by design. |
|
|
| ## 4. Results |
|
|
| Measured with the KB in the prompt and retrieval matching training. |
|
|
| | แกน | ผล | จำนวนเคส | |
| |---|---:|---:| |
| | จับคู่ผังบัญชี | **96.0%** | 200 | |
| | รายจ่ายบวกกลับ ม.65 ตรี — รายงานอย่างเดียว ไม่เคยเทรน | **64.3%** | 28 | |
| | คำนวณจำนวนเงิน | **98.7%** | 150 | |
| | รู้ว่าเมื่อไหร่ข้อมูลไม่พอ — รายงานอย่างเดียว | **86.1%** | 101 | |
| | เอกสารประกอบที่กฎหมายต้องการ | **18.3%** | 60 | |
| | รายการย่อของงบการเงิน (DBD) — รายงานอย่างเดียว ไม่เคยเทรน | **97.1%** | 34 | |
| | ภาษี (ข้อยกเว้น) — รายงานอย่างเดียว ไม่ใช่ gate | **95.2%** | 21 | |
| | ภาษี (เคสธรรมดา) | **98.0%** | 150 | |
| | เลือก template ถูกต้อง | **100.0%** | 200 | |
| | อ่านใบกำกับภาษีจากภาพสแกน (hard-scan 200 ภาพ ครบทุก field) | **77.5%** | 200 | |
|
|
| Small axes (21–34 cases) are report-only — one case moves them 3–5 points. The hard gates are |
| template ≥90, account ≥80, ordinary tax ≥95, amounts ≥98, schema violations = 0; this build |
| passes all of them. |
|
|
| ## 5. How the evaluation works |
|
|
| * **Everything is scored in code.** The label space is closed, so answers compare directly. |
| * **Templates are split by hash into train and holdout**, and the corpus is built only from the |
| train side, so holdout numbers measure generalisation. 26 of 61 templates are held out. |
| * **Two-layer decontamination.** Corpus phrase banks are disjoint from the benchmark, and every |
| record is then re-checked by token overlap; the build fails if anything crosses the threshold. |
| * **Boolean axes carry control cases and are reported per side.** The exceptions axis has 6 |
| controls in 21, add-back has 10 in 28. Without them add-back would read 18/18 and the |
| conclusion would be exactly backwards — see caution 3. |
| * **Small axes are report-only.** At 21–34 cases one case is 3–5 points; use them for direction |
| and for reading individual failures, never as a gate. |
| * **The image axis is mandatory for quantised builds.** Text benchmarks cannot detect a damaged |
| vision tower — a model with no image processor at all still passes every text axis. |
|
|
| ## 6. The knowledge base is a separate download |
|
|
| Not bundled with the weights. It lives at |
| [`icdevelop/tai1-kb`](https://huggingface.co/datasets/icdevelop/tai1-kb), also private and gated. |
|
|
| It holds **98 chunks from five Revenue Department documents plus the DBD notification** — laws, |
| Director-General notifications and official manuals, which under section 7 of the Thai Copyright |
| Act B.E. 2537 are not copyright works and may be redistributed. |
|
|
| ⚠️ **TFRS for NPAEs is deliberately excluded.** It belongs to the Federation of Accounting |
| Professions (TFAC) and is not a government work under section 7; a private repository is access |
| control, not a licence. **No number reported here depends on it** — it has never been placed in |
| any prompt, which is checkable three ways and documented in the KB repo. If you need it, the KB |
| ships `ADD-YOUR-OWN-TFRS.md` explaining how to add your own licensed copy with the same |
| extraction scripts. |
|
|
| ## 7. Training data |
|
|
| 3,866 records, one epoch, every tax description textually distinct. Two sources: |
|
|
| * **3,764 synthetic records** built from the posting-template catalog, the chart of accounts, |
| and the statutes — the same generator family as the previous build. |
| * **102 real chart-of-account *names*** from two Thai accounting firms, each mapping verified |
| by a licensed bookkeeper before entering the corpus. These are account names only |
| (e.g. "ค่าเสื่อมราคาสะสม-ยานพาหนะ") — **no customer documents, no transactions, no amounts, |
| no personal data**; firm identity is not recoverable from them. |
|
|
| --- |
| I C Develop Co., Ltd. · public release under continuing review — the access gate's accountant-review condition applies to every use |
|
|