
假设一个 Agent 要查询设备名称。模型准备调用 lookup_device,参数里需要填设备编号 DEV_A。使用流式接口时,工具名先到了,参数却分两段到达:前一段只有字段名,后一段才补上编号和结尾。
系统如果看到工具名就开始查,拿到的可能还是空参数;如果一直等整个回答结束,又会把已经收齐的查询工单压在手里,白白等模型输出后面的内容。
提前执行该把等待缩短到哪里?在这份本地实现里,边界是一个工具内容块结束。此前收集参数,此后生成内部可调度事件;整个回答可以继续输出。
流式执行提前的是完整工具块的处理时点,不需要抢跑半截参数。 接下来还要区分两件事:块结束是否说明参数合法,以及事件发出是否说明工具已经真正运行。

工具名到达,先建缓冲区
在这套 cc-python 的 API 适配器里,上游发来 content_block_start 时,程序先检查块的类型。如果是工具调用,就保存工具名、调用编号,并创建一个空的参数字符串。
这一刻解决的是“正在接收哪个调用”。它还没有回答“这个调用要传什么”。工具名和参数属于同一张工单,看到封面,不能推断正文已经齐了。
后面到达的 input_json_delta 携带参数片段。适配器把片段追加到对应的缓冲区,暂时不执行工具,也不在每个片段到达时尝试把它当成最终参数。
设备查询的第一段可以是 {"device_id":,单独拿出来无法解析。第二段接上 "DEV_A"},两段拼起来才成为完整对象。如果首段解析失败就把调用判错,系统会把正常的增量传输误当成坏请求。
反过来,某段文本碰巧已经能解析,也不说明上游已经结束这个块。应用需要遵守内容块的结束信号,不能靠“现在看起来像完整 JSON”猜测后面是否还有内容。
适配器还用块的 index 区分缓冲区。文本、工具或其他内容分别保留自己的状态,增量与结束事件都按编号找到对应块。若只保留一个全局参数字符串,就很容易把不同块的内容拼到一起。
参数片段的边界也不必和字段边界一致。一个设备编号可以分在多段字符串里,字段名、引号和结尾符号都可能单独到达。适配器只负责按顺序还原文本,不能假定每个网络事件都恰好携带一个可以直接使用的字段。


