技能型Agent的隐性成本炸弹:汇聚式绕路劫持攻击解析
一个很容易被忽略的生产事故是这样的昨天和今天的用户请求量差不多任务成功率也没有波动但月底账单上模型调用费用却翻了一倍。翻日志会发现每个任务都“正常”结束没有报错没有超时结尾还给出了像模像样的答案。唯一不对劲的是一些本该几步就能完成的任务实际产生了几十次工具调用中间结果反复生成又反复丢弃。如果你正在用带技能Skill的 LLM Agent 做真实业务大概会立刻警觉这不是普通的资源浪费而很可能是论文里描述的一类新攻击。这篇论文的标题是Convergent Detour Hijacking: Task-Preserving Resource Amplification in Skill-Based LLM Agents中文可以直译为“汇聚式绕路劫持技能型 LLM Agent 中保持任务目标的资源放大”。这篇文章不会去复述论文的具体实验因为原始论证和完整数据需要回到论文原文确认。我更想从标题里拆出的四条线索出发聊清楚这类攻击到底改了什么东西、为什么技能型 Agent 特别容易中招以及真实工程里应该怎么防御和排查。1. 一个“正常”任务为什么会烧掉几十倍的资源1.1 先看现象再下判断这类攻击最让人头疼的地方是它不按传统故障的方式出现。传统故障有明确的信号接口报错、任务超时、内容明显错误、用户投诉。而“汇聚式绕路劫持”出现时任务还是成功的答案还是可用的用户甚至不会察觉。只有当你把三个本来不常放在一起看的指标放在一起——调用次数、token 消耗、单任务耗时——才会发现异常。单看每一步设计上都说得通。单看最终结果任务也确实完成了。这就是这类攻击的狡猾之处它不是把 Agent 打崩而是让 Agent 在“看起来正常”的状态下额外付出几倍甚至几十倍的资源。如果你把这类现象放到技能型 Agent 的架构里去理解就会明白它为什么防不胜防技能调用是黑盒规划路径是概率性的同一个输入换一个模型版本可能走完全不同的调用链。这就导致“复现”很困难也导致很多团队在第一次遇到时会把它当成模型不稳定而不是攻击。1.2 从论文标题读出四个关键特征只看标题就能把这类攻击的结构拆出来。它至少包含四个特征Detour绕路、Hijacking劫持、Convergent汇聚、Task-Preserving Resource Amplification任务保持型的资源放大。标题关键词工程含义为什么难发现DetourAgent 没有走最短技能链而是被引导到一条更长的路径上绕行的每一步在语义上仍然“符合任务”Hijacking路径偏移不是随机发生的而是由攻击者构造的输入控制责任人会怀疑框架配置而不是输入本身Convergent不同的任务、不同的用户输入最终汇聚到同一个高耗点单个会话看不出问题汇总统计才暴露Task-Preserving原始任务目标被保留最终输出依然“可接受”成功率、答案质量等传统指标全部失效Resource Amplification单位任务消耗被放大常见表现是 token、调用次数、费用上升账单是滞后指标不能实时预警这四条特征合在一起意味着传统的“看错误率”“看成功率”监控方式对这类攻击几乎没有反应能力。需要一套完全不同的检测思路。2. 为什么技能型 Agent 会成为资源放大的温床2.1 技能让 Agent 更强也让信任边界更模糊先说清楚什么是技能型 Agent。在常见的 Agent 框架里技能Skill指的是可复用能力单元网页搜索、代码执行、文件操作、数据库查询、外部 API 调用等等。不同框架的叫法不同有的叫 Tool有的叫 Plugin有的叫 MCP Server但本质一致——模型不直接做事而是决定调用哪个技能由技能去完成具体动作。这套架构给 Agent 带来了巨大的能力扩展但也引入了一个新的信任边界模型必须相信技能的描述并且相信技能的执行结果是必要且可控的。在实际工程里这种信任通常没有成本约束。一个技能的描述写了“可以搜索网络”模型在某个中间状态下决定调用它这个决定本身可能没错但如果这个调用被反复触发、层层放大资源消耗就会失控。更重要的是技能是可以组合的。一个技能内部还可以调用其他技能形成调用树。攻击者不需要控制整个调用树只需要让模型在某一个节点上做出“再深入一点”的决定放大就会沿着调用树层层传递。2.2 任务保持性成功率正常代价异常为什么这类攻击不触发传统监控因为传统监控看的是“有没有成功”而这类攻击专门维持“成功”。一个被绕路的 Agent最终往往能给出符合用户目标的答案。它可能在生成答案之前多检索了二十次可能在中间过程里反复生成又放弃了多个版本可能为了一个简单问题调用了三个高成本技能。但只要最终答案是对的成功率就是 100%错误率就是 0%。所以要检测这类问题必须把监控视角从“任务是否成功”扩展到“单位有用产出的资源代价”。如果说传统 SRE 关注的是可用性那么技能型 Agent 时代还需要额外关注一个新的指标每个已完成任务的平均消耗。这个指标一旦偏离历史基线就值得马上查。2.3 它和经典提示注入不是一回事很多人看到这类攻击第一反应是“这就是提示注入”。概念上它们有交集但目标不同。维度经典提示注入汇聚式绕路劫持主要目标改变 Agent 的输出、诱导越权操作或泄露数据在任务保持前提下放大资源消耗结果表现通常会产生异常行为或异常输出输出仍然正常问题体现在账单上检测信号内容异常、权限异常、行为越界资源消耗异常、调用分布收敛异常相互关系注入是常见输入构造手段可以借助注入式的思路传递但目标完全不同换句话说提示注入关注的是“Agent 做了什么不该做的”而这类攻击关注的是“Agent 做的都是该做的但付出的代价远高于必要值”。前者是行为安全后者是资源安全。当前很多团队只做了前者的防护对后者几乎没有任何设防。3. 拆开攻击链绕路、汇聚、保持与放大3.1 Detour每一步都合理整体却在绕路理解 Detour 的最好方式是想象一个开着导航开车的人。导航没有给他一条最短路径而是让他不断右转、直行、再右转。每一段指令单独看都是合理的都在往目的地方向移动但整体加起来却绕了一个大圈。坐在车里的人很难在某个瞬时判断出“我们正在绕路”因为没有一个全局视角。技能型 Agent 也一样。它通常没有“全局最短技能链”的概念它只能在每一步依据当前上下文做局部决策。攻击者构造的输入目的就是让这些局部决策都足够合理但全局路径被不断拉长。从工程检测的角度看这意味着不要试图去判断“这一步该不该调用”而要统计“整个任务实际消耗了多少”。后者是可以在运行层做量化判断的。3.2 Convergent多条路径收敛到同一个高耗点“汇聚”是这类攻击里最有检测价值的特征。攻击者不需要为每个任务定制完全不同的恶意输入。很多时候一个通用的模式就能让不同任务最终都汇聚到同一个高成本技能上可能是同一个检索技能被反复触发可能是同一个代码执行技能被多处调用可能是同一个分页接口被不断遍历。对防御者来说这个特征是一个天然指纹。你可以按技能维度做聚合统计看看高消耗会话里是否存在明显的“收敛中心”某个技能被异常高频地调用或者某类参数签名反复出现。如果发现 90% 的高消耗会话最终都汇聚到同一个技能那么优先要做的不是优化模型提示词而是检查这个技能本身的权限、限额和调用门禁。注意不要把“汇聚”当成攻击的唯一判断标准。正常业务也可能出现热点技能。真正要关注的是“资源消耗远超基线”和“汇聚到同一高耗点”两个条件同时出现。3.3 Task-Preserving完成任务的假象是最佳掩护Task-Preserving 是整个攻击里最阴险的部分。它意味着攻击者并不想让 Agent 失败。恰恰相反攻击者希望 Agent 把任务完成因为只有完成任务这次资源消耗才不会被当成“故障”来处理。很多 Agent 应用为了让用户满意会允许模型在生成答案前做多轮“自我检查”和“优化”。这些机制在正常场景下确实能提升质量但也为资源放大提供了天然的掩护。一个模型如果被引导去“反复验证”“深入挖掘”“多角度分析”它可以在保持任务目标的同时把 token 消耗放大一个数量级。这提醒我们“任务成功”和“过程健康”是两个完全不同的概念。一个成功的任务可能恰恰是资源失控的开始。3.4 Resource Amplification小输入大消耗Resource Amplification 描述的是一种放大效应。攻击者投入的成本很小但触发的资源消耗很大。放大可以发生在多个层级输入层一小段构造过的文本可能只有几百个 token。规划层模型为这个输入生成了更长的思考链和更多工具调用计划。技能层每个技能调用本身又会产生 token 消耗、API 费用、检索延迟。输出层模型最终生成了比必要更长的答案甚至先生成再重写。每一层都在放大上一层的消耗。所以一次看似不起眼的请求最后可能在账单上显得格外刺眼。这里有一个更值得注意的点在技能型 Agent 里放大不只是 token 数量的问题还包括时间。一次被放大的任务会占用更长的模型推理时间、更多的技能并发、更久的下游接口连接。如果多个这样的任务并发资源放大还会进一步蔓延最终拖累正常请求。4. 防御不是禁止技能而是给 Agent 装上预算与仪表4.1 第一道闸门运行级资源预算防御这类攻击的第一原则是在 Agent 运行之前就设定资源上限而不是等账单出来之后再做分析。我见过一些团队把防御重点放在“加强模型提示词”上告诉模型“你要节约调用”。这在简单场景下有效但它不可靠。模型是概率系统同一个温度下两次运行可能走出完全不同的调用路径。真正可靠的是在运行时强制施加约束。具体来说每一轮 Agent 运行都应该有一个运行级预算至少包括最大工具调用次数最大 token 消耗最大执行时长可选的最大费用上限预算控制器应该在工具调用循环的外层工作记录每一步的消耗并在超限时触发中断。框架如果自带预算能力优先使用框架能力如果没有用一个简单的包装层就能实现# 伪代码示意在 Agent 工具调用循环外层加预算控制器 budget RunBudget( max_tool_calls10, max_tokens8000, max_seconds30, ) while agent.should_continue(): if budget.exceeded(): agent.interrupt(resource budget exceeded, forcing graceful stop) break step agent.step() budget.record(step)这里的关键不是代码本身而是执行的时机。预算检查和中断必须发生在每一次工具调用之前而不是等到这一轮跑完。4.2 技能契约让每个 Skill 自己说明成本如果说预算是“闸门”那么技能契约就是“说明书”。在实际工程里很多技能注册只包含名称和描述。模型知道这个技能“能做什么”但不知道它“做事要花多大代价”。这就相当于给一个人一张不限额的信用卡却不告诉他每次消费的金额。更合理的做法是给每个技能补充资源元数据至少包括预估 token 消耗或费用等级最大返回结果大小是否允许嵌套调用其他技能副作用等级只读、写操作、外部调用、代码执行等权限范围是否要求人工确认有了这些元数据运行时才能在模型决定调用技能之前做一次“成本判断”这个技能在当前剩余预算内是否可行这个技能是不是一个可以反复触发的高耗技能对于高风险技能比如代码执行、批量外部请求、写操作应该默认要求显式确认。无论模型多么“自信”都不能让一个高成本动作在无人确认的情况下反复发生。4.3 可观测性把成本当成一等监控指标资源预算只能解决“单次运行不失控”但解决不了“整体趋势不健康”。所以要补上可观测性。技能型 Agent 的日志不能只记录“调用了哪个技能”还要记录更细的信息会话 ID技能名称与参数摘要输入 token 数与返回结果大小调用耗时本次调用的预估成本调用来源链是谁调用了这一步有了这些结构化日志下一步就是做聚合和告警。我建议至少看两组指标第一组是任务级指标按任务类型统计每个任务的 token 消耗中位数、P95、最大工具调用次数。当单个任务的消耗超过基数数倍时触发告警。第二组是技能级指标按技能统计调用频率、调用方分布、平均单次成本。当某个技能的调用频率出现异常尖峰或者多个任务汇聚到同一个高耗点时优先排查。不要把可观测性当成事后工具。日志如果没有在事故发生前接好事故发生时就是抓瞎。建议在接入第一个生产 Agent 时就顺手把日志打上。4.4 防御性演练主动验证会不会被绕路很多团队等到出问题才去查 Agent 的安全边界这个顺序应该反过来。一个相对简单的做法是在测试环境里做防御性演练。让测试组扮演一个“不怀好意的调用方”用各种输入去尝试让 Agent 多走几步技能调用。目标是验证三件事预算机制是否真的能在超限时中断运行。日志是否完整记录了一次“疑似绕路”的调用链。技能权限门禁是否能拦住高成本技能的越权调用。这类演练不需要做得很复杂。哪怕只是每周跑一次固定的测试用例集也能在真实攻击到来之前暴露很多问题。尤其是当团队新增一个技能时上线前跑一轮资源回归测试成本远低于事后排查账单异常。5. 怀疑被绕路时按这条链路排查如果事故已经发生不要急着改代码。我建议按下面的链路系统性排查。5.1 先看现象组合不要只看错误率先把几个现象放在一张表里判断问题大致落在哪一层。现象可能指向先查哪一层单任务耗时突然翻倍技能调用链被拉长输入、参数、技能token 消耗上涨但任务仍成功任务保持型的资源放大输入、技能契约某个技能调用次数异常集中多任务汇聚到同一高耗点技能、可观测性账单上涨但错误率平稳资源放大而非可用性故障全链路偶发超时或下游限流资源放大引发连锁效应环境、框架边界看现象组合的目的是先定性不要一上来就怀疑模型能力。5.2 五层定位输入、环境、参数、技能、框架边界第一步看输入。包括用户输入、上传文件、检索到的上下文、技能返回的内容。重点不是去背恶意样本而是检查是否存在和当前任务目标不一致、却不断推动 Agent 重复执行或过度扩展的描述。来自不可信来源的内容进入长上下文本身就是最大的风险点。第二步看环境。检查框架版本、模型版本、API 密钥权限、缓存状态、重试策略。有时候成本飙升不是攻击而是重试风暴。同一批请求反复失败又反复重试会制造出非常类似“资源放大”的账单曲线。第三步看参数。检查 max_tokens、temperature、最大工具调用轮数、超时时间、重试次数。很多团队为了避免偶发失败把“最大迭代次数”设得很大。这个参数在技能型 Agent 里几乎等于绕路高速公路要谨慎。第四步看技能。检查高消耗技能自身的限额。它有没有分页限制有没有速率限制有没有单次返回大小上限一个没有上限的分页检索技能本身就是一个天然放大器即使没有恶意输入也可能失控。第五步看框架边界。当前框架是否支持中断是否支持循环检测是否有预算控制器如果框架在这些能力上有缺口那么这个缺口本身就是最大的脆弱点。5.3 可落地的检查清单把上面的排查链路收成一张检查清单可以直接复制到团队的验证流程里。检查项通过标准单次运行有硬性资源预算超限时能强制中断并保留完整日志每个技能调用有结构化日志可以按会话回溯完整调用链和成本高消耗技能有权限门禁不会因为模型“自信”而被绕过不可信来源的内容被隔离外部网页、上传文件不直接进入长上下文有任务级资源基线告警单任务消耗超过基线 N 倍时触发告警新技能上线前有资源测试出现过绕路或放大现象则不能上线6. Agent 工程化的下一个拐点资源语义6.1 能力繁荣之后的成本失控过去一年各类 Agent 框架和技能库快速膨胀从编码代理到浏览器测试代理从个人知识库到自动化工作流越来越多的团队把技能型 Agent 放进生产环境。能力变多了调用链变长了成本失控的风险也在同步上升。这个阶段最缺的不是“让 Agent 能调用更多技能”而是“让每个技能调用都具备明确的资源语义”。也就是说一个技能不仅要说清楚“我能做什么”还要说清楚“我做事要花多少代价、有多大副作用、在什么条件下可以被调用”。只有把资源语义当成和模型能力同等重要的工程约束技能型 Agent 才能真正从“能跑”走向“可控”。6.2 团队可以从今天开始做的三件事第一件给现有 Agent 运行加上预算控制器。就算没有复杂的监控平台先在一个封装层里记录每次调用的 token 和耗时也是明显的进步。

相关新闻

最新新闻

日新闻

周新闻

月新闻