K2-Horizon-0.9B meeting agent (zh-TW), fine-tuned weights (safetensors)
IFM/K2-Horizon-0.9B adapted to zh-TW and fine-tuned as a
reading agent: it reads a live zh-TW meeting transcript window by window and writes short cited notes,
then turns the notes into a title and a prose summary. This is the best K2 checkpoint of the project
(release 2026-10-11, internal tag k2-r16n), full fp32 weights for further fine-tuning or re-export.
- GGUF (llama.cpp) build of the same weights: Luigi/K2-Horizon-0.9B-meeting-agent-zh-GGUF
- Code, agent protocol and evaluation: https://github.com/vieenrose/meeting-summarizer
| file | |
|---|---|
model.safetensors | fp32, 4,375,300,664 bytes, sha256 e4dd62f51c9d97bf6bcf366432ce4ba532b362348c3fab4bd4d3c9d90be8b9c7 |
config.json, generation_config.json | LlamaForCausalLM, vocab_size 69312, untied lm_head |
tokenizer.json, tokenizer_config.json | extended zh-TW tokenizer (see below) |
chat_template.jinja | the template used in training and deployment (no BOS, no thinking block) |
system_prompt.txt | agent system prompt, use verbatim |
title_prompt.txt, prose_prompt.txt | the two end-of-meeting conversion prompts ({journal} = the notes, one per line) |
How it was built
- zh-TW vocabulary + continued pretraining. +5,000 zh-TW BPE merges (about 30 % fewer tokens on zh-TW), continued pretraining on zh-TW web text and meeting transcripts with general replay.
- Agent SFT on reading-agent turns distilled from a larger teacher.
- On-policy DPO rounds (full fine-tuning, β 0.1, NLL 0.5 on the chosen side, lr ≤ 3e-6), each round on pairs sampled from the current model and ranked by an LLM judge against the transcript: contradicted-note fixes (≈ 2,200 pairs), speaker-binding swaps, prose, titles, and finally missed-key-point "replace" pairs (the nearest wrongly-stated note replaced by the correct one). Conservative DPO (label smoothing 0.1) on the judge-ranked rounds; ~1,000 replay rows of earlier rounds each time.
Results
38 held-out zh-TW meetings transcribed by ASR, 4k context, window 1,500 tokens, GGUF Q8_0 on llama.cpp, student decoding T 0.2; judge Gemma-4-31B checks each cited statement against the transcript. Two full runs (run-to-run noise ≈ ±2 points / ±0.015 coverage).
| run 1 | run 2 | target (fine-tuned Gemma-4-E2B) | |
|---|---|---|---|
| notes contradicted by the transcript | 13 % | 10–12 % | 17 % |
| notes unsupported | 1–2 % | 3 % | 5 % |
| coverage of the reference key points | 0.92 | 0.89 | 0.92 |
| title score (1–5, mean of 4 runs) | 4.15 | 4.05 | |
| prose sentences supported by the notes | 87.7 % | 88 % | 86.6 % |
The Gemma-4-E2B reference was measured with its mobile runtime, this model with llama.cpp Q8_0. Prefer 8-bit: int4 cost about 7 points of contradiction in our tests.
Use (agent protocol)
One fresh conversation per transcript window (about 1,500 tokens) with the compacted journal of earlier notes
at its head; the model answers with at most 5 lines NOTE [time] (TYPE) text (or REVISE #id [time] text), then NEXT.
Stop at NEXT and cap replies at about 400 tokens. Types: DECISION, ACTION, PROPOSAL, OPEN-ISSUE, NUMBER, -.
Rendered note line, as fed back in the journal and to the conversion prompts: #1 [1:23] (DECISION) 預算照案通過.
The title and prose prompts are single user turns with no system turn.
from transformers import AutoTokenizer, AutoModelForCausalLM
repo = "Luigi/K2-Horizon-0.9B-meeting-agent-zh"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo, torch_dtype="bfloat16")
Tokenizer
Extended vocabulary, not the base IFM tokenizer: 5,000 zh-TW merges at ids 64256–69255; 69,256 tokens,
embedding matrix padded to 69,312 rows. bos <|begin_of_text|> 0 (the model was trained without BOS; the chat template adds none),
<|ifm|im_start|> 64018, <|ifm|im_end|> (eos) 64019, pad 64255. Never pair these weights with the base
tokenizer: ids above 64255 differ.
No training data is included. License: Apache-2.0 (base model).