适合谁
| 场景 | 是否适合 | 原因 |
|---|---|---|
| Node.js 后端里加一个任务助手 | 适合 | SDK 原生支持 JS/TS,容易接 Express、Hono、Next.js API Route |
| 给已有 SaaS 加客服、报告、检索 Agent | 适合 | 工具函数可以直接调用现有业务 API |
| 要让 Agent 改代码、跑测试 | 谨慎 | 可以看 SandboxAgent,但要先做目录隔离和权限控制 |
| 只想日常写代码提效 | 不适合 | 直接用 Claude Code、Cursor、Copilot Agent 更快 |
| 需要极强流程确定性 | 不适合单独使用 | 应结合普通代码状态机,Agent 只负责不确定步骤 |
推荐路线:先做一个单 Agent + 一个工具的闭环,不要一上来做多 Agent。等你能稳定观测输入、工具调用、最终输出后,再考虑 handoffs、sessions 和 tracing。
环境要求
官方 README 标注支持 Node.js 22 或更高版本,也支持 Deno、Bun;Cloudflare Workers 属于实验支持,需要启用 nodejs_compat。本篇示例用 Node.js 22。
mkdir openai-agents-js-demo
cd openai-agents-js-demo
npm init -y
npm install @openai/agents zod
把项目切到 ESM:
npm pkg set type=module
配置 API Key:
export OPENAI_API_KEY="sk-..."
不要把 Key 写进代码或提交到仓库。生产环境应通过平台密钥管理注入环境变量。
版本更新注意
当前最新版为 v0.11.4(2026-05-12)。如果从 v0.10.x 或更早版本升级,注意以下变更:
v0.11.0(2026-05-08)— 包含破坏性变更
Sandbox 本地源物化边界收紧。 LocalFile.src 和 LocalDir.src 现在必须落在物化的 baseDir 内,除非你在 Manifest 里显式声明 extraPathGrants。如果你的沙箱代码从 baseDir 外部复制文件,升级后这些路径会被拦截。修复方式:
const manifest = new Manifest({
// ...
extraPathGrants: ['/data/external-assets', '/tmp/shared-cache'],
});
这是一个安全边界修复——防止沙箱内运行的代码静默访问未授权路径。不要绕过它,而是把实际需要的外部路径显式声明出来。
RealtimeAgent 默认模型切换为 gpt-realtime-2。 如果你的代码没有显式指定模型,升级后 RealtimeAgent 会使用新模型。测试一下语音质量、延迟和 token 消耗是否仍然符合预期。
v0.11.1(2026-05-09)
- 沙箱环境变量解析器在 Manifest 合并时不再丢失(之前合并多个 Manifest 可能覆盖 env 配置)
- Blaxel 沙箱提供方行为对齐修复
v0.11.2(2026-05-11)— 大批量 Bug 修复
这版集中修复了生产环境稳定性问题,以下是影响较大的几项:
| 模块 | 修复内容 |
|---|---|
| Sandbox | 可配置的归档解压上限;结构化错误详情;Cloudflare 执行和清理错误可见 |
| Tracing | Span ID 防护;批量处理不再因导出器异常中断 |
| Realtime | 输出音频内容保留;空音频通道不再崩溃 |
| Sessions | Prisma 和 FileSession 记录损坏时的防护处理 |
| AI SDK | 并行工具调用时推理内容去重 |
| 其他 | GitRepo 子路径别名保留和验证;回调式 handoff hooks 允许;推理项清理 |
v0.11.3 – v0.11.4(2026-05-11 ~ 05-12)
- Tracing 关闭改为 best-effort,超时时主动中止导出,不再阻塞进程退出
- 空 chat completions 工具输出不再发送
- 未知 Realtime 工具不触发自动响应
- Local approval 拒绝原因保留
- Reasoning 身份在 OpenAI Conversations 持久化时保留
升级建议: 如果你用了 SandboxAgent 或 RealtimeAgent,务必升到 v0.11.4。Tracing 和 Session 的修复对生产稳定性直接有效。
第一个 Agent
创建 index.mjs:
import { Agent, run } from '@openai/agents';
const agent = new Agent({
name: 'ReleaseAssistant',
instructions: 'You explain technical release notes as concrete engineering actions.',
});
const result = await run(
agent,
'Summarize how a backend team should evaluate a new SDK release.'
);
console.log(result.finalOutput);
运行:
node index.mjs
这个例子只有一个 Agent,没有工具。它适合验证三件事:包能正常加载、认证能通过、你能拿到 finalOutput。如果这一步不稳定,不要继续加工具或多 Agent。
加一个函数工具
真实 Agent 的价值来自工具。下面的例子模拟一个内部文档查询工具,让 Agent 先查资料再回答。
import { Agent, run, tool } from '@openai/agents';
import { z } from 'zod';
const docs = {
mcp: 'MCP connects models to external tools and resources through a standard protocol.',
tracing: 'Tracing records agent runs, tool calls, and model usage for debugging.',
guardrails: 'Guardrails validate inputs or outputs before the workflow proceeds.',
};
const searchDocs = tool({
name: 'search_docs',
description: 'Search the internal agent glossary by keyword.',
parameters: z.object({
keyword: z.string().describe('One lowercase keyword, such as mcp or tracing'),
}),
execute: async ({ keyword }) => {
return docs[keyword.toLowerCase()] ?? 'No matching entry found.';
},
});
const agent = new Agent({
name: 'DocsAssistant',
instructions: [
'Answer in three short bullets.',
'Use search_docs before explaining glossary terms.',
'If the tool returns no match, say what is missing instead of guessing.',
].join('\n'),
tools: [searchDocs],
});
const result = await run(agent, 'Explain tracing for an agent product team.');
console.log(result.finalOutput);
工具设计要保守:参数越窄,Agent 越容易稳定调用。不要把一个 execute_sql(query: string) 这种高权限工具直接暴露给模型;先封装成 get_user_order_summary(userId) 这类业务动作。
最小项目结构
小项目不需要复杂目录。先用这套结构:
openai-agents-js-demo/
package.json
src/
agents/
docs-agent.mjs
tools/
search-docs.mjs
index.mjs
拆分规则很简单:
| 文件 | 放什么 | 不放什么 |
|---|---|---|
agents/*.mjs |
Agent 名称、instructions、工具组合 | 具体数据库查询逻辑 |
tools/*.mjs |
参数 schema、业务 API 调用、错误返回 | 长篇提示词 |
index.mjs |
运行入口、输入输出、日志 | 复杂业务规则 |
这样拆不是为了"架构优雅",而是方便后续测试:工具可以单测,Agent instructions 可以单独评审,入口只负责把它们串起来。
什么时候加多 Agent
不要因为 SDK 支持 handoffs 就马上拆多 Agent。满足下面任一条件再拆:
| 信号 | 拆法 |
|---|---|
| 同一个 Agent 的 instructions 超过 40 行 | 拆成 Router + Specialist |
| 工具权限差异很大 | 高权限工具放到单独 Agent 后面 |
| 输出需要不同审查标准 | 生成 Agent 和 Review Agent 分开 |
| 任务需要长期运行或文件系统状态 | 研究 SandboxAgent,而不是普通 Agent 硬撑 |
最常见的第一种拆法是 Router 模式:入口 Agent 只判断任务类型,把问题交给"文档检索""数据分析""写作整理"等专门 Agent。不要让 Router 自己完成所有工作。
错误处理基线
上线前至少处理四类错误:
| 错误 | 典型现象 | 处理方式 |
|---|---|---|
| 缺少 API Key | 启动后认证失败 | 进程启动时检查 OPENAI_API_KEY |
| 工具参数不合法 | 工具没有执行或反复重试 | 用 Zod 收窄 schema,描述写具体 |
| 工具内部失败 | 返回异常堆栈给模型 | 捕获异常,返回结构化错误字符串 |
| 输出不可用 | Agent 答非所问或格式漂移 | 缩短 instructions,加输出格式约束 |
工具内部不要直接抛业务细节给模型:
const safeTool = tool({
name: 'get_order_status',
description: 'Get order status by order ID.',
parameters: z.object({ orderId: z.string().min(6) }),
execute: async ({ orderId }) => {
try {
return await getOrderStatus(orderId);
} catch {
return 'ORDER_LOOKUP_FAILED: ask the user to verify the order ID.';
}
},
});
Agent 看到稳定的错误码,才有机会做合理降级。随机堆栈只会污染上下文。
生产化检查表
| 检查项 | 最小要求 |
|---|---|
| 输入边界 | 用户输入长度、文件大小、请求频率有限制 |
| 工具权限 | 每个工具只做一个业务动作,不暴露通用 Shell 或 SQL |
| 沙箱路径 | Sandbox Manifest 声明 extraPathGrants,不依赖 baseDir 外的隐式访问 |
| 日志 | 记录 run id、工具名、耗时、错误码,不记录敏感原文 |
| 回归样例 | 保存 10-20 个真实用户问题,每次改 instructions 后重跑 |
| 人工兜底 | 高风险操作必须有人确认或只生成草稿 |
JS/TS SDK 的优势是容易嵌进现有产品;风险也是太容易把现有产品的高权限 API 暴露给模型。先把工具边界做窄,再谈复杂编排。
和 Python 版怎么选
| 你当前团队 | 推荐 |
|---|---|
| 主应用是 Node.js / Next.js / Cloudflare Workers | 先用 JS/TS SDK |
| 数据、评估、机器学习脚本主要在 Python | 先用 Python SDK |
| 要接前端实时语音体验 | 看 JS/TS 的 Realtime Agents(注意 v0.11.0 后默认模型为 gpt-realtime-2) |
| 要做离线批处理、评估流水线 | Python 生态更顺手 |
选择标准不是"哪个 SDK 更强",而是哪个能更快接入你已有的鉴权、日志、数据库和部署链路。Agent 框架本身只是运行时,真正的工程成本在工具边界和观测系统。