Featured image of post 2572 条测试揭示的盲区:Agent 套件大多在测"管道",不在测"决策"

2572 条测试揭示的盲区:Agent 套件大多在测"管道",不在测"决策"

模型榜单和基准评测拿走了几乎全部注意力,而团队为自己开发的智能体应用写的测试,几乎没人系统看过。一项经过同行评审的实证研究补上了这块空白:研…

模型榜单和基准评测拿走了几乎全部注意力,而团队为自己开发的智能体应用写的测试,几乎没人系统看过。一项经过同行评审的实证研究补上了这块空白:研究者不跑分、不发问卷,而是把真实开源项目里的测试方法逐条人工标注,统计它们究竟断言了什么。结论不太客气——绝大多数测试验证的是工具能被调用、代码能跑通,而不是这个智能体是否做出了正确判断。

对正在把大模型能力接进业务系统的团队来说,这份统计的价值不在"分数低",而在于它给出了明确的、可以对照自己套件去核对的比例。

研究是怎么做的

方法本身值得先看,因为它决定了后面的数字能不能信。

研究团队从代码托管平台检索基于智能体框架的 Python 项目,得到 1,190 个候选仓库,覆盖 11 种框架,从中提取出 1,723 个智能体与 4,111 个工具。为了保证人工标注的对象有代表性,深挖范围收窄到"具备一定规模测试套件"的项目,最终对 12 个项目、240 个测试模块里的 2,572 个测试方法逐条标注。

标注由两人独立完成,一致性系数(Cohen’s kappa)为 0.92,属于接近完全一致的区间。分类体系也事先固定:跨 fixture、测试数据、测试目标、断言四个维度共 23 种测试模式,所有百分比都从明确定义的类别里算出,而不是凭印象归纳。此外还访谈了 10 位资深从业者,平均从业年限超过 17 年,用来和仓库数据相互印证。

这是一份关于真实代码的计数证据:不是对意图的问卷调查,也不是厂商跑分。

标注样本中各类测试所占比例,数据来源为该项实证研究的人工标注结果

发现一:多数测试从未让整个智能体跑起来

61.8% 的被标注测试只评估一个工具或一个智能体的孤立行为;34.6% 针对智能体之间、或智能体与其他组件之间的交互;覆盖多工具连续调用的只有 3.5%;通过应用对外暴露的 API 做端到端验证的仅 0.1%。

把这个分布和生产环境里的失效方式对照一下,问题就很清楚。智能体的故障通常发生在交互层:第一步看似合理之后选错了工具、状态跨轮次被错误携带、第二个工具收到的输出结构与第一个工具的约定不一致。而这些恰好落在测试最薄的那一层。

研究还观察到框架会悄悄决定测试形态:提供清晰工具隔离边界的框架(如基于 MCP 的项目)更偏单元测试;把编排逻辑显式写在代码里的框架(如 LangChain、LangGraph 一类)则出现更多集成测试。技术选型在无意中决定了团队"会顺手测什么"。

发现二:三分之一测试在 mock 自己声称要测的东西

34.4% 的测试以某种形式 mock 了智能体或工具:21.7% 替换部分组件,22.3% 替换整个智能体,两类有重叠。而所有 mock 场景里,只有 13.4% 使用了为特定验证目标专门构造的测试替身,其余依赖标准打桩与 fixture。

mock 本身没有原罪,它让测试快速、确定。问题在于智能体系统里一个工具其实有两个接口:面向机器的调用 API,以及面向模型的自然语言描述——后者决定了模型如何理解"什么时候该用它、参数该怎么填"。一个返回正确值的 mock,完全无法说明这段描述是否会让模型在恰当的时机、用恰当的参数调用这个工具,甚至是否调用它。

换句话说,mock 测试证明的是编排逻辑没写错,不是工具选择没写错。这两件事在测试报告里都显示为绿色。

发现三:输入比真实任务干净得多

39.9% 的测试使用简单的、示例式的输入,只有 10.5% 覆盖多步场景。

这是"测试数据比用户更整洁"的经典问题换了一层皮。一个语义明确、答案唯一的干净提示词,几乎在任何模型版本、任何提示词微调、任何工具改动下都会通过;它同样会在真实复杂请求把系统打崩的前一周顺利通过。当测试输入比线上请求整齐一个数量级,套件测量的就只是那个整齐的世界。

具体到智能体,缺失的往往是这些:字段不全的请求、上一轮对话改变了本轮含义、工具第一次返回错误后需要重试或改道、用户中途修正目标。这些才是多步场景的实际内容。

发现四:推理是产品本身,却几乎没有被断言

断言目标里,输出占 55.9%,状态占 51.1%,而与推理相关的行为只有 8.7%。研究对这 8.7% 的评价相当直接:它们大多只检查"类似推理的行为出现了没有",不检查它是否正确、是否有用。文中举的例子是验证子智能体的活动出现在日志里——至于这次委派是否恰当、子智能体的工作是否改善了最终结果,测试并不关心。

另一个数字更值得警惕:只有 4.1% 的测试验证与非确定性、非智能体组件的交互,2.4% 验证与确定性组件的交互。对一类主要风险来自副作用的系统(写文件、改记录、发消息、触发支付)来说,“做了什么"这一层几乎没有留下可核查的证据。最终答案正确但过程调错了工具、用了错误的客户 ID,输出断言是抓不到的。

发现五:安全、性能与成本几乎不在测试范围内

触及非功能需求的测试只占 7.5%。在这本就不大的一块里,49.0% 关于安全,33.5% 关于性能,8.8% 关于内存,4.6% 关于策略合规。折算下来,全体标注测试中涉及性能的大约 2.5%——而这类软件单个任务就可能循环调用几十次付费模型。

访谈中的从业者比开源项目更看重非功能测试,这大致说明生产环境的教训会补上仓库里看不到的那一课。但两边报告的核心缺口是一致的:缺乏成体系的测试基础、测试目标不清晰、难以生成高质量测试数据。

从"只测管道"到覆盖轨迹、状态与副作用的四层补强路径

重新配平,而不是推倒重来

不需要重建整套测试体系,只需要按下面五个方向调整比例。研究给出的百分比正好是"应当远离"的基准线。

  • 每个关键工作流补一条端到端任务测试。 用真实工具、带噪声的真实输入,断言的不是最终文本,而是世界的最终状态:如果智能体应当更新一条记录,就去查那条记录。
  • 断言轨迹,而不只断言答案。 检查哪些工具被调用、调用顺序、传入参数。用错误客户 ID 调错工具却凑出正确答案,是输出断言必然漏掉的失败。
  • 保留 mock,但标明它证明不了什么。 被 mock 的工具测试只证明编排逻辑;在测试名或注释里写清这一点,避免后来者把绿灯读成端到端置信度。
  • 给输入加点脏东西。 歧义请求、缺失字段、改变语义的前序轮次、首次返回错误的工具。10.5% 的多步场景占比,是自己套件可以对照超越的数字。
  • 至少加一条非功能测试。 单任务 token 或成本上限、超时、或者"检索内容里夹带提示注入字符串时不得触发工具调用”。一条就比 92.5% 的测试覆盖为零要强。

这项研究的边界

把结论用准,比引用结论更重要,有三点必须同时说明。

样本偏向"规范到愿意维护较大测试套件"的项目,因此行业整体实践可能比这些数字更差,也可能在性质上不同;研究统计的是仓库里编码下来的测试,不覆盖链路追踪复核、评测看板、人工探索性测试等同样真实但不在套件内的验证路径,作者也明确承认这一点;此外单元测试占多数本身并不错误,任何健康套件里快速廉价的单测都应当多于缓慢的端到端测试,这里讨论的是其他层几乎缺席,而不是第一层不该存在。

反过来,支撑结论的证据也相当扎实:人工双标注且一致性 0.92,分类体系具体到 23 种模式,访谈结论与仓库数据在核心缺口上指向一致,成果经过同行评审而非博客断言。

研究还给出了三条"什么会推翻我"的条件,很适合作为团队自己跟进的观察指标:如果出现一份针对闭源生产系统的同规模人工标注研究,发现推理断言与非功能测试占比高出数倍,那么开源样本就不再是有效警示;如果单测与 mock 密集的团队在生产事故率上并不劣于做轨迹与状态测试的团队,这些缺失层的实际重要性就要下调;如果框架把轨迹断言、状态差分做成默认能力且有数据表明开发者真的在用,那这份统计就只是一个时间切片,而非长期问题。

一个可以马上做的自检

打开自己项目的智能体测试套件,逐条问一句:如果模型从明天起不再好好推理、但所有管道照常工作,这些测试里还有多少条会通过?

这个比例就是当前套件真正覆盖智能体能力的部分。它通常比覆盖率报告上的数字低得多,而且低得有道理——因为绝大多数断言从写下那一刻起,针对的就不是模型最可能出错的地方。把一条端到端状态断言、一条轨迹断言、一条成本上限加进去,套件才开始测试这个系统之所以是智能体的那部分。

使用 Hugo 构建
主题 Stack 由 Jimmy 设计