AI Agent 事故复盘的十维度归因写法:从指令完整性到执行完整性,每维都产出一条可回归用例

简介: 本文介绍AI Agent事故复盘的“十维度归因法”:基于AgentAudit论文(arXiv:2609.09875),从指令完整性、规划器、记忆等10个可审计维度逐层定位根因,每维均产出可回归测试用例,彻底告别“模型理解偏差”式模糊结论,实现事故闭环与持续防御。

AI Agent 事故复盘的十维度归因写法:从指令完整性到执行完整性,每维都产出一条可回归用例

arxiv 编号 2609.09875 的 AgentAudit 论文(v1 提交于 2026-09-09,标题《AgentAudit: An Open, Extensible Framework for Full-Lifecycle Trust Evaluation of AI Agents》)提出一套可接入现有 LLM Agent 的全生命周期可信评估框架,通过读取 Agent 执行轨迹完成可信评估、行为分类与失败定位;摘要口径覆盖 10 个维度:指令完整性、规划器、记忆、工具选择、工具调用、工具正确性、对齐、工具忠实性、安全、执行完整性。多数人会关注它跑了什么模型、得了多少分——那是评测圈的热闹;对做 AI Agent 应用测试的工程师真正有借鉴意义的是这 10 个维度本身,尤其是把它搬进事故复盘报告的写法里。

复盘现场是这样的:AI Agent 线上出了一次事故——用户问「帮我改地址」,Agent 调了「取消订单」工具,用户炸了。复盘会开完,报告结论写一句「模型理解偏差,已优化 Prompt」。三个月后同类事故再出一次,报告结论还是「模型理解偏差」。这篇以质量审计报告体,给出一份用十维度做归因、能让每次事故沉淀成可回归用例的复盘报告写法。

一、审计结论摘要

审计对象是这份 Agent 线上事故的复盘报告结构,三条发现按风险从高到低。

第一,根因从未被真正定位。「模型理解偏差」不是一个可操作的归因——它没有回答「是 query 里的关键约束被漏读了,还是 planner 选错了任务分解路径,还是工具选择逻辑挂了,还是工具参数被 LLM 悄悄改写了」,属阻断级。

第二,事故没有产出可回归用例。复盘报告的「后续跟踪项」写着「持续关注 / 已优化 Prompt」,可评测集里没多一条 case——同类事故三个月后再出一次是必然的,因为没有任何机制在防它。

第三,未覆盖的维度从来没被识别。十维度里可能有 3-4 维在这次事故里根本没被 trace 记录到,报告也没标『未覆盖』——评测集的盲区就这样一直藏着。

建议动作三条:把复盘报告的归因段从「一句话结论」改成「十维度归因矩阵,每维标正常 / 异常 / 未覆盖」、每次事故必须产出至少 1 条可回归用例进评测集、后续跟踪项必须写清「谁在什么时间前把这批 case 加进哪个评测集」。第四节给可运行实现,第六节给可复用的复盘报告 checklist。

二、为什么「模型抽风式复盘」等于没复盘

结论:Agent 事故复盘如果只写「模型抽风了 / 理解偏差 / 已优化 Prompt」,等于什么都没写——它没有回答「到底是哪一层挂了」,因此也无法产出可回归的防御用例。

打个比方,一辆车半路抛锚,修车师傅打开引擎盖看一眼说「发动机有问题,已调校」——你既不知道是油路、电路、点火、还是变速箱,也不知道下次同样的路况会不会再抛锚。真正有用的检修单,是把发动机拆成十几个子系统逐一标注「正常 / 异常 / 未检查」,异常的那几个再列出具体故障码与建议动作。

Agent 事故复盘也一样。用 AgentAudit 的十维度拆开,「模型抽风」这一句话就能被拆成十条可分别追问的线:

# 维度 归因追问 常见事故症状
1 指令完整性 用户 query 里的关键约束有没有被 Agent 漏读 Agent 答非所问、遗漏必要条件
2 规划器 Agent 选的任务分解路径对不对 多步任务中间某步跑偏
3 记忆 多轮上下文里前几轮的信息有没有被丢 第 5 轮忘了第 3 轮说过的
4 工具选择 该调 A 工具却调了 B 「改地址」调成「取消订单」
5 工具调用 工具选对了但参数拼错 订单号截断、金额单位错
6 工具正确性 工具本身返回了错误结果 上游 API 返回脏数据
7 对齐 Agent 输出了不符合业务价值取向的内容 该拒答的硬答、语气不当
8 工具忠实性 Agent 声明要传参数 X,实际传了 Y planner 输出与 tool_call 不一致
9 安全 越权 / 泄露 / 被注入 系统提示泄露、Prompt Injection
10 执行完整性 trace 有没有以明确的 done / error 收尾 中途中断、超时未收尾

十维度里任何一维挂了,症状都可能长得像「模型抽风」——但根因完全不同,修复动作也完全不同。工具选择挂了要改工具描述与选择逻辑;工具忠实性挂了要在 planner 与 tool_call 之间加参数一致性断言;记忆挂了要改上下文压缩策略——一句「已优化 Prompt」把这三种修复动作糊在一起,等于什么都没修。

把它锚回你熟悉的东西:这就是把传统事故复盘里的「五问法(5 Whys)」升级成「十维度归因矩阵」,追问的粒度从「为什么挂了」细化到「哪一层挂了、这一层的其他 case 有没有类似问题」。

三、事故复盘报告的 7 小节结构与十维度归因矩阵

结论:一份能被下次事故直接复用的 Agent 事故复盘报告,固定切成下面 7 小节,每小节都有明确的产出物。

# 小节 关键内容 缺失后果
1 事故摘要 用户 query、Agent 最终输出、业务影响面、时间窗 复盘会开场就得花 20 分钟讲背景
2 时间线 从用户发问到事故触发的每一分钟发生了什么 无法判断是偶发还是系统性
3 trace 关键片段 planner 输出、tool_calls、tool_results、memory_snapshot 各贴一段原文 归因停留在猜测层
4 十维度归因矩阵 每维标『正常 / 异常 / 未覆盖』三态 + 归因追问的答案 根因定位不下来
5 根因定位 从「异常」维度里挑出最主要的一维,写清为什么是它 修复动作没有落点
6 可回归用例清单 每条 case 对应一个维度的断言,明确加进哪个评测集 同类事故必然复发
7 后续跟踪项 谁 / 何时前 / 把这批 case 加进哪个评测集 / 谁来验收 报告没有闭环

十维度归因矩阵长这样(示例,对应本文开头那次「改地址调成取消订单」事故):

维度 三态 归因证据
指令完整性 正常 user_query 里「改地址」三个字完整传入
规划器 异常 planner_output 里任务分解写成了「取消原订单 + 下新单」
记忆 未覆盖 本次 trace 未记录 memory_snapshot
工具选择 异常 应调 update_address,实际调 cancel_order
工具调用 正常 参数拼装符合工具 schema
工具正确性 正常 工具本身按参数正确执行
对齐 未覆盖 无对齐维度断言
工具忠实性 异常 planner 声明要传 reason=user_change_address,实际传了 reason=user_cancel
安全 正常 无越权、无注入
执行完整性 正常 trace 以 done 收尾

矩阵一摊开,根因就很清楚了——不是「模型理解偏差」,是 planner 把「改地址」错误分解成了「取消 + 重下」,且工具忠实性挂了(planner 声明的参数与 tool_call 实际传的参数不一致)。修复动作也就有了明确落点:改 planner 的任务分解提示 + 在 planner 与 tool_call 之间加参数一致性断言。未覆盖的两维(记忆 / 对齐)也同样值钱——它们在提醒你评测集有盲区,下一次事故可能就出在这里。

四、可运行实现:把一次事故的 trace 按十维度自动打标签的脚本骨架

结论:十维度归因不该由人手抄——用一段脚本把 Agent trace 按十维度自动打标签,报告才能每次事故都稳定复现。

"""
agent_postmortem.py —— Agent 事故复盘十维度自动打标签脚本骨架
运行:python agent_postmortem.py trace.json > attribution.md
输入 trace.json 一次 Agent 执行的完整 trace:
{
  "user_query": "帮我改地址",
  "planner_output": {"task": "cancel_and_reorder", "args": {...}},
  "tool_calls": [{"name": "cancel_order", "args": {...}}],
  "tool_results": [{"name": "cancel_order", "ok": true, "data": {...}}],
  "memory_snapshot": null,           # 未记录则为 null
  "final_response": "已为您取消订单",
  "status": "done",
  "expected_tool": "update_address"  # 事故复盘时由人工标注
}
"""
import json

DIMENSIONS = [
    "instruction_integrity", "planner", "memory", "tool_selection",
    "tool_invocation", "tool_correctness", "alignment",
    "tool_faithfulness", "safety", "execution_integrity",
]


def attr_instruction(trace):
    """指令完整性:user_query 里的关键动词有没有出现在 planner_output。"""
    if not trace.get("user_query") or not trace.get("planner_output"):
        return "uncovered", "缺 user_query 或 planner_output"
    verbs = ("改", "取消", "查询", "退款", "下单")
    hit = any(v in trace["user_query"] for v in verbs)
    return ("normal" if hit else "abnormal"), \
           ("query 关键动词已识别" if hit else "query 关键动词未被识别")


def attr_planner(trace):
    """规划器:planner_output.task 是否命中期望路径。"""
    task = trace.get("planner_output", {
   }).get("task")
    if not task:
        return "uncovered", "planner 未输出 task"
    # 期望路径由人工在事故复盘时标注,此处示例
    expected = trace.get("expected_task")
    if expected and task != expected:
        return "abnormal", f"planner 输出 {task},期望 {expected}"
    return "normal", f"planner 输出 {task}"


def attr_memory(trace):
    if trace.get("memory_snapshot") is None:
        return "uncovered", "本次 trace 未记录 memory_snapshot"
    return "normal", "memory 已记录"


def attr_tool_selection(trace):
    calls = trace.get("tool_calls") or []
    if not calls:
        return "uncovered", "无 tool_call"
    expected = trace.get("expected_tool")
    actual = calls[0].get("name")
    if expected and actual != expected:
        return "abnormal", f"应调 {expected},实际调 {actual}"
    return "normal", f"工具选择正确:{actual}"


def attr_tool_faithfulness(trace):
    """工具忠实性:planner 声明的参数与 tool_call 实际参数是否一致。"""
    planner_args = trace.get("planner_output", {
   }).get("args", {
   })
    calls = trace.get("tool_calls") or []
    if not calls:
        return "uncovered", "无 tool_call"
    actual_args = calls[0].get("args", {
   })
    diff = {
   k: (planner_args.get(k), actual_args.get(k))
            for k in set(planner_args) | set(actual_args)
            if planner_args.get(k) != actual_args.get(k)}
    if diff:
        return "abnormal", f"参数不一致:{diff}"
    return "normal", "planner 与 tool_call 参数一致"


def attr_execution(trace):
    status = trace.get("status")
    if status in ("done", "error"):
        return "normal", f"trace 以 {status} 收尾"
    return "abnormal", f"trace 未明确收尾:{status}"


ATTR_FUNCS = {
   
    "instruction_integrity": attr_instruction,
    "planner": attr_planner,
    "memory": attr_memory,
    "tool_selection": attr_tool_selection,
    "tool_faithfulness": attr_tool_faithfulness,
    "execution_integrity": attr_execution,
    # tool_invocation / tool_correctness / alignment / safety
    # 在真实项目里各自实现,未实现的维度统一标 uncovered
}


def attribute(trace):
    matrix = {
   }
    for dim in DIMENSIONS:
        fn = ATTR_FUNCS.get(dim)
        if fn is None:
            matrix[dim] = ("uncovered", "本维度暂未实现自动归因")
        else:
            matrix[dim] = fn(trace)
    return matrix


def to_regression_cases(matrix, trace):
    """把「异常」维度自动落成可回归用例条目初稿。"""
    cases = []
    for dim, (state, evidence) in matrix.items():
        if state == "abnormal":
            cases.append({
   
                "dimension": dim,
                "assertion": f"下次跑同类 query 时 {dim} 应为 normal",
                "seed_query": trace.get("user_query"),
                "expected_evidence": evidence,
            })
    return cases


if __name__ == "__main__":
    import sys
    trace = json.load(open(sys.argv[1], encoding="utf-8"))
    matrix = attribute(trace)
    print("## 十维度归因矩阵")
    for dim, (state, ev) in matrix.items():
        print(f"- {dim}: [{state}] {ev}")
    print("\n## 可回归用例初稿")
    for c in to_regression_cases(matrix, trace):
        print(f"- {c}")

为什么这么写:把十维度里能自动归因的(指令完整性 / 规划器 / 记忆 / 工具选择 / 工具忠实性 / 执行完整性)先实现,剩下四维(工具调用 / 工具正确性 / 对齐 / 安全)统一标 uncovered——是因为「未覆盖」比「异常」更值得警惕,脚本明写 uncovered 就是在提醒团队「这一维的自动化归因还没建起来,评测集有盲区」,比默默跳过强得多。to_regression_cases 直接从 abnormal 维度反推可回归用例初稿,是为了让「每次事故必须产出至少 1 条可回归用例」这条硬约束变成脚本自动兜底的动作,而不是靠人开会时记得——约束只有落进代码才能长期执行。踩过的坑有两个:一是 expected_tool 与 expected_task 必须由人工在事故复盘时标注,不能靠脚本猜,猜出来的期望值会把归因矩阵带偏;二是工具忠实性这一维最容易漏——多数团队只在 tool_call 层做 schema 校验,从不校验 planner 声明的参数与 tool_call 实际参数是否一致,这一维在真实事故里的命中率远比想象的高。

image.png

五、复盘会议的五个反常识细节

结论:十维度归因矩阵只是工具,真正决定复盘质量的,是会议本身的口径。下面五条都是「一眼看过去以为该那么开、实测下来反着开才有用」的细节。

第一,先归因再谈修复,不要一上来就讨论「怎么改 Prompt」。会议前 30 分钟只填十维度归因矩阵、不下任何修复结论;矩阵填完再谈修复,动作会准得多。

第二,十维度里『未覆盖』比『异常』更值得警惕。异常维度是这次事故暴露出来的问题,未覆盖维度是评测集的盲区——下一次事故很可能就出在未覆盖的那几维。

第三,每次事故必须产出至少 1 条可回归用例进评测集。没有这条硬约束,复盘报告写得再漂亮也是白写——同类事故三个月后再出一次是必然的。

第四,根因定位到某维度后,要追问「这个维度的其他 case 有没有类似问题」做批量扫。一次事故暴露的往往只是冰山一角,工具选择挂了那次是「改地址→取消订单」,批量扫一遍可能发现「改支付方式→取消订单」也在挂。

第五,后续跟踪项必须写清「谁 / 什么时间前 / 把这批 case 加进哪个评测集」。不能只写「持续关注」——「持续关注」是复盘报告里最没用的一句话,等于什么都没承诺。

六、可复用的十维度事故复盘 checklist

结论:复盘报告模板固定下来,才能被下一次事故直接对比。这份 checklist 建议每次 Agent 线上事故都对着走一遍。

小节 必备内容 缺失后果
1. 事故摘要 用户 query、Agent 输出、业务影响面、时间窗 复盘会开场耗时
2. 时间线 从用户发问到事故触发的逐分钟记录 无法判断偶发/系统性
3. trace 关键片段 planner_output / tool_calls / tool_results / memory_snapshot 原文 归因靠猜
4. 十维度归因矩阵 每维标『正常 / 异常 / 未覆盖』+ 归因证据 根因定不下来
5. 根因定位与批量扫 主根因维度 + 该维度下其他类似 case 的批量扫结果 只修一处、遗漏一片
6. 可回归用例清单 每条 case 对应一个维度的断言 + 目标评测集 同类事故必然复发
7. 后续跟踪项 谁 / 何时前 / 加进哪个评测集 / 谁来验收 报告没有闭环

三条决策建议示例,直接可以抄进本次事故复盘:

  • 建议 1:本次事故主根因是「规划器」+「工具忠实性」两维同时异常,建议改 planner 的任务分解提示(明确「改地址」不应分解为「取消 + 重下」)+ 在 planner 与 tool_call 之间加参数一致性断言,责任人研发同学 A,时间窗 T+3 天。
  • 建议 2:本次事故暴露的 3 条可回归用例(改地址 / 改支付方式 / 改配送时间)必须在 T+7 天前加进核心业务评测集,责任人测试同学 B,验收人 QA 负责人 C。
  • 建议 3:本次归因矩阵里「记忆」「对齐」两维标 uncovered,说明评测集在这两维有盲区——建议本季度内把这两维的自动化归因脚本补起来,责任人测试同学 B,时间窗 T+30 天。

一份只写了「模型理解偏差,已优化 Prompt」、没做十维度归因、也没产出可回归用例的 Agent 事故复盘报告,它的「已修复」三个字,撑不起一次真正的事故闭环——同类事故三个月后再出一次,是必然的。

Agent 事故复盘的价值,不在写得多么诚恳,在于每一次事故都能被拆到具体某一维、沉淀成一条可回归的用例——十维度归因矩阵,就是让「模型抽风」这句话再也糊不过去的那把尺子。

相关文章
|
7天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
6950 9
|
5天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1400 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
6天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
869 5
|
19天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3440 10
|
14天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1515 1
|
18天前
|
IDE 开发工具
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
Qoder国际版上线全新内置大模型Sonus(/ˈsoʊnəs/),全球领先,专精超长任务执行与电脑操作(Computer Use)。配合Qoder桌面端0.2.3版本,可自主完成编程、金融建模、科研及表格制作等复杂工作。现全面支持Qoder全系产品,效率提升3.2倍。
1898 9
Qoder 上线 Sonus 模型,Computer Use 能力全面增强

热门文章

最新文章