这里的每一项事实都经过实际运行验证(Amazon Nova Pro us-east-1 按需,Strands Agents,以及 traccia 0.1.29,每 1K 输入 $0.0008、每 1K 输出 $0.0032;EU AI Act 附件 III 的信用评分义务自 2027 年 12 月 2 日起适用)。演示系统全程为合成数据。

可观测性告诉我,智能体批准了一笔本应拒绝的贷款。它向我展示了那次把申请人邮箱泄露到日志里的运行。然后它什么也没做,因为观察是它唯一会做的事。

本系列第 1 部分在一个多智能体 AWS 团队下面放了一个真正的可观测性层,并抓到了一次看起来健康、却在悄悄超支的运行。本部分讲的是可观测性无法做到的两件事:阻止那次糟糕的运行,并在事后把文书交给监管机构。所以我在 Amazon Bedrock 上构建了一个合成的多智能体贷款决策团队,把它接入 Traccia,并在真实基础设施上让四件事发生:在任何模型调用之前硬阻断一次提示注入、在每个子智能体的 trace 中脱敏申请人 PII、在每个 span 上盖上 EU AI Act 证据戳,以及平台本身以一项真实、有引用的决策拒绝一个失控的智能体。

然后它没有奏效。我写的策略中有两条没有拒绝任何东西,而且不是因为我把它们配置错了:三种策略类型中有两种在这个团队里结构上就没有可匹配的信号。弄清楚原因正是本文最有用的部分,因为这是没人写下来的部分。

我如何测试这一点:构建过程、平台拒绝阻断的那个下午、我修复的两个真实 bug,以及接近结尾处的批评,全都出自我手。屏幕上的一切都是真实的(真实的 Nova Pro 调用、真实的治理决策、真实导出的证据),团队是刻意合成的,它产生的是证据,而非合规——这一区分贯穿全文。$0 的 SDK 层不需要账户。在第 1 部分之后,高级平台层级上的 14 天免费试用(@govern执行与 Governance Hub)正是推动我深入挖掘、并为社区提炼出有意义内容的原因,所以这里的一切都可以零成本复现。

这篇文章面向的是已经在 AWS 上运行智能体的人(Strands、CrewAI、LangGraph,或者你自己在 Bedrock 上的循环),他们已经听够了「EU AI Act」这个词,紧张到不行,想要运行时护栏加上审计证据,又不想围绕某个合规框架重写整个应用。凡是治理相关的术语第一次出现,我都会给出定义。

如果你只有两分钟,直接跳到平台带来的回报,以及它一开始为什么没跑通。铺垫部分很重要,但那一节才是重点。

目录


为什么智能体治理是一个不同的问题

可观测性回答的是「智能体做了什么,花了多少钱」。治理回答的是一对更难的问题:「我能不能阻止它做错事,我能不能证明发生了什么。」这两者不是同一层,单靠一条 trace 只能给你前者。

对于一个确定性服务,治理主要就是访问控制和输入校验。两者都很显眼,而且都在任何工作开始之前就在边缘执行了。AI 智能体打破了这一点。它自己决定控制流,所以一次阻断必须打断一个已经在运行的推理循环。它按你没有硬编码的顺序调用工具,所以失控是一种真实的故障模式,而不是假设。

而当它是一个多智能体团队时,故障面会以三种方式成倍放大。一次阻断必须停下整个团队,而不是一个子智能体。脱敏必须覆盖树中的每一个span,而不只是入口点。而真正烧掉预算的那个智能体,可能距离你包裹的那个已经隔了三层委派。

现在这上面有监管要求,而不仅仅是最佳实践。EU AI Act 将信用评分列为高风险用途(附件 III 第 5(b) 点),并附加了具体义务:记录保存(第 12 条)、对部署者的透明度(第 13 条)、人工监督(第 14 条)、上市后事件报告(第 72 和 73 条),以及对某些部署者而言的基本权利影响评估(第 27 条)。第 50 条的透明度要求,即告知某人其正在与 AI 打交道,已经可强制执行。所以这里的“治理”是具体的:是一份具体清单,列明某个具体监管机构会要求你出示的东西。

先快速锚定一个词汇,因为后文都依赖它。一个护栏会检查输入、输出或工具调用,并决定其是否被允许。一项策略是平台在运行时执行的规则(支出上限、工具调用上限、允许的模型列表)。强制执行是当策略匹配时发生的事情:该调用被拒绝。证据是这一切的持久记录。整篇文章讲的就是把正确的护栏和策略放到正确的智能体上,然后再把证据读回来。


这个团队,以及它为何是合成的

一位主管信贷员委派给三位专家,使用 AWS Strands 的 agents-as-tools 模式,每位专家都调用 Amazon Nova Pro(amazon.nova-pro-v1:0)。

  • 受理将申请人的自由文本解析为一个 id 和一个请求金额。PII 首先落在这里,这就是为什么脱敏要在这里测试(尽管它覆盖每一个片段)。
  • 信用与风险(credit-risk)调用一个模拟 credit_score工具和一个受区域限制的pull_bureau_report。这就是发起工具调用的智能体。记住它,因为这就是平台阻断那一节的全部情节。
  • 策略应用一条确定性的、可解释的贷款规则(收入与债务之比、请求金额与收入之比,绝不使用受保护属性),并返回批准、转交或拒绝。

还有两个护栏与注入阻断一起位于边界处:一个输出验证检查,会拒绝任何做出绝对批准声明的建议,以及一个公平性检查如果受保护属性驱动了评分,就拒绝该决策。公平性在这里有真正的分量,因为正是它让信用评分在 EU AI Act 下成为高风险。因此,团队会对评分信号进行断言,一旦出现受保护属性就阻断。

多智能体也有其存在的价值。它恰恰以最要紧的方式让治理变得更难,而单智能体演示会掩盖全部三个问题:阻断必须能停下整个团队,脱敏必须覆盖整棵树,而且一个团队确实可能失控,所以循环上限是可信的,而非刻意设计的。

现在,必须坦率说明的诚实之处:信用评分是模拟的。没有真实的征信机构,没有真实的模型决策,没有真实的申请人。评分是一个确定性启发式规则,只使用合法的金融信号,并且从构造上就绝不触碰受保护属性(有一个单元测试正是断言这一点)。一个真实的高风险信用系统需要法律合规评估;这个项目产出的是证据基底这样的系统会生成的东西,而不是合规本身。我在屏幕上把所有内容都标注为“synthetic”,原因相同:一个假装自己是真实贷款机构的治理演示,恰恰是不值得信任的反面。


两层,且只有一层需要密钥

Traccia 的治理分为两层,而把这种划分做对,是本文的大部分内容。

层 需要密钥? 它做什么
SDK / 进程内 否($0,离线) 护栏检测、显式硬阻断、PII 脱敏、EU AI Act 标记、透明度证据、完整性哈希。全部作为 OpenTelemetry span processor 在导出前运行。
平台 是(TRACCIA_API_KEY) @govern网络化执行(Spend Cap、Model Boundary、Loop Cap),外加 Governance Hub:系统注册表、人工审核、事件、证据包、FRIA。

@observe让你在任何 OTLP 后端上获得可观测性,无需密钥。@govern增加运行时策略执行,并且需要平台。承重点,直白地说,因为它很容易被模糊:本地硬阻断和 PII 脱敏无论有没有密钥都在进程内运行。密钥并不驱动阻断。密钥增加的是网络化执行和审计中心。所以诚实的表述是“SDK 在本地进行治理;平台负责执行和记录”,而不是“你必须付费才能拦截任何东西”。

关于 SDK 这一层,还有一点需要诚实说明,因为我读了源码来确认:Traccia 的护栏检测,它并不执行。三层引擎将发现结果写入 span。下面 Beat 1 中的“拦截”是我自己的代码在护栏结果上抛出异常,而不是护栏引擎阻止了任何东西。把这一区别弄清楚,就是准确描述这个工具和过度吹嘘它之间的差别。


前置条件

三样东西,只有第三样是为了平台层面的收益。

  1. Python 3.10+以及这些 SDK(strands-agents,strands-agents-tools,traccia,boto3)。仓库在requirements.txt中固定了经过测试的版本(traccia 0.1.29、strands-agents 1.56.0、boto3 1.43.99)。
  2. AWS 凭证并带有bedrock:InvokeModel在 Nova Pro 上。仓库在iam/bedrock-invoke-policy.json提供了一个最小权限策略,仅允许对amazon.nova-pro-v1:0执行 InvokeModel。你还需要在 Bedrock 控制台的模型访问下启用一次 Nova Pro(控制台授权不是 IAM 权限,所以两者都需要)。“$0 Traccia”仍然意味着真实的 Bedrock 调用,因此要运行这个 crew 就必须具备这些。
  3. 一个 Traccia 平台密钥(TRACCIA_API_KEY)仅用于@govern执行和治理中心。其他所有内容都不需要它即可运行。

让它跑起来就是克隆、设置、开跑:

git clone https://github.com/simplynadaf/ai-agent-governance-aws.git
cdai-agent-governance-aws
ls -a                # 这里没有 .env - 只有随附的 .env,其中密钥被注释掉了
cat .env             # 证明 $0 的各个 beat 不需要密钥
make setup           # venv + 固定依赖 + git 钩子
make test            # 10/10 单元测试:纯逻辑,无 AWS,无密钥

全新克隆后运行 $0 的各个 beat 时无需密钥。被跟踪的.env随附的密钥行是注释掉的,所以cat .env在镜头前展示就是证明“$0,无密钥”是真实的,而不是一个脚注。你的真实密钥放在本地同一个文件中;一个 pre-commit 钩子会阻止任何包含未注释密钥的提交。


三个 $0 治理 beat

这些只需安装和 AWS 凭证即可运行,将 trace 写入本地traces_gov.jsonl文件。

Beat 1:硬拦截提示注入

一个用@observe(as_type="guardrail")装饰的检测器返回 bool,SDK 会据此自动设置guardrail.triggered。你自己的代码在此基础上抛出异常。crew 在 supervisor 调用模型之前就停止了。

@observe(as_type="guardrail", attributes={"guardrail.category": "prompt_injection",
                                           "guardrail.enforcement_mode": "block"})
def injection_check(text: str) -> bool:
    return any(kw in text。lower() for kw in INJECTION_KEYWORDS)

# 在 crew 入口点:if injection_check(text):
    raise BlockedByGuardrail("检测到提示注入。Crew 在任何模型调用之前就被阻断。")

证据不是日志行,而是 trace:被阻断的运行没有任何子智能体 span。Intake、Credit & Risk 和 Policy 从未运行。我通过统计导出文件中的 span 数量验证了这一点:被阻断的 trace 只包含注入检查和 crew 根节点。一个真正阻止多智能体 crew 的阻断不会留下任何下游内容,而 trace 正是你确认这一点的地方,而不是去相信一条 print 语句。

有一个命名细节值得坦诚说明:SDK 的真实信号是guardrail.triggered(由 guardrail 的 bool 返回值自动设置)。crew-stopped 标志demo.crew.blocked是我自己的属性,不是 SDK 的。我把两者区分开来,这样就不会有人以为 SDK 在做它实际没做的事。

Beat 2:在每个子智能体中脱敏 PII

init(redact_pii=True)添加了一个 regex 处理器,将 email、phone 和 SSN 掩码为[REDACTED_EMAIL],[REDACTED_PHONE],[REDACTED_SSN]在每个树的 span 上,在导出之前。我用唯一算数的方式验证了它:在所有 span 属性中搜索字面测试 email 和 SSN。零匹配,覆盖整个多智能体树,而不仅仅是 intake 入口点。

坦诚的局限,大声说出来:这是尽力而为的 regex,不是 ML NER。它能捕获像 email 和 SSN 这样的带标签模式;它会漏掉姓名、地址和未标记的 id,而且可能过度脱敏。在真实系统中,你要直白说明这一点,并在上面叠加一个真正的 PII 分类器。

Beat 3:盖上 EU AI Act 证据

init(compliance={"frameworks": ["eu_ai_act"], "risk_tier": "high"})会eu_ai_act.risk_tier=high自动放到每个 span 上。信用评分是教科书式的 Annex III 第 5(b) 条案例,所以我手动盖上eu_ai_act.annex_iii_category="5b_creditworthiness"。这个区分是刻意的,并对照 SDK 源码验证过:SDK 会自动写入risk_tier,但 Annex III key 是一个保留常量,永远不会被自动填充,所以如果你想要它,就得自己设置。disclosure()记录 Article 50 透明度,并且每个 span 都带有一个自动的governance.integrity_hash。

一份通俗语言的报告直接从 trace 文件读取,因此合规审查者无需打开原始 span JSON:

AGENTS THAT RAN: loan-prescreen, intake, credit-risk, policy
GUARDRAIL TIERS:  A explicit YES · B provider-native "not observed" · C heuristic YES
EU AI ACT:        risk_tier N/N spans · annex_iii YES · Art.50 YES · integrity_hash YES
PII LEAK CHECK:   raw test PII found in 0 places  (must be 0)

这是大多数教程跳过的诚实说明,而我的verify_trace.py现在会打印它。Traccia 的 guardrail 引擎有三个检测层级:A(显式,你的@observeguardrails),B(provider 原生,当模型自身返回安全或停止信号时触发),以及C(启发式规则,当工具 span 因拒绝关键词报错时触发)。我展示了 A 和 C 触发(注入块是 A;对欧盟申请人报错的地域限制 bureau 拉取是 C)。Tier B 在干净运行时不会触发,这是预期内的,不是缺口。所以诚实的说法是“A 和 C 已演示;B 在模型自身的安全信号上触发”,而不是“三者全部触发”。


平台带来的收益,以及为什么它一开始没有生效

这是我失去的那个下午,以及从中得出的教训。

我在 crew 入口点上设置了@govern(fail_open=False),把密钥放进.env,然后运行它。结果:ALLOWED。没有拦截。

在任何策略能被评估之前,还有一个配置陷阱需要先清除。@govern需要一个 tracingendpoint,而不只是一个密钥。没有设置TRACCIA_ENDPOINT时,SDK 会记录“Traccia endpoint not found”,静默跳过强制执行,并返回 ALLOWED。我设置了TRACCIA_ENDPOINT=https://api.traccia.ai/v2/traces,警告就消失了。现在强制执行才真正运行起来,所以真正的诊断可以开始了。它仍然返回 ALLOWED。

然后我创建了一个Model Boundary策略,只允许gpt-4o(该 crew 使用 Nova Pro),将其作用域限定到 crew 智能体loan-prescreen,设为 Block,并激活它。再次运行。仍然是 ALLOWED。那是第一个本应拦截却没有拦截的策略。

仪表盘里的 Decision Log 帮我破解了这个问题。它按 trace 对每次调用的策略检查进行分组,每一行都说了同样两件事:No Match,并且该检查被归因到智能体credit-risk,而不是loan-prescreen。

Traccia Decision Log showing per-call policy checks grouped by trace: a Denied row for the Loop Cap on the credit-risk agent with the reason 'tool calls 2 exceed 1', above it earlier No Match rows for the same agent, each linking to the trace
Decision Log 就是帮我破解这个问题的那个界面。每一行都是绑定到某个 trace 的每次调用检查。No Match 行告诉了我为什么我最初的策略失败;Denied 行(Loop Cap、credit-risk、“tool calls 2 exceed 1”)是最终生效的拦截。每个检查都被归因到credit-risk,而不是@govern入口点。

由此得出两条教训,而它们正是文档和参考论文里没有的内容。

教训 1:把策略的作用域限定到实际发起调用的那个智能体。我的 crew 把每个子智能体都包在一个 Strandsrun_identity里,所以每次调用的策略检查是在子智能体的身份(credit-risk)下运行的,而不是@govern入口点的(loan-prescreen)。作用域限定到入口点的策略永远不会匹配,因为没有任何调用会被归因到它。要限定到子智能体,或者组织范围。

教训 2:让策略类型与 span 实际携带的内容相匹配。我重新限定了Spend Cap的作用域,预算为 $0,以credit-risk. 仍然不匹配。每条 trace 中的两个 span 检查就是那两tool调用(credit_score和pull_bureau_report),而它们的成本几乎为零,所以消费规则没有什么可触发的。Model Boundary 需要一个自动打补丁的 LLM 客户端来检查正在使用的模型,而 StrandsBedrockModel并不在 Traccia 自动打补丁的客户端之列。所以两种策略类型都无法匹配这个 crew,原因各不相同。

一个Loop Cap会统计每次运行的工具调用次数。这个 crew 恰好调用两次。所以我把 Max Tool Calls Per Run 设为 1、Block,作用域为credit-risk,激活它,然后运行:

PLATFORM BLOCK - AgentBlockedError:
   reasons: ['toolcalls2exceed1']
   decision_id: b5a3a3e4-6b62-4c81-9c07-358773735d44   (每次运行都不同)
   remaining_budget_usd: None

Traccia Policies view showing one Active policy: the Loop Cap named 'Loan Crew Loop Cap deny credit-risk', scoped to the credit-risk agent, enforcement Block
生效的 Loop Cap:Max Tool Calls Per Run = 1,作用域为credit-risk,执行动作为 Block。这是三种策略类型中唯一一个其信号真正存在于这个 crew 的 span 中的。

那是一次真实的、经过网络的拒绝,带有原因和 decision id(该 id 每次运行都是新的)。我在 SDK 源码中验证过的一个微妙但重要的细节:那些被填充的字段(reasons、一个真实的decision_id)来自逐调用拒绝路径。来自滞后状态检查的 block 会抛出一个裸 AgentBlockedError,reasons 为空且没有 id。所以,一个显示出真实原因字符串和 decision id 的 block,证明是逐调用策略引擎拒绝了它,而不是认证失败或状态熔断器触发了。remaining_budget_usd是None因为这是循环路径,而不是消费路径(只有 Spend Cap 拒绝才会填充该字段)。

这并不是“Loop Cap 好、另外两个坏”的情况。运行时执行取决于模型调用在哪里对治理平面可见以及哪个智能体身份承载了这次调用。对于一个工具密集、LLM 成本近乎为零的 Strands crew,Loop Cap 是那种其信号真正存在于 span 中的策略类型。Decision Log 的“N span checks, No Match versus Denied”会同时告诉你这两个事实,这就是为什么它是我全程一直开着的那个界面。

我在此过程中修复了两个真实的 bug,都已提交:crew 入口点把整个 prompt 句子当作applicant_id转发(一个KeyError),而平台初始化在传 key 时没有带 endpoint。两者都不算离奇;两者都是那种只有真正对着平台跑一遍才会发现的问题。


监管者所要的证据

一旦存在真实的阻断,Governance Hub 就会把它变成文书工作。基于这一条被阻断的 trace,我完成了注册、审查、记录和导出。

Traccia Compliance Hub dashboard showing Readiness 85, AI Systems 1, Pending Reviews 1, Open Incidents 1, with the Add AI System form below
运行后的 Compliance Hub:就绪度 85,一个已注册的 AI System,一个待处理审查,一个未关闭事件。这些都是真实的、非零的,而且每一个都能追溯到那一次被阻断的运行。

从这一条被阻断的 trace 出发,我构建了监管机构所期望的文书链条。我把该 crew 注册为高风险 AI System(Article 12 记录保存),风险等级为 High,关联三个智能体,并填写了 Annex III 5(b) 预期用途,这使注册表从 0 个系统变为 1 个。我就这条被阻断的 trace 请求了人工审查(Article 14 人工监督),Reviews 标签页变为 Pending 1。我记录了一个事件(Articles 72 和 73),内容为“Loop Cap block: credit-risk exceeded tool-call cap (2 > 1)”,携带决策 id 和 trace,Incidents 标签页变为 Open 1。最后我导出了一个审计包(Article 12 / Annex VIII),这是最终的成果物:一个经哈希密封的 JSON,约 10 KB,把所有内容串联在一起。

Traccia Audit Bundle export screen: a Standard Audit Bundle for the Loan Decision Crew SYNTHETIC (High, 3 agents), with a Download Audit Bundle button and a note that it snapshots registered systems, policy violations, human reviews, incidents, and audit events
Audit Bundle 是一个经哈希密封的 JSON,它快照了已注册系统、策略决策、人工审查、事件以及管理员审计轨迹。已验证内容:带有三个关联智能体的高风险系统,review_requests_count 1其中包含被阻断的 trace id,incidents_count 1,audit_events_count 110,以及一个顶层integrity_hash。

在 Settings 中打开 EU AI Act 模块后,解锁了欧盟特有的成果物:一份FRIA 草稿(Article 27),加上使用说明(Article 13)、一份Annex IV技术文档大纲,以及一份EU 注册预填(Annex VIII)。每一项都是与已注册系统绑定的真实导出。

Traccia FRIA wizard: a Fundamental Rights Impact Assessment for the selected AI system 'Loan Decision Crew (SYNTHETIC) (high)', with fields for provider, deploying authority, role, and legal basis
FRIA 向导(Article 27),与已注册的高风险系统绑定。它导出一份草稿 JSON,包含真实的 ai_system_id 和完成百分比,这是高风险系统部署者预期需要产出的另一项成果物。

再次说明诚实的局限,因为一个过度宣称的治理工具比没有工具更糟:

  • @govern默认为fail_open=True。如果平台不可达,执行会继续。我为高风险 crew 设置了fail_open=False,但这只会强化运行前的状态检查。每次调用的策略检查始终是 fail-open,且没有覆盖选项,因此运行中途的网络抖动会让那次单独的调用通过。镜头前的拦截是真实的逐次调用拒绝,但它并不能保证平台永远不会漏掉某次调用。
  • integrity_hash是一个普通的无密钥 SHA-256。它是防篡改证据,不是签名。任何能重写该 bundle 的人都可以重新计算哈希。
  • EU 注册导出是预填的,而且它自己也这么说:annex_iii_category返回 null,因为注册表字段不会从 SDK span 标记自动填充,而且该导出带有一项免责声明:Traccia 不是官方的 EU 注册表。
  • 证据基座不等于法律合规。律师或公告机构仍然决定是否符合。这生成记录;它并不为记录背书。

实时执行 vs 定时检测

仪表盘上有一件事让我困惑,值得花 30 秒说清楚,因为它看起来像 bug,但其实不是。Policies 页面显示 "Open Violations 0",尽管我确实有真实的拦截。原因是 Traccia 有两个策略族,它们出现在不同的地方:

  • 预防性(逐次调用)策略(Loop Cap、Spend Cap、Model Boundary)在实时生效,在每次调用之前,并立即出现在Decision Log中,显示为 "Denied"(外加AgentBlockedError)。我的拦截就是其中之一。
  • 检测性(监控)策略(Output Token Limit、Cost Spike Alert)在之后评估运行结果,按计划执行(最短周期为每小时),并填充Open Violations卡片。

因此,Denied 行旁边的 "Open Violations 0" 是正确的:该拦截是实时预防性拒绝,而检测性违规只会在下一个计划周期开启。我添加了一条检测性 Output Token Limit 策略来演示第二条路径,在每小时评估之后,Open Violations 变为 1。给任何构建此类系统的人的经验:不要在镜头前(或演示中)等待每小时的那次 tick,并且要讲清这个区别。实时拦截看 Decision Log;定时检测看 violations 卡片。

为了完整起见,关于实时数字,在运行该 crew 几十次之后,注册的智能体显示如下。

Traccia agent detail for the Loan Decision Crew (SYNTHETIC): Executions 37, Error rate 43 percent, Median duration 1.97s, per-run cost near zero, 7-day total cost about $0.002, a No Spend Cap notice, and a Guardrail Posture panel
该 crew 的每智能体成本和态势:37 次执行、43% 的错误率,以及约 $0.002 的 7 天成本。错误率高是故意的,因为每次演示运行都包含一次蓄意的注入尝试,而且每次@governdeny 按设计会抛出错误。这里的高错误率是护栏在触发,而不是缺陷。

这 37 次执行和近乎为零的成本是真实的,没有被限流或削减:每次运行都是一小段 Nova Pro 调用序列,我没有为了显得更好看而伪造其中任何一个数字。43% 的错误率也应同样看待,那是护栏和 deny 在履行职责,而不是可靠性问题。


为什么现在做这件事正当时

第 50 条的透明度义务已于 2026 年 8 月 2 日生效。附件 III 中针对信用评分的高风险义务自 2027 年 12 月 2 日起适用。这是一个准备窗口,而不是免死金牌,在截止日期前构建证据层,远比事后补建要便宜得多。(发布当天请核实这些日期;监管时间线会变动,而那种会改变它们的综合调整,正是需要反复核对的东西。)


对 Traccia 治理的坦诚评价

我针对它部署了一个真实的 crew,并阅读了 SDK 源码以理解其行为,所以以下评估基于这些,包括那些物有所值的部分,以及那些让我花掉一下午的部分。

先说物有所值的部分。两层拆分在 $0 的成本下做了实实在在的工作:无需密钥即可在进程内获得真正的治理(拦截、脱敏、盖章),而密钥则增加了网络化执行以及审计中心。免费层不是演示性质的噱头;它在不关联任何账户的情况下完成真正的工作。Decision Log 是产品中最好的诊断工具。“N span checks, No Match versus Denied, attributed to agent X”既告诉了我策略为何失败,也告诉了我如何修复,没有它,上面两条教训会让我多花一个下午。证据中心也清晰地映射到真实的 EU AI Act 条款:registry、review、incident、evidence pack、FRIA 和 EU exports 分别对应第 12、13、14、27、72/73 条以及附件 IV 和 VIII,这对一个需要展示某些东西的团队来说价值很大。而且它在导出内容中也没有过度吹嘘自己;那些免责声明(“not the official registry”、无密钥哈希)已内置于产品输出中,而不只是我在本文里添加的东西。

现在说说它让我费劲的地方,以及它应该做得更好的地方:

  • 端点要求是静默的。 @govern在没有端点的情况下跳过强制执行(撰写本文时)。只设置密钥,你会得到 ALLOWED,以及一行大多数人都会忽略的日志。一个硬错误,或者一个更响亮的警告,本可以避免这种困惑。
  • 每次调用都始终 fail-open 的检查值得更醒目地标注出来。 fail_open=False读起来像是“这会始终阻止”,但它只是强化了状态检查;每次调用的引擎仍然 fail-open。这是一种站得住脚的设计(网络抖动不应该让生产调用硬失败),但这恰恰是高风险部署者需要在一开始就被告知的细微之处。
  • 每次调用的身份归属对于多智能体团队来说是一个真正的坑。该检查在子智能体的run_identity下运行,而不是@govern入口点,这是正确的行为,但针对这种情况没有文档记录,而这恰恰是多智能体构建最先出错的地方。
  • 文档才是真正的缺口,与第 1 部分相同。我通过运行平台并阅读源码,而不是从文档中,学到了身份优先级、端点要求、每次调用始终 fail-open 的规则,以及策略匹配逻辑。能力是有的;针对多智能体 Strands 构建的指导还没有被写下来,而这正是本文要填补的缺口。

净结论:治理是真实存在的,证据结构也确实有用。缺口在于文档和几个开发者体验上的小痛点,我不会把它们全都当作产品阶段性的成长阵痛而一笔带过。对于一个全部价值就在于可信审计证据的工具来说,发布未记录的每次调用始终 fail-open 行为绝非表面问题;高风险部署者需要它被明确揭示出来,而不是自己去发现。能力是有的,而且能工作。指导文档和几个默认值还没有跟上。


诚实的注意事项

  • 贷款团队是合成的。信用模型是模拟的,申请人是虚构的,没有任何输出是真实决策。这产生的是证据,不是合规。
  • 本地拦截和 PII 脱敏在进程内运行无论有没有密钥。密钥增加的是网络化强制执行和 hub,而不是本地护栏。
  • Traccia 护栏检测;它不强制执行。Beat 1 的拦截是我自己的控制流在发现问题时抛出的。
  • PII 脱敏是尽力而为的正则,而非 ML NER。它会漏掉姓名和地址,并且可能过度脱敏。
  • integrity_hash是一个无密钥的 SHA-256:防篡改证据,而非签名。
  • @govern默认值fail_open=True;每次调用的检查是始终失败开放(fail-open),即使你设置了fail_open=False。
  • 我展示了护栏层级A 和 C;Tier B 是提供商原生的,在干净运行时不会触发。不要声称三者都会触发。
  • 每一美元和 token 计数都是真实的,但它们会随运行而变化。把其中的关系(一个 crew 发起两次工具调用;Loop Cap 为 1 会阻止它)当作经验教训,而不是精确的小数。
  • 起作用的那个块是一个Loop Cap,其作用域限定为credit-risk,而不是 Model Boundary 或 Spend Cap,原因见收益部分。你的策略选择取决于你的 span 携带什么。

要点不是“买一个治理工具”。而是:观察一次失败和阻止一次失败是不同的层次;在多智能体 crew 中,强制执行必须针对真正发起调用的那个智能体;而审计证据是你有意生成的,要在监管者开口之前。


常见问题

什么是 AI 智能体治理,它与可观测性有何不同?
可观测性记录智能体做了什么以及花了多少成本。治理决定智能体是否被允许这样做(护栏和运行时策略),并生成持久的审计记录。可观测性观察;治理阻止并证明。

我能在没有付费平台的情况下阻止失控的智能体吗?
你可以在本地用一个进程内护栏来阻止,它会抛出异常(这里的注入拦截以 $0 运行,无需密钥)。需要平台的是网络化强制执行:Loop Cap、Spend Cap 或 Model Boundary,由平台在每次调用时评估,并以一个你可以引用的 decision id 拒绝。

为什么我的@govern策略没有阻止任何东西?
三个常见原因,我都遇到了。你没有设置TRACCIA_ENDPOINT,所以 SDK 静默跳过了强制执行。你把策略的作用域限定到了@govern入口智能体,但在 Strands crew 中,每次调用的检查被归因到子智能体的run_identity。或者你选择了一种其信号不在你的 span 中的策略类型(在一个约 $0 的 crew 上设 Spend Cap,或在一个非自动补丁的客户端上设 Model Boundary)。打开 Decision Log;“No Match 与 Denied”会告诉你原因。

这如何对应 EU AI Act?
信用评分属于 Annex III 第 5(b) 条,高风险。该演示生成了记录保存(Art. 12)、对部署者的透明度(Art. 13)和对用户的透明度(Art. 50)、人工监督(Art. 14)、事件日志记录(Arts. 72/73)、一份 FRIA 草案(Art. 27),以及 Annex IV / VIII 导出。它是证据基础,而非合规签核。

Traccia 是开源的吗?
该 SDK(traccia-py)采用 Apache-2.0 许可,并且是 OpenTelemetry 原生的,因此这些 span 是标准 OTel,本地治理无需账户即可运行。@govern执行和 Governance Hub 是托管、商业化的部分。

这能开箱即用地配合 Strands 使用吗?
$0 SDK 治理(阻断、脱敏、盖章)适用于任何你可以装饰的代码。该平台@govern同样适用,但按调用进行的策略匹配存在上述多智能体身份方面的细微差别:将作用域限定到发起调用的子智能体,并为工具密集型的团队选择一个 Loop Cap。


试一试

更想先看它实际运行?完整演示在 YouTube 上:观看演示。

完整代码(该团队、三个 $0 环节、平台@govern脚本、10 个单元测试,以及一个 Makefile)在 GitHub 上:ai-agent-governance-aws。克隆它,运行make demo以 $0 查看本地的阻断、脱敏和 EU AI Act 盖章,然后将 Traccia 密钥放入.env,添加端点,并运行make platform以获得真正的AgentBlockedError。

如果你在生产环境中运行智能体:你在请求路径中有一个真正的阻断,还是一个在钱(或错误决策)已经没了之后才触发的警报?这就是整篇文章所讨论的区别。


关注我,了解更多关于 AWS 架构、DevOps 和 AI 基础设施的内容:
作品集|LinkedIn|Dev.to|YouTube|Email|AWS Builder Center|X