工具使用能力的评测,已经被 BFCL 和 τ-bench 雕琢到了"调对"的极致——选对工具、填对参数、JSON 合规、多轮串并。可真正决定 Agent 能否把一个工具调用变成一次正确决策的,是工具返回之后的那一段:读懂返回值里的数值、分辨空与错的区别、追踪多跳结果之间的依赖、从嵌套结构里挖出埋在第四层的字段。这一段,恰恰是当前所有主流评测的公共盲区。本文实测六大"返回消化"退化模式,并给出对应的对冲工程。
先厘清一条事实链:工具调用的生命周期可以切成四段——意图理解 → 调用合成 → 结果返回 → 结果消化。BFCL V1–V4 几乎把火力全部压在第二段,V3 引入 multi-turn/multi-step 后开始触及第四段,但它的判分仍以"最终答案字符串是否匹配 ground truth"为准,过程里 Agent 是真的读懂了返回值还是蒙对了答案,无从分辨;τ-bench / τ²-bench(Sierra)用 dual-control 双控制环境测多轮客服任务,同样只在任务级打分。结果就是:一个"调对工具、参数完美、却把返回值里的 total: 0 当成 total: null 从而胡乱补救"的 Agent,在两者榜单上都能拿高分。
这就是本文要钉死的那条缝——消化力(result comprehension)。下面六态,是把这条缝撑开后的实测图谱。
| 评测体系 | 核心测什么 | 是否覆盖"返回消化" | 典型盲区 |
|---|---|---|---|
| BFCL V1–V2 | 工具选择 + 参数格式(串行/并行) | 否 | 完全不验证返回值是否被正确理解 |
| BFCL V3 | Multi-turn / Multi-step 链式调用 | 间接(仅看终态匹配) | 过程消化质量被答案匹配掩盖 |
| BFCL V4 | 多跳 web search、agentic 检索 | 部分 | 多跳结果链的中间断裂不可见 |
| τ-bench / τ²-bench | 多轮客服任务、用户+工具双控制 | 任务级 | 返回值误读被后续对话"自圆其说" |
这是最被低估也最致命的一态。Transformer 的注意力呈 U 型曲线:开头和结尾的 token 被牢牢抓住,中段无论多关键都会被稀释。原研究在多个长上下文模型上测得的"关键信息置于中段时"准确率仅 76%–82%,而置于首尾时接近 100%。把这个结论平移到工具返回上:当一个 search_orders 返回 40 条记录、而正确答案藏在第 18–22 条里时,Agent 漏判率会陡升。
工程上的对冲很直接——重排(reranking)与去中段化。在把工具结果写回上下文前,做一次摘要前置 + 关键字段置顶:
def reshape_tool_result(rows, key_fields):
# 把命中的关键字段提到结果头部,打破 U 型谷底
head = [{k: r[k] for k in key_fields} for r in rows if matches(r)]
tail = {"total_returned": len(rows), "full_rows": rows}
return {"highlighted_hits": head, "context": tail}
这一步在 BFCL 评测里拿不到分(因为它不关心你怎么摆),但在真实生产里能把漏判率压下一个数量级。
Agent 读返回值里的数字,常在三处翻车:单位剥离("price": "30 USD" 被当 30 个单位,与另一处 "amount": 3000 cents 直接比大小)、量级误读(1_000_000 与 1000000 在某些分词下被拆解后比较出错)、聚合自造(返回里没有总和,Agent 凭"看起来像"自己算一个并当成返回值的一部分)。
这背后是 LLM 对结构化数值的"读"和"算"是两个脱钩的能力。对冲工程是把数值推理外包给确定性工具——任何涉及比较、求和、排序的,强制走一个 calculator 工具而非让模型脑算:
# 错误:让模型直接读 JSON 算总额
agent.run("从返回结果里算出这批订单的总退款")
# 正确:强制走工具,模型只负责提取数值、不负责算
agent.run("用 calc.sum 提取每单 refund 字段求和,再返回结果")
这条规则在"自主智能体完成幻觉破局"之外,是另一个独立的数值层——它解决的是读对却算错,而非声称做完了实际没做。
这是最隐蔽的一态。工具返回有四种"没有东西"的语义:空数组 [](查到了、但确实没有)、null(字段不存在)、空对象 {}(资源存在但无内容)、以及 error(调用失败)。当前 Agent 倾向于把这四态塌缩成同一个"为空",然后给出统一的"未找到"或更糟的——统一触发兜底编造。
实测场景:一个 get_user_coupon(user_id) 返回 [](用户没有任何优惠券)时,Agent 若把它当 null(不确定有没有),就可能去自造一张优惠券参数去调 apply_coupon——这正好踩中"最大似然填补"的本能。对冲工程是给工具结果加结构化语义标记,让模型不靠猜:
@tool
def get_user_coupon(uid):
rows = db.query(uid)
return {
"status": "ok", # ok / empty / not_found / error
"count": len(rows),
"rows": rows,
"semantic": "user_has_no_coupons" if not rows else "ok"
}
把"为什么是空"显式写出来,比指望模型从 [] 推断出"用户确实没有"要可靠得多。
BFCL V4 引入多跳(multihop)web search 任务,本质就是"前一个工具的返回值要喂给后一个工具"。这正是消化力被压测的地方:第一跳返回的实体 ID、时间戳、坐标,必须在第二跳的参数里被原样且正确地传递。实测发现的高频断裂点是实体消歧——第一跳返回 Paris(法国)和 Paris(德州),Agent 在第二跳参数里传了一个模糊的 Paris,导致整条链偏航。
BFCL V4 用 DuckDuckGo API 做数据源、用多跳判分,已经暴露了这个问题,但它仍只在终态打分,中间跳的断裂会被"换条路也到了终点"掩盖。生产环境的对冲是显式的跳间契约(hop contract):每一跳必须输出一个类型化的中间凭证,下一跳的参数 schema 强制引用它,类型不匹配直接拒绝。
@dataclass
class HopResult:
entity_id: str # 强类型凭证,带命名空间
entity_type: str
source_hop: int
工具返回一个四层嵌套的 JSON,关键决策字段埋在 data.results[0].policy.refund.eligible 时,Agent 的命中率会断崖式下跌。这不是 lost-in-the-middle(位置问题),而是深度问题——模型的"结构指针"能力随嵌套深度衰减。同一份信息,平铺成 eligible=True 时几乎全对,埋进第四层时漏过半。
对冲工程是工具侧做投影(projection),而不是寄望模型爬深。让工具支持 fields= 参数,按调用方需求只返回扁平后的相关字段;或在结果回写上下文前,用一个廉价的确定性抽取层把深层字段拍到表层。这是"工具调用上下文工程"在消化端的延伸——前者管"塞进去的形状",这里管"读出来的形状"。
最后一态最危险:返回值明明不支持某个结论,Agent 却做出了这个结论。典型表现是工具返回 confidence: 0.4 的低置信结果,Agent 报告时把它当成确定事实;或返回 approx_count 却被当成精确计数用于下游。这与"完成幻觉"的区别在于——它发生在单次工具调用的消化窗口内,而不是整轮任务收尾时。
对冲工程是强制置信度传播:任何带 confidence / estimated / caveat 字段的返回,必须在 Agent 的最终输出里原样回显,并在低于阈值时触发追问或降级。用一个轻量的结果校验器挂在 agent loop 的工具返回回调上即可:
def on_tool_return(result: dict):
if result.get("confidence", 1.0) < 0.6:
inject_system_note(
"上一条工具结果为低置信,禁止据此下确定性结论,需追问或换工具。"
)
flowchart LR
A[用户意图] --> B[调用合成<br/>BFCL/τ-bench 覆盖]
B --> C[工具执行]
C --> D[结果返回]
D --> E1[中段失明]
D --> E2[数值失真]
D --> E3[空值混淆]
D --> E4[多跳断裂]
D --> E5[嵌套盲区]
D --> E6[因果短路]
E1 --> F[结果消化层<br/>当前评测公共盲区]
E2 --> F
E3 --> F
E4 --> F
E5 --> F
E6 --> F
F --> G[决策输出]
F -.对冲工程.-> H[重排/外包计算/语义标记/跳契约/投影/置信传播]
style F fill:#fee,stroke:#c33,stroke-width:2px
style H fill:#e8f5e9,stroke:#2e7d32
把六态摆在一起,能看到一条规律:消化退化几乎都源于"模型用读自然语言的本能去读结构化数据"。BFCL 和 τ-bench 给了行业一把测"调对"的尺子,却没人递上测"读懂"的尺子。在垂直行业落地(金融核对、医疗检索、法律引证)里,真正酿成事故的多半不是调错了工具,而是读懂错了返回——把 0 当成 null,把 approx 当成 exact,把第四层字段当成不存在。
对冲工程的共性也很清晰:不要让模型在消化窗口里做它不擅长的事。读,可以让它做;但比较、聚合、深度寻址、置信判定,都应该被推给确定性层或显式契约。这与"无框架智能体"所揭示的"抽象税"是同一枚硬币的另一面——不是抽象越少越好,而是该硬的地方必须硬。
| 场景 | 首选对冲 | 次选 |
|---|---|---|
| 高频检索类 Agent(订单/文档) | 返回重排 + 关键字段置顶(破 U 型谷) | 工具侧 fields= 投影 |
| 涉金额/计数的金融核对 | 数值推理强制外包 calc 工具 |
结果校验器卡量级与单位 |
| 多源融合决策 | 显式跳间契约 + 类型化凭证 | 多跳结果去重与冲突消解层 |
| 空结果敏感业务(库存/权限) | 结构化语义标记四态 | 空态触发追问而非兜底 |
| 低延迟流式场景 | 摘要前置(首字即消化) | 置信传播阈值降级 |
训练维度上,这六态恰好能直接落成一套独立于 BFCL 的"消化力小项"——给每个工具调用配一个过程级判分(返回值里的哪个字段被用到了、是否被正确解读),而非只看终态答案。这套小项本身就是一份可交付的训练营实训靶子:六个退化、六个对冲、一套可复现的探针,闭环完整。
工具调用评测的下一代竞争,大概率不在"调得更对"——那已经被 BFCL V4 卷到边际收益递减;而在"读得更懂"。谁先把消化力做成可量化的尺子,谁就拿到了生产级 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 等场景全覆盖。
