先说个我观察到的普遍现状:很多AI Agent项目在验收前的demo演示里特别风光,能回答问题、会调工具、还能把多步任务串下来。可一旦脱离那几个精心挑选的演示用例,进入真实的内测环境,队伍就开始头疼了——同一个任务上午还跑得通,下午就莫名其妙卡住;用户换个说法,Agent就像换了个人;更让人崩溃的是,你盯着日志找了一晚上,随手重跑一次,它又通过了。这种“偶尔成功”的状态,比完全不可用更磨人,因为你根本说不清修复到底有没有生效。
走了几次弯路之后我才想明白,症结往往不在某个prompt写得不好,也不在模型选型不对,而是整个项目缺少一个最基本的评测闭环。没有稳定反馈回路的Agent开发,本质上就是在碰运气。这篇文章我就把搭评测闭环的完整思路、落地步骤和踩过的坑展开说说,适合那些已经把Agent demo跑通、但正在被稳定性和可维护性折磨的团队或个人开发者。
1. 为什么你的Agent只能“偶尔成功”:缺的不是调优,是反馈回路
1.1 非确定性让“修bug”变成了“猜问题”
我经常听到团队说:Agent的问题很难修,因为bug是飘的。这其实很正常,LLM的每次输出都带有随机性,温度、采样策略、上下文里每个细微的变化都会让结果发生偏移。普通程序同一份代码加同一个输入,输出几乎是一模一样的,所以单元测试就能保证质量;但Agent不一样,每一次模型调用都像一次小规模掷骰子,即使温度调成0,还有top_p、缓存策略、工具返回内容的变化在起作用。
更麻烦的是,Agent是一个多步骤链路。我在模拟项目X里观察过,一个八轮任务只要中间任一步的输出稍微偏一点,后面几步就会跟着歪掉,最后呈现为“整条路径失败”。想象你让一个容易受情绪影响的朋友帮忙办事:有时候他听一遍就懂,有时候需要反复解释,有时候做了一半把任务忘了。你没法靠对他“喊大声一点”来解决问题,你需要的是观察他到底在哪一步开始跑偏、为什么跑偏。评测闭环的价值就在这里:它不直接给你答案,但把“哪里开始偏”的证据摆到你面前。
1.2 失败可能发生在三层里的任何一层
另一个让Agent排查困难的地方,是错误层级不清晰。我把Agent运行里的问题分成三层:
- 模型层:返回内容不符合约定格式、参数名写错、幻觉出一个根本不存在的工具、输出大段废话而不是工具调用。
- 工具层:外部API超时、返回空结果、数据结构变化、鉴权失败。
- 编排层:多步任务里选择了错误的工具顺序、陷入重复循环、中途退出、忘了初始目标。
每次人工排查失败,都得打开trace逐层看,才能判断锅在哪一层。没有结构化记录时,这个分析过程极其费时。我见过不少团队,出问题先怀疑模型不够强,于是换更大的模型,问题依旧;再怀疑prompt写得不好,逐字逐句调了一整天,还是没效果。原因就是大家都下意识假设问题出在某一个固定位置,但实际上失败往往横跨两层:比如工具层返回了一个空值,导致模型层误判“任务已完成”,最后在编排层直接退出。
评测闭环解决的正是这个问题:它不能帮你直接定位,但能把“哪类失败最多、集中在哪些环节”自动呈现出来,让排查从大海捞针变成带着地图挖宝。
1.3 评测闭环的本质:可复现、可归因、可回归
我理解的评测闭环,不是简单的“跑一批case看准确率”,而是包含四个环节的首尾相连的循环:
- 任务集:覆盖真实使用模式的有标签case集合。
- 评测执行:以可复现的方式运行Agent,并记录详细trace。
- 指标体系:从结果、路径、成本多个维度衡量每次运行。
- 迭代流程:把失败聚类传导回开发,修复后再回归,并把新badcase沉淀进任务集。
这四个环节连起来,其实就是在回答三个问题:失败能不能稳定复现?失败出在哪个环节?改动之后有没有让情况变好?想从“偶尔成功”走到“稳定可用”,没有这条路,光靠调prompt、换模型、多试几次,都是头痛医头。
2. 评测题库怎么搭:既要覆盖真实场景,又要能判定成功或失败
2.1 先从层级结构搭任务集
第一个要纠正的观念是:评测集不能是“几个碰巧能跑通的prompt”,也不能直接挪用公开benchmark。公开benchmark适合横向对比模型能力,但它代表不了你的实际用户会怎么使用Agent。我建议按复杂度把任务分成三层:
- L0:单步工具调用,比如“查一下今天的天气”“把这段文字翻译成英文”。它验证的是模型能不能正确理解工具schema、生成符合格式的调用。
- L1:多步固定流程,比如“查资料-总结-写邮件”,步骤顺序基本固定。它验证的是编排能力和中途状态保持。
- L2:长程开放任务,比如“帮我做一份季度竞品调研报告”,没有唯一答案,需要规划、搜索、筛选、生成。它验证的是规划能力和从失败中恢复的能力。
为什么要分层?因为不同层级的失败原因完全不一样。你在L0层发现格式错误,大概率是模型层的问题,改prompt或换更强模型即可;在L1层频繁失败,多半是编排逻辑僵硬,需要把步骤拆分得更弹性;到了L2层失败,往往是Agent不会做长期规划、不会在无结果时换路线。分层之后,修复动作才有明确的指向性。
2.2 种子任务从哪来:日志、反馈、业务方提问
用例不是坐在工位上拍脑袋编的。我推荐三步走:第一步,从线上或准线上日志里捞高频请求,哪怕产品还在内测,把用户最常问的20个问题捞出来,它们就是最好的种子。第二步,把内测群、反馈表里的负面场景补充进去,尤其是那些“用户觉得它蠢”的case。第三步,对每个种子做语义变异,同一意图换时间、换数量、换格式、换干扰条件。比如“搜一下本周的AI新闻”可以变成“只找上周的,不要本周的”“找和医疗相关的”“给出新闻来源和链接”等。
为什么要变异?因为Agent对措辞极其敏感,同一个意图换个说法,成功率可能从80%掉到40%。如果评测集全是原始种子,你修完之后可能只是背下了那20道题,用户真实输入一变就露馅。通过变异,任务集覆盖的语义域才会变大,评测结果才更有参考价值。
2.3 评测任务的“标准答案”要可判定
和传统测试最大的不同是,Agent任务不能写死一个预期输出。比如搜索行业新闻,即使两条输出都相关,模型产出一版好一版坏,很难说谁对谁错。所以任务要用“关键检查点”而不是整段结果作为评判标准。一个任务条目应该包含下面这些字段:
{ "task_id": "research_weekly_001", "level": "L2", "scenario": "用户要求根据本周行业新闻生成周报", "input": "帮我整理本周AI行业的几条重要动态,输出一份300字以上的周报", "environment": { "search_mock": "industry_news_2025W11", "doc_ready": true }, "checkpoints": [ { "type": "tool_call", "name": "search", "min_times": 1 }, { "type": "content", "desc": "至少包含3条独立事件" }, { "type": "format", "desc": "输出含Markdown小标题" } ], "success_criteria": "checkpoints全部通过,且输出中无事实错误" }我特别强调checkpoint的作用:它不要求Agent复现我们手动跑的路径,只要求关键动作发生、关键内容出现。有些团队试图让Agent完全按照人工预定义的“黄金路径”走,结果把Agent调成了脚本复读机,输入一变就死。灵活性和可控性的平衡,就落在checkpoint的设计上。
至于数量,我个人经验是一开始不用贪多,30到50条高质量、覆盖三个层级的用例就足够建立基线了。关键是每个用例要真的能反映业务使用模式,等闭环跑起来后再慢慢扩充到几百条。
3. 结果、路径、成本:三个视角衡量一次Agent运行
3.1 结果指标:成功率和质量分级
最基础的指标当然是最终任务成功率,也就是Agent运行完毕,输出的东西满足验收条件。但只有这一个指标,你会立刻遇到两个新问题。第一个是部分成功怎么算?比如用户要一份调研报告,Agent搜到了资料、也写了文档,但漏掉了其中一个小节,这算成功还是失败?强行二值化会丢失大量信息。我的处理办法是在最外层加质量分级:S级完全达标,A级基本达标但有瑕疵,B级部分完成,C级失败。报告里看S+A的比例,而不是只看单一成功率。
第二个问题是有些任务“看起来成功,实际作弊”。比如任务是把一份PDF总结成PPT,Agent跑完却输出“请用户手动下载后上传到网盘”,流程没走完,但最终文案看起来像完成了。如果没有路径检查,这种假成功很容易骗过你的指标。结果指标不是不行,而是必须搭配下面这些“过程指标”,才能看清Agent是不是真在干活。
3.2 路径指标:步骤成功率、无效重试、过早放弃
路径指标是Agent评测里最容易被忽略、也是最有价值的部分。我常用的有三个:
- 步骤成功率:整条链路上工具调用真正成功的比例。
- 无效重试次数:同一个动作反复执行却始终失败,说明Agent不懂“此路不通就换条路”。
- 过早放弃率:任务目标还没达成,Agent就自己判定结束,把半成品交给用户。
我在模拟项目X里就看到过一个典型例子:某条用例的成功率已经到80%,但细看trace里的无效重试次数从来不低于5次——Agent一遍遍用同一个搜索词搜一个不存在的话题,最后才勉强换词成功。这说明它在“空结果”处理上靠的是碰运气,而不是真有策略。这类问题如果不看路径指标,你永远发现不了。
路径指标的另一个作用是反作弊:检查Agent是否真的主动调用了必要的工具,还是靠大模型的常识硬编答案。硬编答案在某些评测题里也能得分,可一旦到了真实环境就会露馅。用路径指标可以过滤掉这种“看起来聪明”的假成功。
3.3 成本指标:轮次、token、延迟、稳定性
从Demo到生产,成本是不能回避的指标。同样一个任务,A版本8轮迭代完成,B版本12轮完成,虽然两者都成功,但B的token消耗可能多出50%。在成本敏感的场景里,这就是不能接受的回退。延迟同理:一个Agent如果平均要两分钟才回一个普通查询,用户早就跑了。我建议固定记录四个成本指标:平均轮次、平均和最大token、端到端延迟的P50和P95、工具调用次数。
还有一个容易被忽略的稳定性指标。同一个任务,固定seed、温度调到0跑五次,如果Agent给出的结果时好时坏,那这个“成功”的置信度就很低。实际操作中,我建议每个任务在评测时至少跑3到5遍,即使不把重复次数计入总分,也要记录方差。因为“有时成功”对于生产环境来说已经是灾难了。
3.4 用一张评分卡固定不同场景的偏好
不同业务对指标的偏好差异很大。做一个给客服用的FAQ助手,结果质量的权重最高,成本可以放宽;做一个批量数据处理Agent,路径稳定和成本效率甚至比单次结果质量更重要。所以我建议团队做一张评分卡,把不同指标的权重固定下来。下面是一个简单示例:
| 指标 | 客服问答Agent权重 | 自动化数据处理Agent权重 |
|---|---|---|
| 任务成功率(S+A占比) | 45% | 30% |
| 步骤成功率 | 10% | 25% |
| 无效重试次数 | 5% | 15% |
| 平均轮次/token | 10% | 20% |
| 端到端延迟 | 15% | 5% |
| 稳定性(多次运行方差) | 15% | 5% |
权重不一定要严格算出一个加权总分,但团队心里必须有数。否则开发过程中很容易出现“为了提升1%成功率,把平均轮次从8推到15”的得不偿失。评分卡的作用就是逼你明确优先级,不然每个人都在按自己的直觉优化指标。
4. 跑评测本身就是工程:怎么让失败从“玄学”变成“证据”
4.1 确定性控制:种子、温度与mock依赖
要让失败从偶然变成证据,第一步是提高可复现性。评测运行时要固定随机种子,把推理温度调到0,关闭任何采样随机性的选项。同一个任务用同一套配置跑,结果偏差会小很多。但完全确定性不等于真实,所以我建议保留两套配置:一套是“固定配置”,用于回归对比;另一套是“随机配置”,比如温度0.7左右连跑多次,用于评估稳定性。两个都要,缺一不可。
另一个重点是mock外部依赖。Agent越真实,依赖的外部服务就越多:搜索引擎、数据库、文档解析、第三方API。真实调用这些服务,评测结果就会被外部抖动污染——某次失败是因为搜索超时,而不是Agent逻辑错误,你很难从失败case里区分出来。我们的做法是把外部服务替换成预先录制好返回结果的mock桩。搜索服务mock成固定返回30条新闻的数据源,评测就只能考察Agent怎么使用这个数据源,而不会把网络波动算进Agent头上。
第一次跑自动化评测时,我犯过一个错误:直接用真实API并发跑100条任务,结果把搜索服务的配额打爆,评测失败,还顺带影响了线上功能。从此以后,所有大规模评测都放在mock环境,全量回归才用真实API做小流量抽样。
4.2 每次运行都要留下结构化trace
无论评测通过还是失败,都必须把整次运行的决策过程dump成结构化日志。我习惯每个step记录:当前轮次、模型输入摘要、选择的工具、工具入参、工具返回状态码和摘要、模型最终决策、耗时、token数。生成的trace大致长这样:
{ "run_id": "research_weekly_001_run_003", "task_id": "research_weekly_001", "seed": 42, "model_config": {"temperature": 0, "top_p": 1}, "steps": [ { "step": 1, "chosen_tool": "search", "tool_input": "本周 AI 行业新闻", "tool_result_code": "ok", "tool_result_preview": "30条新闻,第一条标题...", "decision": "use_search_result", "latency_ms": 800, "cumulative_tokens": 1500 }, { "step": 2, "chosen_tool": "write_doc", "tool_input": "周报草稿...", "tool_result_code": "ok", "decision": "generate_final", "latency_ms": 200, "cumulative_tokens": 2400 } ], "final_state": "completed", "final_output_preview": "周报正文前100字..." }为什么要求这么细?因为只记录最终结果根本无法定位问题。你看到任务失败,但不知道是哪一步偏了;有了结构化trace,你可以自动对齐“预期该调用的工具序列”和“实际发生的工具序列”,快速知道第几步开始偏。这套数据日后还能用来做失败聚类、输入压缩、微调数据筛选,是整套闭环里最宝贵的资产。
4.3 失败自动分类,而不是只统计一个“失败数”
成功只有一种形态,失败各有各的姿态。一个成熟的评测系统必须在跑完后自动把失败归入预设分类,至少覆盖以下常见类型:
- 工具格式错误:模型返回的调用不符合schema,或参数名写错。
- 工具执行失败:调用本身返回了error、超时或空结果。
- 策略缺失:拿到空结果后不换策略,反复重试同一操作。
- 上下文截断:任务太长,后半程模型丢失初始指令。
- 约束违反:生成内容不在允许范围内。
- 死循环或超限:轮次超过上限,或重复同一动作超过N次。
分类逻辑其实不复杂:分析trace里的工具返回码、模型参数解析结果、轮次数和token累计,就能自动贴上标签。分类出来的统计结果比单一失败率有用得多——你第一时间就能看到“本轮的失败中,40%是工具格式错误,30%是空结果后无策略”,然后就知道该先修哪个方向。
4.4 评测报告长什么样
一套可用的评测报告,我觉得至少要包含四块:整体指标汇总表、失败分类占比、每个任务的单条结果和trace链接、与上一次基线的diff。我也给一个示例表格作为参考:
| 失败类别 | 频次 | 占比 | 典型任务 | 关联run_id | 建议检查环节 |
|---|---|---|---|---|---|
| 工具格式错误 | 12 | 34% | task_batch_007 | run_007_01 | 工具schema提示词 |
| 空结果后无策略 | 9 | 26% | task_research_003 | run_003_04 | 系统提示/检索策略 |
| 上下文截断 | 6 | 17% | task_report_011 | run_011_02 | 记忆压缩/历史裁剪 |
| 其他 | 8 | 23% | - | - | 人工复核 |
报告里最关键的其实不是那些数字,而是每条失败都能跳转到对应的trace。开发同学看到一条失败分类之后,点进去就能复现、审查、修改。如果评测系统只输出一张分数表,研发还是只能全靠猜。
5. 让评测结果驱动下一次开发:回归、badcase沉淀与日常流程
5.1 修改之前先建基线,改完之后跑diff
闭环真正转起来的第一件事,是给当前系统存一个基线报告。以后每次改prompt、改编排逻辑、替换模型,都先跑全量评测,再和基线做diff。diff时我习惯看三点:成功率有没有回退、失败类别分布有没有偏移、成本指标有没有劣化。三者都能接受,才允许合入。
有个团队直到引入diff才发现,他们之前调prompt经常是“东边亮了西边灭”——某个case成功率上去了,另外三类任务的失败率悄然上涨。没有基线对照,这种回归往往要等线上用户骂了才知道。有了diff,回归在评测阶段就被拦截住了。
5.2 失败聚类后,按性价比而不是按面子修
当评测报告给出失败分类之后,最忌讳的是“哪个case看着难修复就修哪个”,或者“哪个case被领导点名就先修哪个”。正确顺序是:按频次乘以影响再除以修复成本来排序。先处理高频且影响大的类别,哪怕它的修复看起来只是改一句系统提示;低频但影响恶劣的case,比如触犯安全约束的,优先人工兜底;高成本低收益的失败,先列入待办清单,不急着动。
我举个例子:模拟项目X初期报告里,“搜索无结果后策略缺失”占失败总量的26%,修起来只需要在系统提示里写清楚“无结果时换关键词、换来源、再告知用户”,改动小收益大;而“历史对话压缩”涉及整个上下文管理模块的重构,虽然也能提升成功率,但工程量大,就放在第二阶段。按性价比排序,让闭环能快速见效,团队也更有信心把流程坚持下去。
5.3 badcase沉淀回题库,防止“修好又坏”
每轮评测暴露出的典型失败case,必须沉淀回评测集。比如你修复了“搜索无结果后策略缺失”,这个case就要作为永久回归用例留在任务集里——下次任何改动如果让Agent再次放弃搜索,评测会立刻报警。这一步决定了闭环是否真正存在:没有badcase回流,你做的只是一次性抽样调查,下一次修复很可能让旧问题复发。
我建议把badcase单独建一个“回归集”,和主线任务集分开管理。回归集里的case不需要太多,但每一个都至少是对应过真实bug的高价值样本。主线集负责衡量整体能力,回归集负责钉死历史问题。
5.4 把评测变成日常开发流程的一部分
AI Agent项目和普通软件一样,自动化测试必须成为开发流程的一部分。我们在模拟项目X的实践是:每次PR触发轻量评测,20条关键用例,5分钟跑完;合入主干前触发全量评测并对比基线;模型或工具升级固定每两周做一次全量回归。评测结果直接挂在变更请求的评论里,评估不通过,代码就不允许合入。
一开始开发同学会不太适应,觉得评测太慢、太严格。但只要团队坚持一两个迭代,大家就会感受到好处:频繁的小步改动有了安全网,模型升级再也不是“开盲盒”。这套机制越早建起来,你被线上事故教育得就越少。
6. 落到模拟项目X上:评测闭环如何把“偶尔成功”磨成“稳定可用”
6.1 项目背景与前后数据
模拟项目X是我们的一个多工具Agent,它需要搜索行业资料、读取本地文档、整理要点、生成周报。功能听起来简单,可内测时随机拿10个任务给Agent跑,经常只有三四个能顺利产出合格周报。团队知道大概是编排或提示词不稳,但没有证据,只能一遍遍试。
我们花了一周左右搭出最小闭环:50条任务集、mock搜索和文档服务、固定种子和温度、结构化trace、失败自动分类、基线diff。之后连续跑了四周迭代,核心数据出现了明显变化:
| 指标 | 搭建评测前(人工抽测) | 闭环运行4周后(自动全量) |
|---|---|---|
| 单任务成功率 | 约42% | 83% |
| 步骤成功率 | 约70% | 96% |
| 平均轮次 | 12.4 | 7.1 |
| 无效重试次数 | 4.6 | 1.2 |
| P95端到端延迟 | 110s | 43s |
变化并不是一天出现的。第二周我们只修了“无结果后策略缺失”,成功率就跳到65%;第三周修了工具格式的松动问题,到了78%;第四周优化了长任务的上下文压缩,才站上83%。每一步都有评测数据做背书,不再靠感觉。
6.2 评测暴露的三个典型问题:工具格式、策略缺失、上下文截断
工具调用格式不稳定是最先暴露的问题。模型偶尔会把参数名写成“keyword”,而schema里要求的是“query”。这类问题在单个case上偶发,人工根本不会注意到,但聚合后一看占了失败的三成。修复方式是加强工具schema的说明和few-shot示例,并在Agent侧加一层格式校验自动重试,把偶发错误从源头消化掉。
搜索无结果时不会换策略,是第二个问题。那段时间mock搜索数据源里故意放了几条没有结果的查询,Agent就一直用同一个关键词重试,重试到超限,然后输出“抱歉我找不到资料”。修复成本很低:在系统提示里明确写出“无结果时先换同义词、再换时间范围、再换搜索来源”,并增加主动向用户确认的可选项。
第三个问题是长任务后半程上下文把目标挤掉了。周报任务进行到第五轮后,Agent忘了用户要求“300字以上”,生成了一张简短的提纲。这不是模型笨,而是任务上下文管理有缺陷。我们加了记忆压缩机制,每轮结束后把历史摘要压缩成不超过500字的运行摘要,问题就消失了。
6.3 复盘:四条我从这套闭环里换来的经验
自动指标必须先和人工抽评对齐。我们出现过自动评测判定“成功”但人眼一看明显不合格的case,原因是checkpoint漏了“内容准确性”这一项。在跑自动评测之前,先随机抽20条结果让评审人把关,把checkpoint补全,再放开自动评分,否则分数好看但没有意义。
一次只动一个变量。闭环建立后,我们严格遵守“每次提交只改一个方面”——要么只改提示词,要么只改编排逻辑,要么只换模型。只有这样,评测diff的归因才干净。混合修改虽然感觉上更快,但失败时你根本不知道该怪谁。
评测数据质量大于数量。50条精心设计的任务集,好过500条从网上拉来的通用case,后者的覆盖度和你真实业务的相关性完全不在一个层面上。
无法复现的失败先放一放,集中处理可复现的失败。偶尔出现一次的case,大概率是外部抖动或模型随机性,追着它调prompt是浪费时间。先抓那些在同一配置下重复出现的失败,把可复现的问题清零后,再回头处理偶发性问题。
我心里很清楚,这套闭环把我们从“开着灯找钥匙”的窘境里拽了出来——灯亮了,钥匙的位置其实一直都在那里。最后分享一个我一直在用的小习惯:每次全量评测跑完,把当前基线报告按日期存档;之后任何改动,先和最近一次存档做diff再讨论结论。这个习惯帮我挡住了好几次“看起来优化成功、实际上悄悄劣化”的提交,希望你也用得上。