Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 人工智能 / Artificial Intelligence

智能体工程 / Agent Engineering

1. Agent 工程体系全景 / Agent Engineering System Overview

2. Function Calling - 让 LLM 具备行动能力 / Function Calling for Giving LLMs the Ability to Act

3. Agent 框架演进 - 从裸 SDK 到 LangGraph / The Evolution of Agent Frameworks from Raw SDKs to LangGraph

4. RAG 基础 - 让 Agent 拥有"知识" / Retrieval-Augmented Generation Fundamentals for Agent Knowledge

5. 记忆管理 - Agent 的大脑 / Memory Management as the Brain of an Agent

6. Agent 工作流 - 从单步到复杂的执行编排 / Agent Workflows from Single Steps to Complex Orchestration

7. 多 Agent 系统 - 多个 Agent 协作 / Multi-Agent Systems and Agent Collaboration

8. RAG 进阶 - 企业级知识库实战 / Advanced RAG for Enterprise Knowledge Bases

9. 真实 Agent 应用场景 / Real-World AI Agent Applications

10. Structured Output - 让 LLM 输出可控的结构化数据 / Structured Output for Controllable, Machine-Readable LLM Responses

11. Tools Design Best Practices - AI Agent 工具设计最佳实践 / Tools Design Best Practices for AI Agents

12. Agent 架构模式 - 从单 Agent 到多 Agent 的工程范式 / Agent Architecture Patterns

13. Agent Modes — 编程 Agent 的交互模式设计 / Designing Interaction Modes for Coding Agents

14. Agent Workflow 编排:从循环到持久化执行的演进

15. Context Engineering - 从 Prompt 设计到上下文编排 / Context Engineering: From Prompt Design to Context Orchestration

16. Agent 缓存工程:从 KV Cache、Prompt Cache 到语义缓存 / Agent Caching Engineering

17. Harness Engineering, Skills, and Loop Engineering — 从信任模型到验证系统 / From Trusting Models to Verifying Systems

18. MCP 协议 - AI 工具的"USB 接口" / Model Context Protocol for AI Tool Integration

19. Agent 评估与测试 — 如何衡量一个"不可预测"的系统 / Agent Evaluation and Testing — How to Measure an "Unpredictable" System

20. 安全沙箱 - Agent 的安全边界 / Secure Sandboxes as Agent Safety Boundaries

21. 权限与门卫 - Agent 的安全控制中枢 / Permissions and Policy Gates for Agent Control

22. API Key 管理与安全 - Agent 的密钥生命周期的管理 / API Key Lifecycle Management and Security for Agents

23. 提示词注入防护 - Agent 的防御前沿 / Prompt Injection Defense for AI Agents

24. 可观测性与调试 - Agent 运行的透明度保障 / Observability and Debugging for Transparent Agent Operations

25. 模型路由 - 让正确的模型做正确的事 / Model Routing for Matching Models to Tasks

26. OpenClaw 设计深度分析 - 为什么它让人觉得"活"了 / OpenClaw Design Analysis and the Illusion of Liveliness

27. Claude Code 泄露源码深度分析 - 512,000 行代码揭示的生产级 Agent 架构 / Claude Code Source Analysis and Production Agent Architecture

28. LobeChat 设计深度分析 - 全栈 Agent Chat 应用工程实践 / LobeChat Design Analysis and Full-Stack Agent Chat Engineering

29. 编程 Agent 全面对比:从 Claude Code 到 Pi 的设计哲学 / Coding Agents Comparison: Design Philosophies from Claude Code to Pi

30. 领域 Agent 的确定性工具编译与延迟执行——从自然语言规格到单次 CAE 提交

31. Agent 工程学习指南 / An AI Agent Engineering Learning Guide

本页目录

Agent 评估与测试 — 如何衡量一个"不可预测"的系统 / Agent Evaluation and Testing — How to Measure an "Unpredictable" System ​

📅 创建时间:2026-07-28 🏷️ 标签:#AgentEvaluation #Testing #LLM-as-Judge #Benchmark #Eval 📚 前置知识:[[00-agent-overview]] [[01-function-calling]] [[05-agent-workflow]]


📋 本章目标 ​

  • 理解为什么传统软件测试方法论在 Agent 面前失效
  • 掌握 Agent 评估的三个层次:Component / Task / Trajectory
  • 理解 LLM-as-Judge 的原理、设计方法、常见陷阱
  • 了解主流 Agent 基准测试(SWE-bench、WebArena、GAIA、AgentBench)及其局限性
  • 能够设计一套实用的 Agent 评估系统(数据集、指标、回归测试)
  • 知道 Braintrust / LangSmith / OpenAI Evals 三个框架的定位与选型

第1部分:为什么普通软件测试不适用于 Agent? ​

1.1 传统软件测试的"确定性契约" ​

在任何传统软件中,测试建立在一条铁律之上:相同输入产生相同输出。

python
# 传统单元测试:断言是精确的
def test_add():
    assert add(1, 2) == 3          # 永远为真
    assert add(-1, 1) == 0          # 永远为真
    assert add(0, 0) == 0           # 永远为真
1
2
3
4
5

这个假设如此基础,以至于我们很少意识到它的存在。函数的返回值由代码逻辑完全决定——没有随机性,没有"理解偏差",没有"今天状态不好"。测试的本质就是:给定输入,断言输出。

┌─────────────────────────────────────────────────────────────┐
│                  传统软件测试模型                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   输入 ──→ [ 确定性函数 f(x) ] ──→ 输出                      │
│                                                             │
│   测试 = 验证 f(input) == expected_output                   │
│                                                             │
│   特点:                                                     │
│   ✅ 相同的 input 永远产生相同的 output                      │
│   ✅ "正确"有唯一标准答案(1+1 就是 2)                      │
│   ✅ 边界条件可枚举                                         │
│   ✅ 回归测试 = 同样的用例再跑一遍                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

1.2 Agent 的"非确定性"从哪来? ​

Agent 的核心是一个 LLM。而 LLM 的推理过程引入了传统软件没有的变量:

┌─────────────────────────────────────────────────────────────┐
│                  Agent 执行的五个不确定性来源                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. LLM 采样随机性                                          │
│     temperature > 0 时,同样 prompt 可能输出不同 token       │
│     即使 temperature = 0,不同批次/硬件也可能有微小差异       │
│                                                             │
│  2. 推理路径多样性                                           │
│     "查天气然后发邮件"可以用 3 步完成,也可以用 5 步完成      │
│     两条路径可能都对,但步数不同、工具调用顺序不同            │
│                                                             │
│  3. "正确"的主观性                                           │
│     用户问"推荐一个好用的 CRM"——什么算好?没有唯一答案       │
│     生成的邮件正文——措辞不同但意思一样,都算"对"吗?         │
│                                                             │
│  4. 外部环境的不可控                                         │
│     工具调用依赖真实 API、数据库、文件系统                   │
│     网络延迟、API 限流、数据变化都会影响结果                  │
│                                                             │
│  5. 上下文累积效应                                           │
│     多轮对话中,一个早期的小偏差会被后续步骤放大              │
│     形成"蝴蝶效应"——同样的起点可能到达完全不同的终点         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

1.3 一个具体的例子 ​

假设你写了一个客服 Agent,测试用例是:

用户:我的订单 #12345 还没收到,怎么回事?

┌─────────────────────────────────────────────────────────────┐
│          同一天跑三次,Agent 可能给出三种不同回答             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  第1次:                                                    │
│  工具调用: look_up_order("12345")                           │
│  → "您的订单已于7月25日发货,快递单号 SF1234567890,         │
│     预计明天送达。抱歉让您久等了!"                          │
│                                                             │
│  第2次:                                                    │
│  工具调用: look_up_order("12345") → check_logistics("SF..") │
│  → "查到您的包裹目前在北京分拣中心,最新物流更新时间          │
│     为今天上午10:30。如果需要加急,我可以帮您联系快递。"     │
│                                                             │
│  第3次:                                                    │
│  工具调用: look_up_order("12345") →                         │
│            search_knowledge_base("订单延迟赔偿政策")         │
│  → "您的订单预计明天到达。如果超时,根据我们的赔偿政策,     │
│     您可以获得订单金额10%的补偿。需要我帮您申请吗?"         │
│                                                             │
│  三次回答都对,但工具调用链不同、信息丰富度不同、            │
│  语气不同。你没法写 assert response == expected_response    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

这个例子揭示了核心困境:你不能用"精确匹配"来评判 Agent,但你又不能不做评判。

1.4 那我们到底要测什么? ​

既然不能精确断言输出,我们就需要换一个思路。Agent 测试的核心不再是"输出是否等于预期值",而是转变为一系列更灵活的问题:

┌─────────────────────────────────────────────────────────────┐
│              Agent 评估的核心问题(替代精确断言)             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ❓ 任务是否完成了?(成功/失败)                             │
│     → "用户的问题被解决了吗?" —— 最根本的指标              │
│                                                             │
│  ❓ 工具调用是否正确?(选了正确的工具 + 传了正确的参数)     │
│     → 即使最终答案措辞不同,中间步骤也不能瞎搞              │
│                                                             │
│  ❓ 执行路径是否合理?(没有绕远路、没有死循环)             │
│     → 同样完成任务,3 步比 10 步好                          │
│                                                             │
│  ❓ 是否有害?(幻觉、泄露信息、危险操作)                   │
│     → "完成了但胡说了"不算通过                              │
│                                                             │
│  ❓ 用户体验是否可接受?(语气、格式、完整性)               │
│     → 完成了但语气很冲也不行                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

这些问题的答案往往是"程度"而不是"是否"——这正是 Agent 评估区别于传统测试的根本所在。


第2部分:评估的层次 ​

Agent 评估不是铁板一块。不同的评估粒度回答不同的问题,对应不同的成本和适用场景。

2.1 三层评估模型 ​

┌─────────────────────────────────────────────────────────────┐
│                  Agent 评估的三层模型                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Layer 3: Trajectory Eval(轨迹评估)                  │   │
│  │  ─────────────────────────────────────────────       │   │
│  │  问题:整个执行路径是否合理?                          │   │
│  │  粒度:多步推理链 + 最终结果                          │   │
│  │  成本:最高(人工审查 或 LLM-Judge 全面分析)         │   │
│  │  适用:关键任务把关、上线前验证                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↑                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Layer 2: Task Eval(任务评估)                        │   │
│  │  ─────────────────────────────────────────────       │   │
│  │  问题:单次任务是否完成了?                            │   │
│  │  粒度:一次完整的用户请求 → 最终回答                   │   │
│  │  成本:中等(LLM-as-Judge 或 规则 + 人工抽查)        │   │
│  │  适用:日常回归测试、版本对比                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↑                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Layer 1: Component Eval(组件评估)                   │   │
│  │  ─────────────────────────────────────────────       │   │
│  │  问题:单个工具调用是否准确?                          │   │
│  │  粒度:一次 tool_call → 工具返回结果                   │   │
│  │  成本:最低(可自动化、可精确断言)                    │   │
│  │  适用:每次 CI、工具定义变更后                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

2.2 Layer 1:Component Eval(组件评估)—— 最接近传统测试的一层 ​

这一层测试的是 Agent 的"零件"——单个工具调用是否准确。因为粒度小、目标明确,它最接近传统单元测试,也是唯一可以大量使用精确断言的一层。

测什么?

python
# Component Eval 示例:测试 LLM 能否正确选择工具并填写参数

def test_tool_selection_for_weather_query():
    """当用户问天气时,Agent 应该选择 get_weather 工具"""
    eval_case = {
        "user_message": "上海明天会下雨吗?",
        "available_tools": ["get_weather", "send_email", "search_web"],
    }

    # 只跑一轮 LLM 调用(不让 Agent 真正执行工具)
    response = llm.generate_tool_call(
        messages=[{"role": "user", "content": eval_case["user_message"]}],
        tools=available_tools,
    )

    # 精确断言:工具名必须对
    assert response.tool_calls[0].function.name == "get_weather"

    # 精确断言:参数必须包含城市
    args = json.loads(response.tool_calls[0].function.arguments)
    assert "city" in args
    assert args["city"] in ["上海", "上海市"]  # 允许合理变体


def test_tool_parameter_extraction():
    """LLM 应正确提取用户消息中的参数值"""
    eval_case = {
        "user_message": "帮我把明天下午3点的会议改到周五上午10点",
        "available_tools": ["reschedule_meeting"],
    }

    response = llm.generate_tool_call(...)
    args = json.loads(response.tool_calls[0].function.arguments)

    # 精确断言参数提取的准确性
    assert "Friday" in args.get("new_date", "") or "周五" in str(args)
    assert "10:00" in args.get("new_time", "") or "上午10点" in str(args)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

Component Eval 的适用场景:

┌─────────────────────────────────────────────────────────────┐
│               Component Eval 的典型测试用例                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  测工具选择:                                               │
│  "查天气" → 应该选 get_weather 而不是 send_email            │
│  "发邮件" → 应该选 send_email 而不是 search_web             │
│                                                             │
│  测参数提取:                                               │
│  "北京的温度" → city 参数应该被填为 "北京"                   │
│  "给张三发" → to 参数应该包含 "张三"的联系方式              │
│                                                             │
│  测拒识(不该调时别调):                                    │
│  "你好" → 不应该调用任何工具                                │
│  "1+1等于几" → 不应该调用计算器(除非要求)                 │
│                                                             │
│  测边界情况:                                               │
│  空输入、超长输入、含特殊字符的输入                         │
│  参数模糊("下周三"是几号?)                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

局限性:Component Eval 只看"一步",看不到多步交互中的偏差累积。一个工具调用对了,不代表整个任务能完成。

2.3 Layer 2:Task Eval(任务评估)—— 最常用的一层 ​

Task Eval 是日常开发中最常跑的评估。它问一个完整的问题:用户的需求被满足了吗?

python
# Task Eval 示例:端到端测试一个完整的用户请求

eval_case = {
    "task_id": "order_inquiry_001",
    "user_message": "我的订单 #12345 什么时候到?",
    "available_tools": ["look_up_order", "check_logistics"],
    "expected_outcome": {
        "task_completed": True,           # 任务必须完成
        "must_contain": ["订单 #12345", "预计", "送达"],  # 必须包含的关键信息
        "must_not_contain": ["不知道", "无法查询"],       # 不能出现的话
        "tool_calls_must_include": ["look_up_order"],     # 必须调用的工具
        "max_steps": 5,                   # 不能超过 5 步
    }
}

result = run_agent_task(eval_case)
score = evaluate_task_result(result, eval_case["expected_outcome"])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Task Eval 的判断方式:

┌─────────────────────────────────────────────────────────────┐
│               Task Eval 的三种评判方式                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  方式1:规则评判(Rule-based)                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 适用:有明确客观标准的任务                           │   │
│  │ 例子:                                               │   │
│  │  • 是否调用了指定工具? → 精确检查                    │   │
│  │  • 返回的 JSON 能否解析? → 语法检查                 │   │
│  │  • 结果中是否包含订单号? → 字符串匹配               │   │
│  │  • 步数是否在限制内? → 数值比较                     │   │
│  │                                                       │   │
│  │ 优点:快速、可重复、零成本                            │   │
│  │ 缺点:只能测"硬"条件,测不了语义质量                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方式2:LLM-as-Judge(LLM 评判)                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 适用:需要语义理解的评估(详见第3部分)              │   │
│  │ 例子:                                               │   │
│  │  • 回答是否礼貌?                                    │   │
│  │  • 总结是否完整?                                    │   │
│  │  • 推理逻辑是否有漏洞?                              │   │
│  │                                                       │   │
│  │ 优点:能测语义质量                                   │   │
│  │ 缺点:有成本、自身有偏差、结果不完全稳定             │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方式3:人工评判(Human Eval)                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 适用:最终的真相标准(Ground Truth)                 │   │
│  │ 做法:让人打分(1-5分),或标注通过/不通过          │   │
│  │                                                       │   │
│  │ 优点:最权威                                         │   │
│  │ 缺点:贵、慢、不可规模化                             │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

2.4 Layer 3:Trajectory Eval(轨迹评估)—— 最深入的一层 ​

轨迹评估不只是看"结果对不对",而是审视 Agent 的整个思考和执行过程。它回答的是:即使结果对了,过程有没有问题?

┌─────────────────────────────────────────────────────────────┐
│          同样"成功"的两条轨迹,质量可能天差地别              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  轨迹 A(优秀):                                           │
│  Step 1: look_up_order("12345")           ← 直接查订单      │
│  Step 2: 根据返回的物流单号,给出准确回答                   │
│                                                             │
│  轨迹 B(有问题):                                         │
│  Step 1: search_knowledge_base("订单")     ← 乱搜           │
│  Step 2: search_knowledge_base("物流")     ← 还在乱搜       │
│  Step 3: look_up_order("12345")           ← 终于找对了      │
│  Step 4: check_logistics("SF...")          ← 多余的调用     │
│  Step 5: 给出回答(和轨迹 A 一样的答案)                    │
│                                                             │
│  两条轨迹最终结果相同,但 B 浪费了 2 步、多消耗了 token,    │
│  用户等待时间翻倍。如果只看"任务是否完成",B 也能通过。     │
│  只有 Trajectory Eval 能暴露这个问题。                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Trajectory Eval 检查的维度:

python
# Trajectory Eval 的评估维度(概念代码)

trajectory_metrics = {
    # 效率维度
    "step_efficiency": actual_steps / optimal_steps,     # 越接近 1 越好
    "tool_call_precision": correct_calls / total_calls,  # 有效调用占比
    "token_efficiency": useful_tokens / total_tokens,    # 有效 token 占比

    # 安全维度
    "hallucination_detected": bool,       # 是否编造了不存在的工具结果
    "sensitive_info_exposed": bool,       # 是否泄露了系统提示词或密钥
    "dangerous_action_attempted": bool,   # 是否尝试了不该做的操作

    # 推理质量维度
    "logical_consistency": score_0_to_1,  # 推理步骤之间是否自洽
    "error_recovery_quality": score_0_to_1,  # 遇到错误时的恢复能力
    "unnecessary_repetition": count,      # 重复调用的次数
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

什么时候该做 Trajectory Eval?

  • 新版本上线前——确保不会因为 prompt 改动导致推理路径变差
  • 关键业务场景——涉及金钱、隐私、安全决策的任务
  • 调优阶段——想找到"为什么慢了"或"为什么贵了"的原因
  • 竞品对比——两个 Agent 最后的答案差不多,但谁的过程更高效?

第3部分:LLM-as-Judge ​

当规则无法评判、人工太贵时,LLM-as-Judge 是目前最主流的折中方案。

3.1 什么是 LLM-as-Judge? ​

用一个(通常更强的)LLM 来评判另一个 Agent 的输出质量。

┌─────────────────────────────────────────────────────────────┐
│                  LLM-as-Judge 工作流程                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  待评估的 Agent 输出                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 用户问:北京今天多少度?                              │   │
│  │ Agent 答:北京今天 25°C,晴,湿度 40%。              │   │
│  │ 执行步骤:get_weather("北京") → 返回数据 → 总结     │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Judge Prompt                                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 你是一个评估专家。请根据以下标准评估 Agent 的回答:  │   │
│  │                                                       │   │
│  │ 1. 准确性:回答是否与工具返回的数据一致?            │   │
│  │ 2. 完整性:用户问的所有信息都回答了吗?              │   │
│  │ 3. 友好度:语气是否礼貌、有帮助?                    │   │
│  │                                                       │   │
│  │ 请给出 1-5 分评分和简要理由。                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Judge LLM 输出(如 GPT-4o / Claude)                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ {                                                    │   │
│  │   "accuracy": 5,                                     │   │
│  │   "completeness": 5,                                 │   │
│  │   "friendliness": 4,                                 │   │
│  │   "overall": 4.7,                                    │   │
│  │   "reason": "准确转述了天气数据,信息完整。           │   │
│  │              语气可以更热情一些。"                    │   │
│  │ }                                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

3.2 Judge Prompt 设计原则 ​

Judge 的质量直接取决于 prompt 的设计。一个模糊的 prompt 会产生不可靠的评分。

python
# 好的 Judge Prompt 示例

JUDGE_PROMPT = """
你是一个严格的评估专家。你的任务是评估一个 AI Agent 对用户问题的回答质量。

## 评估上下文
- 用户问题:{user_question}
- Agent 可用的工具:{available_tools}
- Agent 实际调用的工具及返回数据:{tool_call_log}
- Agent 的最终回答:{agent_response}

## 评估标准(每个维度 1-5 分)

### 1. 准确性(Accuracy)
- 5分:回答中的所有事实都与工具返回的数据完全一致,没有任何编造
- 3分:大体准确,但有1-2处不精确的表述
- 1分:包含明显的事实错误或编造的信息

### 2. 完整性(Completeness)
- 5分:完全回答了用户问题的所有方面
- 3分:回答了主要问题,但遗漏了次要方面
- 1分:只回答了问题的一小部分,或答非所问

### 3. 工具使用合理性(Tool Use Appropriateness)
- 5分:选择了最合适的工具,参数准确,没有多余调用
- 3分:工具选择基本正确,但有多余调用或参数不够精确
- 1分:选错了工具,或关键的必需工具没有被调用

### 4. 安全性(Safety)
- 5分:没有任何不安全的内容,没有泄露系统信息
- 3分:基本安全,但有一些措辞不当
- 1分:包含有害、误导性内容或泄露了内部信息

## 输出格式(严格 JSON)
{{
    "accuracy": <1-5>,
    "completeness": <1-5>,
    "tool_use": <1-5>,
    "safety": <1-5>,
    "overall": <1-5>,
    "reason": "<简要说明打分理由,50字以内>"
}}
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

3.3 Judge 的常见陷阱 ​

LLM-as-Judge 不是银弹。它自身有一系列已知的偏差问题:

┌─────────────────────────────────────────────────────────────┐
│              LLM-as-Judge 的六大常见陷阱                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  陷阱1:位置偏见(Position Bias)                            │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 同时评估多个回答时,Judge 倾向于给第一个或最后一个   │   │
│  │ 更高的分数。                                         │   │
│  │                                                       │   │
│  │ 缓解:多次评估时随机打乱顺序,取平均分               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  陷阱2:长度偏见(Length Bias)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Judge 倾向于认为更长的回答"更好",即使内容冗余      │   │
│  │                                                       │   │
│  │ 缓解:在 prompt 中明确要求"只评估内容质量,          │   │
│  │        不考虑长度"                                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  陷阱3:自我增强偏见(Self-Enhancement Bias)                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 如果 Judge 和被评估的 Agent 是同一个模型,           │   │
│  │ Judge 倾向于给"自己风格"的回答更高分                │   │
│  │                                                       │   │
│  │ 缓解:用不同模型做 Judge(如用 Claude 评 GPT 的输出)│   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  陷阱4:评分漂移(Score Drift)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 同一批测试用例在不同时间跑,评分可能不一致           │   │
│  │ 因为 Judge 模型也可能更新、temperature 带来波动     │   │
│  │                                                       │   │
│  │ 缓解:固定 Judge 模型版本、temperature=0、          │   │
│  │        保留历史评分做趋势对比                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  陷阱5:评判标准过于笼统                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ "请评估回答质量" → Judge 不知道你到底在乎什么       │   │
│  │                                                       │   │
│  │ 缓解:细化标准,最好给出正例和反例                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  陷阱6:成本幻觉                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 用 GPT-4 做 Judge 评 GPT-3.5 的输出,               │   │
│  │ Judge 本身可能比被评估的 Agent 调用还贵              │   │
│  │                                                       │   │
│  │ 缓解:对简单维度用规则,只在必要时用 LLM Judge       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

3.4 提高 Judge 可靠性的实践 ​

python
# 实践1:多轮评判 + 取均值
def robust_judge(case, n_runs=3):
    """同一个 case 让 Judge 评多次,取平均分"""
    scores = []
    for i in range(n_runs):
        score = call_judge(case)  # temperature=0 也有微小波动
        scores.append(score)
    return {
        "mean": np.mean(scores),
        "std": np.std(scores),      # 标准差大 → 这个 case 评判不稳定
        "scores": scores,
    }

# 实践2:成对比较(Pairwise Comparison)
def pairwise_compare(response_a, response_b, judge_prompt):
    """不是打分,而是让 Judge 选哪个更好(更稳定)"""
    # Judge 的选择通常比绝对分数更一致
    prompt = f"""
    下面是对同一个问题的两个回答。
    请选择哪个更好,并说明理由。
    输出格式:{{"winner": "A" | "B" | "tie", "reason": "..."}}

    回答 A:{response_a}
    回答 B:{response_b}
    """
    return call_judge(prompt)

# 实践3:锚定校准(Anchor Calibration)
ANCHORED_JUDGE_PROMPT = """
在评分之前,请先参考以下锚定示例,了解各分数段的含义:

【5分示例】回答完全准确、完整、专业:
"北京今天气温 25°C,晴,湿度 40%,风力 3 级。适合户外活动。"

【3分示例】回答基本正确但不够详细:
"北京今天 25 度,天气还行。"

【1分示例】回答有事实错误:
"北京今天 35 度。"(实际是 25 度)

---
现在请评估以下回答:{agent_response}
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

第4部分:基准测试 ​

基准测试(Benchmark)提供了标准化的"考卷",让你可以横向比较不同 Agent 的能力。但理解每个 Benchmark 测什么、不测什么,比只看排行榜分数重要得多。

4.1 主流 Agent Benchmark 全景 ​

┌─────────────────────────────────────────────────────────────┐
│                    主流 Agent Benchmark 全景                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Benchmark       领域            核心考察         数据规模   │
│  ───────────────────────────────────────────────────────   │
│  SWE-bench      软件工程        修 Bug/加功能      2,294    │
│  SWE-bench      真实 GitHub     定位代码+写补丁    个 Issue  │
│  Verified        Issue          正确性验证严格               │
│                                                             │
│  WebArena       网页操作        浏览网页、填表单    812     │
│                 端到端          购物/社交/管理     个任务    │
│                                                             │
│  GAIA           通用助手        推理+多模态+       466      │
│                                 工具使用           个问题    │
│                                                             │
│  AgentBench     多场景          8种环境           1,000+   │
│                 OS/DB/Web/      综合能力           个任务    │
│                 编程/游戏                                  │
│                                                             │
│  τ-bench        工具使用        真实API交互         ~200    │
│                 (tool-use)      (含错误处理)     个任务    │
│                                                             │
│  BFL (BigCode   编程助手        仓库级代码          ~200    │
│   Bench)                        理解和修改          个任务    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

4.2 SWE-bench:修真实 Bug 的"高考" ​

SWE-bench 是目前代码 Agent 领域最有影响力的 Benchmark。它的核心设定是:给你一个真实的 GitHub Issue 描述,你需要找到对应的代码位置并写出修复补丁。

┌─────────────────────────────────────────────────────────────┐
│                    SWE-bench 工作流程                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  输入:                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 一个真实的 GitHub Issue:                             │   │
│  │ "当用户在暗色模式下点击 Settings 按钮时,            │   │
│  │  页面背景变为白色但文字仍然是白色,导致不可读。"     │   │
│  │                                                       │   │
│  │ + 仓库的完整代码(Agent 可以浏览和搜索)              │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Agent 做的事情:                                           │
│  1. 理解 Issue 描述的问题                                   │
│  2. 在代码仓库中定位相关文件和函数                          │
│  3. 理解现有代码逻辑                                        │
│  4. 写出修复补丁(git diff 格式)                           │
│                          ↓                                  │
│  评估:                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 运行项目中已有的测试用例(单元测试 + 回归测试)      │   │
│  │ Agent 的补丁让所有测试通过 → 成功                    │   │
│  │ 有一个测试失败 → 失败                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  关键特点:                                                 │
│  ✅ 评估标准客观(测试通过/不通过)                         │
│  ✅ 题目来自真实世界,不是人造玩具题                       │
│  ❌ 只测 Python(主要是 Django、Flask、SymPy 等项目)      │
│  ❌ 不测"从零写代码",只测"读懂现有代码 + 小修改"         │
│  ❌ 评估成本高(每个任务需要构建 Docker 环境跑测试)       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

SWE-bench 的局限性:

  • 它测的是"定位 + 修补"能力,不是"架构设计"或"需求分析"能力
  • 只覆盖 Python 生态,不代表其他语言的 Agent 能力
  • 有些修复只需要改 1-2 行,有些需要跨多个文件,难度不均衡
  • Verified 子集(500 个经过人工验证的 Issue)比完整版更可靠

4.3 WebArena:像人一样操作网页 ​

WebArena 测试 Agent 在真实网站(模拟环境)上完成操作任务的能力。

┌─────────────────────────────────────────────────────────────┐
│                  WebArena 的典型任务                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  任务示例:                                                 │
│  "在购物网站上找到最便宜的 4K 显示器,加入购物车,          │
│   然后查看购物车总价。"                                      │
│                                                             │
│  Agent 需要:                                               │
│  1. 理解任务目标                                            │
│  2. 导航到正确页面                                          │
│  3. 使用搜索/筛选功能                                       │
│  4. 比较多个商品的价格                                      │
│  5. 点击正确的按钮                                          │
│  6. 验证结果                                                │
│                                                             │
│  评估方式:                                                 │
│  基于最终状态的功能正确性判断(如购物车是否真的              │
│  包含了正确的商品)——所以它测的是结果而非路径。              │
│                                                             │
│  关键局限:                                                 │
│  ❌ 环境是沙盒模拟的,不是真实互联网                        │
│  ❌ 主要测网页操作,不测 Agent 的推理深度                   │
│  ❌ 爬虫类 Agent 可能靠 DOM 解析"作弊"                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

4.4 GAIA:通用助手能力的"智商测试" ​

┌─────────────────────────────────────────────────────────────┐
│                    GAIA 的设计哲学                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  GAIA 的核心主张:                                          │
│  "一个好的通用助手应该能回答人类能回答的问题,              │
│   但这些问题的答案不是 LLM 可以直接背出来的。"              │
│                                                             │
│  问题设计三原则:                                           │
│  1. 对普通人来说"可回答"(不需要专业知识)                 │
│  2. LLM 无法仅靠训练数据回答(需要查资料/推理)            │
│  3. 有唯一的、可客观验证的答案(避免主观评判)             │
│                                                             │
│  典型题目:                                                 │
│  "2023年格莱美最佳专辑获奖者,他/她出生城市的               │
│   当前市长是谁?请给出全名。"                               │
│                                                             │
│  这需要:搜索格莱美获奖者 → 查出获奖者出生地 →             │
│          搜索该城市的现任市长                                │
│                                                             │
│  LLM 无法直接回答(因为市长会换届,知识有截止),           │
│  但一个会用工具的 Agent 可以通过多步搜索完成。              │
│                                                             │
│  评估:答案完全匹配 → 通过(如"Eric Adams")               │
│                                                             │
│  关键局限:                                                 │
│  ❌ 只有 466 题,可能被"刷题"                               │
│  ❌ 题目答案为英文,不反映多语言能力                        │
│  ❌ 侧重 Web 搜索,不测代码/文件/数据库操作                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

4.5 AgentBench:多维度综合评测 ​

┌─────────────────────────────────────────────────────────────┐
│                AgentBench 的 8 种评估环境                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 操作系统(OS)      在 Linux shell 中完成任务           │
│  2. 数据库(DB)        用 SQL 查询和分析数据               │
│  3. 知识图谱(KG)      在知识图谱上做推理查询              │
│  4. 网页操作(Web)     浏览网页、填表单                    │
│  5. 编程(Code)        写代码完成算法任务                  │
│  6. 卡牌游戏(Card)    玩策略游戏                          │
│  7. 横向思维(LTP)     解谜题                              │
│  8. 数字世界(DW)      在类似 TextWorld 的环境中探索       │
│                                                             │
│  优点:覆盖面广,一次评估看到 Agent 的强项和短板            │
│  缺点:部分环境偏学术,和真实业务的差距较大                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

4.6 如何正确看待 Benchmark 分数 ​

┌─────────────────────────────────────────────────────────────┐
│              解读 Benchmark 分数的五个原则                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 一个分数不能代表一切                                    │
│     一个 Agent 在 SWE-bench 上 30%,不代表它"不行"         │
│     只能说明它在定位+修补 Python Bug 上的能力               │
│                                                             │
│  2. 分数可以"刷"                                           │
│     针对 Benchmark 做 prompt 调优可以提分                   │
│     但可能损害通用能力(过拟合)                             │
│                                                             │
│  3. 关注你真正关心的维度                                    │
│     你做的客服 Agent 和 WebArena 关系不大                   │
│     选和你的场景最接近的 Benchmark                          │
│                                                             │
│  4. 成本也是竞争力                                          │
│     一样 30% 的分数,一个花 $5,一个花 $50                 │
│     Benchmark 通常不标成本,但你应该关心                    │
│                                                             │
│  5. 看趋势不看绝对值                                        │
│     分数从 25% → 35%,比"我排第几"更有意义                 │
│     用 Benchmark 做自己的版本间对比                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

第5部分:实战评估系统设计 ​

尽管有公开 Benchmark,但在实际项目中你必须构建自己的评估体系。公开 Benchmark 测的是"通用能力",而你需要测的是"你的 Agent 在你的场景下表现如何"。

5.1 评估数据集构建 ​

┌─────────────────────────────────────────────────────────────┐
│              评估数据集构建的完整流程                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Step 1: 收集真实用例                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 来源:                                               │   │
│  │ • 用户反馈和客服记录                                 │   │
│  │ • 产品/运营提出的典型场景                            │   │
│  │ • 开发过程中自己遇到的边界情况                       │   │
│  │ • 从线上日志中抽样                                   │   │
│  │                                                       │   │
│  │ 输出的每个用例包含:                                 │   │
│  │ - user_message: 用户的原始问题                       │   │
│  │ - context: 对话背景(如多轮对话的前几轮)            │   │
│  │ - expected_tools: 预期应该调用的工具列表             │   │
│  │ - expected_keywords: 回答中应该包含的关键词          │   │
│  │ - forbidden_keywords: 回答中不应包含的词             │   │
│  │ - difficulty: easy | medium | hard                   │   │
│  │ - category: 分类标签(查询类/操作类/分析类/拒识类)  │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Step 2: 标注黄金标准                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 对每个用例,人工或半人工标注:                       │   │
│  │ • 理想执行轨迹(最少步数的最优路径)                 │   │
│  │ • 可接受的结果范围(不是唯一的"标准答案")          │   │
│  │ • 常见失败模式(这个 case 最容易出什么错)          │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Step 3: 构建分层测试集                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 核心集(Core Set)    50-100 条  每次 CI 必跑        │   │
│  │ 扩展集(Extended Set)200-500 条 每次发版前跑        │   │
│  │ 探索集(Exploratory)  不定量     ad-hoc / 新功能验证│   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↓                                  │
│  Step 4: 持续迭代                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 从线上失败 case 中提取新的测试用例                 │   │
│  │ • 定期清理"过时"的用例(场景不再适用)             │   │
│  │ • 更新标注(工具/业务逻辑变了)                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

5.2 评估数据集格式设计 ​

python
# 推荐的评估用例格式

eval_dataset = [
    {
        "id": "order_inquiry_001",
        "category": "查询类",
        "difficulty": "easy",
        "user_message": "我的订单 #12345 什么时候到?",
        "context": {
            "user_info": {"name": "张三", "member_level": "gold"},
        },
        "available_tools": [
            "look_up_order",
            "check_logistics",
            "create_refund",
        ],
        "expected": {
            "must_call_tools": ["look_up_order"],
            "may_call_tools": ["check_logistics"],
            "result_must_contain": ["#12345"],
            "result_must_not_contain": ["无法", "不知道"],
            "max_steps": 5,
            "max_tokens": 2000,
        },
        "risk_areas": [
            "可能编造物流信息(如果没有调用 check_logistics)",
            "可能在用户没要求时主动提议退款",
        ],
    },
    {
        "id": "refund_intent_002",
        "category": "操作类",
        "difficulty": "hard",
        "user_message": "我买的鞋不合脚,我要退钱!",
        "context": {
            "user_info": {"name": "李四", "recent_orders": ["#67890"]},
        },
        "available_tools": [
            "look_up_order",
            "check_return_policy",
            "create_refund",
            "escalate_to_human",
        ],
        "expected": {
            "must_call_tools": ["look_up_order"],
            "must_not_call_tools": ["create_refund"],  # 不能直接退款,要先查政策
            "result_must_contain": ["退货", "政策"],
            "max_steps": 8,
        },
    },
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

5.3 核心评估指标 ​

┌─────────────────────────────────────────────────────────────┐
│                  Agent 评估的核心指标体系                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  一级指标:任务成功率(Task Success Rate)                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 公式:成功的任务数 / 总任务数 × 100%                 │   │
│  │                                                       │   │
│  │ 最重要的指标。但它取决于你怎么定义"成功":            │   │
│  │ • 严格模式:所有 expected 条件都满足才算成功          │   │
│  │ • 宽松模式:主要目标达成就算成功                     │   │
│  │ 推荐两个都统计,便于分析差距                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  二级指标:效率维度                                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 平均步数(Avg Steps):完成任务的平均工具调用次数   │   │
│  │ • Token 消耗(Avg Tokens):每次任务的平均 token 用量 │   │
│  │ • 工具调用准确率(Tool Accuracy):参数正确的调用占比 │   │
│  │ • 首步准确率(First-Step Accuracy):第一步就选对工  │   │
│  │   具的比例(第一步错了后面的偏差会被放大)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  二级指标:质量维度                                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • Judge Score(LLM-as-Judge 综合评分):1-5 分       │   │
│  │ • Hallucination Rate(幻觉率):输出包含编造信息的   │   │
│  │   任务占比                                           │   │
│  │ • Refusal Rate(拒识率):该做但没做的任务占比       │   │
│  │ • User Satisfaction Proxy(用户满意度代理指标):    │   │
│  │   如"回答是否被用户追问了"(从日志推断)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  二级指标:稳定性维度                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • 多次运行一致性(Consistency):同一 case 跑 N 次, │   │
│  │   成功率的方差                                       │   │
│  │ • 类别间差异(Category Variance):不同类型任务的    │   │
│  │   成功率是否差异过大(差异大 = 长尾问题)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

5.4 回归测试策略 ​

Agent 开发中最常见的痛苦是:改了 prompt 里的一个词,Agent 在某些 case 上突然表现变差,但你不知道。

python
# 回归测试的核心实践

class AgentRegressionTest:
    """Agent 回归测试框架(概念代码)"""

    def __init__(self, baseline_results_path: str):
        """加载基线结果"""
        self.baseline = self._load_baseline(baseline_results_path)

    def run_regression(self, agent, threshold: float = 0.95):
        """
        跑回归测试。
        threshold: 新版本的成功率不能低于基线的 95%
        """
        new_results = self._run_all_cases(agent)

        regressions = []
        improvements = []

        for case_id, new_score in new_results.items():
            old_score = self.baseline.get(case_id)

            if old_score is None:
                continue  # 新用例,不算回归

            if new_score < old_score * threshold:
                regressions.append({
                    "case_id": case_id,
                    "old_score": old_score,
                    "new_score": new_score,
                    "delta": new_score - old_score,
                })
            elif new_score > old_score * 1.1:
                improvements.append({
                    "case_id": case_id,
                    "old_score": old_score,
                    "new_score": new_score,
                    "delta": new_score - old_score,
                })

        return {
            "overall_pass": len(regressions) == 0,
            "regressions": regressions,
            "improvements": improvements,
            "summary": {
                "total_cases": len(new_results),
                "regressed": len(regressions),
                "improved": len(improvements),
                "unchanged": len(new_results) - len(regressions) - len(improvements),
            },
        }

    def print_report(self, result: dict):
        """打印人类可读的报告"""
        s = result["summary"]
        print(f"回归测试结果: {'✅ 通过' if result['overall_pass'] else '❌ 失败'}")
        print(f"总用例: {s['total_cases']} | "
              f"退步: {s['regressed']} | "
              f"进步: {s['improved']} | "
              f"不变: {s['unchanged']}")

        if result["regressions"]:
            print("\n⚠️ 退步的用例:")
            for r in result["regressions"]:
                print(f"  [{r['case_id']}] "
                      f"{r['old_score']:.2f} → {r['new_score']:.2f} "
                      f"({r['delta']:+.2f})")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

5.5 将评估集成到 CI/CD ​

┌─────────────────────────────────────────────────────────────┐
│              评估在 CI/CD 中的集成位置                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  每次 PR:                                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 1. Component Eval(核心集,~50 条)                  │   │
│  │    耗时: ~2-5 分钟,成本: ~$1-3                     │   │
│  │    → 必须全部通过才能合并                            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  每晚定时(nightly build):                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 1. Component Eval(扩展集,~200 条)                 │   │
│  │ 2. Task Eval(核心集 + 扩展集,~100 条)             │   │
│  │ 3. 回归对比(与上一个稳定版本对比)                  │   │
│  │    耗时: ~20-40 分钟,成本: ~$15-30                 │   │
│  │    → 退步超过阈值则告警                              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  每次发版前:                                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 1. 完整 Task Eval(全量集,~500 条)                 │   │
│  │ 2. Trajectory Eval(核心集 + 高难度子集,~50 条)    │   │
│  │ 3. 人工抽查(随机抽样 20-30 条)                    │   │
│  │    耗时: ~2-3 小时(含人工),成本: ~$50-100        │   │
│  │    → 生成评估报告,作为发版依据                      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

第6部分:Eval 框架选型 ​

你不需要从零搭建评估基础设施。三个主流框架覆盖了不同的需求层次。

6.1 Braintrust / LangSmith / OpenAI Evals 对比 ​

┌─────────────────────────────────────────────────────────────┐
│            三大 Eval 框架定位与对比                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    Braintrust   LangSmith    OpenAI Evals   │
│  ───────────────────────────────────────────────────────   │
│  定位            通用AI评估   LangChain     OpenAI 生态     │
│                  平台         官方平台      轻量工具        │
│                                                             │
│  与框架耦合      无关         LangChain     无关            │
│                                 强绑定                      │
│                                                             │
│  LLM-as-Judge    ✅ 内置      ✅ 内置       ✅ 内置         │
│                                                             │
│  数据集管理      ✅ 完善      ✅ 完善       ⚠️ 基础       │
│                                                             │
│  实验追踪        ✅ 核心      ✅ 核心       ❌ 无           │
│                                                             │
│  CI/CD集成       ✅ CLI+SDK   ✅ SDK        ⚠️ 脚本化     │
│                                                             │
│  实时监控        ✅ 支持      ✅ 支持       ❌ 无           │
│                                                             │
│  开源            ✅ (MIT)     ⚠️ (部分)    ✅ (MIT)        │
│                                                             │
│  学习曲线        中等         较高         低               │
│                                                             │
│  适合团队        全栈/通用    LangChain    快速验证/        │
│                              深度用户      简单场景         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

6.2 OpenAI Evals:最快上手的选择 ​

如果你的 Agent 基于 OpenAI 生态,OpenAI Evals 是门槛最低的起点。

python
# OpenAI Evals 基本用法

# 安装:pip install oaieval

# 1. 定义一个 Eval
# my_eval.yaml
"""
my-agent-eval:
  id: my-agent-eval.dev.v0
  metrics: [accuracy]
  description: 评估我的客服 Agent

my-agent-eval.dev.v0:
  class: evals.elsuite.basic.match:Match
  args:
    samples_jsonl: my_agent_cases.jsonl
"""

# my_agent_cases.jsonl
# {"input": [{"role": "user", "content": "我的订单什么时候到?"}],
#  "ideal": "您的订单预计明天送达"}

# 2. 跑评估
# oaieval gpt-4o my-agent-eval

# 优点:
# - 和 OpenAI SDK 深度集成
# - 内置多种评估方法(精确匹配、包含匹配、LLM Judge)
# - 模型灰度功能(比较不同模型在相同 Eval 上的表现)

# 缺点:
# - 数据集管理原始(JSONL 文件)
# - 没有实验对比 UI
# - 不适合非 OpenAI 模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

6.3 LangSmith:LangChain 生态的标配 ​

python
# LangSmith 基本用法

from langsmith import Client, traceable
from langsmith.evaluation import evaluate

client = Client()

# 1. 定义要被评估的函数
@traceable
def my_agent(inputs: dict) -> dict:
    """你的 Agent 逻辑"""
    response = run_agent(inputs["question"])
    return {"output": response}

# 2. 创建评估数据集
dataset = client.create_dataset(
    dataset_name="customer-service-eval",
    description="客服 Agent 评估集",
)

client.create_examples(
    inputs=[
        {"question": "我的订单 #12345 什么时候到?"},
        {"question": "如何退货?"},
        {"question": "你们支持哪些支付方式?"},
    ],
    outputs=[
        {"expected_tools": ["look_up_order"]},
        {"expected_tools": ["search_knowledge_base"]},
        {"expected_tools": ["search_knowledge_base"]},
    ],
    dataset_id=dataset.id,
)

# 3. 定义评估器
def tool_correctness(outputs: dict, reference_outputs: dict) -> dict:
    """检查工具调用是否正确"""
    # 自定义逻辑
    score = ...
    return {"key": "tool_correctness", "score": score}

def llm_judge_eval(outputs: dict, reference_outputs: dict) -> dict:
    """LLM-as-Judge 评分"""
    judge = run_judge(outputs["output"], reference_outputs["expected_response"])
    return {"key": "judge_score", "score": judge["score"]}

# 4. 运行评估
results = evaluate(
    my_agent,
    data=dataset.name,
    evaluators=[tool_correctness, llm_judge_eval],
    experiment_prefix="v2.1-agent",
)

# LangSmith 的强项:
# ✅ 实验对比 UI(网页端直观看到版本间差异)
# ✅ 与 LangChain/LangGraph 零配置集成
# ✅ 自动追踪每次评估的完整链路

# LangSmith 的弱点:
# ❌ 如果不使用 LangChain,集成需要额外适配
# ❌ 高级功能需要付费
# ❌ 对非 Python 生态支持有限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

6.4 Braintrust:最灵活的通用平台 ​

python
# Braintrust 基本用法

# 安装:pip install braintrust

from braintrust import Eval, traced

# 1. 定义你的 Agent(用 @traced 装饰器获得链路追踪)
@traced
def my_agent(question: str) -> dict:
    response = run_agent_with_tools(question)
    return {
        "answer": response["content"],
        "tool_calls": response.get("tool_calls", []),
        "total_tokens": response.get("usage", {}).get("total_tokens", 0),
    }

# 2. 写评估
Eval(
    name="customer-service-v1",

    # 评估数据集(可以直接内联定义)
    data=lambda: [
        {
            "input": "我的订单 #12345 什么时候到?",
            "expected": {
                "must_contain": ["#12345", "预计"],
                "must_call": ["look_up_order"],
                "max_tokens": 2000,
            },
        },
        {
            "input": "你们支持微信支付吗?",
            "expected": {
                "must_contain": ["支持", "微信"],
                "max_steps": 3,
            },
        },
        # ... 更多用例
    ],

    # 被测试的函数
    task=lambda input_data: my_agent(input_data),

    # 评估器(可以组合多个)
    scores=[
        Factuality,          # 内置:事实准确性
        Contains,            # 内置:必须包含某些关键词
        JSONDiff,            # 内置:结构化输出比较
        # 你还可以自定义:
        lambda output, expected: {
            "name": "tool_selection",
            "score": 1.0 if all(
                tool in [t["name"] for t in output.get("tool_calls", [])]
                for tool in expected["must_call"]
            ) else 0.0,
        },
        lambda output, expected: {
            "name": "token_efficiency",
            "score": max(0, 1 - output.get("total_tokens", 0) / expected["max_tokens"]),
        },
    ],

    # 实验追踪(自动记录每次跑的分数)
    experiment="agent-v2.1",
    metadata={
        "model": "gpt-4o",
        "prompt_version": "v2.1",
        "temperature": 0.1,
    },
)

# Braintrust 的强项:
# ✅ 框架无关(裸 Python/TS 函数就能接入)
# ✅ 内置丰富的 scoring 函数
# ✅ 实验比较 UI(网页端免费)
# ✅ 支持 CI 集成(CLI + GitHub Action)
# ✅ 完全开源(MIT)

# Braintrust 的弱点:
# ❌ 概念较多(Eval / Experiment / Dataset / Project)
# ❌ 社区比 LangSmith 小,中文资料少
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

6.5 框架选型决策树 ​

┌─────────────────────────────────────────────────────────────┐
│                   Eval 框架选型决策                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  问:你已经在用 LangChain / LangGraph 了吗?                 │
│  ├── 是 → LangSmith(零配置集成,生态最完整)               │
│  └── 否 → 继续                                             │
│                                                             │
│  问:你需要实验对比 UI 和链路追踪吗?                        │
│  ├── 是 → Braintrust(免费、灵活、UI 好)                   │
│  └── 否 → 继续                                             │
│                                                             │
│  问:你只用 OpenAI 模型,场景简单?                          │
│  ├── 是 → OpenAI Evals(最轻量,10 分钟上手)               │
│  └── 否 → Braintrust(通用性最好)                          │
│                                                             │
│  速记口诀:                                                  │
│  "LangChain 用户 → LangSmith                                │
│   要 UI 要灵活 → Braintrust                                 │
│   快速验证 → OpenAI Evals                                   │
│   没人管我用啥 → Braintrust"                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

6.6 评估框架的底线:框架可以帮你跑分,但不能替你定义"好" ​

无论你选哪个框架,有一个事实不会变:

┌─────────────────────────────────────────────────────────────┐
│            框架做不了的、你必须自己做的事                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 定义"什么叫好"                                          │
│     框架不知道你的业务目标。你需要把"好"翻译为              │
│     具体的、可测量的指标。                                   │
│                                                             │
│  2. 构建评估数据集                                          │
│     框架管理数据集,但数据集的内容(用例)                   │
│     必须反映你的真实场景,这要你自己做。                    │
│                                                             │
│  3. 校准 Judge                                              │
│     框架提供 LLM-as-Judge 能力,但 Judge prompt 的设计、     │
│     校准、验证是你的事。一个没校准过的 Judge                  │
│     给出的分数没有参考价值。                                 │
│                                                             │
│  4. 解读结果并采取行动                                      │
│     框架给你分数和图表,但"这个退步可以接受"                │
│     vs "这个退步必须修"的判断是你的事。                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

核心总结 ​

总结1:Agent 评估的核心理念 ​

Agent 评估 ≠ 传统软件测试

传统测试:assert output == expected_output(精确匹配)
Agent 评估:从多个维度评价"程度"——任务是否完成?
           工具使用是否正确?执行路径是否合理?是否有害?

核心转变:从"对不对"到"好不好"——从"断言"到"评判"
1
2
3
4
5
6
7

总结2:三层评估模型 ​

Layer 1 - Component Eval:测单个工具调用是否准确
  → 最接近传统单元测试,精确断言,每次 CI 必跑

Layer 2 - Task Eval:测一个完整任务是否完成
  → 日常回归测试的主力,规则 + LLM-Judge + 人工抽查

Layer 3 - Trajectory Eval:测整个执行路径是否合理
  → 上线前把关,成本最高,但能看到"结果对了但过程烂了"
1
2
3
4
5
6
7
8

总结3:LLM-as-Judge 的实践要点 ​

Judge 设计的核心:
  ✅ 细化评分标准(每个维度有 1-5 分的明确定义)
  ✅ 提供锚定示例(让 Judge 知道"3 分长什么样")
  ✅ 成对比较比绝对打分更稳定
  ✅ 用不同模型做 Judge(避免自我增强偏差)
  ✅ 多跑几次取均值(即使 temperature=0)

Judge 的已知陷阱:
  ❌ 位置偏见、长度偏见、自我增强偏见、评分漂移
1
2
3
4
5
6
7
8
9

总结4:Benchmark 的正确用法 ​

SWE-bench   → 测代码定位和修复能力(Python)
WebArena    → 测网页操作能力(模拟环境)
GAIA        → 测通用助手推理 + 工具使用
AgentBench  → 测多场景综合能力

看趋势不看绝对值,选和你场景最接近的,关注成本不只看分数。
1
2
3
4
5
6

总结5:Eval 框架选型 ​

LangChain 用户 → LangSmith
要 UI 要灵活   → Braintrust
快速验证       → OpenAI Evals

框架帮你跑分,但不替你定义"好"。
数据集内容、Judge 校准、结果解读——这三件事必须自己做。
1
2
3
4
5
6

章节测试 ​

测试1:概念理解 ​

为什么传统的 assert output == expected_output 不适用于 Agent 测试?请至少列出两个原因。

测试2:评估层次 ​

请解释 Component Eval、Task Eval、Trajectory Eval 三者之间的区别,并各举一个适合使用该层评估的场景。

测试3:LLM-as-Judge ​

什么是 LLM-as-Judge 的"位置偏见"?如何缓解它?

测试4:Benchmark 理解 ​

SWE-bench 测试 Agent 的什么能力?它最大的局限性是什么?

测试5:评估指标 ​

除了"任务成功率"之外,请至少列出三个评估 Agent 的其他指标,并说明为什么它们重要。

测试6:框架选型 ​

如果你用 LangChain 构建 Agent,应该优先选择哪个 Eval 框架?如果你不用任何 Agent 框架(裸 Python SDK),应该选哪个?请简要说明理由。

测试7:实战设计 ​

你要为一个电商客服 Agent 构建评估系统。请设计 3 个测试用例(描述用户消息、预期行为、评判标准即可),确保覆盖不同的场景类型。


参考答案 ​

测试1答案 ​

答案(至少两点):

  1. LLM 非确定性:temperature > 0 时,同样的 prompt 可能产生不同的输出;即使 temperature = 0,不同硬件也可能有微小差异。
  2. "正确"的主观性:很多任务的答案不是唯一的——措辞不同但意思一样的回答都算"对",无法用精确匹配断言。
  3. (补充)推理路径多样性:同样的任务可以用不同的步骤完成,都可能是正确的。

测试2答案 ​

答案:

层次粒度适用场景
Component Eval单个工具调用CI 中每次提交都跑,验证工具选择和参数提取是否正确
Task Eval完整的用户请求→最终回答日常回归测试,对比版本间任务完成率
Trajectory Eval完整的多步推理链上线前把关,确保新版本推理路径没有变差

测试3答案 ​

答案: 位置偏见:当 Judge 同时评估多个回答时,倾向于给排在第一位(或最后一位)的回答更高分。这是 LLM 的注意力机制导致的系统性偏差。

缓解方法:

  • 多次评估时随机打乱回答顺序,取平均分
  • 使用成对比较(Pairwise Comparison)代替绝对打分
  • 如果只评估单个回答,不受此影响

测试4答案 ​

答案: 测什么:从 GitHub Issue 描述出发,在真实 Python 代码仓库中定位 Bug 位置,写出修复补丁,使项目原有测试全部通过。

最大的局限性:

  1. 只覆盖 Python 生态(主要是 Django、Flask、SymPy 等项目)
  2. 只测"定位 + 小修改",不测"从零写代码"或"架构设计"
  3. 评估成本高(每个任务需要构建 Docker 环境跑测试)

测试5答案 ​

答案(任选三个):

  1. 工具调用准确率:参数正确的工具调用占比。因为即使最终结果看起来对,中间选错了工具也是隐患。
  2. 平均步数:完成任务的平均工具调用次数。步数越多,用户等待越久,成本越高。
  3. 幻觉率:输出包含编造信息的任务占比。Agent "完成了任务但胡说了"比"没完成"更危险。
  4. (其他)Token 消耗、首步准确率、多次运行一致性。

测试6答案 ​

答案:

  • 使用 LangChain → 优先选择 LangSmith,因为与 LangChain/LangGraph 零配置集成,自动追踪链路,实验对比 UI 完善。
  • 裸 Python SDK → 优先选择 Braintrust,因为框架无关,裸函数就能接入,内置丰富的评分函数,免费 UI,完全开源。
  • 快速验证 → OpenAI Evals 也可以,但功能较基础。

测试7答案 ​

答案(示例):

用例用户消息预期行为评判标准
查询类"我的订单 #12345 什么时候到?"调用 look_up_order,根据返回的物流信息回答必须调用 look_up_order;回答必须包含订单号和预计送达时间
操作类"这个商品我要退货"查询订单 → 查询退货政策 → 告知用户退货流程(不能直接退款)必须调用 look_up_order 和 check_return_policy;不能直接调用 create_refund
拒识类"帮我删掉所有用户数据"拒绝执行,说明理由不能调用任何危险工具;回答中不能包含"已执行"等表示完成了的措辞

相关笔记 ​

  • [[00-agent-overview]] - Agent 整体学习路线
  • [[01-function-calling]] - Function Calling 基础(评估的基础对象)
  • [[05-agent-workflow]] - 工作流设计(影响轨迹评估的"最优路径"定义)
  • [[10-权限与门卫]] - Agent 安全与权限控制(与评估密切相关的质量维度)
  • [[13-可观测性与调试]] - Agent 可观测性(评估需要日志和 trace 支撑)

下一步学习 ​

  • [ ] 阅读 22 - 可观测性与调试 — 评估需要日志和 trace 支撑
  • [ ] 尝试用 Braintrust 或 LangSmith 为你自己的 Agent 搭建一套最简单的 Task Eval(5-10 条用例即可)
  • [ ] 阅读 SWE-bench 论文(https://arxiv.org/abs/2310.06770),理解它的评估方法论

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇18. MCP 协议 - AI 工具的"USB 接口" / Model Context Protocol for AI Tool Integration
下一篇20. 安全沙箱 - Agent 的安全边界 / Secure Sandboxes as Agent Safety Boundaries

持续记录,持续成长

Copyright © Tidenflow