# OpenRouter Agent SDK 推出 HITL 工具：满足 EU AI Act、Colorado ADMT 与 NIST AI RMF 合规要求

- 来源：OpenRouter：Announcements（RSS）
- 发布时间：2026-06-08 20:00
- AIHOT 分数：63
- AIHOT 标记：精选
- AIHOT 链接：https://aihot.virxact.com/items/cmq9zl2ha0gp6slldhoei8cbp
- 原文链接：https://openrouter.ai/blog/tutorials/human-oversight-eu-ai-act-compliance-agent-sdk

## 精选理由

8 月就是欧盟 AI 法案高风险的生效日，这个教程把三个监管框架的 HITL 要求变成可直接复用的代码，做金融医疗代理的开发者该收藏。

## AI 摘要

OpenRouter 的 Agent SDK 新增人类参与循环（HITL）工具，用于 AI 智能体的合规监督。该工具可帮助 AI 智能体满足欧盟 AI 法案、科罗拉多州自动化决策技术法（SB26-189）以及 NIST AI 风险框架（NIST AI RMF）的监管要求。

## 正文

欧盟 AI 法案与科罗拉多州 ADMT 合规：AI 智能体的人类监督

Kenny Rogers · 2026 年 8 月 6 日

On this page

把这个交给你的智能体

1. 根据风险等级对你的工具进行分类

2. 为每一次监督事件添加审计日志

3. 实现基于超时的升级处理

4. 为你的 StateAccessor 提供持久化存储支持

5. 将所有组件串联起来

从今天开始构建

常见问题

AI 智能体不再仅仅是回答问题。它们正在审批贷款申请、分诊患者入院表格、运行薪资计算、决定谁应被标记为欺诈审查对象。当其中某个决策出错时，责任将落在部署方身上。

监管机构已经跟进。第一个硬性截止日期落在 2026 年 8 月，如果你正在构建涉及金融服务、医疗、招聘或任何错误输出会对真实个体造成实际后果的领域的智能体，合规倒计时已经开始。

三项法规都指向同一项义务：人类必须能够监督、干预并推翻影响人类的 AI 驱动决策。Agent SDK 已经提供了将这些控制机制嵌入你智能体的基本构建单元。

法规生效时间适用对象核心要求

欧盟 AI 法案，第 14 条2026 年 8 月（高风险义务）任何为欧盟居民提供或部署高风险 AI 系统的提供商或部署方，无论公司总部位于何处。人类监督，具备干预和推翻能力。监督行动的审计追踪。

科罗拉多州 ADMT 法律（SB26-189）2027 年 1 月任何在科罗拉多州开展业务的开发者或部署方，包括在科罗拉多州之外但就对科罗拉多州居民做出重大决策的公司。被覆盖的开发者/部署方必须提供文档、披露信息、消费者权利流程，以及在受覆盖的 ADMT 对重大决策产生实质性影响时提供有意义的人类审查/复议。

NIST AI RMF（GOVERN 1）自愿性，被美国监管机构引用任何开发或部署 AI 系统的组织（自愿性，但美国联邦机构的期待度日益提高）。与风险相称的人类监督。监督控制措施的文档记录。

共同点：如果你的智能体做出或影响对人们有实质性影响的决策（信贷、就业、医疗、安全），你需要在模型的推荐与行动的执行之间设置一个可审查的门控。

以下是利用 @openrouter/agent 满足这些需求的5种模式，这些模式建立在 HITL 工具指南（涵盖 SDK 机制）之上。这里我们介绍的是你可以在其上附加的合规模式。

注意：本文提供的是工程模式，而非法律建议。请咨询法律顾问，以确定哪些法规适用于你的具体用例和司法管辖区。

将此内容交给你的智能体

希望你的编码智能体实现这一功能？复制以下提示词：

I need to add regulatory-compliant human-in-the-loop controls to my AI agent using the OpenRouter Agent SDK.

Inspect my codebase to identify which tools and actions are high-risk (financial, PII, legal, or safety-critical), then infer the appropriate risk tiers and implement a compliance layer using the Agent SDK HITL tools.

The compliance layer should:

1. Mark high-risk tools with requireApproval or onToolCalled gates based on my risk classification.
2. Log every oversight event (tool invocation, human decision, timestamp, reviewer ID) to my audit backend.
3. Add timeout-based escalation: if no human responds within the deadline, escalate to a supervisor or reject the action.
4. Stamp each human decision with reviewer identity and timestamp via onResponseReceived.
5. Persist conversation state with a StateAccessor backed by my chosen storage so audit records survive restarts.

Consult these pages for current SDK shapes and patterns:
- HITL tools reference: https://openrouter.ai/docs/sdks/typescript/call-model/tools#human-in-the-loop-hitl-tools
- Tool Approval & State: https://openrouter.ai/docs/sdks/typescript/call-model/approval-and-state
- callModel API reference: https://openrouter.ai/docs/sdks/typescript/call-model/api-reference

Do not hard-code secrets. Use environment variables for API keys and database credentials.

1. 按风险层级对工具进行分类

法规要求对有重大影响的行动进行人工审核。首先将你的工具划分为不同层级：

层级示例行动控制方式

高风险金融交易、个人身份信息处理、访问决策、医疗建议带强制暂停的 HITL 工具（返回 null）

中等风险批量邮件、内容审核、数据导出带条件谓词的 requireApproval

低风险搜索、只读查询、格式化无需门控

import { OpenRouter, tool } from '@openrouter/agent';
import { z } from 'zod';

// High-risk: always pauses for human review
const processCreditDecision = tool({
name: 'process_credit_decision',
description: 'Issue or deny a credit application',
inputSchema: z.object({
applicationId: z.string(),
recommendedAction: z.enum(['approve', 'deny', 'refer']),
riskScore: z.number(),
applicantName: z.string(),
}),
outputSchema: z.object({
decision: z.enum(['approved', 'denied', 'referred']),
reviewerId: z.string(),
reviewedAt: z.number(),
justification: z.string(),
}),
onToolCalled: async () => {
// Always escalate to human. No auto-resolve path for high-risk.
return null;
},
});

对于中等风险工具，使用基于上下文进行门控的条件谓词：

const sendBulkEmail = tool({
name: 'send_bulk_email',
description: 'Send email to a recipient list',
inputSchema: z.object({
recipients: z.array(z.string().email()),
subject: z.string(),
body: z.string(),
}),
outputSchema: z.object({ sent: z.boolean(), count: z.number() }),
requireApproval: (params) => {
// Gate kicks in above 50 recipients
return params.recipients.length > 50;
},
execute: async (params) => {
await sendEmails(params);
return { sent: true, count: params.recipients.length };
},
});

2. 为每个监督事件添加审计日志

法规要求你证明人工监督确实发生了。这意味着要记录谁审核了什么、何时审核以及做出了什么决定。将其接入 onResponseReceived：

import { tool } from '@openrouter/agent';
import { z } from 'zod';

const auditSchema = z.object({
decision: z.enum(['approved', 'denied', 'referred']),
reviewerId: z.string(),
justification: z.string(),
});

const processCreditDecision = tool({
name: 'process_credit_decision',
description: 'Issue or deny a credit application',
inputSchema: z.object({
applicationId: z.string(),
recommendedAction: z.enum(['approve', 'deny', 'refer']),
riskScore: z.number(),
applicantName: z.string(),
}),
outputSchema: z.object({
decision: z.enum(['approved', 'denied', 'referred']),
reviewerId: z.string(),
reviewedAt: z.number(),
justification: z.string(),
}),
onToolCalled: async (input) => {
// Log the escalation event itself
await writeAuditLog({
event: 'escalated_to_human',
toolName: 'process_credit_decision',
input,
timestamp: Date.now(),
});
return null;
},
onResponseReceived: async (raw) => {
const parsed = auditSchema.parse(raw);
const reviewedAt = Date.now();

// Write the immutable audit record
await writeAuditLog({
event: 'human_decision_recorded',
toolName: 'process_credit_decision',
reviewerId: parsed.reviewerId,
decision: parsed.decision,
justification: parsed.justification,
reviewedAt,
});

return { ...parsed, reviewedAt };
},
});

writeAuditLog 函数应写入仅追加存储。一个最小化的接口：

interface AuditEntry {
event: string;
toolName: string;
timestamp?: number;
reviewerId?: string;
decision?: string;
justification?: string;
input?: unknown;
reviewedAt?: number;
escalatedTo?: string;
}

async function writeAuditLog(entry: AuditEntry): Promise<void> {
// Write to your audit backend: Postgres, S3, Datadog, Splunk, etc.
// The record must be append-only and tamper-evident for compliance.
await db.insertInto('audit_log').values({
...entry,
timestamp: entry.timestamp ?? Date.now(),
id: crypto.randomUUID(),
}).execute();
}

欧盟 AI 法案第12条（记录保存）要求高风险系统在其运行生命周期内保留日志。将审计日志存储在耐用、仅追加的存储中，并设置符合你监管要求的保留策略。

3. 实现基于超时的升级机制

没有人响应的人工审核门控比根本没有门控更糟糕。法规期望系统能够处理不响应的审核者。实现一个超时机制，要么升级给主管，要么默认拒绝该行动。

此模式在 callModel 循环之外运行，由轮询陈旧待审核项的服务来执行。

interface PendingReview {
conversationId: string;
callId: string;
toolName: string;
createdAt: number;
assignedTo: string;
}

const REVIEW_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes

async function escalateStaleReviews(
pendingReviews: PendingReview[],
): Promise<void> {
const now = Date.now();

for (const review of pendingReviews) {
const elapsed = now - review.createdAt;
if (elapsed < REVIEW_TIMEOUT_MS) continue;

await writeAuditLog({
event: 'review_timeout_escalated',
toolName: review.toolName,
reviewerId: review.assignedTo,
timestamp: now,
});

// Option A: Escalate to supervisor
await assignToSupervisor(review);

// Option B: Default-deny and resume the agent with a rejection
// await resumeWithDenial(review);
}
}

选择哪个选项取决于您的风险偏好。对于需要符合 EU AI Act 的高风险系统，默认拒绝（选项 B）更安全：未经明确人工批准，操作绝不执行。对于延迟会产生运营成本的低风险系统，升级到主管（选项 A）可在保持监督链的同时推进流程。

4. 使用持久化存储来支撑你的 StateAccessor

内存中的状态会在进程重启时消失。为了合规，你的 StateAccessor 必须使用持久化存储，以确保待审核项、对话历史和审计上下文在崩溃、部署和水平扩展后仍然存在。

import type { ConversationState, StateAccessor, Tool } from '@openrouter/agent';

function createDurableStateAccessor<TTools extends readonly Tool[]>(
conversationId: string,
): StateAccessor<TTools> {
return {
load: async () => {
const row = await db
.selectFrom('conversation_state')
.where('id', '=', conversationId)
.selectAll()
.executeTakeFirst();

if (!row) return null;
return JSON.parse(row.state) as ConversationState<TTools>;
},
: async (state) => {
await db
.insertInto('conversation_state')
.values({
id: conversationId,
state: JSON.stringify(state),
updated_at: new Date(),
})
.onConflict((oc) =>
oc.column('id').doUpdateSet({
state: JSON.stringify(state),
updated_at: new Date(),
}),
)
.execute();
},
};
}

每次状态转换为 'awaiting_hitl' 或 'awaiting_approval' 时，待审查项都会被持久化。你的升级服务（第3步）将查询此表，找到过期的审查项。

5. 将所有部分连接起来

以下是完整流程：分类、门控、记录、超时、恢复。这里假设你已经拥有第1-2步中的 processCreditDecision 和 sendBulkEmail，第2步中的 writeAuditLog，以及第4步中的 createDurableStateAccessor。

import { OpenRouter } from '@openrouter/agent';

// processCreditDecision, sendBulkEmail defined in steps 1-2
// createDurableStateAccessor defined in step 4

const openrouter = new OpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});

const tools = [processCreditDecision, sendBulkEmail] as const;
const conversationId = `conv-${crypto.randomUUID()}`;
const state = createDurableStateAccessor<typeof tools>(conversationId);

// Initial request
const result = openrouter.callModel({
model: 'openai/gpt-4o',
input: 'Review application APP-2024-001 and issue a credit decision',
tools,
state,
});

// Wait for the call to complete (or pause for human review)
const snapshot = await result.getState();

if (snapshot?.status === 'awaiting_hitl' || snapshot?.status === 'awaiting_approval') {
const pending = snapshot.pendingToolCalls ?? [];

// Surface to your review UI, queue, or notification system.
// 'awaiting_hitl' fires for onToolCalled tools (processCreditDecision).
// 'awaiting_approval' fires for requireApproval tools (sendBulkEmail).
// Both resume via function_call_output here; see approval-and-state docs
// for the approveToolCalls/rejectToolCalls alternative for requireApproval tools.
for (const call of pending) {
await createPendingReview({
conversationId,
callId: call.id,
toolName: call.name,
createdAt: Date.now(),
assignedTo: getReviewerForTool(call.name),
arguments: call.arguments,
});
}
}

当审核人做出响应时（通过你的管理界面、Slack 操作、队列消费者等）：

// Retrieve the pending call from your review queue (by conversationId, callId, etc.)
const pendingCall = await getPendingReview(conversationId);

// Human supplies their decision
const humanDecision = {
decision: 'approved' as const,
reviewerId: 'reviewer-jane-smith',
justification: 'Risk score within policy limits, verified income docs',
};

const resumed = openrouter.callModel({
model: 'openai/gpt-4o',
input: [
{
type: 'function_call_output',
callId: pendingCall.callId,
output: JSON.stringify(humanDecision),
},
],
tools,
state,
});

const text = await resumed.getText();

onResponseReceived 钩子触发，标记审计记录，然后模型接收经过验证的决策。

立即开始构建

EU AI Act 高风险义务将于2026年8月生效。科罗拉多州的 ADMT 法律将于2027年1月1日生效。NIST AI RMF 是自愿性的，但越来越多的美国联邦机构将其作为基准期望来引用。一种实现方案（风险分类、审计日志记录、超时升级、持久化状态）即可满足所有三个框架的要求。

Agent SDK 负责暂停执行、在重启之间持久化状态、根据模式验证人类响应，以及干净地恢复执行。你的任务是将它接入你的审核工作流和审计存储中。

有关相关的治理控制（预算上限、数据保留策略、模型限制），请参阅 Guardrails。

完整的 SDK 参考和工作示例：请参阅 HITL 工具文档。

FAQ

EU AI Act 第14条要求什么？

第14条要求高风险AI系统必须包含人工监督措施。人类必须能够理解系统的能力、监控其运行、解读输出结果，并能够干预或否决决策。审计日志留存要求分别属于第12条（记录保存）和第9条（风险管理）。

欧盟《AI法案》何时生效？

《AI法案》于2024年8月生效，但高风险义务（包括第14条的人工监督）从2026年8月起适用。这是被归类为高风险的系统必须展示合规监督控制的截止日期。

科罗拉多州的《ADMT法案》何时生效？

科罗拉多州的《自动化决策技术法案》（SB26-189）总体上于2027年1月1日生效，并适用于该日期当天或之后做出的重大决策。科罗拉多州总检察长的规则制定页面会跟踪实施细节。

科罗拉多州的《ADMT法案》是否适用于科罗拉多州以外的公司？

是的。该法案适用于任何“在科罗拉多州开展业务”的开发者或部署者，而不仅仅是总部设在科罗拉多州的公司。如果你部署的ADMT对科罗拉多州居民的重大决策（就业、金融、住房、保险、医疗、教育、基本政府服务）产生实质性影响，那么你很可能受到该法案的约束。这遵循了与《科罗拉多州隐私法案》相同的管辖权模式，后者涵盖在科罗拉多州开展业务或向科罗拉多州居民提供商业产品或服务的实体。执法通过《科罗拉多州消费者保护法案》进行（违规行为被视为欺骗性贸易行为）。

对于AI智能体而言，什么是“人在环中”（HITL）？

HITL指的是在AI智能体执行某项行动之前，由人类审核并批准（或拒绝）其提出的行动。在Agent SDK中，这是通过onToolCalled（暂停执行并等待人工输入）和requireApproval（根据参数有条件地控制工具执行）来实现的。
