Agent 评测换判据:用终态数据库状态判定任务是否完成
原文:Hugging Face Blog(Microsoft 联合发布)- 《The Agent Said It Was Done. The Database Disagreed.》(https://huggingface.co/blog/microsoft/thinkingbox)
一个客服 Agent 处理一笔 745 美元的家电配送工单:它连做了九次看着都合理的工具调用,正确读到了退款政策,然后把工单标成已解决。但有两处仍然是错的------承运商的异常件还挂着,按规则工单应该停在挂起状态;客户真正问的那个问题也始终没被回答。只看工具调用序列或最后那句总结,这次运行会被判成功。数据库不同意。
2026 年 10 月 3 日,Microsoft 与 Hugging Face 联合发布了评测框架 ThinkingBox 和基准集 ThinkingBox-Bench,把 Agent 的判据从"说了什么"换成了"在后端留下了什么"。这篇按落地的顺序拆开讲:判据怎么定、为什么必须重复跑、失败究竟卡在哪一层。
一、"看起来没问题"的轨迹才是最难的
先看一组数字。论文在 12 个模型、121,680 次有效试验上做了一次消融,其中 79,853 次没有通过可执行检查。而在这 79,853 次失败里,67.24% 是在一次改变状态的工具调用之后"干净结束"的------最后一次工具调用没有报错。
这句话的信息量很大。它意味着两件平时常被当成通过信号的东西都不可靠:
- 工具有没有报错:不报错不代表改对了地方;
- 结尾那句"已完成":模型是在生成了状态变更之后才说这句话的,措辞流畅和状态正确之间没有任何强制关系。
真正被改错的地方,只有回到数据里才看得见。
二、判据换成终态与副作用
ThinkingBox 的每个任务由五个部分定义,缺一不可:
- 起始后端状态;
- 用户目标;
- 可用的 MCP 工具集合;
- 该领域的策略规则;
- 针对终态的可执行断言。
任务里还有一个模拟用户,手里握着私有上下文------比如预订编号、个人偏好、出生日期------只有在 Agent 主动询问时才释放。这一点还原了真实场景里"信息不是默认给全的"这个约束。
跑完之后,一个副作用提取器先推导出这次尝试实际改动了什么,再由确定性判分器拿它和要求终态比对。判分器的取向值得记下来:它接受任何能产生正确结果的轨迹,同时拒绝错误的、缺失的、以及多余的副作用。也就是说过程随便走,终点必须对,而且不能顺手多改东西。
每次尝试都拿到一个独立的 MCP 会话,状态全新初始化,同一个任务的两次尝试不会共享任何数据库行或缓存的工具状态。这是后面"重复 20 次"能成立的前提------否则第二次跑的是第一次留下的现场。
三、语义类要求用窄二元问题兜住
并不是所有要求都能落成一个干净的数据库值。像"Agent 有没有说明这不保证?"这种,就没有字段可查。
ThinkingBox 的做法是分两类处理:507 道题里有 477 道只按状态判分,剩下 30 道额外加一份响应评分表,用一道很窄的二元问题处理语义。这个比例本身就说明了设计取向------能交给状态判的,绝不交给语言模型判。
还有一条容易被忽略的边界,原文写得很清楚:模型能看到任务、对话和工具 schema;而标准答案状态、断言、判分内部实现和凭据,全部留在评测方一侧。评测环境的信任边界是从一开始就划好的,不是事后补的。
四、做对一次和次次做对是两件事
这一节是整篇最值得带走的部分。
ThinkingBox-Bench 把 507 道题每道跑 20 次,于是同一批模型上出现了两套完全不同的排序。
单次成功率第一是 Claude Opus 5.5,67.16%,比 Claude Opus 5 的 66.50% 略高。但换成"20 次全过"的题目数,两个模型都是 241 题,也就是 47.53%------平均分提高了,可靠任务一个没多。
开源权重侧的对比更刺眼。Kimi-K3 至少成功过一次的题目占 93.89%,可 20 次全对的只有 68 题,13.41%。
这两个数字放在一起看就够了:如果只报单次成功率,可用性会被系统性高估。前端一次演示成功、生产和长任务里反复出岔子,根子就在这个差距上。
五、失败八成发生在工具层
失败特征分布比总分更有指导性。在前面那 79,853 次失败里:
- 77.61% 出现字段值错误;
- 43.30% 产生多余的副作用;
- 25.36% 缺少必需的副作用。
三类之间有重叠,一次失败可能同时中好几项。
按可观测标签归因,79.9% 的失败落在工具使用上,之后依次是状态更新错误 10.3%、用户问题未解决 7.0%、完全没有做状态变更 2.9%。原文特意注明这些是可观测标签而不是因果解释,但从工程角度看结论已经够用:多数失败是重试与恢复的问题,不是推理不够聪明。
域之间的差异同样值得注意。零售场景平均单次成功率约 59.52%,而车险只有 33.83%------同一个模型换个业务域,表现可以拦腰砍。
成本口径也换了一个看的角度。这里不是算每次调用多少钱,而是算"每个可靠任务"多少钱:最早完成全部 20 次的有 GPT-5.4 的 128 题、GPT-6 Astra 的 231 题、Claude Opus 5.5 的 241 题,对应约 6.80、7.45、7.80 美元。原文说明价格取自 2026 年 9 月 20 日的一份报价快照、用未打折的标价计算,是个横向比较用的指数,不等于真实云账单。
六、把它跑起来
框架和数据集都已经公开:harness 是 MIT 许可,benchmark 数据是 CDLA-Permissive-2.0。运行环境要求 Linux 或 WSL,Python 3.11 以上,外加 uv 和 Docker。OpenEnv 镜像只起 OpenEnv API,其余服务自己跑。安装分三步:
bash
# 1. OpenEnv + ThinkingBox 环境
git clone https://github.com/huggingface/OpenEnv
cd OpenEnv
uv sync --project envs/thinkingbox_env --frozen
# 2. 可执行基准,切到钉住的发布版本
git clone https://github.com/microsoft/thinkingbox-data
git -C thinkingbox-data checkout thinkingbox-bench-v1.0
# 3. ThinkingBox CLI,提供 tb 命令
uv tool install "thinkingbox @ git+https://github.com/microsoft/thinkingbox"
接下来是四个进程:Typesense 30.1 起检索后端、会话代理与 MCP 服务器、OpenEnv server 按 YAML 配置连上三个模型(Agent、模拟用户、judge 可以共用一个端点),最后用就绪接口做一次门控。就绪检查在可观测数据、配置和会话代理三项通过前会一直返回失败,但它看不到 Typesense,也不会去探活每个模型端点,这两项要自己确认。
跑一道题的评分长这样:
bash
# 指定单道题,跑 1 次,输出结果与错误旁路
echo "- sandbox_external_retail_group1.py:test_case_ST002_001" > one_task.yaml
uv run --project envs/thinkingbox_env thinkingbox-eval \
one_task.yaml \
--config "$PWD/thinkingbox.yaml" \
--output results.jsonl \
--errors-output errors.jsonl \
--repeat 1 --message-timeout 1800
这里有个很实用的设计:操作性失败(环境、超时之类)会写进单独的 errors 旁路文件,可以重跑,而不会和模型本身的对错混在同一个结果里。一份规范的结果必须把所有尝试都判掉或者显式说明,不能把没跑成的算成模型失败。研究里用的重复次数是 20,自己项目里跑不起 20 次的话,先从 5 次起步看稳定性也行。
七、四条可以搬回自己项目的做法
原文最后给了几条建议,都是从上面的数据里推出来的:
- 提交变更前先检查终态,别把"工具没报错"当成"改对了";
- 给工具错误分类,只有可恢复的错误才值得重试,否则只是在消耗预算;
- 收缩可用工具面,工具越多,选错和参数错的表面积越大;
- 不能廉价回滚的变更要求人工审批。
作者也坦承,这几条改动能带来多少提升,他们没有在基准上量过。这算是个诚实的边界------方法是数据读出来的,效果还得自己在自己的场景里验证。
小结
ThinkingBox 的核心贡献不是又出了一份排行榜,而是换了一个判据:不看 Agent 说了什么,看它往数据里写了什么。加上每道题 20 次独立重复,单次成功率和"次次做对"之间的巨大落差被直接暴露了出来------67.16% 的单次准确率,对应的是 47.53% 的可靠任务。
对做 Agent 的人来说,最省事的一步是先在自己的评测里加上两个东西:一个终态断言,一个重复次数。前者让"看起来完成"不再蒙混过关,后者让稳定性成为可以被报告的数字。