多轮 Agent 的失败通常不是“最后一轮突然答错”这么简单。一个早期决策如果写错了状态、误解了用户意图,或者调用了错误的工具,后续多轮可能只是沿着错误前提继续推理。只看最终结果,评估者很难判断问题究竟发生在哪里。
Agent Evaluation Metric(AEM)提供了一种更适合多轮对话的拆解方式:把 Agent 质量按轮次观察,并将“造成失败的轮次”和“继承了错误的轮次”区分开。本文聚焦 AEM 的第一个维度:正确性(correctness),并给出一个可以直接改造成评估脚本的最小实现。
为什么单轮评估会漏掉关键问题
单轮评估通常把一次输入和一次输出放在一起判断:答案是否正确、工具是否调用成功、格式是否符合要求。这种方式适合独立问答,却不适合具有状态的多轮 Agent。
考虑下面的对话:
- 用户要求查询订单
A-100的配送状态。 - Agent 错把订单号保存成
A-001。 - 用户继续询问预计送达时间。
- Agent 根据错误订单继续调用物流工具。
- 最终回复看起来格式完整,但内容属于另一笔订单。
如果只给最终回复打分,评估结果可能是“第 5 轮错误”。但真正改变了后续轨迹的是第 2 轮。第 3 至第 5 轮可能存在不同程度的问题,却不一定都是根因。
这一区分直接影响修复策略:
- 根因轮次需要检查意图识别、状态写入、工具参数或决策逻辑。
- 继承轮次需要检查 Agent 是否能发现矛盾、重新确认关键事实,或者及时停止错误链路。
- 如果把所有错误都归因于最后一轮,团队容易修补输出模板,却放过真正导致状态污染的步骤。
AEM 的核心:按轮次拆解正确性
可以把一段多轮交互表示为:
T = (t1, t2, ..., tn)
其中每个 ti 是一轮交互,可能包含用户输入、Agent 输出、工具调用和状态变化。对每一轮分别判断正确性后,可以得到:
C = (c1, c2, ..., cn)
ci 表示第 i 轮是否满足当前轮次的任务要求。实际评估中也可以使用连续分数,例如 0 到 1,以表达部分正确。
但仅有 C 还不够。多轮 Agent 的重要问题是错误会传播。因此,评估时还应记录每一轮错误的类型或归因关系:
root_error:这一轮首次引入了会影响后续结果的错误。inherited_error:这一轮主要延续了之前已经存在的错误。recovered:Agent 发现并纠正了此前的错误。correct:当前轮次独立完成了预期任务。
AEM 的价值不在于把一个总分换成多个数字,而在于让评估结果可以回答一个工程问题:哪一轮改变了对话的正确轨迹?
一个可运行的最小评估器
下面的 Python 示例使用一个简化的状态模型。它假设每一轮记录了:期望状态、Agent 实际状态,以及当前轮次是否直接满足任务要求。代码不是某个具体 AEM 实现的官方接口,而是将“按轮次评分”和“识别根因与继承错误”落地的一种实践方式。
运行环境只需要 Python 3.9 或更高版本,不依赖第三方库。
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Turn:
index: int
expected_state: str
actual_state: str
directly_correct: bool
note: str = ''
def evaluate_turns(turns: List[Turn]) -> List[dict]:
results = []
active_root: Optional[int] = None
for turn in turns:
state_matches = turn.expected_state == turn.actual_state
if turn.directly_correct and state_matches:
label = 'correct'
elif active_root is None:
label = 'root_error'
active_root = turn.index
else:
label = 'inherited_error'
results.append({
'turn': turn.index,
'correctness': 1.0 if turn.directly_correct and state_matches else 0.0,
'label': label,
'root_turn': active_root,
'note': turn.note,
})
return results
conversation = [
Turn(1, 'order=A-100', 'order=A-100', True, '识别订单号正确'),
Turn(2, 'order=A-100', 'order=A-001', False, '写入了错误的订单号'),
Turn(3, 'order=A-100', 'order=A-001', False, '继续使用已有错误状态'),
Turn(4, 'order=A-100', 'order=A-100', True, '重新确认后恢复正确状态'),
]
for result in evaluate_turns(conversation):
print(result)
示例输出的关键信息类似于:
{'turn': 1, 'correctness': 1.0, 'label': 'correct', 'root_turn': None, ...}
{'turn': 2, 'correctness': 0.0, 'label': 'root_error', 'root_turn': 2, ...}
{'turn': 3, 'correctness': 0.0, 'label': 'inherited_error', 'root_turn': 2, ...}
{'turn': 4, 'correctness': 1.0, 'label': 'correct', 'root_turn': 2, ...}
这个实现有意保持简单,但已经能支持三种比总分更有用的分析:
- 找到首次引入错误的轮次。
- 统计错误传播了多少轮。
- 观察 Agent 是否在后续轮次恢复正确。
在真实系统中,可以把 expected_state 和 actual_state 换成结构化对象,例如订单号、用户权限、购物车商品或任务计划。不要把复杂状态直接转换成字符串后再比较;应使用领域对象或 JSON 解析器比较关键字段,这样才能区分无关字段变化和真正影响任务的错误。
如何把正确性评估接入 Agent 测试
实际评估不应只比较最终文本。可以为每一轮定义一个小型判定契约:
conversation: order-status-follow-up
turns:
- id: 1
input: 查询订单 A-100 的配送状态
expected:
state:
order_id: A-100
action: get_delivery_status
- id: 2
input: 预计什么时候送达?
expected:
state:
order_id: A-100
action: get_delivery_eta
测试执行后,至少保存以下数据:
- 用户输入和可见上下文。
- Agent 的最终回复。
- 工具名称与参数。
- 本轮写入或修改的状态。
- 该轮的正确性分数。
- 错误是首次引入、继承,还是已经恢复。
这样,失败报告可以从“这条对话最终答错了”升级为:
任务:order-status-follow-up
根因轮次:2
传播轮次:3
恢复轮次:无
主要问题:工具参数中的 order_id 与用户原始请求不一致
对于有人工标注的数据集,可以让评估者只标注每轮的关键事实和动作,而不是重新评价整段对话。对于自动评估,则可以用确定性检查处理订单号、金额、权限和工具参数等字段,再用模型评审自然语言质量。两者应分开记录,避免模型评审的主观判断掩盖了一个可以精确验证的参数错误。
AEM 结果应该怎样用于改进
AEM 的分解结果适合连接到具体工程动作:
- 根因集中在状态抽取:检查上下文压缩、记忆写入和实体解析。
- 根因集中在工具调用:检查工具 schema、参数校验和调用前确认。
- 大量继承错误:增加矛盾检测、状态重新验证或人工确认节点。
- 经常能够恢复:保留恢复策略,并单独统计恢复成功率。
- 每轮正确,但最终任务失败:检查跨轮目标是否定义完整,不能只看局部正确性。
需要注意,逐轮正确性并不自动等于整段任务成功。一个 Agent 可能每轮都做出局部合理响应,却没有完成用户的最终目标。因此,建议同时保留两层指标:
- turn-level correctness:每一轮是否完成当轮任务,以及是否保持了正确状态。
- conversation-level success:整段对话是否达到最终目标。
两者结合,才能区分“某一轮错了”和“每一轮都没错,但任务设计本身不完整”。
落地前的检查清单
开始使用 AEM 风格的多轮评估时,可以先确认以下事项:
- 每轮是否有明确的预期状态或预期动作?
- 是否记录了工具参数和状态变化,而不只是最终文本?
- 是否能识别首次引入错误的轮次?
- 是否区分根因错误、继承错误和恢复行为?
- 是否同时统计逐轮正确性与整段任务成功率?
- 对可确定验证的字段,是否优先使用规则或结构化比较?
- 对主观的语言质量,是否单独使用模型评审或人工标注?
多轮 Agent 的评估重点,不是把更长的对话压缩成一个更复杂的总分,而是保留错误发生和传播的时间顺序。AEM 的正确性维度提供了一个清晰起点:先定位哪一轮改变了轨迹,再判断后续轮次是继续犯错、主动恢复,还是完成了新的局部任务。这样,评估结果才真正能指导提示词、状态管理、工具调用和恢复机制的改进。