Ingot — Chrono SLM (Qwen3-0.6B)

Turns a Japanese or English scheduling sentence into a strict RFC 5545 object: an RRULE, an ISO-8601 local start, an IANA timezone, a duration, exception dates, and a holiday-avoidance policy.

Trained entirely on NagaYu/ingot-chrono, whose labels were constructed before their sentences existed. Code: github.com/NagaYu/ingot.

Read this before using the model

A hand-written dateutil parser beats this model on every split — 90.5% vs 67.5% exact match on test, and the gap is statistically significant (McNemar p = 2.5e-05). If your inputs resemble this dataset's surfaces, use the parser (baseline_rule.py), not this model.

The checkpoint is also deliberately undertrained: 1,000 optimiser steps, roughly 8% of one epoch, stopped so the GPU could run the evaluation inside one session. Validation loss was still falling monotonically (0.042 → 0.024 → 0.013 at steps 200/400/800).

It is published as a reproducible reference point for the Ingot pipeline, not as a recommended parser. The honest artifact of this project is the dataset.

Files in this repository

path what size
*.safetensors, config.json, tokenizer* (root) MLX 4-bit, ready for mlx_lm.load 335 MB
gguf/ingot-chrono-Q4_K_M.gguf llama.cpp, works with the bundled GBNF grammar 384 MB
adapter/adapters.safetensors the raw LoRA (r=16), for fusing onto the base yourself 11 MB

The bf16 fused checkpoint (1.1 GB) and the Q8_0 GGUF (624 MB) are not uploaded — both are reconstructible from the adapter in about a minute:

python -m mlx_lm fuse --model Qwen/Qwen3-0.6B --adapter-path adapter --save-path fused

Usage

from mlx_lm import load, generate

model, tokenizer = load("NagaYu/ingot-chrono-qwen3-0.6b")

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},   # ingot.prompts.SYSTEM_PROMPT
    {"role": "user", "content": "Today: 2026-04-01 (Wednesday)\nDefault timezone: Asia/Tokyo\n\n"
                                "毎月第2水曜10:30から45分、祝日なら前営業日に"},
]
prompt = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True, enable_thinking=False, tokenize=False
)
print(generate(model, tokenizer, prompt, max_tokens=160))
{"dtstart":"2026-04-08T10:30:00","tzid":"Asia/Tokyo","rrule":"FREQ=MONTHLY;BYDAY=2WE","duration_minutes":45,"exdate":[],"holiday":{"calendar":"JP","shift":"before"}}

enable_thinking=False is required. Qwen3 is a hybrid-thinking model. That flag makes the generation prefix end with an empty <think></think> block, exactly matching the training rows. Leave thinking on and the model emits a monologue instead of JSON.

reference_date and default_tz are supplied in the prompt because the sentence cannot determine them. Without them, relative expressions ("来週頭", "next Monday") would be unanswerable rather than hard.

Grammar-constrained decoding (GGUF)

python -c "from ingot.decode import save_gbnf; save_gbnf('schedule.gbnf')"
llama-cli -m gguf/ingot-chrono-Q4_K_M.gguf --grammar-file schedule.gbnf -p "$PROMPT"

Evaluation

n = 200 per split, greedy decoding, exact match on RRULE + DTSTART + TZID after canonicalising every system's output. (A) is the hand-written parser, (D) this model at bf16, (E) the Q4_K_M GGUF under grammar constraints. Frontier-API baselines could not be run (no credential) and are reported as n/a, never as zero.

split (A) rules (D) bf16 (E) Q4_K_M quantization cost
test 90.5% 67.5% 65.5% 2.0 pts
unseen_template 90.0% 67.5% 60.0% 7.5 pts
unseen_combo 77.0% 47.5% 44.0% 3.5 pts

Two things worth more than the headline column:

Semantic accuracy is much higher than exact match. On test, (D) scores 67.5% exact but 83.5% occurrence-exact — in a sixth of cases it writes a rule that is not byte-identical to the gold RRULE yet produces the same next ten meetings. Exact match is the strict metric; occurrence match is the one a calendar user would feel.

The two approaches fail on opposite languages. On unseen_combo:

system ja en
(A) rule-based 64.0% 98.7%
(D) this model 52.8% 38.7%

That is the one slice where they look complementary rather than ranked.

Syntax validity

decoding syntax valid
free (bf16) 98.5%
GBNF-constrained (Q4_K_M) 100%

Measuring this found a real bug: the grammar admitted FREQ=WEEKLY;BYDAY=1TU, an ordinal weekday under WEEKLY, which RFC 5545 forbids. All grammar dialects now couple the ordinal to the frequency, and a test pins the invariant that the grammar must be a subset of valid specs.

Speed (Apple M2, 16 GB, real ~250-token prompt, batch 1)

build tok/s time to first token peak RSS
MLX 4-bit 104.9 279 ms 946 MiB
GGUF Q4_K_M 96.4 57 ms 1632 MiB

Training

base Qwen/Qwen3-0.6B (596M params)
method LoRA r=16, alpha=32, dropout=0.05
target modules q/k/v/o/gate/up/down projections, top 16 layers
trainable 2.88M params (0.48%)
data NagaYu/ingot-chrono, train split only
steps 1,000 (≈4,000 samples, ≈8% of one epoch)
sequence length 448 (corpus p99 is 433)
loss completion-only (prompt masked)
hardware Apple M2, 16 GB — no discrete GPU
throughput 0.44 it/s, 3.6 GB peak, ≈38 min
final val loss 0.013
python scripts/build_dataset.py --n 24000 --variants 2
python scripts/train_lora.py --base Qwen/Qwen3-0.6B --iters 6000   # longer than the release
python scripts/merge_and_quantize.py --model runs/qwen3-0.6b-chrono

Limitations

  • Synthetic surfaces. Sentences come from 31 templates plus label-preserving noise operators. Transfer to open-world scheduling text is untested and not claimed.
  • Undertrained, and beaten by a rule parser — see the box at the top.
  • Quantization is not free, and costs most out of distribution (7.5 points on unseen_template). The repository's quantization budget test fails on this, on purpose.
  • Two holiday calendars only (JP, US); years 2026–2028; the Japanese calendar excludes the one-off 2020–2021 Olympic moves.
  • Not a general assistant. It emits one JSON object and nothing else.

Citation

@software{ingot2026,
  title  = {Ingot: inverted generation for strictly-labelled synthetic data},
  author = {NagaYu},
  year   = {2026},
  url    = {https://github.com/NagaYu/ingot}
}

Apache-2.0. The base model carries its own licence.

Downloads last month
260
Safetensors
Model size
0.6B params
Tensor type
U32
·
BF16
·
MLX
Hardware compatibility
Log In to add your hardware

4-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for NagaYu/ingot-chrono-qwen3-0.6b

Finetuned
Qwen/Qwen3-0.6B
Adapter
(573)
this model

Dataset used to train NagaYu/ingot-chrono-qwen3-0.6b