跳转到主要内容

运行时意图判断胜过静态允许列表:为 Agent 出站流量把关

静态允许列表跟不上运行时组合出来的 Agent 工具调用。运行时意图检查能捕捉到目标过滤遗漏的情况——前提是这项检查在热路径上足够廉价。

Perspective of multiple yellow pipes in Beijing creating a geometric pattern.

为什么静态策略对 Agent 不够用

静态出站策略假设目标集合在 Agent 运行之前就是可知的。对于人类工作流,这个假设大体成立:一个服务账号访问一组固定的主机,一个开发者访问已知的包仓库,一个 cron 任务与一个数据库通信。这份列表是有限的、可审查的,而且变化缓慢。

Agent 打破了这个假设,因为工具调用是在运行时组合出来的。目标往往是推导出来的,而不是事先声明的。一个 retrieval 步骤返回一个 URL,一个 summarisation 步骤从该 URL 中提取主机名,一个 fetch 步骤去调用它。没有工程师把这个主机名写进策略文件,因为在编写策略时没有工程师知道它。这次调用在构造上就是合法的,并且对预先批准的列表不可见。

The usual response is to widen the list until it stops blocking. That produces the opposite failure: an allowlist broad enough to admit every derived destination is effectively an allow-everything rule with extra steps. The policy still looks like a control, but it no longer discriminates. Between the two failure modes there is no static setting that works, because the policy is being asked to answer a question it cannot see.

更深层的问题在于,目标本身就是错误的判断单位。同一个端点可以是良性的,也可以是恶意的,取决于 payload 和产生它的步骤。对内部 metadata 服务的调用,在获取配置时是例行公事,在参数是凭据路径时则是严重问题。对合作伙伴 API 的请求,当 body 是状态查询时没问题,当 body 包含 Agent 本次会话读到的所有内容的拼接时就有问题。仅按主机过滤,丢掉了区分这些情况的信息。

运行时意图实际检查什么

运行时意图检查把决策从调用去哪里转移到调用想要达成什么。这需要看的不仅仅是目标。

参数,而不只是目标。 参数、payload 形态,以及这些值的来源。来源是最重要的部分,也是静态工具通常缺失的部分。如果一个参数可以追溯到用户消息,它是一种值。如果它可以追溯到一个读取了不可信内容的工具的输出,它是另一种值。在轨迹中追踪这种血缘关系,才能让检查区分用户提供的参数和注入文档提供的参数。

Detailed view of a liquid cooling system inside a desktop computer.

序列位置。 一次调用相对于产生它的轨迹是否可疑。在一次失败的身份验证尝试之后立即读取 secrets 存储,与在 provisioning 运行的第一步读取它,是不同的事件。同一次调用,处于不同位置,含义不同。这就是为什么意图检查需要把近期轨迹作为输入,而不只是单个工具调用。

频率与重复。 同一个良性调用连续四十次,与同一次调用只发生一次,是不同的事件。重复往往是区分枚举与单次查询的信号,而且它测量起来很廉价,因为计数器已经存在于编排层中。

一个把这些联系起来的具象机制:维护一个按运行划分的来源图,其中每个值都携带一个污点标签,记录哪些来源对它有贡献。当一次工具调用即将触发时,guard 从该调用的参数、这些参数上的污点标签、该调用在轨迹中的位置,以及到该目标的近期调用频率,组装出一个特征向量。一个小型分类器对该向量打分。策略依据的是分数,而不是主机名。污点传播是承重的部分;没有它,分类器只能从表面语法上猜测。

延迟预算

意图检查位于模型和工具之间,所以每一毫秒都按步骤付费。一个每个任务发起几十次工具调用的 Agent,要付几十次 guard 成本,而这个成本在关键路径上。一个每次调用都增加明显延迟的 guard 改变的是产品,而不只是安全态势。

实际的结构是分层的。廉价启发式先运行:目标类别、参数形态、污点标签是否存在、调用频率阈值。这些是表查找和比较,能在没有模型介入的情况下解决绝大多数调用。昂贵的分类只在模棱两可、廉价层无法决断时运行。升级规则必须公开,而不是隐式的,因为它定义了系统会捕捉什么、不会捕捉什么。如果规则是“当任何参数携带不可信污点标签且目标在内部类别之外时升级”,这是一个运营者可以推理、审查者可以质疑的陈述。

诚实的权衡是,分层用覆盖率换取延迟。廉价层放行的调用永远不会到达分类器,所以启发式看不见的任何东西都会被设计性地漏掉。收紧升级规则以捕捉更多,意味着更频繁地支付分类器成本。不存在既最快又最敏感的设置;这个选择必须被明确做出,并随着 Agent 行为的变化而重新审视。

The cost of getting it wrong is also asymmetric in a way that alert-based thinking obscures. Measure false positives in agent steps, not in alerts. A blocked step can invalidate a whole run: the agent loses a tool result, the trajectory derails, and the task either fails or completes with a degraded result the user cannot distinguish from a correct one. A guard that fires too often does not produce a queue of alerts to triage; it produces silent failures that look like model errors. That is why the false-positive budget for an agent guard is tighter than for a conventional network control, and why the guard's

Close-up of an advanced audio mixing panel with slide controls and knobs in a studio setting.

运营这个模型

分类器不是一次性的产物。把意图模型与 Agent 一起做版本管理。策略变更就是一次部署:它随 Agent 版本一起发布,记录在运行轨迹中,并且可以用同样的方式回滚。把策略当作独立于 Agent 漂移的配置,正是 guard 最终执行没人记得写过的规则的原因。

保留一个 shadow 模式,记录本会发生的拦截但不强制执行,并每周审查差异。Shadow 模式是在 guard 开始消耗运行之前了解其误报率的唯一方法。每周审查是调整升级规则的地方,也是 Agent 工具使用模式漂移在变成事故之前显现出来的地方。

把已确认的事故作为带标签的轨迹反馈回去。分类器的训练集就是事故日志,这意味着事故审查流程和模型训练流程是同一个流程。每一个已确认的事故都成为一个附带其轨迹的正样本;每一个被审查推翻的 shadow 模式拦截都成为一个负样本。这闭合了循环,让模型保持最新,而不需要一个没人维护的独立数据收集工作。

这里的权衡是运营负担。一个从事故中学习的 guard 要求事故审查及时且一致,这是一项长期承诺,而不是一个项目。无法持续做到这一点的团队,用一个更简单、被充分理解的启发式层会更好,而不是用一个悄悄过期的分类器。

从中可以得出什么

静态允许列表没有错;它们是不拟合的。它们回答的是关于目标的问题,而风险存在于参数、来源和序列之中。运行时意图检查回答的是正确的问题,但前提是意图信号在热路径上足够廉价可评估。把检查分层,公开升级规则,用被作废的运行而不是告警来衡量误报,并把模型与 Agent 一起做版本管理。安全属性不是每一次调用都被预先批准。而是每一次调用都在上下文中被判断,且成本是 Agent 在每一步都负担得起的。

封面照片:Atlantic Ambience / Pexels。

分享XLinkedIn永久链接6 分钟阅读

相关阅读

这能回答的问题

Why do static allowlists fail for agent tool calls?

Agent tool calls are composed at runtime, so the destination is often derived from earlier steps rather than declared in advance. An allowlist sized for human workflows either blocks legitimate composition or has to be widened until it admits nearly everything, at which point it no longer discriminates.

What does runtime intent inspection look at beyond the destination?

It examines arguments and their provenance, the position of the call in the trajectory that produced it, and the rate and repetition of similar calls. The same endpoint can be benign or hostile depending on the payload and the step that generated it.

How do you keep an intent check fast enough for the hot path?

Use a tiered structure: cheap heuristics such as destination class, argument shape, taint labels and call-rate thresholds resolve most calls, and expensive classification runs only on ambiguity. The escalation rule should be published so its coverage limits are explicit.

Why measure false positives in agent steps rather than alerts?

A blocked step can invalidate an entire run, causing the agent to fail or produce a degraded result the user cannot distinguish from a correct one. That makes the false-positive budget tighter than for a conventional network control, and it means guard decisions need to be visible in the run trace.