跳转到主要内容

静默工具截断:你的智能体在不知情下进行推理的默认限制

阅读需 2 分钟Tian PanTian Pan

一个工具调用返回了 142 KB 的 JSON 数据块。你的智能体框架丢弃了 8,192 字节之后的所有内容,将前缀交给模型,而模型根据一个它从未意识到是不完整片段的内容写出了一个自信的答案。三周后,一名客户升级了投诉。你翻看追踪记录(trace),看到“工具返回成功”,随后的复盘变成了寻找哪一步“忽略”了证据——然而没有哪一步忽略了它。证据在到达推理引擎之前就被裁剪掉了。

这并非假设。Codex 将工具输出截断硬编码为 10 KiB 或 256 行。Claude Code 的工具结果默认为 25,000 个 token,并且带有一个单独的显示层限制,曾在 2025 年短暂地将 MCP 响应裁剪到 700 个字符左右。OpenAI 的工具输出提交上限为 512 KB。每个框架都选择了一个看起来安全的数字,对于短工具调用确实如此。当单步输出越界时,故障模式就出现了——悄无声息地,没有异常,也没有模型可见的标记。

更深层次的问题不在于限制的存在。限制必须存在;工具输出可能是无限的,而上下文窗口则不然。问题在于,“丢弃溢出内容并继续”对于任何下游消费者是概率推理引擎(probabilistic reasoner)的系统来说,都是错误的默认设置。确定性程序会在截断的 JSON 上崩溃。而推理引擎不会崩溃。它会推论、填补空白并给出回答。故障模式从堆栈跟踪(stack trace)转变为自信的错误回答——而堆栈跟踪的缺失正是让这个 bug 难以被发现的原因。

截断是如何变得隐形的

从“工具返回了有用结果”到“模型产生幻觉”的路径跨越了多个子系统,其中每一个都可能在不通知下一个系统的情况下进行裁剪。

框架层(The framework layer)。 大多数智能体框架会对每个结果设置字节或 token 上限。Codex 选择 10 KiB 或 256 行(以先到者为准),并使用中间标记来保留头部和尾部。该标记是模型可以自由忽略的信息性文本——工具响应中没有结构化字段指示 truncated: true。当一个 CSV 文件从中间被切断时,模型会看到格式错误的行,要么通过猜测来修复它们,要么将可见的行视为整个数据集。

传输层(The transport layer)。 即使框架接受更大的负载,Node 子进程缓冲区或 gRPC 消息限制也可能在更上游失效。Claude Code 的问题追踪到了它的症状——原本 8,000 字符的 MCP 响应显示为 700 字符的代码片段——部分原因是 RangeError [ERR_CHILD_PROCESS_STDIO_MAXBUFFER]: stdout maxBuffer length exceeded。完整的响应生成了,支付了推理成本,写入了临时文件,却从未到达模型。用户可以在磁盘上找到它,但智能体找不到。

显示层(The display layer)。 某些裁剪仅发生在面向开发者的记录(transcript)中。模型仍然能获得完整的响应,但尝试调试行为的工程师看到的是代码片段,并得出“工具返回了正确数据”的结论——而他们实际看到的只是 UI 截断,而不是模型的视角。这种方向的不对称虽然少见,但后果更严重:它让工程师对模型掌握的信息产生了错误认知。

记忆层(The memory layer)。 LangGraph 用户遇到过记忆总结器在总结过程中悄悄丢弃 ToolMessage 条目的情况,破坏了框架要求的 AIMessage / ToolMessage 配对。智能体的表象故障表现为运行时错误或混乱的下一步,但根源在更上游:总结器的截断策略不知道工具调用协议的结构化约束。

这些故障在孤立状态下都是合理的。让它们具有工业级危险性的是它们的组合效应。一个 50 KB 的结果被框架裁剪到 25 K token,然后被一个丢弃了 ToolMessage 的记忆层进行总结,最后在显示前 700 个字符的 UI 中展示给开发者。工程师看到了一个看起来真实的记录;模型看到了另一个看起来真实的记录;而两者都与原始的工具输出不符。

当模型只有一半结果时会做什么

推理引擎擅长利用手头的证据回答问题。这是核心技能,也是故障模式。

一个只拿到一半 API 响应的推理引擎不会说“这看起来被截断了,我不应该回答”。它会根据可见部分进行推理,并以满分的置信度评估这些证据,然后生成一个看起来完整的结论。如果缺失的行恰好包含用户真正需要的答案,返回的答案就是错误的,且不带任何不确定性标记。复盘追踪显示模型“忽略了证据”,但从模型的角度来看,那些证据从未存在过。

这与确定性系统在截断下的失效方式有着本质的不同。获得部分结果集的 SQL 客户端会抛出异常。JSON 解析器会在未闭合的大括号处失败。Python 的 pandas.read_csv 处理被裁剪的文件时会抛出 ParserError。在错误数据向前传播之前,这些系统都会停止运行。推理引擎没有等效的停止机制。它的损失函数奖励生成连贯的答案;而当一半的约束条件缺失时,连贯性的成本是非常低廉的。

这种不对称性也体现在评估(evals)中。检查“智能体是否生成了答案”的测试套件会静默通过。检查“智能体是否针对完整的证据集生成了正确答案”的测试套件,则需要构建一个正确答案取决于截断边界之外的数据的案例——大多数团队在第一次事故发生之前都不会想到要测试这一点。

必须落地的检测规范

大多数团队在发生用户可见的故障后,才发现他们的截断率,随后发现 12% 的工具调用在长达数月的时间里一直被静默裁剪。评估(eval)未能捕捉到这一点是结构性的原因:基于生产环境追踪构建的评估过度代表了那些响应内容符合长度要求的调用,因为那些响应被裁剪的调用静默失败了,从未进入“值得关注”的集合。

在截断变得可观测(作为数据而非轶事)之前,必须具备以下三个要素:

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 10 分钟

你的智能体把指针当成了值:工具输出里的引用 vs 值

当工具的返回值是 ID、路径或 URL 时,它实际上是在让智能体去做一次解引用。但模型何时解析、何时直接"假装已解析"地继续往下编,这套策略是隐式的、不一致的、悄无声息地出错的。把这层间接寻址显式地写进类型里。

insider
ai-engineering
阅读需 10 分钟

MCP 冷启动税:工具服务器开销如何在智能体第 7 步发生累加

为什么 200 毫秒的 MCP 工具调用会演变成 4 秒的智能体循环,冷启动税究竟存在于何处,以及如何通过预热池规范将数秒的惩罚降低到 100 毫秒以下。

insider
mcp
阅读需 8 分钟

你的工具描述是模型遵循的指令通道

工具描述是模型视为权威指令的散文,但代码审查和输入清理从未检查过它们。本文将探讨被投毒的元数据和地毯式攻击是如何渗透进来的,以及弥合这一差距的规范。

insider
ai-engineering
阅读需 9 分钟

智能体内存驱逐:为什么 LRU 在模型升级中屹立不倒,而显著性评分却不行

基于显著性权重的内存驱逐在上线首日看起来像是提升了质量,但每次模型升级都会演变成一场迁移工程 —— 本文将探讨为什么 LRU 这种“无聊”的选择才是最终的赢家。

insider
agents
阅读需 10 分钟

MCP 中的 OAuth:在工具服务器中传递用户身份

MCP 标准化了智能体如何获取工具服务器令牌的方式,但将更棘手的问题——这些服务器如何将用户身份传递给下游 API——留给了实现者。本文探讨了哪些方案能够通过严格的审计。

insider
mcp