Amazon Bedrock AgentCore 新增 Policy Authoring 功能,可将自然语言政策文档自动转换为 Dogwood 强制约束,支持时间条件等细粒度控制。
AI 智能体可以自动化复杂的工作流,但如果没有适当的控制措施,其行为可能无法与组织的策略或监管约束保持一致。为解决这一问题,我们在 Amazon Bedrock AgentCore 中构建了 Policy,使团队能够实施跨 Amazon Bedrock AgentCore 中运行的智能体统一应用的控制措施。近日,我们进一步扩展了这些能力,新增了强制约束智能体跨时间维度的行为限制功能,支持诸如速率限制、前置条件与工具调用的顺序编排、以及累积效应等策略。这些策略以 Dogwood——一种开源治理语言——表达,并由内置于 AgentCore Gateway 中的 Dogwood 监控器在运行时实时应用于智能体行为。
作为本次发布的一部分,我们扩展了 Policy Authoring 的能力——这是一款由 AI 驱动的工具,可将自然语言策略规范文档转换为语法和语义正确的 Dogwood 形式化规格。通过这一新功能,您可以生成强制执行时间与轨迹约束的策略,调用 Amazon Bedrock Guardrails 服务来检测自由文本语义中的不当内容,还可以生成对工具输入参数施加限制的策略——后者在上一版 AgentCore Policy 中已可用。无论您的技术背景如何,都可以直接将自然语言编写的策略文档导入 Amazon Bedrock AgentCore 中的策略,以保护已部署的智能体系统。
在本文中,我们通过示例演示这一新功能,并提供有关在构建自然语言策略时如何遵循最佳实践的指导。
Dogwood 策略完全可以手写,对于少量控制规则而言,从手写开始也是完全合理的选择。当您已有用自然语言编写的规则,且面前的工作是转录而非设计时,Policy Authoring 的效果最佳。您可以提供一份包含清晰规则集的文档:策略列表、运维程序中的规则部分,或者是描述允许或限制操作的书面段落。Authoring 是一个翻译器而非摘要器,因此,如果一份文档将其规则与理由、背景和说明交织在一起,最好先将其精简为纯粹的规则。
为了使示例具体可感,我们以零售银行的客服智能体为例。它负责验证来电者身份、提交争议、处理争议扣款的退款、在客户自有账户间转移资金,并可以请求主管批准一笔扣款。其工具通过 AgentCore Gateway 访问,每个工具接收少量参数并返回结果:
除了策略文档之外,Authoring 还需要接收一个模式(schema),其中精确携带上述信息:工具名称、接受的参数及其返回值。该模式从智能体的 Model Context Protocol(MCP)工具清单中生成,因此输出的策略所引用的名称与智能体实际调用的名称一致。例如,生成策略中的 context.input.amount 就是上表中 issue_refund 的 amount 参数。Authoring 还会获得可用的 Amazon Bedrock Guardrails 检查项列表,以及策略允许引用的身份声明集合。
银行的合规团队以其对人类员工相同的形式维护着一份书面控制文档。以下规则摘自该文档,每条规则后都附有 Policy Authoring 为其生成的 Dogwood 策略。两个约定使输出更易于阅读。Dogwood 默认拒绝,且 forbid 优先于 permit,因此授予能力的规则变为带有条件的 permit,而限制或封顶的规则变为 forbid。条件可以检查正在决策的调用,也可以检查同一会话中已发生的行为。以下示例同时涉及两者。
以下示例展示了自动形式化工具如何将自然语言策略翻译为 Dogwood 公式。
只有在工作时间(定义为 UTC 时间上午 9:00 至下午 5:00)才能处理退款,且金额不得超过 $2,500。
permit ( principal, action == AgentCore::Action::"issue_refund", resource )
when { context.system.now.toTime() >= duration("9h")
&& context.system.now.toTime() <= duration("17h") }
when { context.input.amount <= 2500 };
一句话包含两个独立要求,变成一条带有两个条件片的策略,两个条件都必须满足才能允许退款。context.input.amount 是智能体发出的 issue_refund 调用中的 amount 参数,按照该工具声明的单位进行比较。文档中的 "$2,500" 与工具中的 amount 需要在该单位上达成一致。时间比较在调用决策时刻读取时钟,且两个条件都不依赖于智能体之前所做的操作。有关 duration 等基于时间的函数的更多详情,请参阅基于时间的策略支持。
除非来电者的身份在同一账户上于过去 15 分钟内已通过验证,否则不得发起转账。
permit ( principal, action == AgentCore::Action::"initiate_transfer", resource )
when temporal {
formerly within 15m AgentCore::Action::"verify_identity"::response{
input.account: context.input.account,
output.verified: true
}
};
这条规则无法仅凭转账请求本身来确定,因此生成的条件会查看智能体已经执行的操作。formerly within 15m 查询其所描述的事件是否在过去十五分钟内的任意时刻发生过。此处指一个 verify_identity 调用的完成(::response,即结果,而非调用本身),且返回时 verified: true。在事件模式中,裸写的 input.account 命名的是较早事件的字段,而 context.input.account 命名的是正在决策的调用上的字段。将两者设为相等正是使"同一账户"精确化的方式。对其他账户的验证,或尝试后返回未验证状态的验证,都不满足此规则。并且由于检查的历史是当前会话的,因此该规则不需要单独的来电者 ID,这就是 verify_identity 只需要账户的原因。
如果过去 12 小时内转账总额将超过 $50,000,则阻止转账。
forbid ( principal, action == AgentCore::Action::"initiate_transfer", resource )
when temporal {
exists (total: Long). (
(sum a for (a: Long), (t: Timepoint). where (
formerly within 12h (
AgentCore::Action::"initiate_transfer"::request{ input.amount: a } && tp(t)
)
)) == total && total > 50000
)
};
此处检查的不是历史记录而是求和。策略取过去 12 小时内每次转账的 amount 参数,求和后如果运行总额超过 $50,000 则拒绝当前调用。该时间窗口内的每笔单独转账可能很小且不起眼,但该条件约束的是它们的总和。还要注意文档未作说明的部分:它说"transferred"但未说明被阻止或失败的尝试是否计算在内。翻译汇总的是 ::request 事件,即智能体尝试的每次转账,这是对上限而言更安全的解读。但在文档中明确说明可以消除这种猜测,以下第一个最佳实践正是讨论这一点。
同一账户在一小时内尝试退款不得超过三次。
forbid ( principal, action == AgentCore::Action::"issue_refund", resource )
when temporal {
exists (n: Long). (
(count for (t: Timepoint). where (
formerly within 1h (
AgentCore::Action::"issue_refund"::request{ input.account: context.input.account } && tp(t)
)
)) == n && n > 3
)
};
此策略与上一条具有相同的结构,但统计的是事件数量而非对某个字段求和。统计范围限定为与正在考虑的调用中指定的相同账户的退款,并包含该调用本身,因此一小时内第四次尝试将被拒绝。该规则明确说了"尝试",因此与上一条不同,无需任何推断:被拒绝或失败的退款仍计入限制。
拒绝描述中包含社会安全号码的任何争议提交。
forbid ( principal, action == AgentCore::Action::"file_dispute", resource )
when {
BedrockGuardrails::SensitiveInformation(["US_SOCIAL_SECURITY_NUMBER"], [context.input.description])
.maxConfidenceScore().greaterThanOrEqual(decimal("0.2"))
};
有些规则关乎自由格式文本的含义而非结构化值,仅对某个字段进行比较无法判定。对于这些规则,生成的策略会在规则所命名字段上内联调用 Amazon Bedrock Guardrails 检查,并将报告的置信度与阈值进行比较。该规则未指定阈值,因此翻译使用该检查的默认值。当文档确实指定了一个阈值时(例如"高置信度"或具体数值),则使用该值。
超过 500 美元的退款需要主管对该笔费用进行审批,且该审批记录应在最近 30 分钟内。
forbid ( principal, action == AgentCore::Action::"issue_refund", resource )
when { context.input.amount > 500 }
unless temporal {
formerly within 30m AgentCore::Action::"request_approval"::response{
input.charge_id: context.input.charge_id,
output.approved: true
}
};
这个句子包含两个以截然不同方式检查的部分:一个是对当前调用的某个参数进行阈值判断,另一个是对已经发生的事件进行条件判断。两个子句位于同一策略中。该规则收窄了一项已有权限:它拒绝超过 500 美元的退款,而 unless 子句是例外——当有匹配的审批记录时则解除拒绝。与前面前置条件的例子一样,通过 charge_id 进行关联是为了防止用一个费用的审批记录来授权另一费用的退款。
清晰且无歧义的策略会带来更可预测的行为和更少的错误,无论实施者是人类用户还是自主智能体。此外,这也会提升前面介绍的从自然语言到 Dogwood 创作方案的性能。接下来,我们将回顾一些从自然语言策略构建的技巧和最佳实践。
明确你说的是尝试还是结果。"After a transfer"是有歧义的。"After a transfer succeeds"则没有。尝试指的是智能体发出的任何调用,包括被拒绝或失败的调用。只有完成的调用才会携带工具返回的值。速率限制和累积上限通常针对的是尝试,而前置条件和排序规则则针对结果。
明确时间窗口。"Recently"无法翻译。"Within the past 30 minutes"可以。窗口是从正在被裁决的调用向前回溯的,因此如果一个规则应该在日历边界重置而不是随时间滑动,需要明确说明,因为这需要不同的控制机制。
说明规则所依赖的键。"No more than three transfers per hour"没有说明是谁的限额:是这个调用者的三次,还是针对这个账户的三次?两者都可以表达,是不同的策略,而这句话两者都没选。无论规则在计数、求和还是关联,都需要指明将事件联系在一起的字段。
给出阈值及其边界。"More than three"和"at least three"相差一个操作,通常是规则旨在阻止的那个操作。内容检查的置信度阈值同样适用。
审查生成的 Dogwood 策略的正确性。每条 Dogwood 策略都会与它所来源的句子一起返回,这样你就可以将两者对照阅读。验证可以确认策略是格式正确的并锚定在正确的模式上,但不能确认策略表达的是作者的本意。这个判断仍然由文档所有者来做出。
虽然创作服务可以过滤并高亮与 AgentCore 中 Policy 执行不兼容的策略,你还应该了解一些常见问题。
这不是关于操作的规则。"Agents should always act in the customer's best financial interest and exercise sound professional judgment."这里没有任何关于操作、字段或主体的条件。这确实是一个需求,但它属于智能体的指令、评估和训练范畴,而不是授权引擎。
它要求的是操作,而非裁决。"When a dispute description contains a Social Security number, redact it before the note is stored."策略引擎允许或拒绝一个调用,它不会修改调用。拒绝包含社会安全号码的 filing 的相邻规则是可以表达的,并在前面的例子中出现过。编辑是另一种控制,在流水线的不同阶段应用。
它超出了语言所表达的范围。"Deny wire transfers on weekends and U.S. federal bank holidays."Dogwood 中的日期和时间支持涵盖时间点、偏移量和差值。没有星期几的访问器,也没有节假日日历。Dogwood 语言指南详细说明了哪些构造是可用的,当一条规则被策略创作服务搁置时,值得阅读该指南,既为了确认这个差距,也为了看看是否有类似的表述方式可以得到支持。
它超出了执行的范围。"A customer might initiate at most ten transfers per day, counted across all of that customer's concurrent sessions."执行评估的是单个会话内的轨迹,因此跨会话合并的限额无法通过不同的措辞来恢复。
在每种情况下,有用的输出不是策略,而是一个标签,表明它无法被翻译成 Dogwood,这告诉你应该考虑替代方案:重写它、将其移到不同的控制点,或者接受它保持为人工流程。
自动形式化管道分四个步骤运行。它首先对文档进行分解。为读者编写的规则往往是复合的:编号条款通常包含多个独立义务,而单个句子有时也包含两个,如前面的营业时间例子所示。分解将它们拆分成原子规则,每个规则都是关于可独立强制执行的特定工具或工具集的陈述。然后每条规则被路由。规则要么可以用 Dogwood 及其组成监控器来表达,要么不能,不能的会被搁置而不是翻译,通常是因为上一节提到的四个原因。在翻译尝试前进行过滤,可以防止不可表达的规则变成一条验证通过但执行了错误内容的策略。剩余的规则被自动形式化为 Dogwood,锚定在随文档提供的工具模式上。最后,每个候选策略都使用开源语言附带的相同 Dogwood 命令行工具进行验证。这是管道中不需要判断的部分:编译器是关于策略是否可解析以及其中每个名称是否存在于模式中的精确且确定的权威。当候选被拒绝时,其诊断信息会被反馈回去,规则会在已知这些错误的情况下重新翻译,会有有限的轮次限制。
最终输出的是两个集合:通过语法和环境模式兼容性验证的策略及其生成的原子自然语言规则,以及被搁置的原子自然语言规则。
这篇文章演示了 Policy Authoring 如何将书面策略文档转换为 Dogwood 策略。你已经看到了涵盖工具参数约束、前置条件、累积上限、速率限制和自由形式内容检查的翻译示例。此外,你还回顾了使自然语言规则易于翻译的特性:明确的时间窗口、命名的主体、显式的阈值,以及在尝试和结果之间的明确选择。Dogwood 可以直接编写,喜欢使用该语言的团队可以继续这样做。Authoring 功能适用于规则已经以散文形式存在的常见场景,以缩短从你已经维护的文档到你可以审查和部署的策略集的路径。
要开始使用,请参阅 AgentCore 中 Policy 文档了解如何创建策略引擎和从文档创作策略,以及 Dogwood 语言指南(如果你想阅读或扩展生成的策略)。要了解更多关于这些策略在运行时如何被解释和执行的信息,请参阅《用 Amazon Bedrock AgentCore 中的时间策略保护 AI 智能体安全》和《介绍 Dogwood:面向 AI 智能体的运行时验证》。
我们还要感谢团队中其他做出贡献的应用科学家 Chao Shang、Sadat Shahriar、Wanyu Du 和 Devang Kulshreshtha。