把 60 个工具挂到一个 Agent 上,第一轮调用准确率 97%——这是几乎所有厂商 demo 里的数字。但真实 Agent 不是一轮跑完的:每调一次工具,结果就原样回填进上下文。当回填的观测结果累积到 48K–64K token 时,我们实测工具选择准确率从 97.2% 跌到 52.6%,幻觉调用(编造清单外工具)率从 0.3% 飙到 14.7%。问题的根因不是模型笨,也不是上下文窗口不够——而是工具定义静静躺在系统提示的开头,被中段堆积的工具结果"挤飞"出了有效注意力区。本期用一个四档(4K/16K/40K/64K 回填 token)压测,把"工具视野退化税"量化,并对比五种对冲策略(截断 / 滑窗 / 摘要 / 重锚 / 按需加载)的真实代价。
| 观测回填档位 | 等效 token | 工具选择准确率 | 参数保真度 | 幻觉调用率 | 典型现象 |
|---|---|---|---|---|---|
| Tier A 鲜活 | 0–4K | 97.2% | 94.1% | 0.3% | 一切正常,厂商 demo 区 |
| Tier B 微涨 | 8–16K | 88.5% | 86.3% | 1.8% | 开始漏可选参数、枚举值偏移 |
| Tier C 膝点 | 24–40K | 71.4% | 68.9% | 6.2% | 选对工具概率腰斩前兆,串话 |
| Tier D 断崖 | 48–64K | 52.6% | 49.8% | 14.7% | 编造清单外工具、重复已完成调用 |
测试集:60 个注册工具(CRUD/检索/计算/外部 API 混合),每档 200 条多步任务轨迹,6 个主流商用模型取均值,控制工具定义总量恒定(约 3.8K token)。
工具调用能力评测有一个长期被忽略的隐含假设——评测时上下文是空的。几乎所有公开 benchmark(BFCL、τ-bench、API-Bank)都把工具定义一次性塞进去、立刻问一个问题。这与生产 Agent 的运行轨迹完全不同:生产 Agent 是一个 ReAct 循环,每一步的 Observation(工具返回值)都会原样追加进对话历史。
当工具返回的是日志、搜索命中、数据库行集时,单次观测动辄几千 token。跑 8–12 步后,中段就堆起几万 token 的"观测海"。而工具定义(schema + description)通常放在系统提示的最前面,位置固定。注意力机制对中段信息存在已知的稀释效应——这就是 lost-in-the-middle 在工具域的精确再现:模型不是忘了怎么用工具,而是"看不到"工具还躺在开头。
这解释了一个反直觉现象:扩上下文窗口到 200K 并不解决问题。Chroma 的 context rot 研究与多项长上下文评测都表明,性能退化主要由上下文密度而非窗口上限驱动。把窗口从 32K 扩到 200K,工具定义依然沉在开头,淹没它的"观测海"反而可以堆得更深、塌得更狠。
为了把"视野退化"和"模型能力"剥离,我们设计了定义恒定、回填可调的压测协议:
commit_transaction,且要填一个来自第二步结果的 account_id。这样,选择准确率衡量"看得见定义",参数保真衡量"还能从淹没的中段里捞回 account_id",幻觉率衡量"是否开始编清单外的工具"。
结果如表所示。关键判读:
把三种失败模式拆开看,能指导对冲策略的优先级:
参数糊化(最早,8K 起测):模型选对了 commit_transaction,但把第二步返回的 account_id 填错——要么用了第一步的旧值,要么凭空造一个。根因是相关证据(第二步结果)已被中段淹没。这一类占总失败约 38%,危害中等(调用失败可重试)。
选择塌方(居中,24K 恶化):模型选了一个邻近工具,比如用 transfer_funds 代替 commit_transaction。根因是定义可见性下降。占总失败约 44%,危害高(错误工具执行了错误动作)。
幻觉调用(最晚,48K 爆发):模型调用清单外的工具,如 finalize_payment(不存在)。这是一种"激活训练分布"的失效——当当前上下文无法锚定真实工具集时,模型回退到训练时见过的常见工具名。占总失败约 18%,但危害最高:框架层往往直接抛 "tool not found",触发重试级联,浪费预算甚至触发副作用。
实务含义:截断/滑窗这类"删观测"策略只能压参数糊化和部分选择塌方;要治幻觉调用,必须显式地把"可用工具清单"重新锚定到模型注意力的高权重区。
在同一 Tier D(56K 回填 token)下,对五种主流对冲策略做横向对比:
| 策略 | 选择准确率 | 幻觉率 | 相对 token 开销 | 实现难度 | 治标/治本 |
|---|---|---|---|---|---|
| 不清屏(baseline) | 52.6% | 14.7% | 1.0× | — | — |
| 结果截断(top-K 字符) | 64.3% | 11.2% | 0.40× | 低 | 治标 |
| 滑动窗口(只留近 N 步) | 69.8% | 9.1% | 0.60× | 低 | 治标 |
| 摘要压缩(compaction) | 78.5% | 6.4% | 0.35× | 中 | 治本(压密度) |
| 定义重锚(再注入清单) | 86.7% | 2.9% | 1.15× | 中 | 治本(提可见性) |
| 按需加载(MCP 风格) | 91.2% | 1.1% | 0.50× | 高 | 治本(降候选数) |
判读:
最优组合是摘要压缩 + 定义重锚(在按需加载难以落地时),或按需加载 + 轻量重锚(在工程能力充足时)。
定义重锚之所以性价比高,是因为它几乎不需要改 Agent 主循环,只需在每次组装上下文时多加一条"锚点消息":
def build_turn(tools, trajectory, keep_recent=3, max_summary=800):
# 1. 工具定义放系统提示开头,并打缓存点(减少重复编码开销)
system = [{
"type": "text",
"text": render_tool_defs(tools),
"cache_control": {"type": "ephemeral"} # 提示缓存
}]
# 2. 中段:旧观测压缩为摘要 + 保留近 N 步原文
messages = [
{"role": "system", "content": summarize_history(trajectory[:-keep_recent], max_summary)},
*trajectory[-keep_recent:]
]
# 3. 关键:末尾重锚——可用工具白名单 + 进展锚定
messages.append({
"role": "user",
"content": (
f"【工具白名单】仅允许调用这 {len(tools)} 个工具:"
f"{[t.name for t in tools]}。严禁调用清单外工具。\n"
f"【进展锚定】当前步骤:{current_step(trajectory)};"
f"上一步关键返回值:{last_result_key(trajectory)}"
)
})
return system, messages
三个动作各有分工:render_tool_defs 保证定义位置稳定;summarize_history 降密度(对应"摘要压缩"策略);末尾的白名单 + 进展锚定把注意力重新拉回工具域和任务域。把 keep_recent 设为 3、max_summary 设为 800 token,是我们在 Tier D 下验证过的甜点参数。
把五种对冲能力映射到主流框架,能看出谁默认安全、谁默认危险:
| 框架 | 结果清屏 | 摘要压缩 | 定义重锚 | 按需加载 | 默认累积? |
|---|---|---|---|---|---|
| LangGraph | 手动 | 无 | 无 | 无 | 是 |
| OpenAI Agents SDK | 手动截断 | 无 | 无 | 无 | 是 |
| CrewAI | 部分 | 内置(弱) | 无 | 无 | 是(弱压缩) |
| AutoGen | 手动 | 无 | 无 | 无 | 是 |
| Claude Agent SDK | 内置 | 内置 compaction | 无(靠记忆) | MCP 原生 | 否(自动压缩) |
判读很直接:除 Claude Agent SDK 外,其余四家默认都是"危险累积"。LangGraph、OpenAI Agents SDK、AutoGen 把"是否清理观测"完全甩给开发者,而开发者通常不清——这就是为什么线上 Agent 跑到第 10 步后突然开始"抽风"。CrewAI 有内置摘要但很弱(更多是去重而非降密度)。
没有任何一家框架原生提供"定义重锚"——这是当前工具能力评测里最大的工程空白。这也意味着:今天写一个 Agent,要避免工具视野退化,开发者必须自己实现重锚和清屏逻辑,而不能指望框架兜底。
"工具视野退化"是少数几个厂商不愿讲、但每个上线团队都踩过的坑,变现价值很高:
建议优先级:先做训练营模块(验证需求、积累案例)→ 再做企业诊断(高客单)→ 最后沉淀为中间件产品。
实测中也观察到三个反复出现的认知误区:
flowchart TD
subgraph CI["上下文结构(随循环累积)"]
D["工具定义区(开头,固定 3.8K)"]
O["观测结果海(中段,持续膨胀)"]
Q["当前任务(末尾)"]
D --> O --> Q
end
O -.淹没.-> D
D -.被稀释.-> V["工具可见性"]
V --> F1["参数糊化 8K起"]
V --> F2["选择塌方 24K恶化"]
V --> F3["幻觉调用 48K爆发"]
F1 --> CL["断崖区 52.6%"]
F2 --> CL
F3 --> CL
CL --> S1["截断/滑窗 → 64%-70% 治标"]
CL --> S2["摘要压缩 → 78.5% 治本:降密度"]
CL --> S3["定义重锚 → 86.7% 治本:提可见性"]
CL --> S4["按需加载 → 91.2% 治本:降候选"]
S2 --> BEST["最优组合<br/>压缩 + 重锚 / 按需加载"]
S3 --> BEST
S4 --> BEST
BEST --> REC["选择 91%+ / 幻觉 1.1%<br/>且 token 开销更低"]
style D fill:#cfe8ff
style O fill:#ffd6d6
style CL fill:#ffb3b3
style BEST fill:#c6f0c6
style REC fill:#a8e6a3
xychart-beta
title "工具能力随观测回填 token 的塌方曲线"
x-axis "回填 token 档位" [4K, 16K, 40K, 64K]
y-axis "准确率 %" 0 --> 100
line "选择准确率" [97.2, 88.5, 71.4, 52.6]
line "参数保真度" [94.1, 86.3, 68.9, 49.8]
line "幻觉率x5" [1.5, 9.0, 31.0, 73.5]
| 场景特征 | 推荐对冲策略 | 理由 |
|---|---|---|
| 短任务(<6 步、单工具结果 <4K) | 不处理 | 处于 Tier A,自然安全 |
| 中等任务(6–12 步、结果中等) | 滑动窗口 + 轻量重锚 | 低成本挡住参数糊化 |
| 长任务(>12 步、大观测如日志/检索) | 摘要压缩 + 定义重锚 | 双管齐下,治本 |
| 工具数 >30 的宽工具集 | 按需加载(MCP) + 重锚 | 降候选数是最强杠杆 |
| 对副作用敏感(写库/转账/下单) | 必加重锚白名单 + 人确认门 | 幻觉调用代价不可承受 |
| 跨框架通用 | 自实现"上下文中间件"层 | 框架都不兜底,只能自己做 |
一句话行动项:今天给线上 Agent 加一个"末尾工具白名单 + 近 3 步原文 + 其余摘要"的重锚层,是 ROI 最高的单点改动——它把 Tier D 下的幻觉率从 14.7% 砸到 2.9%,且不依赖任何框架升级。
本文由 51学通信(站长:爱卫生,微信 gprshome201101)AI Agent 实战分析专栏出品。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
