Agent 评测为什么特殊
评测一个 RAG 系统,最终答案就是评测对象------对或错,准确或不准确。
Agent 的过程本身也是评测对象。绕 3 步找到的正确答案,和调对工具但参数错误的情况,只看最终答案都会漏掉。
Agent 评测需要覆盖两个维度:
csharp
维度 1:工具调用准确性(可自动化)
工具名准确率:选了正确的工具?
参数准确率:工具调用参数正确?
步骤效率:用了多少步完成任务?
维度 2:轨迹质量(LLM-as-Judge)
推理是否合理:每步调用有逻辑依据?
有无冗余调用:是否存在重复或无效的工具调用?
错误处理:工具返回空结果时有没有正确应对?
实验设计
被测 Agent: 客服助手,3 个工具:
python
search_faq(query) # 搜索产品常见问题
get_order_status(order_id) # 查询订单状态
calculate_refund(amount, days_since_purchase) # 计算退款金额
15 个测试用例,覆盖三类场景:
| 类别 | 用例数 | 示例 |
|---|---|---|
| 简单单工具 | 9 个 | "退款政策是什么" → search_faq |
| 多步骤 | 3 个 | "ORD-004 能退款多少" → get_order_status + calculate_refund |
| 边界情况 | 3 个 | 不存在的订单、已取消的订单、无需工具的闲聊 |
每个用例有 ground truth:期望的工具调用序列和参数。
运行结果
工具调用准确率
ini
[T01] ✓ tools=['search_faq'] name=✓ params=100%
[T02] ✓ tools=['get_order_status'] name=✓ params=100%
[T03] ✗ tools=[] 期望=['search_faq'] name=✗ params=100%
[T04] ✗ tools=[] 期望=['get_order_status',...] name=✗ params=100%
[T05] ✓ tools=['calculate_refund'] name=✓ params=100%
[T06] ✓ tools=['get_order_status','calculate_refund'] name=✓ params=100%
...
[T10] ✗ tools=[] 期望=['search_faq'] name=✗ params=100%
[T13] ✓ tools=[] 期望=[](闲聊,无需工具) name=✓ params=100%
[T14] ✗ tools=[] 期望=['get_order_status'] name=✗ params=100%
汇总指标
ini
Tool Name Accuracy: 73% (11/15 correct sequences)
Parameter Accuracy: 100% (avg across all tool calls)
Step Efficiency: 0.73x (1.0 = optimal)
Trajectory Quality: 3.73/5 (LLM-as-Judge)
Failed cases (4):
[T03] expected=['search_faq'] actual=[]
[T04] expected=['get_order_status', 'calculate_refund'] actual=[]
[T10] expected=['search_faq'] actual=[]
[T14] expected=['get_order_status'] actual=[]
Per-category breakdown:
Simple (1 tool) tool_acc=75% trajectory=3.75/5
Multi-step (2 tools) tool_acc=67% trajectory=3.67/5
Edge cases tool_acc=67% trajectory=3.67/5
三个发现
发现 1:失败类型只有一种------"应调工具却没调"
4 个失败案例的失败模式完全一致:Agent 直接给出答案,没有调用任何工具。参数准确率 100% 说明凡是 Agent 决定调工具的情况,参数都是对的。
失败分布:
工具选错类型(调了但选错):0 个
参数错误类型(选对但参数错):0 个
未触发工具类型(应调未调):4 个
工具执行逻辑没有问题,工具触发逻辑是瓶颈。Agent 在某些情况下认为自己知道答案,跳过了工具调用。
T03("配送需要多少天?")和 T10("我是会员,有什么优惠?")失败原因:这两类问题 glm-4-flash 有内置知识,即使 Prompt 要求"必须使用工具",模型仍然直接回答了。T04(需要先查订单再计算退款)和 T14(已取消订单的退款问题)失败原因:复合问题和边界问题,模型倾向于直接推断而不是查询。
修复方向: 在 System Prompt 里针对这些场景加更强的约束,或者用 Rule-based 路由在 LLM 判断之前预处理特定类型的问题。
发现 2:步骤效率 0.73x------低于 1.0 是因为有些任务少用了步骤
步骤效率 < 1.0 看起来是好事,实际原因是失败案例中 Agent 少做了必要步骤。
理想情况(无失败)下的效率:
T06(需要 2 步):Agent 用了 2 步 → 效率 1.0
T12(需要 2 步):Agent 用了 2 步 → 效率 1.0
失败案例(减少了步骤,但答案质量下降):
T04(需要 2 步):Agent 用了 0 步 → 效率 0.0
步骤效率低于 1.0 有两种原因:
- Agent 真的找到了更高效的路径(好事)
- Agent 跳过了必要步骤(坏事)
单看步骤效率数字无法区分这两种情况,需要结合工具名准确率一起解读。
发现 3:多步骤任务和边界情况的轨迹质量更低
ini
Simple (1 tool): tool_acc=75% trajectory=3.75/5
Multi-step (2 tools): tool_acc=67% trajectory=3.67/5
Edge cases: tool_acc=67% trajectory=3.67/5
多步骤和边界情况的工具名准确率都是 67%,比简单任务的 75% 低。轨迹质量分也低。
多步骤任务的失败模式:Agent 认为可以一步完成,跳过了中间步骤。边界情况(已取消订单)的失败模式:Agent 直接推断"已取消订单没有退款",没有先查询订单状态确认信息。
这个分布符合大多数 Agent 系统的规律:简单直接的任务表现好,复合/边界任务表现差。测试集设计时必须包含足够比例的多步骤和边界用例,否则准确率数字会被单步任务拉高,掩盖真实问题。
工具调用评测的实现
工具名准确率
最严格的评测:工具调用序列必须完全匹配。
python
def tool_name_accuracy(actual: list[str], expected: list[str]) -> bool:
"""检查工具调用序列是否完全匹配。"""
if len(actual) != len(expected):
return False
return all(a == e for a, e in zip(actual, expected))
参数准确率
允许字符串部分匹配和数值容差,避免因格式差异导致漏判:
python
def param_match_score(actual_calls, expected_args) -> float:
"""计算参数准确率,返回 0.0-1.0。"""
total, correct = 0, 0
for actual, expected in zip(actual_calls, expected_args):
for key, expected_val in expected.items():
total += 1
actual_val = actual["args"].get(key)
if actual_val is None:
continue
# 数值容差(允许 0.01 以内误差)
if isinstance(expected_val, (int, float)):
if abs(float(actual_val) - float(expected_val)) < 0.01:
correct += 1
# 字符串部分匹配
elif str(expected_val).lower() in str(actual_val).lower():
correct += 1
return correct / total if total > 0 else 1.0
轨迹质量(LLM-as-Judge)
python
TRAJECTORY_JUDGE_PROMPT = """评估以下 Agent 执行轨迹的质量(1-5分):
用户问题:{question}
Agent 调用的工具:{tool_calls}
Agent 的最终回答:{answer}
5分:工具调用完全合理,每步都有必要,回答准确完整
4分:工具调用基本合理,有1个小问题
3分:工具调用方向正确,但有冗余或遗漏
2分:工具调用部分错误,回答质量差
1分:工具调用完全错误或完全无关
只返回 1-5 的整数分数。"""
测试集设计的三个关键
1. ground truth 需要工具序列,不只是最终答案
python
TestCase(
id="T04",
question="ORD-004 这个订单能退款多少钱?",
expected_tools=["get_order_status", "calculate_refund"], # 工具序列
expected_args=[
{"order_id": "ORD-004"},
{"amount": 99.0, "days_since_purchase": 15}
], # 期望参数
expected_min_steps=2, # 最少需要几步
)
2. 覆盖三类难度
erlang
简单(单工具): 测基础工具识别能力,应占 50%
多步骤(多工具): 测规划能力,应占 30%
边界情况: 测鲁棒性(不存在的资源、空结果处理),应占 20%
3. 包含"不需要工具"的用例
纯闲聊和问候测试 Agent 是否会过度调用工具。一个正确的 Agent 应该知道"你好"不需要查订单数据库。
总结
- 工具名准确率 73%,参数准确率 100%:失败全是"应调未调",不是"调错了";这说明工具触发逻辑是瓶颈,工具执行逻辑没问题,优化方向很清晰
- 步骤效率 < 1.0 需要结合工具名准确率解读:低效率可能是找到更短路径(好),也可能是跳过必要步骤(坏)
- 测试集必须包含多步骤和边界用例:简单单工具任务准确率 75%,多步骤和边界任务只有 67%,如果测试集全是简单任务,73% 会虚报成 85%+
参考资料
- BFCL(Berkeley Function Calling Leaderboard)
- 本系列完整 Demo 代码:eval-05-agent
欢迎访问 PrimeSkills ------ 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页