把 system / user / assistant / tool 消息序列化成模型真正看到的 token 序列,解释角色、特殊 token、工具调用和训练推理一致性
| 层 | 它是什么 | 例子 | 常见误解 |
|---|---|---|---|
| message object | 应用层结构化消息 | role=user, content=... | 以为模型原生理解 JSON 消息数组 |
| chat template | 把 messages 渲染成模型训练时见过的格式 | <|user|>...<|assistant|> | 所有模型的 role 标签都一样 |
| special tokens | BOS、EOS、role token、tool token、stop token | <s>、</s>、<|im_end|> | 特殊 token 可以随便换成普通文本 |
| generation prompt | 告诉模型从 assistant 位置开始续写 | 最后追加 assistant header | 把最后一个 user 消息直接丢给模型就够了 |
| stop rule | 生成何时结束的协议 | EOS、stop sequence、tool_call_end | 停不下来一定是解码参数问题 |
| 角色 | 作用 | 序列化要点 | 错了会怎样 |
|---|---|---|---|
| system | 定义全局行为、边界、风格和优先级 | 通常放在最前,并用模型专属 system 标记包住 | 模型把系统约束当普通用户内容,安全边界变弱 |
| user | 表达用户请求和上下文输入 | 需要清楚闭合,避免用户内容吞掉后续 role 标记 | 提示注入更容易伪造 assistant / tool 消息 |
| assistant | 模型历史回答或当前要生成的位置 | 训练时通常对 assistant 内容算 loss,推理时追加 assistant header | 模型不知道该从哪个角色继续说话 |
| tool | 工具返回结果或外部执行证据 | 要区分 tool call 请求、tool result 和普通自然语言 | 模型把工具结果当用户指令或把工具参数当文本答案 |
| developer / policy | 部分系统中的中间优先级指令 | 必须映射到模型支持的角色或模板扩展 | 优先级丢失,线上行为和预期不一致 |
| 字段 / 规则 | 回答的问题 | 检查点 |
|---|---|---|
| BOS / EOS | 序列从哪里开始,哪些位置代表结束 | 是否重复添加 BOS,EOS 是否和 stop rule 一致 |
| role header | 当前片段属于哪个说话者 | system / user / assistant / tool 是否有稳定边界 |
| message separator | 多轮消息之间怎样隔开 | 换行、特殊 token、结束标记是否和训练模板一致 |
| assistant generation prompt | 模型应该从哪里开始生成 | 最后是否追加 assistant 起始标记而不是完整 assistant 消息 |
| tool schema block | 工具定义怎样提供给模型 | 工具名、参数 schema、描述和权限提示是否被稳定序列化 |
| tool call format | 模型怎样表达“我要调用工具” | JSON、XML、special token、function_call 字段是否和解析器一致 |
| stop tokens | 生成遇到什么就停止 | stop sequence 是否会误伤正常文本,是否覆盖 tool call 结束 |
| 不一致点 | 表现 | 根因 |
|---|---|---|
| 训练用 A 模板,推理用 B 模板 | 模型不按角色回答、格式漂移 | role token、分隔符、assistant 起始标记不同 |
| 训练时算错 loss mask | 模型复述用户问题或学会生成 role 标签 | user / assistant 区域没有正确区分 |
| 缺少 generation prompt | 模型继续补全用户消息,而不是回答 | 没有给出 assistant 起始位置 |
| stop rule 和模板冲突 | 回答截断、工具调用 JSON 不完整 | stop sequence 命中了普通内容或工具字段 |
| 工具调用格式和解析器不一致 | 模型看似调用了工具,但运行时解析失败 | 模板、schema、parser、tool runtime 没有同一版本 |
| 对象 | 应该序列化什么 | 为什么重要 |
|---|---|---|
| tool registry | 工具名、描述、参数 schema、返回类型、风险等级 | 模型需要知道可用动作,运行时需要知道权限边界 |
| tool call | 模型选择的工具名、参数、调用 id | 便于 parser、审批、执行和审计追踪 |
| tool result | 工具返回内容、错误、截断、证据 id | 模型后续回答要区分真实工具结果和用户文本 |
| tool error | 错误类型、是否可重试、用户可见信息 | 避免模型把系统错误编造成事实答案 |
| approval state | 是否人工确认、权限快照、执行状态 | 高风险工具调用必须保留责任链 |
| 症状 | 先看什么 | 常见修复方向 |
|---|---|---|
| 模型回答里出现 role 标签 | rendered prompt、labels、loss mask | 修正训练模板和 response-only loss |
| 模型不听 system prompt | system 是否被正确放入模板、是否被用户内容覆盖 | 修正角色边界、上下文优先级和指令层级 |
| 同一问题单轮正常,多轮异常 | history serialization、message separator、truncation | 统一多轮拼接规则,记录被截断消息 |
| 工具调用经常解析失败 | tool call serialization、parser、stop tokens | 让模板、schema、parser 和运行时共用版本 |
| 开源模型部署后行为变差 | tokenizer_config、chat_template、BOS/EOS、stop rule | 使用模型官方模板,避免跨模型复用模板 |
| 评测分数突然变化 | template version、rendered prompt hash、generation prompt | 把模板纳入 eval artifact 和 release bundle |
| 序列化节点 | 必须记录的字段 | 判断重点 |
|---|---|---|
| 消息输入 | conversation_id、message_ids、role_map、source_type、trusted_boundary | 哪些内容是系统规则、用户输入、工具观察或外部证据? |
| 模板渲染 | template_version、template_hash、rendered_prompt_hash、generation_prompt | 线上行为变化是否来自模板、assistant header 或 stop rule 改动? |
| 角色边界 | system_span、user_spans、assistant_spans、tool_spans、escaped_user_content | 用户内容是否伪造了 role 标签,工具结果是否混进控制区? |
| 工具协议 | tool_schema_version、tool_call_format、tool_result_format、parser_version | 工具调用失败是模型问题、模板问题、schema 问题还是解析器问题? |
| 训练 / 推理对齐 | model_template_family、tokenizer_version、stop_tokens、loss_mask_assumption | 开源模型部署后多轮、工具调用或 system 服从为什么退化? |
| 相邻页 | 它回答什么 | 本页补什么 |
|---|---|---|
| Tokenizer / 词表 | 文字、特殊 token 和 chat template 怎样进入 token id | 多轮 message 怎样先被模板序列化,再交给 tokenizer |
| Batch / Mask / Packing | token 序列怎样进入 batch 张量 | 哪些 token 属于 user / assistant / tool,如何影响 loss mask 和 stop |
| Prompt / 上下文工程 | 上下文如何设计和拼装 | 把上下文设计落到可复现的模板、角色和序列化协议 |
| 指令层级 / 上下文可信度 | 不同来源指令的优先级如何判断 | 角色协议怎样承载 system、user、tool、RAG 证据的可信边界 |
| Tool Calling / 执行协议 | 工具调用怎样被解析、授权和执行 | 工具定义、调用和结果怎样序列化给模型 |
| Artifact Registry | AI 资产怎样版本化、追溯和回滚 | 把 chat template 作为 prompt / tool / release artifact 的一部分登记 |