OpenRouter Agent SDK 新增 human-in-the-loop 工具类型
Human-in-the-Loop Tools for the Agent SDK
OpenRouter 的 Agent SDK 新增第四种工具类型 human-in-the-loop(HITL),通过 onToolCalled 钩子按输入决定自动执行还是暂停等待人工。
原文给出 HITL 工具的定义方式与暂停恢复流程,读者可据此判断如何在智能体循环中插入人工审核。
Agent SDK 支持第四种工具类型:human-in-the-loop (HITL) 工具。它们让您的 agent 自动处理常规调用,并在风险较高时暂停等待人工介入,这一切都由单个 hook 控制。
安装 SDK,定义您的 HITL 工具,并按照 cookbook recipe 实现一个可运行的方案。
npm install @openrouter/agent按调用自动解决或升级
常规工具总是执行。手动工具总是暂停。HITL 工具两者兼具:您的 onToolCalled hook 检查输入并做出决定。
import { tool } from '@openrouter/agent/tool';
import { z } from 'zod';
const approvePayment = tool({
name: 'approve_payment',
description: 'Approve a payment, escalating large amounts to a human',
inputSchema: z.object({
amount: z.number(),
recipient: z.string(),
}),
outputSchema: z.object({
approved: z.boolean(),
reviewedAt: z.number().optional(),
}),
onToolCalled: async (input) => {
if (input.amount < 100) {
return { approved: true };
}
// Pause for human review
return null;
},
});返回一个值,agent 继续运行(就像常规工具一样)。返回 null,循环暂停并返回 status: 'awaiting_hitl',将待处理的调用暴露给您的应用程序。您可以通过再次调用 callModel 并传入一个包含人工决定的 function_call_output 项来恢复。
这种模式适用于任何决策依赖数据的地方:金额阈值、风险评分、内容策略标记、合规检查。分支逻辑集中在一个函数中,而不是分散在您的应用程序代码里。
在模型看到人工响应之前对其进行后处理
一个可选的第二个 hook,onResponseReceived,会在人工为暂停的调用提供结果时触发。它在将原始输入传递给模型之前对其进行转换。
onResponseReceived: async (raw) => {
return { ...(raw as Record<string, unknown>), reviewedAt: Date.now() };
},用它来标记元数据、规范化格式、根据业务规则进行验证,或用人工无需手动提供的上下文来丰富响应。如果它抛出异常,错误会以 { error: ..., originalOutput: ... } 的形式暴露给模型,因此不会有任何东西被静默吞掉。
暂停和恢复循环的工作原理
以下是完整的生命周期:
- 模型在 agent 循环期间调用您的 HITL 工具。
onToolCalled运行。如果它返回一个值,agent 继续运行。如果它返回null,循环暂停。- 您的应用程序通过
getToolCalls()读取待处理的调用,并将其呈现给用户。 - 用户做出决定。
- 您再次调用
callModel,并将决定作为function_call_output项传入。 onResponseReceived(如果已定义)转换响应。- 模型接收结果,agent 循环恢复。
const result = openrouter.callModel({
model: 'openai/gpt-4o',
input: 'Pay $500 to Acme Corp for the May invoice',
tools: [approvePayment] as const,
state,
});
const response = await result.getResponse();
if (response.state?.status === 'awaiting_hitl') {
const pending = response.state.pendingToolCalls ?? [];
// Present pending[0] to your user, collect their decision, then resume:
const resumed = openrouter.callModel({
model: 'openai/gpt-4o',
input: [{
type: 'function_call_output' as const,
callId: pending[0].id,
output: JSON.stringify({ approved: true }),
}],
tools: [approvePayment] as const,
state,
});
}SDK 处理所有状态跟踪、hook 分发和 schema 验证。您无需编写任何循环代码。
何时使用 HITL 与 requireApproval
两者都会暂停以等待人工输入。区别在于决策逻辑。
HITL (onToolCalled) | requireApproval | |
|---|---|---|
| 何时暂停 | 仅当您的 hook 返回 null 时 | 始终,在任何执行之前 |
| 决策类型 | 数据驱动(阈值、评分、策略) | 二元是/否同意 |
| 自动解决 | 返回一个值以跳过人工审核 | 不可用 |
| 后处理 | onResponseReceived 转换响应 | 不可用 |
当每次调用都需要明确的人工同意而无论输入如何时(例如:“删除此数据库”、“发送此电子邮件”),请使用 requireApproval。当某些调用可以自动进行而其他调用需要人工介入时(例如:“如果金额低于 $100,则批准此付款”),请使用 HITL。
开始构建
HITL 工具 cookbook recipe 将引导您完成一个完整的实现:定义工具、检测暂停、收集人工输入并恢复循环。
有关完整的类型签名和 API 接口,请参阅 工具文档 和 API 参考。
获取您的 API 密钥,并在 Discord 上告诉我们您正在构建什么。
来源:OpenRouter Blog · openrouter.ai