被允许不等于被意图
策略引擎回答的是一个狭窄的问题:这次工具调用是否被允许?允许列表枚举了可达的工具、作用域和端点。它完全没有说明某一次特定调用、在特定步骤上,是否服务于用户实际授权的任务。一个 agent 可能持有支付 API、文件系统、邮件网关和代码解释器的有效凭证,每一次单独的调用都可能通过策略,而整个序列却在做用户从未要求的事情。可达性是配置的属性。正当性是运行的属性。
这一区分之所以重要,是因为运维人员关心的故障模式很少是单次被禁止的调用。它们是组合:一次读取把文档拉入上下文,一个摘要步骤悄悄丢掉了一条约束,一次写入传播了被截断的版本。每一步都被允许。审查者需要回答的问题是,这一步是否被意图——它是否由任务、观察结果和当时生效的策略所推出。
意图记录必须包含什么
意图记录是每执行一步就发出一次的结构化事件。它不是为人类书写、之后用正则解析的日志行;它是带有契约的 schema。最低可行字段:
- 任务标识符。 用户授权目标的稳定句柄,在第一步之前创建,并贯穿后续每一步。
- 步骤索引。 在单次运行内单调递增,因此缺口可见。
- 调用的工具。 具体能力,而不是泛化标签。
- 提交时的参数。 归一化之前的载荷,因为归一化正是意图丢失之处。
- 准入策略规则。 哪条规则允许了该调用,以及依据哪个版本的策略集。
- 观察摘要。 触发该步骤的观察结果的哈希,使记录无法被悄悄改写以匹配后来的叙述。
- 终止原因。 运行为何结束——完成、预算耗尽、策略拒绝、错误、超时——包括成功的运行。

终止字段是最常被省略的字段,也是让其余部分可审计的字段。如果每次运行都应以一条终止记录收尾,那么终止记录的缺失本身就是信号:崩溃的执行器、被终止的容器、从未上报的进程。没有它,缺失的记录与从未发生过的运行无法区分。
一个具体机制:执行器在派发之前立即计算 observation_digest = H(canonical_json(observation)),并且仅在保留策略允许时,将摘要与原始观察结果一起存储。摘要成本低廉,在实践中不可变,并且足以证明第 N 步呈现给模型的观察结果就是记录所声称的那一个。如果后续调查需要完整的观察结果,可以按摘要从内容存储中恢复,并受与任何其他用户内容相同的保留规则约束。
由执行器发出,而非模型
如果意图记录由模型生成——运行结束时的摘要调用,或自我报告的理由——它们就会变成模型可以叙述的又一样东西,因而也是对手可以影响的又一个表面。记录必须由实际派发工具调用的组件发出,在策略准入之后、执行之前,并附上策略引擎的决定。模型可以提议;执行器作证。这是证人陈述与收据之间的区别。
捕获与保留是两个独立决定
捕获一条意图记录成本很低。保留其中的内容则不然。一条只包含任务 ID、步骤索引、工具名称、策略规则和摘要的记录很小、敏感度低,可以长期保存。一条嵌入原始参数和观察结果的记录,则继承用户当时所处理内容的敏感度。诚实的权衡是这样的:激进的保留为事件响应者提供了所需材料,同时创建了一个用户内容存储,并附带其自身的访问控制、删除和泄露义务。实际的分割方式是长期保留结构化记录,内容按摘要存储,并为内容存储设置单独的

一个 schema,三类消费者
同一条记录必须在不增加第二条流水线的情况下服务于评分器、事件响应者和成本核算。这在有用的方向上约束了 schema。评分器需要步骤序列和准入规则,以评估某条轨迹是否正当。事件响应者需要观察摘要和策略版本,以重建 agent 看到了什么以及哪些规则当时生效。成本核算需要工具身份、参数大小和终止原因,以按任务归集支出。一个携带任务 ID、步骤索引、工具、参数摘要和大小、策略规则和版本、观察摘要以及终止原因的 schema 可以服务这三者。只为单一消费者设计的 schema,会被另外两者从原始日志中重新推导——组织最终得到同一事件的三个互不兼容版本,就是这样发生的。
签名与排序
记录应当链式相连:每条记录包含其前驱的摘要,运行以签名的根终止。这使静默删除可被检测,并给响应者一个可验证的序列。代价是运维性的:密钥管理、轮换,以及审计路径中的验证步骤。这一代价是真实的,也是许多团队从无签名记录和单调步骤索引开始,待 schema 稳定后再加入签名的原因。从无签名开始是站得住脚的;从没有步骤索引开始则不然,因为排序是使后续一切添加成为可能的属性。
弥合缺口的产物
策略定义了被允许动作的空间。意图记录展示了这些动作中哪些被采取、以什么顺序、依据哪条规则、跟随哪个观察结果,以及运行为何停止。前者是配置;后者是证据。将 agent 部署到具有真实后果的环境中的团队两者都需要,而后者必须由运行时在决策时刻产生——而不是事后从一份已不再包含关键上下文的对话记录中重建。
封面照片:Pixabay / Pexels。
