跳转至

Agent 时间性策略(Temporal Policies):基于轨迹的有状态授权架构

📊 Level ⭐⭐⭐ | 16.0KB

核心论点:传统 stateless 授权(每个请求独立判定)对 AI Agent 根本不够——Agent 在运行时决定调用哪些工具、以什么参数、什么顺序,单看一个工具调用是安全的,放在轨迹上下文里可能是灾难。Temporal Policy 在网关外围(gateway perimeter)基于 agent 轨迹(trajectory)做有状态授权,agent 自身代码无法拦截或篡改策略。

Stateless 授权的三个失效场景

  • 链式工具间的输出伪造:agent 调用 lookup_customer 拿到账户号后,凭空捏造另一个账户号传给 transfer_funds,把资金转给错误客户。单个调用各自都合法,只有轨迹级检查能发现。
  • 失控循环的累计暴露:失控 agent 在循环中执行几十笔交易,因为没有机制追踪"累计暴露已超过风险上限"。
  • 矛盾动作:agent 在几秒内既批准又拒绝同一份保险索赔。

Temporal Policy 的机制

Temporal Policy 是对"给定网关观察到的最近轨迹,这个请求是否被授权"这一问题的回答。它基于当前请求 + 会话内近期事件(trajectory)做评估,不转换请求、不调用工具、不直接编排 agent。

评估流程(网关收到工具调用时):

  1. 查询轨迹状态中与策略相关的 actions/inputs/outputs
  2. 在当前请求的 historical scope(客户定义的轨迹内的先前事件)上下文中评估每条 temporal policy
  3. 返回确定性的 ALLOW/DENY 并记录完整决策上下文

关键设计点:

  • 每个请求必须携带 x-amzn-bedrock-agentcore-policy-session-id header;session 边界由你定义(单次对话/多步任务/长流程),同一 session ID 下并发授权请求只能有一个,因此 session 范围越窄越好
  • session ≠ ID 本身:AgentCore 将 session ID 与终端用户身份组合产生唯一 session——两个不同身份可以用同一 session ID 但轨迹完全隔离
  • 轨迹 look-back 窗口上限 24 小时,超时事件自动删除
  • 策略变更会使现有 session 全部失效,确保每个 session 都用当前策略集评估
  • deny-by-default,forbid 优先于 permit

常见 Temporal Policy 用例分类学

  • 链式工具输出完整性(output integrity):要求当前工具调用的参数必须与先前工具调用的输出完全一致,防止 agent 在步骤间幻觉或替换值——可抵御 prompt injection 诱导 agent 用伪造 ID 交易(策略验证值与 CRM 系统实际返回值一致)
  • 工具调用顺序(workflow sequencing / SOP):要求某工具必须在另一工具之前调用,验证标准操作流程(如先 get_client_profile 再 load_portfolio 才能 rebalance_portfolio)
  • 特权动作前人工审批(one-time consumption):阻止破坏性/敏感工具调用直到轨迹中记录显式人工审批事件;每个审批只消费一次——单个审批不能当作多个大额交易的 blanket permission
  • 数据新鲜度(data freshness):要求数据查询在给定时间窗口内完成才授权依赖动作(如市场价格必须在交易前 30 秒内获取,防陈旧报价)
  • 累计预算上限(cumulative budget cap):单 session 交易总额不超过 $60,000,遏制失控 agent 或成功攻击的爆炸半径——几十笔单独看起来没问题的小交易累计后达到上限即全部 DENY
  • 互斥规则(mutual exclusion):同一轨迹内禁止"买入后亏损卖出同一证券"等自相矛盾动作

Dogwood:为 agent 与工具设计的新开源治理语言

Temporal policies 使用 Dogwood——一种为 agent 及其工具设计的新开源治理语言,兼容现有 Cedar 策略(无需迁移),并支持 temporal 条件。这是状态化 agent 授权的语言层基础:策略语法中的 when temporal { formerly within 5m (...) } 模式表达"先前事件时间窗"约束。

深度分析

一、分野:从纯函数授权到状态机守卫

stateless 策略是纯函数,输出只取决于当前请求;temporal policy 把它变成序列上的谓词,等于给轨迹装一台状态机,每条策略是某个迁移的守卫。系统不真存"状态",只存事件日志,评估时按窗口与 session 投影——24 小时 look-back 会截断,session 边界会切断,都不是措辞能绕过的。于是策略强度不由规则决定,而由边界定义决定:session 越窄,轨迹越干净,也越容易被"多开 session"稀释(跨 session 的累计上限无法表达,原文列为不可执行的一类);越宽则累计效应完整,查询成本与失效半径同步变大。

二、轨迹授权如何改写威胁模型

stateless 问"这个动作是否被允许",temporal 问"这段叙事是否被允许"。这正是 confused-deputy 的形态:agent 握着过宽能力,被投毒的工具输出或注入指令牵着走,每一步单看都合法。输出完整性规则检查的是对应关系而非合法性,累计上限把粒度从一次调用抬到一段调用。但轨迹由 agent 自己的动作写成,任何"此前发生过 X"都能被能廉价执行 X 的对手制造——一次性消费修补的是复用,不是伪造前置条件;顺序规则抬高成本,不证明意图。

三、为什么是 policy-as-code 而非正则/JSON 规则表

默认拒绝加 forbid 覆盖 permit 是单调组合:判决与书写、加载顺序无关,多团队维护的片段可直接叠加,不会"后写的悄悄覆盖先写的";有序 JSON 规则表恰好相反,遮蔽只在运行时暴露,也无法静态判定冲突。input.account 与 context.input.account 的区分是语法强制,schema 由 MCP manifest 生成,命名漂移在编译期就被挡下。语言刻意小(无星期访问器、无节假日日历)不是缺陷而是可审计性前提:能表达任意计算的引擎,无法回答"这套策略到底允许了什么"。

四、散文 → schema → 形式化:漏斗在哪里漏

四步:拆分复合条款 → 路由 → 自动形式化 → 编译校验。"先路由再翻译"最关键,它把最坏的失败模式——编译通过却执行错误意图——挡在翻译之前;但编译器只证明良构与命名存在,不证明意图。语义正确性只剩人工比对句子与 Dogwood,那五条最佳实践本质是在枚举翻译器必须自行填补的自由度:尝试还是成功、窗口、键字段、阈值开闭、置信度。散文在这些点上天然模糊,翻译器会挑更保守的读法(求和取 ::request,失败尝试也算)——保守是好默认,但写进执行器的猜测与正确策略行为无异,出错也不告警。噪声同理:交织的 rationale 被当规则继承,过宽 forbid 静默遮蔽合法 permit,症状出现在运行时 DENY 而非 authoring 阶段。

五、运行期成本与治理债

授权在每次工具调用的热路径上,预算看 p99;累计规则要在窗口内 sum/count,需按 (action, 键字段) 建索引,否则正确策略本身就是瓶颈。策略蔓延的风险在集合的交互(遮蔽、重复、边界重叠)而非单条。版本则把可用性与安全性绑死:变更使现有 session 全失效,中途收紧切断长任务、中途放宽是静默的安全事件。判决记录必须钉住策略集版本,否则半年后无法重建"当时为什么 DENY"。

实践启示

  1. 先定 session 边界,再写第一条策略。 它同时决定轨迹可见范围、并发约束与累计规则强度;以"一次用户意图的完整任务"为默认粒度,并显式回答"跨 session 绕过是否可接受"。
  2. 从输出完整性与累计上限起步。 这两类价值最高、散文歧义最小;顺序/SOP 次之,新鲜度与人工审批最后加。
  3. 进 authoring 前做四要素规约。 写明尝试还是结果、时间窗口、键字段、阈值开闭,做成模板让合规团队按格子填。
  4. 语义关口不能自动化。 逐条比对句子与生成的 Dogwood,看条件方向(permit 带条件 vs forbid 带 unless)与键字段是否指对;编译通过只证明良构。
  5. 上线前用历史轨迹回放。 看新策略会 DENY 哪些真实调用,这是产前发现"过宽 forbid 遮蔽合法 permit"的唯一手段;上线后按规则对 DENY 率分桶,某条归零通常意味着被遮蔽。
  6. 拒绝硬翻译不可执行的规则。 价值判断、需要修改而非放行/拒绝、超表达力、跨 session 聚集,应显式标注并转交别的控制点,而不是换个说法再试。

与其他实体关系

  • Agent 安全三步法:三步法把 Governance 放在 Identity 之前;temporal policy 正是 Governance 层的有状态实现形态,补充了"如何具体实施 governance"的机制细节
  • Policy + Lambda interceptors:stateless Cedar policy 的先行方案;temporal policy 是其有状态扩展(同一 Policy engine 之上)
  • AI 工具投毒:工具调用层面的攻击面;temporal policy 的 output-integrity 规则正是防御此类攻击的授权层手段
  • AgentCore Harness:temporal policies 运行于 AgentCore Gateway 外围,是 harness 安全边界的组成部分

局限性

实现细节绑定 AgentCore Gateway(session-id header、AgentCore::Action 命名空间、Gateway ARN),但用例分类学、session 边界设计、deny-by-default 原则、审批一次性消费等模式可直接迁移到任何 agent 网关/代理层。

→ 原文存档

第 2 来源 — Policy Authoring:自然语言 → Dogwood 自动形式化

核心论点:Policy Authoring 是一个"翻译器"而非"摘要器"——把组织已有的散文式控制规则(操作手册、政策文档)自动转译为语法+语义正确的 Dogwood 形式化规范,让非技术背景的合规团队也能直接为部署的 Agent 系统落地治理约束。

自动形式化(Autoformalization)机制

  • 输入:一份干净的规则集(政策列表、操作规程的规则章节、一段允许/禁止动作的文字段落)+ 工具 schema + 可用 Guardrails 检查 + 可引用的身份声明。规则与 rationale/背景/评论交织的文档需先精简为规则本身——Authoring 是翻译不是归纳。
  • MCP 工具清单 → 策略 schema:schema 从 agent 的 MCP 工具 manifest 自动生成,生成的策略引用与 agent 实际调用完全一致的命名(如 context.input.amount 对应 amount 参数),避免策略与运行时命名漂移。
  • permit/forbid 约定:Dogwood 默认拒绝(default-deny),forbid 覆盖 permit——授予能力写成带条件的 permit,限制/封顶写成 forbid;条件既可检查当前调用,也可检查会话内已发生事件。

自然语言 → Dogwood 翻译示例

  • 工具参数约束:"退款仅限营业时间 9:00–17:00 UTC 且金额 ≤$2,500" → 单条 policy 带两个 when 条件(context.system.now.toTime() 时间窗 + context.input.amount <= 2500);工具声明单位须与文档数值一致。
  • 前置步骤:"除非同一账户身份在前 15 分钟内已验证,否则不得发起转账" → when temporal { formerly within 15m AgentCore::Action::"verify_identity"::response{ input.account: context.input.account, output.verified: true } }——formerly within 15m 查询 15 分钟内是否发生过描述事件;::response 取结果而非调用本身;input.account(先前事件字段)与 context.input.account(当前调用字段)相等才满足"同一账户"。
  • 新增能力覆盖:temporal/trajectory 约束(限流、前置/顺序工具调用、累计效应)、调用 Bedrock Guardrails 检测自由文本语义不当内容、工具输入参数限制。

互补角度

  • 本文补上 temporal-policies 实体缺的 authoring 工作流:策略如何从散文"进入系统"——MCP manifest → schema、散文→Dogwood 的翻译约定,而非仅讲运行时评估机制
  • 具体化了第 1 来源的 Dogwood 语法:when temporal { formerly within 15m ... ::response{} } 的实际示例形态
  • 补充 default-deny / permit-forbid 覆盖约定作为 authoring 的语义规则
  • 明确"翻译器≠摘要器"、需先精简规则集的最佳实践(噪声输入会污染输出)

→ 第 2 来源原文存档