智能体面试准备(九十三):智能体持续评测与 EvalOps 工程------评测即代码/CI集成/回归门禁/数据集版本化
引言
本文是 B 系列第 93 篇。前面 B56 讲了评测门禁与回归测试,B65 讲了轨迹评测与工具调用正确性,B91 讲了评测可复现性与基准治理。这些把"怎么评"讲清楚了,但还差一步工程化:评测不能只在大版本发布前人工跑一遍,而要像单元测试一样,每次提交、每次改 prompt、每次换模型都自动跑、自动拦。这就是 EvalOps(评测运维化)。
本文把"持续评测"当成一套工程体系讲清:评测即代码(Eval as Code)、数据集版本化、CI/CD 集成与门禁、回归与漂移检测、评测数据集治理。它和 B56 的关系是:B56 是"门禁概念",本文是"把门禁焊进流水线";和 B91 的关系是:B91 保证单次可复现,本文保证"跨时间、跨提交的持续可复现"。
EvalOps 流水线
==================================================
代码/prompt/模型变更
│
▼
CI 触发 ──► 拉取版本化评测集(Git/对象存储)
│
▼
评测即代码(pytest harness) ──► 跑轨迹 + LLM-as-Judge
│
▼
门禁判定(阈值/回归对比) ──► 通过则合入, 不通过则拦截
│
▼
结果归档 + 漂移告警 + badcase 回流
一、什么是 EvalOps
传统评测是"项目制":攒一批题、人工跑、出报告、归档。问题是智能体迭代极快(prompt 天天改、模型月月换),人工评测跟不上,且不可复现。
EvalOps 把评测当成生产流水线的一部分 :
-
评测集像代码一样版本化、可 review。
-
评测脚本像测试一样可重复执行。
-
评测结果像 CI 一样自动判定门禁。
-
评测趋势像监控一样持续追踪。
核心收益:改一行 prompt,10 分钟后自动知道"准确率从 82% 掉到 79%、哪 5 个 case 退步了",而不是上线后用户投诉才发现。
二、评测即代码(Eval as Code)
把"出题---跑 agent---判分"固化为可执行代码,而不是散落的人工步骤。
数据集版本化:评测集放进 Git 或对象存储(带版本号/哈希),每次变更留痕、可回溯。禁止"临时在 Excel 里改几题就重跑"------那会导致结果不可比。
断言与判分:每个 case 有预期(终态、工具调用序列、关键字段),判分可以是精确匹配、正则、或 LLM-as-Judge。
python
# eval harness 示意 (pytest 风格)
import pytest, json
CASES = load_versioned_dataset("agent_eval@v3") # 版本化评测集
@pytest.mark.parametrize("case", CASES)
def test_agent_case(case):
trace = run_agent(case["input"], model="gpt-4o-mini")
# 硬断言: 必须调用了正确工具
assert called_tool(trace, case["required_tool"])
# 软判分: 终态字段正确
score = llm_judge(trace.final, case["expected"])
assert score >= case.get("min_score", 0.8)
record_metric(case["id"], score) # 落库供趋势分析
数据集版本化要点:每条 case 带 id,这样两次运行才能做逐 case 对比(哪些从 pass 变 fail),而不是只看总分波动。
三、CI/CD 集成与门禁
把评测 harness 挂进 CI(如 GitLab CI / GitHub Actions),在 PR 阶段跑。
门禁类型 :
-
绝对值门禁 :如"整体准确率 ≥ 80% 才放行"。
-
回归门禁:如"相比 main 分支,pass 数不得减少、P99 延迟不得升高 10%"------这比绝对值更关键,能拦住"总分没变但关键 case 悄悄退步"的坏变更。
PR 流水线
push/PR ──► 单元测试 ──► 构建 ──► 评测门禁 ──► 合入 │ 跑 Eval-as-Code │ 对比 main 的基线指标 │ ┌─────────────┴─────────────┐ 通过(无回归) 失败(有回归/阈值不达标) │ │ 允许合入 拦截 + 贴出坏 case 列表
门禁失败不能只报"不过",要贴出退步 case 清单 + 前后轨迹 diff,让作者 5 分钟定位。这与 B56 的"上线守护"一致,只是把触发点前移到开发期。
四、回归与漂移检测
回归检测:每次运行保存指标快照(总分、逐 case 结果、延迟、成本)。新运行与基线对比,标记 flip(pass→fail 或 fail→pass)。flip 到 fail 即回归,必须查。
漂移检测 :即使代码没改,模型供应商升级、检索库更新、外部 API 行为变化都会让分数悄悄漂移。对策:
-
固定模型版本(pin model version),避免"同一个 prompt 今天 85 明天 82"还说不清原因。
-
周期性(如每日)跑同一套评测集,画趋势线,超阈值告警。
python
# 漂移检测伪代码
baseline = load_metrics("main", days=7).median() # 近 7 天基线
today = run_eval_today()
if today.accuracy < baseline * 0.95: # 跌超 5%
alert(f"评测漂移: {baseline:.2f} -> {today.accuracy:.2f}, 查模型/检索变更")
五、评测数据集治理
EvalOps 长期跑,数据集本身会腐化,需要治理:
- 去污染:case 若被写进训练集(数据泄漏),分数虚高。定期审计 case 是否出现在模型训练语料。
- 难度分层:分 easy/medium/hard,避免"总分涨了其实是加了简单题"的假象。
- 覆盖度追踪:按能力维度(规划/工具/记忆/安全)打标签,看哪类能力没被覆盖。
- badcase 回流:线上失败案例自动沉淀为新评测 case,形成"线上问题 → 评测集补强 → 门禁防回归"的闭环。这与 B74 的"badcase 回流质量闭环"呼应。
六、常见坑
| 现象 | 根因 | 对策 |
|---|---|---|
| 总分没变但线上崩 | 只看总分、无逐 case 对比 | 加回归门禁 + case 级 diff |
| 分数忽高忽低 | 模型版本未 pin / 随机性 | pin 版本、固定 seed、多次取均值 |
| 评测集泄漏 | case 进训练语料 | 定期去污染审计 |
| 门禁太严卡死迭代 | 阈值过僵 | 分级门禁 + 人工 override 留痕 |
| LLM-Judge 不稳定 | 判分模型漂移 | Judge 也版本化 + 人工抽检校准 |
| 评测越跑越慢 | 集太大每次全跑 | 分层采样 + 全量定时跑 |
面试速答
- 什么是 EvalOps?把评测像测试一样工程化:评测集版本化、评测脚本可重复执行、CI 自动门禁、结果持续追踪,每次变更自动跑。
- 评测即代码核心?出题---跑 agent---判分 固化为代码;数据集带版本与 case id,支持逐 case 对比与回溯。
- 门禁哪两类?绝对值门禁(总分阈值)+ 回归门禁(对比基线不得退化),后者更关键能拦住悄悄退步。
- 漂移怎么防?pin 模型版本、固定 seed、周期性跑同一集画趋势线超阈值告警;外部依赖变更要能溯源。
- 数据集治理?去污染、难度分层、能力维度覆盖度追踪、badcase 回流补强评测集形成闭环。
高频追问清单
- 绝对值门禁和回归门禁怎么结合用?只设一个会漏掉什么?
- 逐 case 对比的实现前提是什么?为什么 case 必须有稳定 id?
- LLM-as-Judge 本身不稳定,怎么把它也纳入 EvalOps 的可复现体系?
- 评测集多大才够?全量每次跑太慢怎么办(分层采样怎么分)?
- 多模态 Agent 的评测 case(含图/视频)怎么版本化与去污染?
- 门禁误杀(好变更被拦)怎么缓解?override 机制如何既灵活又留痕?
- badcase 自动回流成新 case,怎么避免评测集无限膨胀与偏置累积?
- 评测指标除了准确率,还要追踪哪些(延迟/成本/稳定性)才能反映真实质量?