OpenRouter 发布 Agent SDK,用 callModel 构建多轮智能体工作流
Agent SDK: Building Multi-turn Agent Workflows on OpenRouter
OpenRouter 发布 @openrouter/agent,一个模型无关的 TypeScript SDK,用单个 callModel 函数在 OpenRouter 上 400+ 模型间执行智能体循环。
官方给出 callModel 的循环、停止条件与成本追踪写法,可据此判断多轮智能体工程化的落地方式。
构建一个 agent 需要的是一套分层的行为,远不止聊天补全:它需要调用模型、检查输出中的工具请求、执行这些工具、将结果反馈回去,并重复这一过程直到任务完成。构建这个循环的持久版本意味着要处理输入验证、流式传输、成本追踪,以及知道何时停止。
@openrouter/agent 是一个与模型无关的 TypeScript SDK,它将所有这些打包成一个函数,可以在 OpenRouter 上的 400 多个模型中的任何一个上执行这个 agentic 循环。为了展示这个 agentic 循环有多强大,我们发布了一篇教程,介绍在 Agent SDK 之上构建一个 skill 如何让你构建自己的个人 agent harness。
从聊天补全到 agentic 行为
标准的聊天补全是无状态的:你发送消息,你得到响应。要将其转变为 agent,需要附加若干行为:
工具执行。 模型会生成一个结构化的工具调用。你的代码必须解析它、验证参数、运行函数,并为下一次请求格式化结果。使用 callModel,你可以用 tool() 和 Zod schema 定义工具。工具与模型调用分开运行,边界清晰,逻辑不纠缠。SDK 会在运行时验证来自模型的输入和来自你的函数的输出。如果模型发送了错误的参数,你会得到一个清晰的错误,而不是下游的静默失败。
多轮循环。 一个 agent 很少能一步完成。它可能会搜索、读取结果、再次搜索,然后写一份摘要。这意味着循环:调用模型、执行工具、再次调用模型、重复。callModel 在内部处理这个循环。你通过停止条件来控制它:接收完整步骤历史并决定是否继续的自定义函数。
停止条件。 没有护栏的话,agent 循环可能会永远运行下去(或者至少直到你的账单变得令人不安)。callModel 接受可组合的停止条件:stepCountIs(10) 将循环限制在 10 轮,maxCost(1.00) 设置美元上限,hasToolCall('done') 在调用特定工具时停止。将它们组合起来,或者编写一个自定义函数。
import { stepCountIs, maxCost, hasToolCall } from '@openrouter/agent/stop-conditions';
const result = client.callModel({
model: 'openai/gpt-5',
input: 'Research this topic and compile a report',
tools: [searchTool, writeTool, doneTool],
stopWhen: [
stepCountIs(15),
maxCost(2.00),
hasToolCall('done'),
],
});流式传输。 需要多步执行的 agent 需要展示进度。callModel 为你提供 getTextStream()、getToolCallsStream() 和 getReasoningStream()。并发地流式传输、提取和处理同一个响应,无需事先做出选择。
成本追踪。 每个响应都通过 result.getResponse() 包含 token 计数和成本数据,因此你可以确切知道每次 agent 运行的成本。
工具审批。 对于会执行现实世界操作的 agent,你可以将工具标记为需要审批。当模型调用其中一个时,SDK 会暂停执行,将控制权交还给你的代码,并等待你收集决定后再继续。
callModel 处理了所有这些,因此你可以专注于你的应用程序特有的工具和逻辑。而且由于该 SDK 与模型无关,你可以在 OpenRouter 上的任何模型之间切换,而无需更改你的 agent 代码。
开始使用
npm install @openrouter/agentimport { OpenRouter } from '@openrouter/agent';
import { tool } from '@openrouter/agent/tool';
import { stepCountIs } from '@openrouter/agent/stop-conditions';
import { z } from 'zod';
const client = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const result = client.callModel({
model: 'anthropic/claude-sonnet-4',
input: 'What time is it in Tokyo?',
tools: [
tool({
name: 'get_time',
description: 'Get current time in a timezone',
inputSchema: z.object({ timezone: z.string() }),
execute: async ({ timezone }) => {
try {
return { time: new Date().toLocaleString('en-US', { timeZone: timezone }) };
} catch {
return { error: `Invalid timezone: ${timezone}. Use IANA format like 'Asia/Tokyo'.` };
}
},
}),
],
stopWhen: [stepCountIs(5)],
});
const text = await result.getText();SDK 调用模型,看到它想要使用 get_time,根据你的 Zod schema 验证输入,执行函数,将结果反馈回去,并返回最终文本。你编写的循环逻辑为零。
获取你的 API 密钥,并将你的 agent 指向 callModel 文档。
在 Discord 上告诉我们你正在构建什么。
来源:OpenRouter Blog · openrouter.ai