Skip to content

docs(apertus): document chat-template format#93

Merged
michalharakal merged 1 commit into
developfrom
feature/apertus-chat-template-docs
May 1, 2026
Merged

docs(apertus): document chat-template format#93
michalharakal merged 1 commit into
developfrom
feature/apertus-chat-template-docs

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Summary

PR 2 of the Apertus rollout (see APERTUS_ROLLOUT.md). Researches the actual chat-template format Apertus models expect, before PR 3 implements ApertusChatTemplate against it. Sources fetched from HuggingFace swiss-ai/Apertus-8B-Instruct-2509 2026-05-01.

Headline finding

Apertus is NOT chatml-compatible. The previous ModelRegistry.kt:66 setting chatTemplateFamily="chatml" was a fallback guess; this PR corrects it to "apertus".

Apertus has its own role tokens (<|system_start|>, <|developer_start|>, <|user_start|>, <|assistant_start|>, <|inner_prefix|>, <|tools_prefix|> — no overlap with chatml / llama3 / gemma), renders tools as TypeScript-style type declarations (not JSON Schema), emits a default system message + a developer block unconditionally, and uses a JSON-array tool-call format wrapped in <|tools_prefix|>...<|tools_suffix|>.

Full spec at docs/specs/apertus-chat-template.md (mirrors the existing markdown convention from docs/specs/spring-ai-adapter.md):

  • Per-role token table
  • Turn structure with examples
  • Tool-capability rendering (TypeScript types macro behavior)
  • Tool-call output format from the model
  • Parser strategy outline for ApertusToolCallParserStrategy (PR 3)
  • Comparison table vs chatml / llama3 / gemma2
  • Four canonical parity test cases for ApertusChatTemplateHfParityTest (PR 3)
  • Implementation notes (the Jinja macro complexity → "use Jinja runtime, don't port to hand-coded Kotlin" recommendation for PR 3)

Changes

  • docs/specs/apertus-chat-template.md (new) — the spec.
  • llm-core/.../ModelRegistry.kt:66chatTemplateFamily "chatml""apertus". supportsToolCalling=false stays; PR 3 flips it once the chat template + parser ship.
  • APERTUS_ROLLOUT.md — PR 2 checkbox ticked, status header advanced.

Test plan

  • :llm-core:jvmTest green (chatTemplateFamily change has no behavior impact today — ToolCallingSupportResolver has no "apertus" branch yet, so the fallback path is unchanged).
  • CI green
  • Reviewer reads the spec, the four canonical parity cases, and the "use Jinja runtime not hand-coded Kotlin" recommendation make sense before PR 3 starts.

Out of scope

  • ApertusChatTemplate.kt, ApertusToolCallingSupport.kt, registration in ToolCallingSupportResolver.kt, flipping supportsToolCalling=true — all PR 3.
  • Verifying against a real Apertus GGUF — done via HuggingFace swiss-ai/Apertus-8B-Instruct-2509 source files (chat_template.jinja, tokenizer_config.json, special_tokens_map.json), the canonical authority for the format.

🤖 Generated with Claude Code

PR 2 of the Apertus rollout (APERTUS_ROLLOUT.md). Researches the
actual chat-template format Apertus models expect, before PR 3
implements ApertusChatTemplate against it. Sources fetched from
HuggingFace `swiss-ai/Apertus-8B-Instruct-2509` 2026-05-01:
chat_template.jinja (14601 bytes), tokenizer_config.json,
special_tokens_map.json.

Findings (full spec lives in docs/specs/apertus-chat-template.md):

1. Apertus is NOT chatml-compatible. The previous
   ModelRegistry.kt:66 setting `chatTemplateFamily="chatml"` was
   a fallback guess; this PR corrects it to `"apertus"` so the
   forthcoming PR 3 resolver branch dispatches correctly.

2. Apertus has its own role tokens:
     <|system_start|>...<|system_end|>
     <|developer_start|>...<|developer_end|>
     <|user_start|>...<|user_end|>
     <|assistant_start|>...<|assistant_end|>   (EOS = <|assistant_end|>)
     <|inner_prefix|>...<|inner_suffix|>      (deliberation block)
     <|tools_prefix|>[...]<|tools_suffix|>    (tool calls)
   No overlap with chatml/llama3/gemma. Needs its own
   ApertusChatTemplate.kt + ApertusToolCallingSupport.kt.

3. Tools render as TypeScript-style type declarations, not JSON
   Schema. The Jinja `render_tools` macro emits:
     // <description>
     type <name> = (_: { param: type }) => any;
   PR 3 either ports the recursive type-lowering Jinja macro
   verbatim into Kotlin, or keeps a Jinja runtime (Pebble/jinjava)
   and just substitutes the tools array. The doc flags Jinja-runtime
   as the lower-risk path given the macro's complexity (oneOf,
   nullable, enum, array).

4. A developer block is emitted UNCONDITIONALLY after the system
   message — it carries `Deliberation: enabled|disabled` and
   `Tool Capabilities:` (either rendered tools or the literal
   string `disabled`). PR 3's chat template must emit this even
   when no tools are present.

5. When the caller doesn't supply a system message, the template
   emits a default:
     "You are Apertus, a helpful assistant created by the SwissAI
      initiative.\nKnowledge cutoff: 2024-04\nCurrent date: <YYYY-MM-DD>"
   The model is trained on this; PR 3 must mirror it.

6. Tool-call output format from the model:
     <|tools_prefix|>[{"<tool>": <args_json>}, ...]<|tools_suffix|>
   Single-key JSON objects in a JSON array; multiple parallel calls
   stack with comma separation. Parser strategy spelled out in the
   doc (PR 3 implements ApertusToolCallParserStrategy against this).

Changes in this PR:

- docs/specs/apertus-chat-template.md (NEW): the spec, with
  comparison table vs chatml/llama3/gemma2, role-by-role token
  table, tool format details, parser strategy outline, four
  canonical parity test cases for PR 3 to assert byte-for-byte.

- llm-core/.../ModelRegistry.kt:66:
    APERTUS("apertus", "Apertus", false, "chatml")
        → APERTUS("apertus", "Apertus", false, "apertus")
  `supportsToolCalling=false` stays — PR 3 flips it once
  ApertusChatTemplate + ApertusToolCallingSupport land. Updating
  chatTemplateFamily early is harmless: ToolCallingSupportResolver
  has no "apertus" branch yet, so the fallback path
  (GenericToolCallingSupport) is unchanged.

- APERTUS_ROLLOUT.md: PR 2 checkbox ticked; status header advanced.

Verification:
- :llm-core:jvmTest green (no behavior change).
- Doc renders cleanly; ready for PR 3 to consume as the
  specification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@michalharakal michalharakal merged commit fad07b9 into develop May 1, 2026
4 checks passed
@michalharakal michalharakal deleted the feature/apertus-chat-template-docs branch May 1, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant