观察的局限
Agent 系统通常通过观察来治理。系统发出 trace,搭建仪表盘,设定阈值,并建立 on-call 轮值。这很有用,但它与“控制”是两种不同的属性。仪表盘观察的是已经完成的动作。等到某个面板变红时,tool call 早已执行,写入早已落盘,外部副作用早已发生。监控栈能做到的最好程度,只是缩短损害与发现之间的时间间隔。
观察还依赖于遥测数据的完整性。如果某个工具封装忘记发出事件,如果某条重试路径绕过了已插桩的客户端,或者如果某个新集成上线时没有带上 tracing 装饰器,那么仪表盘恰恰会对那些最不被理解的操作保持沉默。遥测覆盖的缺口并不是均匀分布的;它们聚集在最新、最少被审查的代码路径上,而那里正是事故集中的地方。
一个拥有宽泛权限的被监控 agent,仍然是一个宽泛权限的 agent。可观测性并不会缩小可达状态集合。它只是给一间仍然没上锁的房间加了一台摄像头。权限模型才是决定“什么可能发生”的东西;仪表盘只决定“什么会被注意到”。
告警阈值还会带来进一步的扭曲。阈值被调校以降低噪声,这意味着它们被调校为容忍一定速率的低级别异常。对于检测而言,这是合理的运维折中,但对于预防而言,这是错误的工具。一条“当敏感操作在每个时间区间内发生超过配置次数时触发”的策略,就是一条允许前几次发生的策略。预防需要在第一次发生之前做出决定,而不是在它之后做速率限制。
实际后果是:仅以监控形式表达的治理,往往会收敛到同一种失效模式——系统在总体上被充分理解,在具体处却不受约束。总体视图对于容量、成本和质量分析确实有价值。但它不是控制面。
编码不变量
替代方案是把策略表达为前置条件,在 agent 的意图转化为动作的边界处进行检查:也就是 tool call。Agent 拥有的每一项能力都通过某个工具接口可达,而该接口是能够强制执行决定的最窄之处。如果检查发生在这里,那么它对每个调用方都生效,包括在策略编写之后才加入的调用方。

前置条件是针对拟议调用及其周围上下文的谓词。它可以引用参数、发起请求的 agent 身份、会话、被触及的资源以及环境状态。以下是形态示例,而非具体内容:目标资源必须位于允许列表内的命名空间;当会话未被提权时,操作必须是读取;载荷不得包含被标记为受限的字段;调用必须附带由独立工作流签发的有效审批 token。
类型化 schema 使这一点可强制执行,而不是停留在愿望层面。如果工具的输入由带有必填字段、枚举值和有界类型的 schema 描述,那么格式错误的调用会在解析阶段失败,早于任何 handler 运行。fail-closed 行为源自 schema,而不是源自 handler 内部的防御性代码。一个产生看似合理但违反策略的参数的 agent 不会触达副作用;它会收到结构化拒绝,并必须决定下一步怎么做。
一个具体机制是这样的。Agent 运行时并不直接调用工具。它向策略网关发起结构化请求:
{
"agent": "research-worker-3",
"session": "s-8841",
"tool": "documents.write",
"arguments": {"collection": "contracts", "document_id": "c-2210", "body": "..."},
"context": {"approval": null, "elevated": false}
}
网关评估一个策略包,即一组带版本、由确定性评估器执行的规则。评估返回一个决定、一个原因码以及策略版本。只有在允许时,网关才调用底层工具。拒绝会作为普通工具结果返回给 agent,因此 agent 可以自行适应,而运行时无需对错误处理做特殊分支。
这里有两个属性很重要。第一,策略引擎位于模型上下文之外。它不是 prompt,不是 system message,也不是 agent 可以检索到的文档。它无法被争辩、被总结掉,或被后续指令取代。模型对决定的唯一影响,是它提交的请求内容。第二,给定请求和策略版本,决定是确定性的。同一个调用针对同一个策略包评估两次会产生相同结果,这正是决定在事后可解释的原因。
诚实的取舍是:这移动了复杂性,而不是消除了复杂性。每项新能力都需要一条策略条目,每次策略变更都是对生产行为的变更,需要审查。请求路径中的网关会增加延迟,并引入新的失效模式:如果网关不可用,正确的默认是拒绝,这意味着策略层的故障会变成 agent 能力的故障。采用这种模式的团队通常接受这一成本,因为替代方案是一种沉默且无界的故障。这笔交易是用能力的可用性换取能力的可界定性。
还有第二个值得点明的取舍。严格的 schema 和狭窄的允许列表会缩小 agent 可采取动作的空间,这可能降低它在未被预期任务上的有用性。缓解办法不是放松边界,而是让策略变更快速且可审查,使边界能够被有意识地移动,而不是被
rver-rack-closeup-2ef8e4-33fefc.jpg)
无法被举证的控制,就是会被质疑的控制。每项策略决定,无论允许还是拒绝,都应发出足以在无法访问实时系统的情况下重建推理过程的记录。该记录包括请求、决定、原因码、策略版本,以及对决定规范序列化的签名。
签名之所以重要,有一个具体原因:它使记录具备防篡改能力,并可归因于执行点,而不是归因于日志管道。一行日志可以被编辑、丢弃或重排。一条签名的决定记录可以被独立验证,而序列中的缺口是可检测的。
将策略版本与决定一同保留,才能使过去的行为可被重新解释。策略会变化。在某个策略包下正确的决定,在下一个策略包下可能不正确。没有版本,审查历史操作的审计员就必须猜测当时生效的是哪些规则。有了版本,同一个评估器可以针对记录的请求重放,并精确复现该决定。这把审计从访谈变成了验证。
拒绝应当与允许享有同样的保留。拒绝是边界生效的证据。它也是策略调优的主要信号:一条对合法工作频繁触发的拒绝,表明规则过宽;而一条在某类会话中从不触发的拒绝,可能表明规则不可达。保留两侧使策略面可观测,同时又不使其沦为建议性的。
最后一块是在部署前用记录的 trace 测试策略变更。如果决定与其请求一同被记录,那么候选策略包可以针对真实历史调用的语料库进行离线评估。输出是一份 diff:哪些先前被允许的调用现在会被拒绝,哪些先前被拒绝的调用现在会被允许。这份 diff 可以由审查策略的同一批人审查,它把策略变更从一次判断行为转变为一次测量行为。它还会暴露没人预料到的情况,而策略回归通常就藏在那里。
这就是可观测性与治理之间的实际区别。可观测性产生关于发生了什么事的记录。治理产生一个约束什么可以发生的边界,外加一份可被独立验证的边界决定记录。前者是运行系统的必要条件。后者是把权限委托给系统的必要条件。
这对系统设计意味着什么
把工具边界当作控制面。把策略评估器放在模型触及不到的地方。让 schema 成为第一道防线,并让格式错误的调用 fail closed。为两种结果都发出签名决定,并保持策略版本附加其上。在候选策略进入生产之前,用记录的流量重放它们。
这些都不取代可观测性。Trace、指标和仪表盘仍然是理解和改进系统的方式。改变的是顺序:边界做决定,记录做证明,仪表盘做解释。以这种方式治理的系统不依赖于模型做出正确选择。它依赖于模型无法做出别的选择。
