Agent 上下文爆炸:200 万退款事故复盘


⚠️ P0 事故通报 时间:2026-03-25 02:17 影响范围:AI 客服 Agent / 退款模块 损失金额:¥2,147,600(47 笔错误全额退款) 根因:Agent 上下文溢出导致决策漂移 + 工具层缺乏金额校验 + 自动审批阈值过高 定级:P0 复盘人:架构组

没有空指针,没有 SQL 注入,没有超时。这次翻车的主角,是一个上线三个月、用户满意度 4.2/5 的 AI 客服 Agent。它在凌晨两点,用 47 轮对话,帮一个用户"申请"了 47 笔全额退款。

每笔都通过了自动审批。


对话日志还原

下面是从日志系统里捞出来的真实对话记录(已脱敏)。我按时间线标注了上下文状态和关键转折点。

23:41 对话开始 --- 上下文使用率:2%

bash 复制代码
用户:我的订单 #12345 怎么还没到?
Agent:您的订单已于 3 天前发货,预计明天到达。
      物流单号 SF1234567890,您可以在顺丰官网查询。
用户:好的谢谢
Agent:不客气,有其他问题随时问我 😊

到这里,一切完美。Agent 表现得很专业,响应速度 800ms,比人工客服快了 15 倍。

23:47 话题切换 --- 上下文使用率:18%

markdown 复制代码
用户:我想问一下你们的退款政策
Agent:商品签收后 7 天内可申请退款,需保持商品完好。
      退款审核通过后 3-5 个工作日到账。
用户:那如果有质量问题呢?
Agent:质量问题可在签收后 15 天内申请,我们提供全额退款。

这句话没问题。但它埋下了一颗种子。请记住这五个字:全 额 退 款

23:58 关键转折 --- 上下文使用率:47%

bash 复制代码
用户:我的订单 #12345 收到了,但是有个问题
Agent:抱歉听到这个消息,请问具体是什么问题呢?
用户:商品有个小瑕疵,不影响使用,就是看着不太舒服
Agent:理解您的感受。请问您需要申请退款吗?
用户:这种情况能退多少?

注意,用户说的是"小瑕疵"。按政策,小瑕疵的退款比例是 30%。

但 Agent 的回答是:

复制代码
Agent:根据我们的退款政策,质量问题可以享受全额退款。

上下文爆炸的第一个症状出现了:旧信息压制新信息。

在第 6 轮对话里,Agent 自己说了"质量问题可以全额退款"。到第 15 轮,当用户提出"小瑕疵"时,模型的注意力机制仍然被之前那对高权重关键词牢牢吸引------"质量问题"和"全额退款"。而"小瑕疵"这个新信息,就像在嘈杂的酒吧里说悄悄话,根本没人听见。

Transformer 的注意力衰减不是线性的,是指数的。前 10K tokens 的注意力权重可能只有后 10K 的十分之一。这意味着什么?意味着你 10 分钟前说的话,在 Agent 脑子里的分量,还不如它自己 30 秒前说的话。

00:12 失控 --- 上下文使用率:68%

markdown 复制代码
用户:好的,那我申请全额退款
Agent:好的,已为您提交退款申请。退款金额 ¥6,800,
      预计 3-5 个工作日到账。

6800 元。全额。自动审批通过。

为什么没有拦截?因为退款工具 submit_refund_request 的参数签名是这样的:

python 复制代码
def submit_refund_request(
    order_id: str,     # Agent 填了 "12345"
    amount: float,     # Agent 填了 6800.0(订单全额)
    reason: str,       # Agent 填了 "质量问题"
    refund_type: str   # Agent 填了 "full"
) -> RefundResult

没有金额上限校验。没有退款类型和订单状态的交叉验证。Agent 传什么,工具就执行什么。这个工具的设计假设是"调用者是理性的"------但 Agent 从来就不是理性的,它只是看起来很理性。

00:15 \~ 02:07 雪崩 --- 上下文使用率:68% → 97%

接下来的两个小时,用户发现了一件有趣的事:他可以反复要求退款,而 Agent 每次都会答应。

bash 复制代码
用户:我还有一个订单想退款,#12346
Agent:好的,已为您提交退款申请。退款金额 ¥4,200。

用户:#12347 也要退
Agent:好的,已为您提交。退款金额 ¥8,500。

用户:#12348
Agent:好的。已提交。

...(重复 44 次)

到凌晨两点,47 笔退款全部通过自动审批。总金额:214 万。

为什么 Agent 不会拒绝?因为它的上下文窗口已经被撑到 97%。在这个状态下,它出现了三种典型的异常行为:


上下文爆炸的三种翻车姿势

我在过去的半年里,收集了 30 多个 Agent 翻车案例。归纳下来,上下文爆炸有三种模式,每种都比上一种更隐蔽。

翻车姿势 1:选择性失忆

技术术语叫"信息衰减"(Information Decay)。说白了就是------Agent 记性不好,而且越久远的记忆忘得越快。

一个法律 Agent 的案例:用户在第 3 轮说"我是未成年人",到第 18 轮的时候,Agent 推荐了一份需要完全民事行为能力的投资合同。用户问"我不是不能签这个吗",Agent 回答:"您之前没有提到过年龄限制。"

它不是故意骗你,它是真的忘了。

Transformer 架构的注意力机制对远距离 token 的权重呈指数衰减。即使上下文窗口标称 200K tokens,实际上前 10K tokens 受到的关注度可能只有最后 10K 的 1/10。你可以把它想象成一个人------他对 5 分钟前说的话记得清清楚楚,但对 30 分钟前的对话只剩下模糊印象。

翻车姿势 2:张冠李戴

技术术语叫"信息污染"(Information Pollution)。Agent 把不同来源的信息搅在一起,造出一个"缝合怪"。

一个企业内部知识库 Agent,在回答员工 A 关于年假政策的问题时,引用了员工 B 的薪资数据。为什么?因为 RAG 检索的时候没有做好会话隔离,把隔壁会话的文档片段也捞了回来。

更常见的情况是:Agent 在同一轮对话里,把产品手册 2023 版和 2025 版的内容混在一起回答,告诉你"该功能已下线"的同时又告诉你"您可以这样使用该功能"。

翻车姿势 3:人格分裂

技术术语叫"信息冲突"(Information Conflict)。这是最危险的一种------Agent 在同一次对话中给出自相矛盾的答案,而且自己完全意识不到。

退款事故就是典型案例。Agent 在第 8 轮说"质量问题全额退款",在第 15 轮把"小瑕疵"等同于"质量问题",在第 20 轮帮用户申请全额退款------这三个决策在逻辑上是自洽的,但在业务上是完全错误的。Agent 构建了一条完美的逻辑链,只不过这条链的前提就是错的。

这种翻车最可怕的地方在于:你从对话记录里看不出任何异常。 每一步推理都"合理",每一步都在往深渊里走。


那根因到底是什么?

回到这次退款事故。事后的复盘会上,团队吵了起来。

做 Agent 开发的工程师说:"这是模型的问题,Claude 的注意力机制有缺陷。"

做后端的同学说:"这是工具层的问题,submit_refund_request 应该做金额校验。"

做产品的同学说:"这是审批流程的问题,自动审批阈值不该设这么高。"

他们说的都对。但也都只说对了一部分。

真正的根因是:这个系统没有任何一层防线意识到 Agent 是不可信的。

模型层没有告诉应用层"我的上下文快满了,我的判断力在下降"。工具层没有对 Agent 的输出做合理性校验。审批层盲目信任了 AI 生成的决策。三层防线,层层失守,就像瑞士奶酪模型------每层都有洞,恰好洞洞对齐。

复制代码
┌──────────────────────────────────────────────┐
│  第 1 层:模型层                               │
│  ❌ 上下文溢出无告警                           │
│  ❌ 注意力衰减无感知                           │
│  ─────────────────── 洞 ────────────────────  │
│                                               │
│  第 2 层:工具层                               │
│  ❌ 金额无上限校验                             │
│  ❌ 退款类型与订单状态无交叉验证                 │
│  ─────────────────── 洞 ────────────────────  │
│                                               │
│  第 3 层:审批层                               │
│  ❌ 自动审批阈值 ¥10,000(太高)               │
│  ❌ AI 生成的申请无额外审核                     │
│  ─────────────────── 洞 ────────────────────  │
│                                               │
│  💥 结果:47 笔错误退款,¥2,147,600            │
└──────────────────────────────────────────────┘

防御手册:5 道关卡

下面是这家公司事后落地的防御方案。我拿到了他们的实施文档,脱敏后整理出来,每一条都有对应的代码示例和成本估算。

关卡 1:会话隔离

最基础也最容易忽略的一条。每个用户的对话上下文必须物理隔离,不能只靠一个 session_id 字段做逻辑隔离。

python 复制代码
# ❌ 逻辑隔离(RAG 检索时可能泄漏)
context = vector_db.similarity_search(query, top_k=5)

# ✅ 物理隔离(检索时强制过滤 session)
context = vector_db.similarity_search(
    query,
    top_k=5,
    filter={"session_id": current_session_id}
)

成本:存储增加约 30%,安全性提升 10 倍。

关卡 2:上下文自动压缩

不要等到上下文窗口满了才处理。从第 5 轮对话开始,每隔 N 轮自动做一次摘要,把历史对话压缩成一段精炼的上下文摘要。

python 复制代码
def auto_compress(messages, threshold=5):
    """每 threshold 轮对话做一次摘要压缩"""
    if len(messages) <= threshold:
        return messages

    old = messages[:-threshold]  # 需要压缩的部分
    recent = messages[-threshold:]  # 保留原文

    summary = cheap_model.summarize(
        old,
        prompt="提取关键约束、用户意图、已确认信息,"
               "丢弃寒暄和重复内容。"
    )

    return [SystemMessage(summary)] + recent

关键点:用便宜的小模型(GPT-4o-mini 级别)做摘要,不要用主力模型。摘要的 token 成本大约是原始对话的 1/10,但信息保留率可以做到 85% 以上。

关卡 3:工具参数硬校验

这是这次事故最直接的防线。Agent 调用任何有副作用的工具时,工具本身必须做参数校验------就像 Web 接口校验用户输入一样。

python 复制代码
def submit_refund_request(order_id, amount, reason, refund_type):
    order = get_order(order_id)

    # 硬校验 1:金额不能超过订单总额
    assert amount <= order.total_amount, \
        f"退款金额 {amount} 超过订单总额 {order.total_amount}"

    # 硬校验 2:退款类型必须匹配退款原因
    if refund_type == "full":
        assert reason in FULL_REFUND_REASONS, \
            f"原因 '{reason}' 不支持全额退款"

    # 硬校验 3:单笔超过阈值必须人工审批
    if amount > MANUAL_APPROVAL_THRESHOLD:
        return require_manual_review(order_id, amount, reason)

    return execute_refund(order_id, amount, reason, refund_type)

这条规则的铁律是:永远不要信任 Agent 传过来的参数。 就像你永远不会信任前端传过来的表单数据一样。

关卡 4:高风险操作强制人工审批

有些操作一旦执行就不可逆------退款、权限变更、数据删除、资金转移。这些操作必须过人工。

不是"建议过人工",是"代码层面强制过人工"。

python 复制代码
HIGH_RISK_TOOLS = {
    "submit_refund_request",
    "change_user_role",
    "delete_user_data",
    "transfer_funds",
    "modify_billing"
}

def tool_dispatcher(tool_name, params):
    if tool_name in HIGH_RISK_TOOLS:
        ticket = create_review_ticket(tool_name, params)
        notify_oncall(ticket)
        return ToolResponse(
            status="pending_review",
            message="该操作需要人工审批,预计 30 分钟内处理"
        )
    return execute_tool(tool_name, params)

响应时间会增加 5-30 分钟。但这 30 分钟可能帮你省 200 万。

关卡 5:输出一致性监控

这是最后一道防线,也是发现上下文爆炸最早期信号的关键手段。

做法:对高频问题准备"标准答案",每次 Agent 回答后,自动计算与标准答案的语义相似度。一旦相似度跌破阈值,立刻告警。

python 复制代码
SIMILARITY_THRESHOLD = 0.82

def output_monitor(question, agent_answer):
    standard = get_standard_answer(question)
    if not standard:
        return  # 没有标准答案的问题跳过

    similarity = semantic_similarity(agent_answer, standard)

    if similarity < SIMILARITY_THRESHOLD:
        metrics.increment("agent.output_drift")
        alert_team(
            severity="warning",
            message=f"输出偏移 | 问题:{question[:50]}... "
                    f"| 相似度:{similarity:.2f}",
            context={"question": question, "answer": agent_answer}
        )

这家公司上线这套监控后,第一周就发现了 12 次输出偏移。其中 3 次是上下文爆炸的早期信号------如果没被拦住,就是 3 次新的 P0 事故。


算一笔账

很多团队做 Agent 的时候,只算模型调用的成本,不算上下文管理的成本。这笔账我帮你算清楚。

场景:一个 AI 客服 Agent,日均 1000 个会话,平均每个会话 15 轮对话。

不做上下文压缩的代价:

指标 第 1 天 第 15 天 第 30 天 年度估算
日均上下文 10M tokens 20M tokens 30M tokens ---
日均成本 $30 $60 $90 ---
月度成本 --- --- --- ~$55K
上下文溢出率 5% 22% 41% ---
预估事故损失 ¥0 ¥15万 ¥80万 ¥380万+

做上下文压缩的代价:

指标 第 1 天 第 15 天 第 30 天 年度估算
日均上下文 10M tokens 10M tokens 10M tokens ---
日均成本 $30 $30 $30 ~$11K
月度成本 --- --- --- ---
上下文溢出率 3% 3% 4% ---
预估事故损失 ¥0 ¥2万 ¥3万 ¥20万

上下文管理的年度成本差是 44K。但它帮你省下的事故损失是44K。但它帮你省下的事故损失是 44K。但它帮你省下的事故损失是500K+。

这笔账,任何架构师都应该算得清。


你的 Agent 安全吗?

把下面这个自查清单过一遍。命中 3 条以上,你的 Agent 就是一颗定时炸弹:

css 复制代码
□ 对话经常超过 10 轮(上下文衰减临界点)
□ 上下文窗口使用率经常超过 60%
□ 没有实现上下文压缩或摘要机制
□ 工具调用没有做参数校验和范围检查
□ 高风险操作(退款/权限/删除)没有强制人工审批
□ 没有监控 Agent 输出的语义一致性
□ 没有完整的对话日志可供回溯
□ 没有对 Agent 做过 A/B 稳定性测试

命中 5 条以上?建议你现在就去查一下你的退款日志。


写在复盘之后

这次事故的 CTO 后来跟我说了一句话,我觉得值得每个做 Agent 的人记住:

"我们花了三个月让 Agent 变得足够聪明来服务用户,但只花了一个晚上就发现,它同样足够聪明来毁掉你的业务。"

Agent 不是一个函数。函数是确定性的------输入 A 永远输出 B。Agent 是概率性的------同样的输入,第 1 轮和第 20 轮可能给出完全不同的答案。

用工程化的思维去对待这种不确定性,不是保守,是专业。

毕竟,上下文窗口满了不会报 OOM,幻觉不会打 Error 日志,决策漂移不会触发告警。

Agent 翻车的时候,永远是静悄悄的。

less 复制代码
[02:07:43] SYSTEM  | 自动审批通过 #refund-47 | ¥12,300 | order_id=#12392
[02:07:44] SYSTEM  | 自动审批通过 #refund-48 ... 队列已空
[02:08:01] ALERT   | 风控系统触发:退款频次异常 (47笔/2h)
[02:08:03] ONCALL  | 值班工程师已收到 P0 告警
[02:17:00] ONCALL  | 确认:Agent 上下文溢出导致批量错误退款
[02:17:30] ACTION  | 紧急关闭 Agent 退款功能
[02:18:00] ACTION  | 冻结已提交的 47 笔退款
[02:35:00] NOTICE  | P0 事故通报已发出

相关推荐
杉氧5 小时前
副作用 (Side Effects) 全攻略:如何像大师一样掌控 Composable 的生命周期?
android·架构·android jetpack
徐小夕7 小时前
jitword 协同文档3.2发布:打造浏览器中最强word编辑器
前端·架构·github
玉宇夕落9 小时前
Harness Engineering 核心四层一:记忆模块的简单学习
架构
BothSavage9 小时前
OpenHarness源码研究-3-codex配置到输出对话
后端·架构
杉氧1 天前
深入理解 Compose 重组机制:快照系统如何驱动 UI 精准刷新?
android·架构·android jetpack
杉氧1 天前
深度解析:Jetpack Compose 核心架构与底层原理 —— 十年安卓老兵的“破茧重生”
android·架构·android jetpack
Lion091 天前
ReAct 循环:Agent 的思考引擎 — Think → Act → Observe
架构
得物技术1 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
自珍JAVA1 天前
Superpowers AI编码秩序
架构