跳到正文
北京时间
原文
OpenRouter:Announcements(RSS)· Kenny Rogers·· 2026-06-08精选AI 评分63

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

EU AI Act & Colorado ADMT Compliance: Human Oversight for AI Agents

AI 导读

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

推荐理由

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

正文 · AI 翻译

EU AI Act & Colorado ADMT Compliance: Human Oversight for AI Agents

AI 智能体不再只是回答问题。它们正在批准贷款申请、分诊患者接诊表单、执行薪资计算、决定谁被标记进入欺诈审查。当其中某个判断出错时,责任落在部署方身上。

监管机构已经跟上来了。第一个硬性截止日期落在 2026 年 8 月,如果你正在构建的智能体涉及金融服务、医疗健康、招聘,或任何错误输出会对真实的人产生真实后果的领域,合规的时钟已经在走了。

三项法规汇聚于同一项义务:人类必须能够监督、干预并推翻影响他人的 AI 驱动决策。Agent SDK 具备将这些控制措施接入你的智能体所需的原语。

法规生效时间适用对象核心要求
EU AI Act 第 14 条2026 年 8 月(高风险义务)任何为欧盟居民提供高风险 AI 系统的提供方或部署方,无论公司注册地在何处。人工监督,并具备干预和推翻的能力。监督行为的审计追踪。
科罗拉多州 ADMT 法律(SB26-189)2027 年 1 月任何在科罗拉多州开展业务的开发者或部署者,包括对科罗拉多州居民做出重大决策的科罗拉多州以外公司。受涵盖的开发者/部署者必须提供文档、披露、消费者权利流程,以及在受涵盖的 ADMT 对重大决策产生实质性影响时提供有意义的人工审查/复议。
NIST AI RMF(GOVERN 1)自愿性,被美国监管机构引用任何开发或部署 AI 系统的组织(自愿性,但美国联邦机构日益期望如此)。与风险相称的人工监督。监督控制的文档记录。

共同的主线是:如果你的智能体做出或影响对人们产生实质性影响的决策(信贷、就业、医疗、安全),你需要在模型的建议与动作的执行之间设置一道可审查的关卡。

以下是 5 种使用 @openrouter/agent 满足这些要求的模式,建立在 HITL 工具 cookbook(涵盖 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. 按风险层级对你的工具进行分类

法规要求对后果重大的操作进行人工审核。首先把你的工具划分为不同层级:

层级示例操作控制措施
高风险金融交易、PII 处理、访问决策、医疗建议带强制暂停的 HITL 工具(return 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();
}

EU AI Act 第 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 钩子触发,为审计记录打上时间戳,模型随即收到经过验证的决策。

今天就开始构建

欧盟《人工智能法案》高风险义务将于 2026 年 8 月落地。科罗拉多州的 ADMT 法律将于 2027 年 1 月 1 日生效。NIST AI RMF 是自愿性的,但正被美国联邦机构越来越多地作为基线预期引用。一套实现方案(风险分类、审计日志、超时升级、持久化状态)即可满足全部三套框架。

Agent SDK 负责处理暂停执行、跨重启持久化状态、依据 schema 校验人工响应,以及干净地恢复执行。你的工作是将它接入你的审核工作流和审计存储。

关于相关的治理控制措施(预算上限、数据保留策略、模型限制),请参阅 Guardrails。

完整 SDK 参考文档与可运行示例:HITL 工具文档。

常见问题

欧盟《人工智能法案》第 14 条要求什么?

第 14 条强制要求高风险 AI 系统包含人工监督措施。人类必须能够理解系统的能力、监控其运行、解读输出,并介入或推翻决策。审计日志保留要求属于第 12 条(记录保存)和第 9 条(风险管理)。

欧盟《人工智能法案》何时生效?

《人工智能法案》于 2024 年 8 月生效,但高风险义务(包括第 14 条的人工监督)自 2026 年 8 月起适用。这是被归类为高风险的系统的截止期限,须证明其具备合规的监督控制措施。

科罗拉多州的 ADMT 法律何时生效?

科罗拉多州的自动化决策技术法律(SB26-189)总体于 2027 年 1 月 1 日生效,适用于该日期及之后做出的重大决策。科罗拉多州总检察长的规则制定页面跟踪了实施细节。

科罗拉多州的 ADMT 法律是否适用于科罗拉多州以外的公司?

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

什么是 AI 智能体的人类在环(HITL)?

HITL 指的是在 AI 智能体执行其提议的操作之前,由人类进行审查并批准(或拒绝)。在 Agent SDK 中,这是通过 onToolCalled(暂停执行并等待人类输入)和 requireApproval(根据参数有条件地对工具执行进行门控)来实现的。

来源:OpenRouter:Announcements(RSS) · openrouter.ai