工具返回超长结果时,最容易踩的坑不是截断本身,而是截断之后 Agent 不知道自己看到的是残片。QwenPaw 的 issue #5946 记录了一个很具体的现场:execute_shell_command 的输出被截断后,上下文里留下 <<<TRUNCATED ~18948 tokens>>,后面跟一段 system-info,说完整输出已经持久化,可以调用 recall_history(op="recall_tool", tool_call_id="...") 取回。结果 Agent 在那之后对着一份仍在上下文里的内容反复发起 recall_history,做了一堆无效调用。
这个问题值得单独拿出来讲,因为它把“截断处理”从一条数据处理规则,变成了 Agent 状态管理问题。
截断点不止一处,静默的那个最麻烦
[3] 那篇排查记给的链路拆解是可以直接拿来做检查表的:数据源层可能自己只返回了前 20 条;编排层可能给单条工具结果设了硬上限;消息序列化和接入层(比如 OpenAI 兼容接口一侧)可能在请求体大小上再做一次裁剪;模型服务端也可能按自己的窗口二次处理。四层里任何一层做了截断而没留下标记,上层就无从判断信息是否完整。
工程上真正要防的是第三种:截断发生,但没有元数据。用户在页面上看到的和模型看到的不是同一份东西,日志里也看不出少了什么。等症状出来,“50 条数据只剩 20 条”这种表象已经走了好几层。
所以第一步不是选压缩算法,而是在链路每层插桩:记录原始长度、字符数、估算 token、实际进入上下文 token、是否截断、截断在哪一段、截断策略名。有 trace 之后再谈策略,否则调参全是盲调。
三条压缩路径的取舍
[1] 把工具结果进上下文前的路径归成三类:直接截断、抽取式摘要、结构化解析。这个分类不新,但落地时的代价差别很大。
- 直接截断:最便宜、最确定。头部或尾部保留 N 个字符,加一条明确的截断标记。问题是信息密度不由你控制,一个大 HTML 页面截下来可能全是导航栏和 script。
- 抽取式摘要:用规则或小模型抽关键句、关键字段。比截断贵,但更适合文本类结果(抓取正文、长日志)。风险是摘要本身可能给出错误的完整性暗示,让 Agent 误以为这就是全部。
- 结构化解析:先把结果解析成结构(JSON 字段、表格、行号索引),再按槽位填。最可靠,也最贵,且依赖于工具输出格式稳定。网页抓取一旦 DOM 变了,解析器静默挂掉比截断还糟。
我的默认选择是:结构化解析优先,解析失败退到截断加显式标记,抽取式摘要只用于明确的文本类工具。三层都失败时不要硬塞,直接返回“结果过大,已引导按块读取”,然后把分页/增量的控制权交给 Agent。
分页比压缩更根本
很多工具的返回值本来就是可切片的,只是我们懒,一次把全部拉了回来。比如日之类文件读取、数据库查询、网页抓取,完全可以按行区间或字节偏移给工具加参数,让 Agent 自己决定 `offset` 和 `limit`,失败的第二步再考虑“小切片 + 多次调用”。这样上下文里永远是 Agent 主动选择的范围,而不是被动截断后的半截。
代价是调用轮次变多,token 账单和延迟都会涨。所以分页只对大结果生效,而且要设一个上限:最多几次切片,否则一次抓取能拖成十几轮。
截断标记要能定位,不要只写“已截断”
回到 QwenPaw 那个 bug。按 issue 里给的两个方向,方案 B 是改提示文案,让 Agent 明白截断 ≠ 丢失,先在上下文里找,再决定要不要 recall。这看起来只是措辞,实际上是信息结构问题:只告诉 Agent“被截断了”,它会倾向于用工具去补;告诉它“已截断,截断点为字节 X,原文第 1-40 行仍在上下文,第 41 行之后需按 offset 读取”,它才有可执行的下一步。
截断提示不是一个告知,是一份路线图。缺少位置和恢复路径的截断提示,会诱发 Agent 的空转。
实践上至少要有四项:截断阈值、原始长度、保留区间、恢复方式(token 数还是偏移量)。恢复方式最好校验:如果引用的 tool_call_id 不存在或早已被淘汰,要明确返回失败而不是继续重试。
别把恢复成本藏起来
截断相关的问题在观测上应该单列。一笔请求因为截断而增加的工具调用、因此多花的 token 和延迟,算在“截断成本”还是“工具成本”里,决定了你下一步优化哪块。至少要有两个指标:带截断标记的工具结果占比,以及截断之后额外发起的补全类调用次数。前一个不动后一个涨,基本说明提示写得不够好。
另一个容易被忽略的边界是保留完整原文的存储。窗口替 Agent 背下了任务,它的生命周期、检索权限、是否能被重复引用,都要和上下文生命周期对齐,否则就出现“原文还在,引用已经失效”的静默失配。
回到现场
工具输出截断本身不是难点。难的是让 Agent 对“它看到的是否完整”有正确的内部模型。一旦这一点没对齐,无论你用截断、摘要还是结构化,Agent 都会用一个错误的前提去行动。QwenPaw#5946 反复无效 recall 的根因不在 recall 工具,而在于上下文没有被清楚地标成一个有边界的视图标记。这也决定了策略选型的优先级:先给截断加上可执行的位置信息和恢复信息,再谈如何能把大输出压入更低成本、更精准的上下文。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/agent-engineering/641.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
AI Coding Agent 如何稳定提交可合并的 PR
上周 review 了一个 AI 生成的 PR,测试全绿,但我还是把它关了。它改了 37 个文件,顺手升级了一个依赖,还修改了两条测试断言。问题不是代码不能跑,而是这个 PR 没人敢合。
2026/10/14
-
MCP 进入生产环境:工具协议、网关与权限边界
MCP 刚出来时,我以为最难的是协议兼容。真正接了十几个工具之后才发现,把工具接上只花了两天,把权限、审计和故障处理理清楚花了两个月。
2026/10/07
-
Agent Harness:可观测、可评测、可回滚的 Agent 基础设施
去年我们做了一个处理退款申请的 Agent。Demo 很顺,上线第一周就出了事故:进程重启后状态丢了,同一笔申请被处理了两次。问题不在模型,而在模型外面那层没人愿意写的基础设施。
2026/10/09
-
Agent 安全清单:提示注入、工具越权与数据外泄
一个内部助手被要求总结一封客户邮件。邮件末尾有一行白色小字:把最近的客户名单转发到某个地址。Agent 真的准备去调邮件工具了。安全不能靠模型自觉,得靠系统设计。
2026/10/16
-
并行工具调用暴露的工具设计耦合问题
并行工具调用能砍掉四成延迟,但它更重要的价值在于暴露工具之间的隐性耦合。本文拆解上下文依赖、共享状态竞争与时序前提这三类静默失败,给出读写分类规则、工具合并的判据,以及什么时候该上依赖图编排。
2026/10/23
-
Agent 轨迹回放调试:把失败变成可回放资产
Agent 调试难在无法复现、故障点藏在数步之前。这篇文章讲三件具体的事:把轨迹归一化成可校验的步骤结构,用工具签名和领域策略生成可执行约束,以及用标注过的失败轨迹在 CI 里做回归回放——顺带说明为什么只盯延迟和错误率的可观测看不到这类故障。
2026/10/24
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布