Eval: Agent 说的 Eval 是什么?从单测、TDD 到 Sentry 聊起

最近在很多大模型(LLM)和 AI Agent 的技术讨论里,经常能听到一个词:Eval(评测)。

简单来说,就是写测试用例

大模型每次返回的结果都不太一样,今天回答用中文,明天可能多吐出几个英文单词,这种充满随机性的东西,到底该怎么做评估?

其实,如果换一个大家熟悉的视角,这个问题一点也不神秘。

所谓的 Eval,本质上就是我们前端天天在写的自动化测试 ;而围绕 Eval 展开的工程实践,无非就是 TDD(测试驱动开发)Sentry 错误监控闭环在生成式 AI 时代的一次自然延续。


一、 为什么 Agent 开发不能"凭感觉"?

先从我们最熟悉的前端场景说起。

假设你要在前端写一个商品价格计算的函数 calcDiscountPrice()。作为一个合格的前端工程师,你大概率会用 Vitest 或 Jest 补上几组单元测试:

typescript 复制代码
// 传统前端单测:确定性断言
describe('calcDiscountPrice', () => {
  it('满 100 应该正常减 20', () => {
    expect(calcDiscountPrice(100, 20)).toBe(80);
  });

  it('折扣金额大于原价时,最低应为 0', () => {
    expect(calcDiscountPrice(50, 100)).toBe(0);
  });
});

如果不写这些单测,每次改完代码,你就只能自己在浏览器里手动输入价格,刷新页面看几眼。如果今天心情好点了三组数据觉得没问题,就直接发布上线了,这种做法在业内被戏称为"凭感觉开发"(Vibe Check)。

凭感觉开发最可怕的地方,在于回归盲区(Regression Blindness)------你为了修一个极端情况的 Bug,改动了某段逻辑,自己测了一下这个极端情况确实修好了,却根本不知道这次改动把另外 90% 的常规业务逻辑给破坏了。

在传统代码里,由于逻辑是确定性的,代码行数也不多,即使不写测试,靠人工点点有时候也能糊弄过去。

但到了 AI Agent 时代,大模型是一个巨大的黑盒。你修改了一条 Prompt(提示词),比如加了一句"请以最简短的语言回答",你自测了三个问答,觉得回答确实变简练了;但你完全不知道,这句简短的要求可能导致原本需要输出完整 JSON 结构的几十个工具调用场景全部瘫痪。

没有测试套件的护栏,每一次提示词的微调、每一次底层模型的升级,都无异于在盲人摸象。

Eval,就是专门用来给大模型和 Agent 充当这道测试护栏的。


二、 面对随机性,Eval 到底怎么"测"?

既然要测,很多朋友的第二反应是:前端测试有 expect(a).toBe(b) 这种全等比较,但大模型输出的文本千变万化,我们怎么做断言?

在实际工程中,大家通常会把 Eval 拆分成三个由低到高、由浅入深的层级。

第一层,是确定性硬断言(Deterministic Asserts)。

虽然自然语言千变万化,但很多业务场景下的输出是有硬性契约的。

比如让 Agent 提取一段用户地址并输出 JSON,我们完全可以用标准的 JSON Schema 或者 Zod 进行校验:必须是合法的 JSON 格式、必须包含 provincecity 字段、邮编必须是纯数字。

又比如让 Agent 编写 SQL,我们可以直接把它丢进真实的 SQLite 内存数据库跑一下 EXPLAIN,看看语法是否合法。这一层的运行成本极低,速度极快,不达标直接判错。

第二层,是轨迹与工具断言(Trajectory & Tool Asserts)。

这也是 Agent 与普通 Chat 机器人最大的区别所在。

Agent 往往需要自主规划多个步骤,调用不同的外部 API(Tools)。这时候,我们关心的重点是它的"行为轨迹"是否合规:

  • 它有没有调用预期的工具?(比如查天气时,有没有调用 get_weather?)
  • 工具的入参格式对不对?(日期有没有格式化为 YYYY-MM-DD?)
  • 调用的时序合不合理?(是不是先查询了用户权限,再执行了退款操作?)
  • 有没有陷入死循环?(有没有连续十次尝试同一个无效参数?)

只要校验了它的 Tool Call 序列,Agent 绝大部分的行为可靠性就已经被锁定了。

第三层,是模型裁判(LLM-as-a-Judge)。

当遇到无法用代码精确断言的开放式场景(比如"回答是否礼貌"、"文章润色是否通顺"、"逻辑推导是否严密")时,我们就请出另一个更强大的模型(比如 Claude 3.5 Sonnet 或 GPT-4o)来充当"裁判"。

我们会给裁判模型一份非常详细的评分细则(Rubric)和评判标准:

markdown 复制代码
# 裁判评分标准
- 事实一致性:回答中的数据必须与提供的上下文完全吻合(0/1)
- 语气克制:不能包含推销或过度夸张的修辞(0/1)
- 拒绝越权:如果用户要求查询他人的薪资,必须明确拒绝(Pass/Fail)

裁判模型根据标准逐项打分,并给出判定理由。

准备一个由几十条核心业务用例、历史缺陷样本组成的"黄金测试集"(Golden Dataset),每次改完代码或 Prompt,在本地跑一遍这三层评测,得到一个综合通过率(比如 96%),这就是一个最标准的 Eval 流程。


三、 从 TDD 到 EDD:先写评测,再写 Prompt

在敏捷开发里,大家对 TDD(测试驱动开发) 一定不陌生:

  1. 红灯(Red):先写一个必定失败的单元测试;
  2. 绿灯(Green):写出刚好能让测试通过的最简代码;
  3. 重构(Refactor):在测试用例的保护下,优化代码结构。

在 Agent 开发中,这套思维模式几乎被百分之百复刻了过来,社区里把它称作 EDD(Eval-Driven Development,评测驱动开发)

很多没有经验的开发者做 Agent 时,习惯先打开编辑器,洋洋洒洒写几千字 Prompt,然后去界面上跟它聊两句。聊着聊着发现效果不好,又在 Prompt 里加一段补丁,越改越混乱。

而成熟的做法是:在写第一行 Prompt 之前,先把测试用例定义清楚。

比如我们要开发一个"订单退款审核 Agent",第一步是先把 30 个真实的测试样本写在 JSON 文件里:

json 复制代码
[
  {
    "id": "case-01-normal",
    "input": "我刚拍错了颜色,能帮我把 20260901 的订单退了吗?",
    "expected_tools": ["getOrderInfo", "cancelOrder"],
    "forbidden_tools": ["triggerDispute"]
  },
  {
    "id": "case-02-expired",
    "input": "这件衣服我穿了三个月破了,必须给我全额退款!",
    "expected_tools": ["getOrderInfo", "checkWarranty"],
    "expected_decision": "REJECT_EXPIRED"
  }
]

用例写完,直接运行 Eval。此时由于还没有任何 Prompt 和工具逻辑,测试结果全部飘红(Red)。

接着,你开始编写 Agent 的系统提示词、配置工具描述、编排状态机分支。每一次调整后,都在终端跑一次评测,看着通过率从 20%、60% 稳步爬升到 95% 以上(Green)。

未来无论是要换掉底层模型,还是要给 Agent 增加新功能,只要底下的 Eval 全绿,你心里就有底气。


四、 生成式 AI 时代的 Sentry 闭环

在前端工程中,除了本地的 Vitest 测试,我们还有一个非常重要的基建------Sentry

线上用户一旦遇到页面白屏、JS 报错,Sentry 就会在毫秒内把报错堆栈(Stack Trace)、控制台日志和用户的点击轨迹(Breadcrumbs)抓取下来,聚合为一个 Issue。

以往工程师的做法是:看 Sentry 报错 → 在本地拉代码复现 → 补一个单测 → 提 PR 修复。

而在今天,当 Sentry 遇上大模型和 Coding Agent(比如 Aider、OpenHands 或是 Sentry 最新的 AI CLI),这套闭环正在变得完全自动化:

scss 复制代码
[ 线上生产环境 ]
  │ (捕获用户点踩、Agent 工具调用崩溃或死循环)
  ▼
[ Sentry 监控层 ]
  │ 1. 抓取现场:多轮对话上下文、工具调用轨迹、当前 Prompt 版本
  │ 2. 脱敏去重:去除用户隐私,对相似报错做语义聚类
  ▼
[ 自动化流水线 Worker ]
  │ 3. 逆向合成用例:AI 自动根据报错现场,生成一条新的 Eval 失败用例 (Red)
  │ 4. 自动打补丁:Coding Agent 自动修改代码或调整 Prompt,让用例变绿 (Green)
  │ 5. 全量回归测试:确保本次修复没有破坏已有的 Golden Dataset
  ▼
[ 人工确认 (HITL) ]
  │ 6. GitHub 自动生成 PR,工程师花 30 秒核对 Diff 并点击 Merge
  ▼
[ 自动合并主干 ] ──> 用例正式沉淀进测试集,监控自动标记 Resolved

从传统 Sentry 捕获"确定性的代码崩溃",到 AI 体系捕获"概率性的模型输出偏差";从人工手写测试,到机器自动生成 Eval 用例并尝试自动修复。这个环节节省下来的时间&人力,让我们去做更有意思的事情。


我们前端开发天生对用户体验、接口契约与异常排查非常敏感。面对大模型的不确定输出确实难搞,但只要把它当成一个需要被严密测试的黑盒组件,用写单测和看 Sentry 的平常心去对待它,其实并没有那么遥不可及。

相关推荐
求道於盲1 小时前
python中的类型标注
前端
计算机魔术师1 小时前
从硅谷测试到全球铺开,ChatGPT广告的10亿美元秘密
前端
杨杨杨大侠1 小时前
Agent 是怎么被组织起来的:六种编排方式与选择
aigc·openai·ai编程
jimidou1 小时前
少点几次“允许”,Claude Code 为什么反而更安全?
ai编程
jimidou1 小时前
从 20 人试点到全员使用:Agentic Coding 扩容前,先看团队能不能接住更多代码
ai编程
程序员老刘1 小时前
为了一盘醋吃顿饺子:我把手头的免费AI订阅全榨干了
ai编程
ServBay2 小时前
OpenClaw 2.0 意外更新,龙虾协同能力更强了
aigc·ai编程
专业抄代码选手2 小时前
08|Fiber 上的 `useState`:状态终于属于具体组件
前端·javascript·react.js
默_笙2 小时前
😭 Vibe Coding 翻车实录:AI 编程为什么必须先写"剧本"
前端·javascript