跳到主要内容

OpenAI Agents SDK (JS) — 架构与原理

30 秒导读: 这是 OpenAI 官方的 JS/TS 版「多 agent 编排框架」。你声明一个 Agent(指令 + 工具 + 交接 + 护栏),调一次 run(agent, input),它内部跑一个循环:调模型 → 看模型想干嘛(说话?调工具?交接给别的 agent?)→ 执行 → 把结果喂回模型 → 直到出现最终答案。它 provider 无关,自带人审、会话记忆、流式、追踪。

1. 这是什么(零基础也能懂)

  • 一句话定义: 一个把「LLM + 工具 + 多个子 agent」编排成可控工作流的运行时——你描述 agent,它负责一遍遍调模型、跑工具、按需在 agent 之间交接,直到产出最终答案。

  • 解决什么问题 / 给谁用: 假设你要做一个客服 bot:它要能查订单(调工具)、遇到退款转给「退款专员 agent」(交接)、危险输入要拦截(护栏)、删数据前要人点「同意」(人审)。如果你手写,就是一堆「调一次模型、解析它要调哪个函数、调完再拼消息、再调模型」的胶水代码。这个 SDK 把那条胶水主线做成了引擎,你只填声明。

  • 它能做什么(功能):

    • 定义 Agent:指令(system prompt)、工具、可交接的子 agent、结构化输出类型。
    • Agent 为工具(agent-as-tool)或跑交接(handoff)两种「调别的 agent」方式。
    • 工具:本地函数工具、计算机操作(computer-use)、shell、apply_patch(改文件)、托管 MCP 工具。
    • 护栏(guardrail):输入级、输出级、工具级的安全/合规检查,命中即中止。
    • 人审(HITL):工具调用前暂停等人点同意/拒绝,状态可序列化成字符串存库、之后恢复。
    • 会话记忆(Session)、流式事件(streaming)、全程追踪(tracing span)。
  • 用起来什么样: 一段最小代码就能感受主线(来自 README,可在克隆里跑):

// 示意,非源码(取自 README)
import { Agent, run } from '@openai/agents';

const agent = new Agent({
name: 'Assistant',
instructions: 'You are a helpful assistant',
});

const result = await run(agent, 'Write a haiku about recursion in programming.');
console.log(result.finalOutput);

你只给了 name + instructions + 一句话输入,run 内部就完成了「调模型 → 拿到文本 → 判定这是最终答案 → 返回」。

  • 一句话直觉/类比: 把它想成一台 「带工具箱和分诊台的对话状态机」:模型是大脑,循环是心跳,每一拍问大脑「下一步干嘛」,然后引擎替它动手(调工具/换专家),把结果递回去,直到大脑说「我答完了」。

2. 顶层全景(它大概怎么转)

2.1 仓库布局:一个引擎 + 几层适配

这是个 pnpm monorepo,分层很清晰:核心引擎与具体模型供应商解耦。

干什么在哪
@openai/agents-core引擎:Agent、Runner 主循环、工具、护栏、交接、人审、记忆、追踪的全部逻辑packages/agents-core/src
@openai/agents-openaiOpenAI 模型适配:把引擎的 Model 接口接到 Responses / Chat Completions APIpackages/agents-openai/src
@openai/agents-realtime实时语音 agent(WebRTC / SIP / WebSocket 传输)packages/agents-realtime/src
@openai/agents-extensions第三方适配:Vercel AI SDK 模型、Twilio/Cloudflare 实时传输packages/agents-extensions/src
@openai/agents元包:re-export 上面的东西,给用户一个 import 入口packages/agents

关键点:引擎只认一个 Model 接口(packages/agents-core/src/model.ts:573 Model,两个方法 getResponse / getStreamedResponse)。换模型供应商 = 换一个实现这接口的对象,循环逻辑一行不动。

2.2 引擎内部:部件与职责

部件干什么文件 · 符号
Agent一个 agent 的声明:指令、工具、交接、输出类型;不含执行逻辑agent.ts:483 Agent
run / Runner执行引擎:跑那条 while 循环run.ts:431 runrun.ts:460 Runner
RunState一次 run 的全部可变状态(当前 agent、已生成 items、当前步骤、审批),可序列化runState.ts:474 RunState
RunContext跨工具/护栏共享的用户 context + usage + 审批表runContext.ts:104 RunContext
processModelResponse把模型原始输出分类成「消息 / 函数调用 / 交接 / 计算机动作…」runner/modelOutputs.ts:654
resolveTurnAfterModelResponse执行那些动作、决定下一步(最终输出?再循环?交接?中断?)runner/turnResolution.ts:880
tool / handoff / guardrails三种挂件的工厂tool.ts:1860handoff.ts:346guardrail.ts

2.3 主线走一遍(高层,不进代码)

这是整个 SDK 的「心跳」。从左到右是一拍(turn)内的流向,最右的分叉决定是否再来一拍:

输入(string / items / 恢复的 RunState)


[准备这一拍] 会话记忆拼接 + 输入护栏(可并行) + 组装 system prompt/工具/交接


[调模型] Model.getResponse(...) ← provider 无关


[分类输出] processModelResponse: 消息? 函数调用? 交接? 计算机/shell 动作? MCP 审批?


[执行 + 定下一步] resolveTurnAfterModelResponse

├─ 纯文本、无工具 → next_step_final_output ──► 跑输出护栏 ─► 返回 RunResult ✅
├─ 有工具调用 → 跑工具,把结果记进 items → next_step_run_again ──┐
├─ 模型要交接 → 换当前 agent → next_step_run_again ──────────┤ 回到[准备这一拍]
└─ 工具需人审/MCP 审批 → next_step_interruption ──► 返回 RunResult(带 interruptions) ⏸

「再来一拍」就是回到顶部,只是这次输入里多了上一拍的工具结果/交接消息。循环上限由 maxTurns 守住(runner/constants.ts DEFAULT_MAX_TURNS)。

3. 阅读地图(建议顺序)

这套文档按「先主线、再挂件、再高级特性」排:

  1. 01-agent-loop.md — 主线循环(必读)。讲 Runner.run 那个 while 怎么转:准备一拍 → 调模型 → 分类 → 决定下一步。理解了它,其它都是往这条线上挂东西。
  2. 02-tools-and-agents-as-tools.md — 工具系统tool() 工厂怎么把一个函数变成模型可调用的工具(含 Zod 校验、超时、错误兜底),四类工具的区别,以及 Agent.asTool 如何「把一个 agent 当工具」(嵌套 run)。
  3. 03-handoffs-and-guardrails.md — 交接与护栏。handoff(换掉当前 agent)vs agent-as-tool(不换,当子程序);三种护栏(输入/输出/工具)怎么并行跑、命中怎么中止。
  4. 04-human-in-the-loop.md — 人审与状态序列化。工具审批怎么把循环暂停成 next_step_interruptionRunState.toString()/fromString() 怎么把整个 run 存盘、之后恢复继续。
  5. 05-models-streaming-tracing.md — 模型/流式/追踪 + 兄弟包Model 接口、流式事件路径、tracing span,以及 sandbox-agent 和 realtime 语音两条扩展线。

4. 代码地图(导航索引)

主题文件符号
公共 API 出口packages/agents-core/src/index.ts(re-export 全部)
Agent 声明agent.tsAgentAgentConfigurationAgent.create
顶层 run 函数run.tsrunRunnerRunner.run
非流式主循环run.tsRunner.#runIndividualNonStream
模型输出分类runner/modelOutputs.tsprocessModelResponseprocessModelResponseAsync
一拍的下一步决议runner/turnResolution.tsresolveTurnAfterModelResponseresolveInterruptedTurn
下一步类型runner/steps.tsnextStepSchemaSingleStepResult
工具工厂tool.tstoolcomputerToolshellToolapplyPatchToolhostedMcpTool
工具执行/审批runner/toolExecution.tsexecuteFunctionToolCallshandleFunctionApproval
交接handoff.tshandoffHandoffgetHandoff
护栏guardrail.tsdefineInputGuardraildefineOutputGuardrail
运行状态runState.tsRunStateRunState.toStringRunState.fromString
运行 context/审批表runContext.tsRunContextapproveToolrejectToolisToolApproved
模型抽象model.tsModelModelProviderModelRequestModelResponse
追踪tracing/index.tsaddTraceProcessorwithTrace