Prhub

#2013 [tito] Add the Inkling TITO family (Inkling / Inkling-Small)

原始 PR 作者 Zhichenzzz 合并时间 2026-08-01 01:12 文件变更 8 提交数 2 评论 1 代码增减 +384 / -1

执行摘要

新增 Inkling 家族 TITO 支持,可跑多轮会话

PR body 明确说明目标:'Registers TITOTokenizerType.INKLING so the session server can drive multi-turn / agentic rollouts on Inkling and Inkling-Small'。Inkling 家族靠 HF 仓库自带的 chat_template.jinja 渲染,且与 sglang 的 token 级 renderer 渲染等价,因此接入时不需要固定模板 override 或边界胶水:子类只需固定 assistant 起始标记、声明消息边界特殊 token、绑定 sglang 的 inkling 推理 / 工具解析器。工具调用解析侧的能力来自关联的 sgl-project/sglang#32958(Fix Inkling tool-call parsing recovery),本 PR 依赖该修复后的 serving 行为。

值得精读,重点看三个设计决策:

1) 优先复用 HF 原生 chat_template.jinja,仅把固定模板用作测试渲染基准,避免双份渲染逻辑长期漂移;
2) 用四个角色 sentinel 固化 comparator 边界,把 assistant 轮之后的非 assistant 内容差异提升为硬失败,这是 TITO 追加式会话正确性的关键;
3) 大权重进不了 CI 时先用 slice 手动验证并如实记录缺陷边界,而不是注册无人验证过的配置。建议结合 sgl-project/sglang#32958 的解析器修复一起阅读,理解 serving 侧约束。

讨论亮点

review 交互非常轻:guapisolo 先以 DISMISSED 状态评论 LGTM,随后在 CI passed 后正式 APPROVED,无实质代码讨论。核心经验记录在 PR body 中:作者手动在 6 层 surgery checkpoint(8×H200、双 sglang 引擎 TP4/EP4、megatron actor TP4+SP)上跑 session-server e2e,128 个样本 0 个 token 序列失配;同时记录了两个非 TITO 缺陷——1) slice 无法产生格式良好的 tool call,无法满足 harness 的 append_tool 覆盖门;

2) temperature 0.7 sampling 下近随机输出偶尔复现 Inkling 自己的消息边界特殊 token,造成 segment-count mismatch(37 vs 39 段),greedy 解码可消除。这些记录为后续全权重验证提供了直接参考。

实现拆解

  1. 注册 TITO 子类与工厂:在 miles/utils/chat_template_utils/tito_tokenizer.py 中新增 InklingTITOTokenizer,类属性把 reasoning_parsertool_call_parser 均绑定为 inkling__init__<|message_user|><|message_model|><|message_system|><|message_tool|> 四个角色 sentinel 传入 special_token_ids,使 comparator 在 assistant 轮之后把非 assistant 内容差异判为硬失败(NON_ASSISTANT_TEXT)。随后在 TITOTokenizerType 枚举中新增 INKLING = inkling,并在 get_tokenizer_class 工厂中完成映射,使 CLI 参数 --tito-model inkling 可解析。
  2. 新增固定渲染模板:新增 miles/utils/chat_template_utils/templates/inkling_fixed.jinja(133 行),按 HF 原生模板语义复刻 sglang token 级 renderer 的空 scalar-content 行为:空 content 不渲染空 text block、纯工具调用轮不输出 bare assistant terminator、tool call 参数必须是已解析对象而非 JSON 字符串;模板同时登记到 tests/fast/utils/chat_template_utils/test_fixed_templates.py 的固定模板注册表,供家族覆盖测试校验。
  3. 扩展会话验证 harnessmiles/utils/test_utils/session_verify_runner.pynamespace_to_train_args 新增 --sglang-context-length--sglang-cuda-graph-backend-prefill 条件透传,值为 None 时不输出 flag,保持既有家族命令行不变;tests/e2e/sglang/test_session_server_multi_role/_common.pyModelConfig 新增 context_lengthrollout_max_response_lencuda_graph_backend_prefill 字段,并让 global_batch_sizerollout_batch_size * n_samples_per_prompt 对齐,避免大模型 lane 减少采样数后训练侧 batch 错配。
  4. 测试配套:fast 层新增 comparator 边界测试(TestInklingComparatorBoundaries)、固定模板渲染测试(TestInklingFixedTemplate,如 test_tool_call_only_turn_skips_empty_text_block)、parser 绑定参数化行,以及 test_session_verify_runner.py 的新参数透传与 run_one batch 对齐用例;e2e 层新增 tests/e2e/sglang/test_session_server_multi_role/test_inkling.py,注册 thinkingmachines/Inkling-Small-NVFP4 在 4×H200(TP4、context 32768、cycles 2、append_tool 失败恢复)下的多角色 session 验证。
文件 模块 状态 重要度
miles/utils/chat_template_utils/tito_tokenizer.py 分词器 modified 7.57
miles/utils/chat_template_utils/templates/inkling_fixed.jinja 模板 added 5.81
miles/utils/test_utils/session_verify_runner.py 会话验证 modified 5.07
tests/fast/utils/chat_template_utils/test_tito_tokenizer.py 分词器测试 modified 6.98
tests/e2e/sglang/test_session_server_multi_role/test_inkling.py 会话测试 added 5.65
tests/e2e/sglang/test_session_server_multi_role/_common.py 会话测试 modified 4.24
tests/fast/utils/test_utils/test_session_verify_runner.py 会话验证 modified 6.26
tests/fast/utils/chat_template_utils/test_fixed_templates.py 模板测试 modified 3.28

关键符号

InklingTITOTokenizer TITOTokenizerType.get_tokenizer_class namespace_to_train_args run_one

关键源码片段

miles/utils/chat_template_utils/tito_tokenizer.py core-logic

核心注册点:新增 InklingTITOTokenizer 子类、TITOTokenizerType.INKLING 枚举与工厂映射,绑定 sglang 的 inkling 推理 / 工具解析器,并设置四个消息角色 sentinel 作为 comparator 边界。

InklingTITOTokenizer 与工厂注册

class InklingTITOTokenizer(TITOTokenizer):
    """Inkling 家族(Inkling / Inkling-Small)的 TITO 子类。    线上由 sglang 的 token 级 renderer 服务,本子类只做三件事:
    绑定 inkling 解析器、固定 assistant 起始标记、声明 comparator 边界。
    """
​
    reasoning_parser = 'inkling'
    tool_call_parser = 'inkling'
​
    FIXED_TEMPLATE = FixedTemplate(template='inkling_fixed.jinja')
​
    # Inkling 的 assistant 消息以 <|message_model|> 开头
    _DEFAULT_ASSISTANT_START = '<|message_model|>'
​
    def __init__(self, tokenizer, chat_template_kwargs=None, assistant_start_str=None):
        super().__init__(
            tokenizer,
            chat_template_kwargs=chat_template_kwargs,
            assistant_start_str=assistant_start_str or self._DEFAULT_ASSISTANT_START,
            # 四个角色 sentinel 都是 comparator 边界:assistant 轮之后
            # 非 assistant 内容差异按硬失败(NON_ASSISTANT_TEXT)处理
            special_token_ids={
                tokenizer.convert_tokens_to_ids('<|message_user|>'),
                tokenizer.convert_tokens_to_ids('<|message_model|>'),
                tokenizer.convert_tokens_to_ids('<|message_system|>'),
                tokenizer.convert_tokens_to_ids('<|message_tool|>'),
            },
        )
​
​
class TITOTokenizerType(StrEnum):
    # ... 既有家族省略 ...
    INKLING = 'inkling'
​
    @classmethod
    def get_tokenizer_class(cls, t):
        match t:
            # ... 既有分支省略 ...
            case cls.INKLING:
                return InklingTITOTokenizer
            case _:
                raise ValueError(f'Unknown TITOTokenizerType: {t!r}')

评论区精华

slice 验证的局限与两个非 TITO 缺陷 测试

PR body 记录了手动 e2e 的两个发现:6 层 slice 无法产生格式良好的 tool call,覆盖门无法满足;sampling 下近随机输出偶发复现消息边界特殊 token,导致 segment-count mismatch(37 vs 39 段)。

结论:均判定为非 TITO 缺陷并记录;后续第二个 commit 用 NVFP4 完整权重注册正式 e2e,覆盖门由完整权重的 append_tool 模式承担。 · closed

审核流程:DISMISSED 后 APPROVED other

guapisolo 先以 DISMISSED 状态给出 LGTM,随后在 CI passed 后正式 APPROVED,无代码层面争议。

结论:审核通过并合入 main。 · 已解决

风险与影响

1) 模板漂移inkling_fixed.jinja 是对 sglang token 级 renderer 的复刻,且仅用于测试对照;线上渲染仍以 HF 原生 chat_template.jinja 为准。若 sglang 上游 renderer 或 inkling 解析器更新(如 sgl-project/sglang#32958 的后续演进),模板、comparator 边界与线上渲染可能失配,导致 session server 前缀校验 500。
2) 兼容性namespace_to_train_args 新增读取 ns.sglang_context_lengthns.sglang_cuda_graph_backend_prefill,若仓库内其他调用方构造 Namespace 时未设置这两个属性,将直接触发 AttributeError;本轮已更新 _common.run_one 与 fast 测试的默认值,但仍需核查其余调用路径。
3) e2e 资源与稳定性test_inkling 注册 4×H200(est_time 1200 秒)、上下文截断至 32768(官方 1M 上下文 recipe 需 TP8),与生产形态有差异;CI 拉取 276 B 级 NVFP4 checkpoint 有网络与存储压力,且若跑 sampling 可能复现 body 中记录的 segment mismatch,存在 flaky 风险。
4) 依赖外部权重thinkingmachines/Inkling-Small-NVFP4 属于远端模型,权重变更会影响 e2e 结果。

对训练 / 推理使用方:获得 --tito-model inkling 入口,session server 可对 Inkling / Inkling-Small 执行 append_userappend_systemappend_assistantforce_finalrollbackappend_tool 全动作的多轮验证与 rollout 数据组装。对系统:TITO 家族注册表、comparator 边界、固定模板注册表同步扩展,与既有 qwen3 / glm47 / deepseekv4 等家族的接入模式完全一致,无架构性改动。对团队:新增一个必须跟随 sglang inkling parser 演进而维护的模型家族;CI 时长与资源占用上升(一条 4×H200 lane),且未来 sglang bump 时需要回归该家族的 e2e。

新模型家族接入 手写模板与 sglang 渲染一致性 e2e 依赖大权重资源 namespace 新属性兼容性

关联 Issue

#32958 [Cherry-pick of #32861] Fix Inkling tool-call parsing recovery, content handling, and streaming

完整报告

参与讨论