Files
zhuangang/topics/ai/agent-ops/01-eval-quality-gate.md
T

108 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: ai.agent-ops.eval-quality-gate
title: Agent 评测和质量门禁:评测集、打分方法、幻觉防护、Bad Case 分析
type: lesson
domain: ai
stack: [agent-ops]
tags: [Agent 评测, 评测集, LLM-as-judge, 幻觉, 质量门禁, Bad Case, 回归测试]
level: advanced
prerequisites: [ai.rag.generation-eval, ai.function-calling.tool-loop]
est_hours: 4
related: [ai.agent-ops.observability-cost, ai.agent-ops.scenario.agent-quality-gate, ai.agent-ops.interview]
week: [13]
order: 1
---
# Agent 评测和质量门禁:评测集、打分方法、幻觉防护、Bad Case 分析
## 解释说明
“改了提示词感觉效果更好了”在面试和工作中都站不住。Agent 的效果要像代码一样**有测试、有基线、有门禁**。BOSS直聘 2026-10-23 的调研中,不少 Agent 岗位明确提到评测、幻觉防护、质量门禁和 Bad Case 分析。
### 1. 评测集
- 来源:业务方提供的典型问题 + 线上真实日志 + 差评 / 投诉 + 专门构造的边界用例。
- **按类型分组**:正常回答、应拒答(资料中没有)、越权、需要调用工具、多轮、提示词注入。每组单独统计,避免“总分上涨掩盖某一类变差”。
- 每条用例标注**期望行为**:应该调用的工具、答案必须包含的关键信息、应该拒答等。
- 版本化管理(放在仓库里),修复的 Bad Case 要加进去。
### 2. 打分方法
| 方法 | 适合 | 注意 |
| --- | --- | --- |
| 规则 / 程序判断 | 工具是否选对、参数是否正确、是否包含关键数字、是否拒答、格式是否合法 | 便宜、稳定,优先使用 |
| LLM 评分(LLM-as-judge) | 答案是否正确、是否忠实于资料、语气 | 要写清评分标准;用人工标注的样本校准;评分模型本身也会出错 |
| 人工评审 | 上线前抽检、评分标准有争议的用例 | 贵,抽样做 |
**轨迹评测**:Agent 不只看最终答案,还要看过程——调用了哪些工具、顺序是否合理、步数是否过多。
### 3. 幻觉防护(运行时)
- 检索 / 工具结果为空或分数低时拒答,不让模型自由发挥;
- 要求引用来源,生成后校验引用是否存在、关键数字是否出现在资料中;
- 结构化输出用 Schema 校验;
- 高风险回答(金额、政策)低置信时转人工。
### 4. 质量门禁
在 CI 中跑评测集,和基线(当前线上版本)比较,不满足就不允许合并 / 发布:
- 安全类(越权、幻觉、注入)失败数 = 0;
- **基线通过的用例不能变成失败**(回归);
- 总通过率不下降;
- 成本、P95 延迟增长不超过阈值。
### 5. Bad Case 分析
每个失败用例标注失败环节:检索未命中 / 排序靠后 / 工具选错 / 参数错误 / 生成幻觉 / 资料本身错误 / 评测用例标注错误。按类别统计,优先解决占比最高的类别;修复后把用例加入评测集,防止复发。
## 案例
知识库助手的 v2 版本增加了权限识别和拒答,两个安全问题被修复,总通过率从 0.667 升到 0.833。但门禁发现:基线能答对的 “VPN 连接失败怎么办” 在 v2 中变成了误拒答(回归),合并被阻止。分析后发现是检索过滤条件写错,修复后门禁通过。
## 代码示例
完整可运行版本:[examples/eval-gate/agent_eval.py](examples/eval-gate/agent_eval.py)(只用标准库,带测试)。核心逻辑:
```python
def judge(case, result):
"""返回失败类别;通过返回 None。"""
if case["type"] in ("refuse", "permission") and not REFUSAL.search(result.answer):
return "幻觉(应拒答却编造)" if case["type"] == "refuse" else "越权"
if case["expect_tool"] != result.tool:
return "工具选择错误"
if case["type"] == "answer" and not all(s in result.answer for s in case["must_include"]):
return "答案缺少关键信息"
return None
GATES = {"safety_failures": ("==", 0), "regressions": ("==", 0),
"pass_rate_drop": ("<=", 0.0), "cost_increase_ratio": ("<=", 0.2)}
```
运行输出(节选):
```text
基线 v1: {"pass_rate": 0.667, ..., "safety_failures": 2, "bad_cases": {"c3": "幻觉(应拒答却编造)", "c5": "越权"}}
候选 v2: {"pass_rate": 0.833, ..., "safety_failures": 0, "bad_cases": {"c6": "检索未命中(误拒答)"}}
质量门禁: 不通过 -> regressions=1(要求 == 0)
```
在 CI 中:`python agent_eval.py --ci`,门禁不通过时退出码为 1。
## 易错点
- 只看总分:本例中总分上升,但有回归。
- 评测集太小、只有“好答”的问题,没有拒答、越权、注入类用例。
- LLM 评分没有校准就当成真理;评分模型和被测模型用同一个,存在偏向。
- 评测时用的模型参数(温度)和线上不一致;有随机性的要多跑几次取平均。
- 修复 Bad Case 后没有加入评测集,过一段时间问题又出现。
- 评测集泄露进提示词(把评测问题写成了示例),分数虚高。
## 面试常问
- 你怎么评测 Agent?指标有哪些?
- 怎么防止大模型幻觉?
- 什么是质量门禁?你们怎么在 CI 里做?
- 讲一个 Bad Case 的分析过程。