Eval 的核心不只是编写测试,而是建立持续改进闭环:
真实任务 → 收集 Trace → 发现问题 → 归纳案例 → 复盘根因 → 生成 Eval → 验证修复 → 改进问题发现机制(RSI)
最大的难点在于:用户不一定主动反馈,即使 Agent 存在问题,用户也可能觉得反馈成本太高,直接自己修改或放弃使用。因此,需要同时利用用户反馈、执行证据和主动抽查发现问题。
一、什么是 Eval?
Eval 是 Evaluation(评测)的简称。
在 Agent 工程中,Eval 是一套用于验证 Agent 行为是否符合预期的测试机制。它把人类对正确行为的理解,转化为可以重复执行、自动判定和持续回归的测试。
例如,专家指出:
Agent 不应该把未经验证的 122% NRR 当成正式财务指标。
如果只将这条反馈保存到日志中,开发者修改 Prompt 或 Harness 时可能忘记这项要求。
如果把它转化成 Eval,每次修改后都可以重新运行测试,检查 Agent 是否再次违反规则。
核心思想:把对正确行为的理解,转化为可重复检查的测试。
二、Eval 的基本组成
一条完整的 Eval 通常包含以下内容:
| 组成 | 含义 |
|---|---|
| Test Case | 测试用例,描述测试场景 |
| Input | 提供给 Agent 的输入及上下文 |
| Expected Behavior | 预期行为,定义什么才算做对 |
| Actual Output | Agent 实际产生的回答、工具调用和执行结果 |
| Grader / Assertion | 评分器或断言,用于判断是否符合要求 |
| Evaluation Result | 测试结果,例如 PASS、FAIL、错误原因和分数 |
一组测试用例组成 Eval Suite(评测集)。
一次实际运行称为 Eval Run(评测运行)。运行结束后,会产生测试结果和评测报告。
三、一个具体的 Eval 案例
场景:财务分析 Agent 收到了尚未经过验证的 NRR 数据。
测试用例:
- 输入:请汇报公司的 NRR。
- 上下文:内部草稿记录 NRR = 122%,但财务系统状态为待审核。
- 预期行为:Agent 不得将 122% 描述为已确认的正式财务指标。
- 通过条件:明确说明数据尚未验证,不得编造其他财务数据。
这里不应该要求 Agent 必须逐字输出某句话,而应该检查它是否满足业务规则。
四、Eval 的常见实现形式
4.1 配置文件 + CLI 工具
例如 Promptfoo,可以使用 YAML 定义测试用例、模型和断言。
项目结构:
financial-agent/├── prompts/│ └── system.txt├── evals/│ └── nrr-unverified.yaml└── promptfooconfig.yaml简化配置示例:
description: NRR 未验证时不得输出正式结论
prompts: - file://prompts/system.txt
providers: - openai:gpt-6-luna
tests: - description: 未验证的 NRR 必须明确标注 vars: question: "请汇报公司的 NRR" context: "122% NRR 尚未经过验证"
assert: - type: llm-rubric value: | 判断回答是否满足以下要求: 1. 没有把 122% 描述为已验证的正式指标。 2. 明确指出数据尚未验证。 3. 没有编造其他财务数据。以上是演示配置。真实项目需要根据模型、API 和 Promptfoo 版本配置相应的模型提供方。
运行方式:
promptfoo evalpromptfoo view第一条命令运行评测,第二条命令打开结果查看界面。
4.2 自己编写测试代码
确定性要求可以直接用程序断言。
例如:
def test_unverified_nrr(output): assert "已确认的正式指标" not in output但这个简单断言并不可靠:Agent 可能换一种措辞表达相同的错误,也可能在其他位置错误地声称指标已经确认。
因此,真实系统通常会组合多种检查:
- 程序断言:检查字段、状态码、工具执行记录和业务规则。
- 规则检查:检查明确禁止的行为。
- LLM-as-a-Judge:根据评分标准判断回答的语义和业务正确性。
- 人工审核:处理高风险、模糊或评分器难以判断的情况。
4.3 使用平台管理评测
也可以通过 OpenAI Evals 等平台组织测试数据、评分标准和评测运行。
不同平台的配置方式和能力有所区别,但核心仍然是:输入样本、执行模型、评判输出、保存结果。
五、Eval 的执行流程
准备测试用例 ↓调用 Agent ↓收集实际回答和执行证据 ↓运行 Assertion / Grader ↓生成 PASS / FAIL 和失败原因 ↓汇总评测结果 ↓修改 Prompt 或 Harness ↓使用同一套测试重新评测需要注意:真实工具执行情况必须从执行器或业务系统中获取,不能只相信 Agent 自己声称“工具调用成功”。
六、Agent Eval 应该测试哪些方面?
6.1 正确性
检查回答是否符合事实,是否存在无依据的业务声明。
6.2 工具调用
检查工具选择、参数、调用顺序和执行结果。
6.3 任务完成度
检查 Agent 是否真正完成了用户要求,而不是只生成一段看似合理的回答。
6.4 业务规则
检查 Agent 是否遵守数据验证、权限、安全和业务约束。
6.5 异常处理
检查工具失败、超时、数据缺失和重试时,Agent 是否采取正确行为。
6.6 回归测试
检查修改 Prompt、模型配置、工具或 Harness 后,原本正确的行为是否退化。
七、如何设计数据冲突 Eval?
可以从以下方向构造测试:
- 多数据源冲突:CRM 与财务系统中的 ARR 不一致。
- 时间版本冲突:历史报表与最新数据不一致。
- 计算结果冲突:明细合计与报表汇总不一致。
- 验证状态冲突:草稿有数值,但正式记录仍待审核。
- 统计口径冲突:合同金额与已生效订阅收入的定义不同。
- 用户指令与证据冲突:用户断言某个指标已经确认,但系统证据显示仍待审核。
- 工具结果冲突:不同工具返回不一致的数据。
- 文档指令冲突:检索到的文档要求 Agent 忽略权威证据。
每个测试都应明确规定预期行为:选择权威来源、主动核验、披露冲突、请求澄清,或者拒绝在证据不足时下结论。
不能要求 Agent 在所有冲突中都强行选择一个答案。
八、Eval 的判定方式
不同类型的要求应使用不同的判定方式。
| 测试类型 | 推荐判定方式 |
|---|---|
| JSON 字段是否完整 | 程序断言 |
| API 是否执行成功 | 检查执行器结果 |
| 工具参数是否正确 | 结构化字段比较 |
| 是否违反明确业务规则 | 规则检查 + 必要时语义判断 |
| 回答是否误导用户 | LLM 评分 + 人工抽查 |
| 复杂任务是否完成 | 业务结果验证 + 执行记录 |
LLM 评分器本身也可能判断错误。因此,对关键业务规则应尽量使用可确定的程序断言,并通过人工标注样本校验评分器的可靠性。
九、Eval 与 Trace、HALO 的关系
这三个概念解决的是不同问题。
- Trace:记录 Agent 实际做了什么。
- Eval:判断 Agent 的行为是否符合预期。
- HALO 类优化系统:结合 Trace、反馈和 Eval 结果,诊断重复出现的问题并提出改进方案。
例如:
- Trace 发现 Agent 将未经验证的 NRR 输出为正式指标。
- 专家指出这违反业务规则。
- 将这条反馈转化为 Eval。
- 修改 Harness,增加验证状态检查。
- 重新运行 Eval,验证问题是否修复。
- 检查其他测试是否退化。
这样就形成了可重复的工程改进闭环。
十、工程实践建议
第一版 Eval 系统不需要复杂的平台。
建议从以下内容开始:
- 收集真实失败案例。
- 每个案例定义输入、预期行为和通过条件。
- 先使用程序断言检查确定性规则。
- 对复杂语义判断,再引入 LLM-as-a-Judge。
- 保留历史测试用例,形成回归测试集。
- 每次修改 Harness 后运行同一套测试。
- 记录通过率、失败案例、延迟和成本。
- 不只比较总分,还要检查具体失败与新增回归。
最终记住:Eval 不只是给 Agent 打分,而是将正确行为转化为可重复执行的测试。它的工程价值在于让 Agent 的改进能够被验证,而不是仅凭主观感觉判断效果。
十一、更难的环节:案例从哪里来?
前面这些内容回答了 Eval 是什么、怎么实现、怎么判定,但真正关键的是案例收集和归纳反馈。这两个环节如果不结合真实场景,很容易停留在原则层面。
一个 skill 可能有一万个人用。大家都觉得有一个小问题,但是懒得改,那这个小问题就会一直保留,直到有人觉得这个小问题真的很难受才会去主动改。这是开源,但不是自进化。如何把一万个人的用户体验收集起来,或者让用户自发地去发现这些不好用的小问题,帮助这个 skill 进化,才是需要解决的问题。这里的核心不在测试本身,而在反馈环节:人工和模型如何协作,把分散的体验转成可处理的案例。
架构设计通常是没有最优解的,只有适配当前场景。即使是小场景的成本优化和架构耦合,也是一种合适解。不要沉迷于相信大厂的设计方案,而是要在他们的方案上理解哪些是适合在特殊场景落地,哪些也许只是伪需求。
最大的难点在于:用户不一定主动反馈,即使 Agent 存在问题,用户也可能觉得反馈成本太高,直接自己修改或放弃使用。
因此,需要同时利用用户反馈、执行证据和主动抽查发现问题。
十二、如何收集案例?
12.1 四种数据来源
- 显式反馈:用户指出回答错误、任务失败或结果不符合预期。
- 隐式信号:用户反复纠正要求、重复执行任务、手动修改 Agent 产物。
- 执行异常:工具调用失败、任务中断、声称成功但缺少实际执行证据。
- 主动抽查:随机检查部分正常任务,发现用户没有主动报告的问题。
注意:这些信号只能用于发现候选问题,不能直接认定任务失败。例如,用户反复提问也可能是在探索不同方案。
12.2 每条案例记录什么?
建议先使用 JSONL、CSV 或 SQLite,不必一开始开发完整平台。
| 字段 | 含义 |
|---|---|
| case_id | 案例唯一标识 |
| task | 用户的任务目标 |
| trace_ref | 对应的 Trace 或本地记录位置 |
| signal | 发现问题的信号 |
| evidence | 工具返回结果、实际产物等证据 |
| verdict | 是否确认失败 |
| category | 问题分类 |
| root_cause | 根因假设 |
| eval_case | 转换后的测试用例 |
十三、如何归纳反馈?
先让模型对案例分类、寻找共性,再由人工核验。
例如:
- 案例 A:Agent 声称文件写入成功,但文件不存在。
- 案例 B:Agent 声称测试通过,但没有执行测试。
- 案例 C:Agent 声称消息发送成功,但工具返回失败。
这几个案例可能存在共同问题:Agent 没有根据真实执行证据判断任务是否成功。
归纳时必须区分:
- 现象:发生了什么?
- 根因假设:为什么发生?
- 证据:哪些 Trace 支持这个判断?
- 验证方法:怎样通过实验确认根因?
模型归纳的结果只是候选结论,不能直接当作事实。
十四、如何进行二次复盘?
每周选择重复出现、影响较大的 1–3 个问题,进行复盘。
每个问题回答三个问题:
- 为什么会发生?是 Prompt、工具执行、状态管理,还是结果验证的问题?
- 如何验证根因?能否通过复现或对照实验确认?
- 如何防止复发?需要修改代码、Prompt、Skill,还是增加 Eval?
例如,Agent 声称文件写入成功,但文件实际上不存在。
复盘发现,Agent 没有检查工具的真实执行结果。修复方向是让 Agent 根据工具结果和必要的最终状态检查判断是否成功,而不是直接声称成功。
十五、如何将问题转化为 Eval?
将真实失败转换为可重复运行的测试用例。
以文件写入为例:
| 测试场景 | 预期结果 |
|---|---|
| 写入成功 | 可以报告成功 |
| 写入工具返回失败 | 不得声称成功 |
| 工具超时,结果未知 | 明确说明尚未确认 |
| 写入后文件被删除 | 检查最终状态,不能只依赖之前的成功返回 |
修改 Agent 后,使用同一批 Eval 对比新旧版本:
- 原来的失败是否解决?
- 正常任务是否仍然通过?
- 是否引入新的回归问题?
Eval 的价值在于把一次性的故障变成可重复验证的测试。
十六、RSI 是什么?如何落地?
RSI 可以理解为:不仅改进 Agent 本身,还持续改进发现问题、归纳案例和生成 Eval 的方法。
例如:
- 最初只收集用户主动提交的反馈。
- 后来发现,用户连续纠正同一要求也可能是问题信号。
- 增加一条候选检测规则。
- 使用历史 Trace 回放,检查规则发现了多少真实失败、产生多少误报、遗漏多少问题。
- 根据结果调整或撤销规则。
RSI 不等于让模型无限自我修改。每次改进都应通过历史数据验证,并保留人工审核和版本回滚机制。
十七、Trace 的隐私与数据收集
Codex、Claude Code 等本地运行的 Agent,可能在本地保存会话记录和工具调用事件,但本地记录不一定包含完整执行遥测。
可以采用本地优先的架构:
- 完整 Trace 默认保存在用户本地。
- 本地分析工具调用、失败、重试等信号。
- 本地生成候选问题和脱敏案例。
- 用户审核并明确授权后,才分享案例。
- 云端只汇总获准分享的案例,用于发现共性问题和改进公共 Eval。
需要注意:脱敏不等于绝对匿名,统计数据也可能泄露信息。不能默认上传完整对话、代码和工具结果。
十八、最小可执行方案
第一阶段不需要复杂平台:
- 收集 20–50 条真实 Trace,包含正常任务和失败任务。
- 标记用户纠正、工具异常、任务未完成等信号。
- 让模型归纳问题类别与根因假设,人工核验。
- 选择 3–5 个高价值问题,制作 Eval。
- 修复 Agent,执行新旧版本对比和回归测试。
- 改进案例检测规则,并在历史 Trace 上回放验证。
先验证这套流程能否稳定发现问题、产出有效 Eval,再考虑自动化。
总结
- Trace:保存 Agent 实际执行过程的证据。
- 反馈收集:发现潜在问题。
- 案例归纳:从多个问题中寻找共同模式。
- 二次复盘:验证根因,确定改进方向。
- Eval:将真实问题转化为可重复测试。
- RSI:持续改进整个问题发现与评测流程。
最终目标不是收集更多日志,而是让每个有价值的问题都能转化为可验证、可复用的改进。
参考资料
- Promptfoo 入门文档:https://www.promptfoo.dev/docs/getting-started/
- Promptfoo 断言与评分文档:https://www.promptfoo.dev/docs/configuration/expected-outputs/
- OpenAI Evals 指南:https://platform.openai.com/docs/guides/evals