LLM 上下文消息序列 Dispatch:Role 边界、工具回合与中断重组
上下文能装进窗口不代表消息序列合法。本文把 role、tool call/result、序列化请求和流式 block 固定为一次 dispatch manifest,阻止半截工具参数或旧流进入下一轮。
本文要点
- 主题聚焦:大模型、AI Agent、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
上下文选择和 token 计数都正确,最终请求仍可能非法:两个 tool call 只收到一个 result;流式 JSON 只有一半就被执行;断线后又把 partial 文本追加到历史。Agent 记忆压缩血缘 处理跨会话事实,本篇只控制单次 dispatch 的消息序列和响应提交。
供应商对 message、content block、tool call 和 continuation handle 的结构不同。网关需要有限的内部表示,再由有版本的 adapter 生成请求,不能跨 API 套用 role 规则。
先构建消息图,再渲染 provider 数组
MessageSequence.v1 只从已提交 turn 构建。block 保存稳定 ID、role、kind、摘要、信任标签和顺序;工具边保存 callId、schema digest、参数状态与 result ID。各类 block 不得先拼成字符串再猜边界。
{
"conversationRevision": 81,
"sequenceDigest": "sha256:41d0...",
"blocks": [
{"id":"u-80","role":"user","kind":"text","digest":"sha256:a1..."},
{"id":"a-81-c1","role":"assistant","kind":"tool_call","callId":"call-7"},
{"id":"t-81-r1","role":"tool","kind":"tool_result","callId":"call-7"}
],
"adapterDigest": "sha256:91f2...",
"toolsetDigest": "sha256:7c13...",
"modelRevision": "provider/model@2026-07",
"maxOutputTokens": 1600
}
validator 检查 call ID 在 turn 内唯一。进入 provider render 前,每个已发出的 call 必须有且仅有一个 success/error/cancel terminal result envelope;pending 时停在 WAITING,不生成请求。result 的工具、参数摘要和 generation 必须匹配 call;计划调用不得伪装成 committed block,未知 kind、孤儿或重复 result、未闭合参数均拒绝。并行 result 按目标 API 规则放置。MCP 工具 Schema 管参数合同,这里只管回合归属。
压缩物或检索片段只是带 scope 的 input block;dispatcher 不允许它越过 system/user/tool 边界,也不把 assistant: 文本当成真实 role。上下文 token 准入 对最终序列计数,避免 adapter 添加工具说明后超窗。
Dispatch manifest 固定实际发送的字节
adapter 输出后生成 DispatchManifest.v1,绑定 sequence、adapter、provider、model、工具集、策略、请求摘要和 operation ID。外部 I/O 前,以 (conversationRevision, cancelGeneration, PREPARED) 条件 CAS 分配 attemptGeneration,持久化请求摘要与 idempotency key,并转为 DISPATCHING;这是发送接受点。之后只能到 SENT -> STREAMING -> COMMITTED 或 UNKNOWN。provider handle 立即绑定 manifest digest。
崩溃遗留的 DISPATCHING 一律先转 UNKNOWN。支持 handle 或幂等键时查询、恢复或重放同一 generation;否则旧 attempt 未确认终止前不得升代。canonical CAS 还必须匹配 active generation,迟到 block 只进隔离日志。完整响应成为 canonical 后,tool call 才进入 MCP 超时、重试与幂等 的执行账本。
流式 block 只能完整提交
stream assembler 按 response handle、generation、block index 和 delta sequence 去重。文本 delta 只能作为 PREVIEW;tool 参数留在私有缓冲,直到 block stop、JSON 解析、schema 与 call ID 校验全通过。半截字符串或缺失 stop reason 不得派发工具或写入会话。
LLM 流式协议 管 SSE 事件,浏览器长流解析器 管客户端恢复。这里控制服务端提交边界:解析成功的网络事件仍只是候选 block,最终输出必须满足 message graph 不变量。
断线后可从 handle 续流就从最后确认 sequence 去重;否则丢弃 partial 候选,从原 manifest 新建 attempt。已展示的半段文本绝不能成为下一轮历史,否则会改变 role 图并重复 tool call。UI 必须区分可撤销 preview 与已提交消息。
用乱序、重放和半截参数验收
测试构造孤儿 result、两个 result 指向同一 call、并行 call 乱序、tool 参数在任意字节截断、block delta 重复、stop event 丢失、provider handle 绑定错 manifest、旧流在新流后恢复,以及 adapter 升级改变 role 顺序。断言非法序列发送数为零、partial tool dispatch 为零、每个 conversation revision 最多一个 canonical assistant turn。
指标包括 sequence validator 拒绝、孤儿/重复 tool result、UNKNOWN dispatch 年龄、handle 恢复率、迟到 block、preview 撤回、canonical CAS 冲突和 partial tool dispatch。上线先只生成 manifest 与旧请求做字节/语义 diff,再对无工具请求启用,最后扩到工具回合。回滚切回旧 adapter 也必须读取同一内部消息图;若旧 adapter 不认识新 block kind,就暂停该会话而不是降级拼接。结构化输出 仍负责最终业务 schema,本协议保证送去验证的是一份完整、唯一且顺序合法的响应。
延伸阅读
Related