AI Agent效果评测实战——搭完Agent才是噩梦的开始

📅 2026/6/24 4:16:11
AI Agent效果评测实战——搭完Agent才是噩梦的开始
AI Agent 效果评测实战搭完 Agent 才是噩梦的开始上篇我写了怎么在 WebView 里跑 MCP Agent调通了天气查询、邮件发送那一套。然后老板过来问了一句话把我整不会了——“效果怎么样”我当时心想能跑啊你不是看到了吗又一想不对。他问的不是能不能跑是跑得好不好。而我手里没有一丁点数据能回答这个问题。你想想你花了两周搭了个 Agent上线了。然后有人问你它靠谱吗你只能凭感觉说还行吧——这不就是开盲盒吗反常识的是写 Agent 只占四成功力剩下六成全在搭评测。翻车一人工评测——跑了 10 次我自己先崩溃了我一开始的想法特别朴素设计它十个八个任务挨个跑一遍看能不能完成。任务还挺具体的“查一下下周北京天气”“发邮件给张三说会议改期”“查文档里 API 密钥过期时间然后发邮件通知相关人”看着挺像回事吧然后跑第一轮我就傻眼了。同一个 prompt 跑了两次第一次成功了第二次 LLM 在 tool call 阶段选了完全不同的工具。同一个任务两次结果不一样我当时真的是——这是 LLM 抽风了还是网络抖了要不我再跑第三次第四次然后更大的问题来了——“这算完成了吗”有些任务结果是模糊的。比如发邮件给张三说会议改期—— Agent 调了通讯录找到了张三的邮箱写了邮件正文点了发送。但 SMTP 到底发成功没有日志里显示 200 返回但收件箱里真的收到了吗人工核验的话每跑一次都要去翻一遍收件箱。测了大概七八个任务之后我开始放水了——嗯这个大概成功了吧下一个。你懂吧就是那种测着测着就失去耐心了睁一只眼闭一只眼。人工评测的致命伤不可复现、样本量太小、测到后面自己都糊弄自己。翻车二让 LLM 自己判——它疯狂放水人工不行那就自动化吧。我第一版自动化评测的逻辑特别天真让 LLM 自己看工具调用日志自己判定这个任务完成没有。结果呢它啥都说完成了。最离谱的一次——我故意让 SMTP 服务挂了再跑测试。Agent 调了send_email工具返回了 200但邮件根本没发出去因为 SMTP 挂了但 HTTP 层返回的还是成功。然后我让 LLM 评判它看了一眼日志说“工具调用成功邮件已发送”。它只看工具有没有返回成功不管实际执行结果对不对。这个坑我后来怎么填的呢搞了个双判机制。一层是规则校验——不光看工具返回码还得验证执行结果。发邮件不光要看 API 返没返回 200还得真的去查发件箱确认邮件到了没有。这步是死逻辑靠谱但死板。另一层是LLM 评审——把完整的执行链路用户意图 → LLM 推理 → tool call → 工具返回 → 执行结果丢给另一个更强的 LLM 去判。这步灵活但不靠谱刚刚才被它骗过。所以规则层和 LLM 层结论一致的就直接出结果。不一致的标黄让人工介入。两边互相兜底谁也别想糊弄谁。这套方案也不是完美的但至少把瞎放水的问题解决了七八成。翻车三精心设计了 20 个测试用例上线秒打脸前两个坑爬出来之后我花了整整一天设计了 20 个测试用例覆盖了各种常见场景。跑了一轮全绿。我当时那个得意啊——评测体系建好了Agent 效果稳了上线结果上线第一天第一个真实用户问的问题就把 Agent 干懵了。用户问的是“帮我查一下上周那个项目文档里提到的 API 密钥顺便看看有没有过期如果过期了帮我发邮件给相关的人。”我的测试集里根本没有这种查 A 时顺带发现 B 有问题所以执行 C的多跳推理场景。测试集全是单步任务。测试集和真实场景的 gap 有多大你不上线永远不知道。那后面怎么调整的呢两个方向同时改。一个方向是从真实对话里扒测试用例——上线前三天所有用户对话都打日志挑出有代表性的手动加进测试集。别自己拍脑袋设计用例了用户教你的才是最真实的。你设计的用例是你以为用户会问的真实用户问的永远是你没想到的。另一个方向是分场景评估——单步任务归单步任务多步推理归多步推理条件分支归条件分支分开统计成功率。别只看一个总体成功率那是骗自己的。整体八成好看吧但其中一个场景可能只有两成——平均数把你骗了。哪个场景拉了垮一眼就能看出来。代码评测框架核心就仨东西聊了这么多理论来点实际的。我这套评测框架的核心说白了就三个东西任务定义 → 执行器 → 判定器。任务定义长这样——就是一个 JSON 对象告诉系统你要测什么consttestCase{id:case-001,description:查下周北京天气,input:下周北京天气怎么样,expectedTools:[get_weather],// 预期调用的工具列表expectedResult:/北京.*下周.*晴/,// 输出内容用正则匹配可选validation:rulellm// 双判模式};判定器是核心就是前面说的双判逻辑。代码其实没几行asyncfunctionjudge(result,testCase){construlePassruleCheck(result.toolCalls,testCase.expectedTools);constllmPassawaitllmJudge(result.fullLog,testCase.input);if(rulePassllmPass)returnpass;if(!rulePass!llmPass)returnfail;returnneeds_review;// 不一致标黄让人工看}有意思的是needs_review这个分支——两边结论一致的直接过不一致的标出来等人看。一开始我觉得这个分支应该很少结果实际跑起来大概有两三成的 case 会落到这里。这也说明双判不是多余的两条腿走路确实比一条腿稳。实际实现里还加了超时处理、重试策略、结果缓存但上面这段已经能说明核心思路了。收尾没有镜子你都不知道自己长啥样翻了仨大跟头之后有个感受特别深——没有评测体系你根本不知道改了一个 Prompt 是让 Agent 变好了还是变差了。你自我感觉好像好了一点——那是错觉。跑一遍评测数字说话。我现在的习惯是每次迭代前先跑一遍基线。改完 Prompt 或者 Tool 定义再跑一遍同样的测试集。数字涨了就是涨了跌了就是跌了不靠感觉。听起来麻烦但养成习惯之后其实也就几分钟的事。比起你上线之后被用户骂、再去排查、再修、再上线——这几分钟的投入太值了。你们团队怎么评测 Agent 的有没有碰到比我更离谱的翻车评论区聊聊我最近在攒素材写续篇说不定下篇就有你的故事。