AI stream 场景下,tool calling 的内容通常是增量返回的,单个 chunk 往往不是完整 JSON。
所以我们不会等整个 response 完成再统一解析,而是采用 buffer 增量拼接的方式:
- chunk 到达后先 append 到 buffer
- 每次追加后尝试 parse
- parse 成功则立即触发 tool execution
- parse 失败说明结构未完整,继续等待后续 token
这种模式本质上属于 incremental parsing,可以降低 tool 调用延迟,同时更符合 AI 流式生成的特点。
在复杂场景下,还需要结合状态机处理 JSON 闭合、markdown 包裹、转义字符以及多消息边界问题。
"先想好再说" + 流式响应 = 模型已经把整段回复生成完了,服务器只是分批发送给你。这就像一个完整的面包,被切成一片一片递过来——你看着是一片片来的,但面包早就是完整的了。
自回归 + 流式响应 = 模型真的就是一个一个 token 现算的。第一个 token 出来的时候,第二个 token 还不存在。这才是真正的"边说边想"。
这两种方式对 Agent 开发有一个非常实际的差异:首 token 延迟。
- "先想好再说":你得等模型把整段回复全部生成完,才能开始收到第一个字。回复越长,等待越久。
- 自回归 + 流式:模型生成第一个 token 就立刻发给你。你感受到的响应速度极快,后面的内容边等边看。
这才是流式响应对 Agent 真正的价值——不是"打字机动画好看",而是缩短了用户感知到的等待时间。
既然模型是基于前面所有 token 来决定下一个 token 的,那我如果提前替它把前几个 token 写好了呢?模型没法回头改已经"说过"的字,只能顺着往下说。
比如我想让 Agent 在某个阶段只能调用浏览器工具,我就在 assistant 消息里预填:
{"name": "browser_
模型看到这个前缀,只能在 browser_ 开头的工具名里选了——browser_click、browser_scroll、browser_open……它不可能突然改口去调 file_read。
我的问题是:如果不删工具定义、只靠 prefill,模型就真的绝对不会调错工具吗?从自回归的原理上,它是怎么被"锁死"的?