流式工具结果破坏了请求-响应式智能体规划器
SQL 工具在数据从网络线路传出时即发送行。智能体调用它并期待得到结果。而一年前编写的运行环境(当时所有工具都是请求-响应式的)在调用模型之前,会尽职地将整个流缓冲成一个单一字符串。40 秒后,缓冲区达到了 200 KB,上下文窗口被消耗了一半,智能体正在对一个查询的第 47,000 行进行推理,而它本可以在第 30 行就停止。没有人故意设计这种失败——这仅仅是因为将“工具已返回”视为规划器唯一响应事件的结果。
向流式工具的转变正在规划器尚未察觉的情况下发生。SQL 引擎发出渐进式结果集。文档提取器生成分页。搜索 API 在相关性评分稳定后按批次返回命中结果。MCP 的 Streamable HTTP 传输协议(2025-03-26 规范中 HTTP+SSE 的替代方案)使增量响应成为一流的传输模式,而不再是一项稀有的功能。传输层已经准备就绪,但其上的规划器还没有。
大多数智能体运行环境仍将工具调用建模为 result = tool(args) —— 一个返回类型为单一聚合值的函数。当底层工具使用流式传输时,运行环境唯一的诚实选择是等待直到 EOF(传输 结束)、按硬性的字节限制截断,或者停止读取并丢弃剩余部分。这些选择都没有让模型参与决策。真正有趣的举措几乎没人尝试:让模型在流传输过程中决定何时已经看够了。
缓冲并移交的失败模式
默认的集成路径将流式工具变成了同步工具。运行环境打开流,将数据块累积到缓冲区中,等待关闭事件,然后将整个有效载荷作为下一条用户消息交给模型。从模型的角度来看,工具的行为与缓慢的请求-响应调用没有区别。从系统的角度来看,有三件事已经悄然崩溃。
第一处崩溃是上下文窗口的计算。一个返回 50,000 行中等宽度 JSON 的 SQL 查询可能会产生超过 800 KB 的工具输出。在 200K token 的上下文窗口中,加上通常已经包含系统提示词、先前的工具调用和用户历史记录的智能体状态,一次贪婪的缓冲在模型开始推理结果之前就消耗了三分之一的预算。执行轨迹中的第二次工具调用空间比第一次少。第五次调用则必须剔除一些内容——通常是智能体最需要记住的用户请求部分。最近关于智能体中上下文窗口溢出的研究指出,工具输出膨胀是排名前三的失败模式,甚至排在长指令或草稿纸推理之前。
第二处崩溃是延迟。运行环境无法询问“这些够了吗?”,因为直到 EOF 之前模型都不在链路中。如果工具是按需分页的——例如一个文档提取器,每当上一页被确认时就产生一个新页面——“缓冲并移交”模式产生的流将永远无法到达 EOF,直到触发某些外部超时。智能体停止读取的决定被委托给了挂钟截止时间,而不是智能体自身关于第 30 行是否已经回答了问题的判断。
第三处崩溃是隐形的。在运行环境层进行截断是标准的退路,而 OpenAI Codex 等项目的 issue 队列将其追踪为智能体困惑的常态化来源:模型看到的工具结果只是工具实际输出的前缀,如果团队处理得当,会带有一个类似 [truncated] 的页脚;如果没处理好,则完全没有标记。模型会对部分数据集进行推理,仿佛它是完整的。输出会以追踪日志无法察觉的方式变得极其错误,因为从追踪的角度来看,工具返回了一个值,而模型接受了它。
规划器可以推理的流式工具契约
修复方法不是“逐个 token 地流向模型”——这解决的是 UX 问题(感知到的响应延迟),而不是规划问题。修复方法是教会规划器某些工具是增量发出的,并赋予它参与流的原始语。
最小可行契约由四部分组成:
工具描述符中的 streaming 标志。 工具目录已经声明了名称、参数和描述;添加一个布尔值(或更丰富的模式枚举:request_response、chunked、paginated、unbounded),以便规划器提前知道是否可以预期工具返回一个完整的结果。看到 streaming: true 的规划器应该构建其提示词以建模部分结果,设置中断路径,并且永远不要期待收到单一的“工具返回了 X”的消息。
- https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
- https://docs.langchain.com/oss/python/langchain/streaming
- https://developers.googleblog.com/en/beyond-request-response-architecting-real-time-bidirectional-streaming-multi-agent-system/
- https://arxiv.org/html/2511.22729v1
- https://dev.to/gabrielanhaia/tool-result-truncation-the-silent-bug-that-makes-agents-lie-3epe
- https://dev.to/gantz/handle-mcp-tools-that-return-too-much-data-49h9
- https://www.mindstudio.ai/blog/reduce-token-usage-ai-agents-mcp-optimization
- https://github.com/openai/codex/issues/6426
- https://risingwave.com/blog/mcp-streaming-database-connect-ai-agents-risingwave/
- https://blog.langchain.com/planning-agents/
- https://streamkap.com/resources-and-guides/agent-decision-latency-budget
- https://chatforest.com/guides/mcp-real-time-streaming/
- https://www.codeant.ai/blogs/poor-tool-calling-llm-cost-latency
