智能体面试准备(十一):Agent 评估体系——轨迹、工具选择与成功率的量化方法
前面十篇把 Agent 的构建讲了个遍:ReAct、工具调用、规划、记忆、多智能体、编排、Agentic RAG。但一个尖锐的问题一直悬着:你怎么证明你的 Agent 变好了?上一篇结尾埋的"轨迹级评估指标"伏笔,今天正式展开。
这个主题在面试里的杀伤力被严重低估。很多候选人能把 Agent 架构讲得天花乱坠,一句"你们怎么评估的"就哑火了——要么答"人工看效果",要么把 LLM 评估那套(MMLU、C-Eval)直接搬过来。而 Agent 评估恰恰是生产化的命门:没有评估,每次改 prompt、换模型、加工具都是在赌博。
一、为什么 Agent 评估比 LLM 评估难一个量级
LLM 评估是"一问一答对答案":输入固定、输出单步、答案唯一或有参考。Agent 评估的困难在于它的过程性:
- 多步且路径不唯一:同一个任务,先查天气再订酒店,或先订酒店再查天气,都可能是对的。不能用单一标准路径去对齐。
- 非确定性:同一个 Agent 跑同一个任务两次,轨迹可能完全不同。单次通过说明不了什么,必须引入 pass@k / pass^k 这类多次采样指标。
- 结果对≠过程对:Agent 可能靠猜蒙对了结果,过程中却调错了三次工具;也可能过程完美,最后一步格式化输出出错。只看结果会奖励侥幸、惩罚"差一点的优秀"。
- 环境副作用:Agent 会真实地发邮件、改数据库。评估必须在沙箱里做,环境本身的搭建成本就不低。
一句话总结给面试官:LLM 评估是批改一道题的答案,Agent 评估是给整场驾照路考打分——不仅看有没有到终点,还要看每个动作是否规范。
二、评估的三个层次:结果、轨迹、单步
这是本篇的核心框架,建议整体记忆:
| 层次 | 评估对象 | 典型指标 | 优点 | 局限 |
|---|---|---|---|---|
| 端到端结果 | 任务是否完成 | 成功率、pass@k、任务得分 | 直接反映业务价值 | 无法定位失败环节 |
| 轨迹级 | 整条执行路径 | 轨迹匹配度、步数效率、冗余动作率、成本/延迟 | 可定位问题、奖励好过程 | 参考轨迹难穷举 |
| 单步级 | 每一步决策 | 工具选择准确率、参数填充准确率、单步幻觉率 | 粒度最细、最可解释 | 与最终成败不必然相关 |
轨迹级是重点中的重点。常用的轨迹对比模式有:精确匹配(动作序列完全一致,最严格)、顺序匹配(关键动作按序出现,允许插入冗余步骤)、集合匹配(关键动作都出现即可,不管顺序)、前缀匹配(衡量"走对了多远")。实践中顺序匹配和集合匹配最常用,因为它们容忍合理的路径多样性。
单步级里最重要的是工具调用四连环:该不该调工具(decision)→ 调哪个工具(selection)→ 参数填得对不对(parameterization)→ 结果用得对不对(utilization)。四个环节各自都能出错,分开统计才能知道该修 prompt、改工具描述,还是换模型。
再补一组容易被忽略的效率与成本指标:平均步数、token 消耗、端到端延迟、单任务成本。两个 Agent 成功率都是 90%,一个平均 5 步一个平均 15 步,生产上是天壤之别。
三、谁来打分:规则、LLM 裁判与人工
| 打分方式 | 适用场景 | 成本 | 可靠性 |
|---|---|---|---|
| 规则/断言 | 有客观判据(文件是否生成、API 是否调用、数值是否正确) | 低 | 高(但覆盖面窄) |
| LLM-as-a-Judge | 开放性输出、过程合理性 | 中 | 中(需校准) |
| 人工评审 | 高风险场景、裁判校准 | 高 | 最高 |
生产共识是三层漏斗:能用规则判的绝不用 LLM,LLM 裁判定期抽样与人工对齐校准。用 LLM 裁判必须报告它与人工标注的一致率(如 Cohen's kappa),否则"裁判本身不可信"这一追问就接不住。LLM 裁判还有已知偏差要主动提:位置偏差(偏向先出现的答案)、长度偏差(偏向更长的输出)、自我偏好(偏向同族模型的文风)——缓解手段是交换顺序取平均、明确评分 rubric、用异族模型做裁判。
行业基准可以点名几个增加可信度:SWE-bench(真实 GitHub issue 修复)、WebArena(网页操作)、τ-bench(对话式工具调用,提出 pass^k 衡量稳定性)、AgentBench(多环境综合)。注意 τ-bench 的 pass^k 与常见 pass@k 方向相反:pass@k 是 k 次里至少成功一次(衡量能力上限),pass^k 是 k 次全部成功(衡量稳定性下限)——生产系统更该看后者,这个辨析是高分点。
四、可运行代码:一个迷你 Agent 评估器
下面实现一个不依赖任何框架的轨迹评估器,覆盖三层指标:结果成功率、轨迹顺序匹配、工具选择/参数准确率,并输出 pass^k。可直接运行体会"评估器本身也是代码资产":
import json from dataclasses import dataclass, field @dataclass class Step: tool: str args: dict @dataclass class Trajectory: steps: list # list[Step] final_answer: str success: bool # 端到端结果(由规则断言得出) def order_match(traj_tools, ref_tools): """顺序匹配:参考关键动作是否按序出现在轨迹中(允许插入冗余步骤)""" it = iter(traj_tools) matched = sum(1 for r in ref_tools if r in it) # 消耗式按序查找 return matched / len(ref_tools) if ref_tools else 1.0 def step_accuracy(traj: Trajectory, ref_steps: list): """单步级:工具选择与参数填充准确率(按参考步骤逐位对齐)""" tool_hit = param_hit = 0 for i, ref in enumerate(ref_steps): if i < len(traj.steps) and traj.steps[i].tool == ref.tool: tool_hit += 1 if traj.steps[i].args == ref.args: param_hit += 1 n = len(ref_steps) return tool_hit / n, param_hit / n def evaluate(runs: dict, references: dict): """runs: {task_id: [Trajectory, ...]} 同一任务跑 k 次 references: {task_id: list[Step]} 参考轨迹(关键动作)""" report = {} for task_id, trajs in runs.items(): ref = references[task_id] k = len(trajs) succ = [t.success for t in trajs] report[task_id] = { "pass@k": any(succ), # 至少一次成功:能力上限 "pass^k": all(succ), # 全部成功:稳定性下限 "success_rate": sum(succ) / k, "avg_steps": sum(len(t.steps) for t in trajs) / k, "order_match": sum(order_match([s.tool for s in t.steps], [s.tool for s in ref]) for t in trajs) / k, "tool_acc": sum(step_accuracy(t, ref)[0] for t in trajs) / k, "param_acc": sum(step_accuracy(t, ref)[1] for t in trajs) / k, } return report # ---- 模拟:任务「查北京天气并保存到文件」跑 3 次 ---- ref = {"t1": [Step("get_weather", {"city": "北京"}), Step("write_file", {"path": "weather.txt"})]} runs = {"t1": [ Trajectory([Step("get_weather", {"city": "北京"}), Step("write_file", {"path": "weather.txt"})], "已保存", True), Trajectory([Step("search_web", {"q": "北京天气"}), # 冗余但走通 Step("get_weather", {"city": "北京"}), Step("write_file", {"path": "weather.txt"})], "已保存", True), Trajectory([Step("get_weather", {"city": "上海"})], "查错城市", False), ]} print(json.dumps(evaluate(runs, ref), ensure_ascii=False, indent=2))输出里能清晰看到:pass@k 为 True 而 pass^k 为 False——这个 Agent"有能力但不稳定";第三次运行的 param_acc 掉到 0 暴露了参数幻觉(城市填错)。指标组合起来才能讲出诊断故事,这正是轨迹级评估的价值。
五、评估驱动开发:把评估放进 CI
最后升华一层:成熟团队把 Agent 评估当作回归测试——沉淀一个任务集(含参考轨迹与断言),每次改动(换模型/改 prompt/加工具)都全量跑一遍,指标下降就阻断合并。配合上一篇讲的可观测性埋点,线上 bad case 持续回流进评估集,形成"线上发现→入集→修复→防回归"的飞轮。面试收尾抛出这套"评估即 CI"的工程观,基本能把这个话题聊成加分项。
答题框架回顾:为什么难(四点)→ 三层指标(结果/轨迹/单步 + 效率成本)→ 谁打分(规则/LLM 裁判/人工三层漏斗 + 裁判偏差)→ pass@k vs pass^k 辨析 → 评估即 CI 收尾。
下一篇 B12 是本系列第一篇纯实战:从零写一个完整可运行的 ReAct Agent,把前面所有理论落成一份能跑、能测、能讲的代码——面试带着它去,比十页简历都有说服力。