用 AEM 拆解多轮 Agent 失败:找到真正出错的那一轮

2026-09-10 34 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:12 分钟

多轮 Agent 的失败通常不是“最后一轮突然答错”这么简单。一个早期决策如果写错了状态、误解了用户意图,或者调用了错误的工具,后续多轮可能只是沿着错误前提继续推理。只看最终结果,评估者很难判断问题究竟发生在哪里。

Agent Evaluation Metric(AEM)提供了一种更适合多轮对话的拆解方式:把 Agent 质量按轮次观察,并将“造成失败的轮次”和“继承了错误的轮次”区分开。本文聚焦 AEM 的第一个维度:正确性(correctness),并给出一个可以直接改造成评估脚本的最小实现。

为什么单轮评估会漏掉关键问题

单轮评估通常把一次输入和一次输出放在一起判断:答案是否正确、工具是否调用成功、格式是否符合要求。这种方式适合独立问答,却不适合具有状态的多轮 Agent。

考虑下面的对话:

  1. 用户要求查询订单 A-100 的配送状态。
  2. Agent 错把订单号保存成 A-001
  3. 用户继续询问预计送达时间。
  4. Agent 根据错误订单继续调用物流工具。
  5. 最终回复看起来格式完整,但内容属于另一笔订单。

如果只给最终回复打分,评估结果可能是“第 5 轮错误”。但真正改变了后续轨迹的是第 2 轮。第 3 至第 5 轮可能存在不同程度的问题,却不一定都是根因。

这一区分直接影响修复策略:

  • 根因轮次需要检查意图识别、状态写入、工具参数或决策逻辑。
  • 继承轮次需要检查 Agent 是否能发现矛盾、重新确认关键事实,或者及时停止错误链路。
  • 如果把所有错误都归因于最后一轮,团队容易修补输出模板,却放过真正导致状态污染的步骤。

AEM 的核心:按轮次拆解正确性

可以把一段多轮交互表示为:

T = (t1, t2, ..., tn)

其中每个 ti 是一轮交互,可能包含用户输入、Agent 输出、工具调用和状态变化。对每一轮分别判断正确性后,可以得到:

C = (c1, c2, ..., cn)

ci 表示第 i 轮是否满足当前轮次的任务要求。实际评估中也可以使用连续分数,例如 01,以表达部分正确。

但仅有 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, ...}

这个实现有意保持简单,但已经能支持三种比总分更有用的分析:

  1. 找到首次引入错误的轮次。
  2. 统计错误传播了多少轮。
  3. 观察 Agent 是否在后续轮次恢复正确。

在真实系统中,可以把 expected_stateactual_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 的正确性维度提供了一个清晰起点:先定位哪一轮改变了轨迹,再判断后续轮次是继续犯错、主动恢复,还是完成了新的局部任务。这样,评估结果才真正能指导提示词、状态管理、工具调用和恢复机制的改进。


相关推荐