本篇导读

如果你已经用过 OpenAI API,通常会从一个很直接的流程开始:组织 prompt、调用模型、解析返回值。如果任务只是一问一答,这样足够。但当任务开始包含工具调用、多步骤推理、多 Agent 分工、人工审批、会话记忆、流式输出、Trace 排障、MCP 工具生态或沙箱执行时,直接围绕 API 手写流程会很快变得复杂。

OpenAI Agents Python SDK 要解决的核心问题,就是把这些复杂度收敛到一套统一的 Agent 运行时里。开发者通过 Agent 描述“这个智能体是谁、能做什么、有什么边界”,再通过 Runner 执行一次工作流。模型调用、工具执行、handoff、guardrail、session 和 tracing 都被组织在同一条运行链路中。

本系列会从源码角度拆解这个 SDK。第一篇不深入展开每个类的实现细节,而是先建立项目地图:这个项目是什么、为什么需要它、核心模块在哪里、后续应该按什么顺序阅读源码。

这个项目是什么

当前仓库是 openai-agents-python,发布包名是 openai-agents。从 pyproject.toml 可以看到它是一个 Python SDK 项目,要求 Python >=3.10,核心依赖包括:

  1. openai:连接 OpenAI API。
  2. pydantic:支持结构化输出、参数 schema、类型校验。
  3. websockets:支撑 Realtime 和 WebSocket 场景。
  4. mcp:支撑 Model Context Protocol 工具生态。
  5. requeststyping-extensionsgriffelib:分别支撑基础 HTTP、类型兼容和文档能力。

README 对它的定位非常直接:这是一个用于构建多 Agent 工作流的轻量框架,支持 OpenAI Responses API、Chat Completions API,也能通过 provider 扩展接入其他模型。

更准确地说,它不是一个“聊天机器人模板”,而是一个 Agent runtime SDK。它关注的是以下问题:

  1. 如何声明一个 Agent 的职责、工具、输出、handoff 和安全边界。
  2. 如何在一次 run 中协调模型调用、工具调用和 Agent 切换。
  3. 如何管理上下文、会话历史、流式事件和最终输出。
  4. 如何让运行过程可观察、可测试、可扩展。
  5. 如何把 MCP、Realtime、Voice、Sandbox 等能力接入同一套编排模型。

为什么不直接调用模型 API

直接调用模型 API 的典型流程大致是这样:

from openai import OpenAI

client = OpenAI()
response = client.responses.create(
    model="gpt-5.4-mini",
    input="请总结这段文本。",
)
print(response.output_text)

这段代码很清晰,适合一次性问答。但真实应用很少停留在这里。比如一个客服 Agent 可能需要:

  1. 识别用户意图。
  2. 查询订单系统。
  3. 判断是否需要退款审批。
  4. 如果是技术问题,交给技术支持 Agent。
  5. 如果用户输入涉及敏感信息,提前拦截。
  6. 保存对话历史,下一轮继续处理。
  7. 在后台记录模型调用、工具调用、耗时和错误。
  8. 前端需要实时展示模型输出和工具执行进度。

如果全部自己手写,就会出现大量横切逻辑:工具 schema、工具结果回填、错误转换、循环控制、人工审批、上下文裁剪、trace 记录、流式事件合并、重试和取消。这些逻辑和业务代码混在一起后,后续维护成本会快速上升。

Agents SDK 的价值就在这里:它把这些横切逻辑抽象成稳定对象和运行时流程。你仍然需要设计业务 Agent 和工具,但不需要从零维护整套 Agent loop。

最小使用形态

README 中的普通文本 Agent 示例可以简化成下面这样:

from agents import Agent, Runner

agent = Agent(
    name="Assistant",
    instructions="你是一个简洁、准确的技术助手。",
)

result = Runner.run_sync(agent, "解释什么是 Agent runtime。")
print(result.final_output)

这个例子里出现了两个最重要的对象:

  1. Agent:描述智能体,包括名称、指令、模型、工具、guardrails、handoffs、输出类型等。
  2. Runner:执行智能体工作流,把输入交给 Agent,并驱动后续模型调用、工具调用或 handoff。

从使用体验上看,这是一段很短的代码。但从源码视角看,它背后已经进入了完整运行时。

核心对象地图

先把主要概念放在一张表里,后续每篇文章会逐个展开。

概念 主要源码入口 解决的问题
Agent src/agents/agent.py 声明智能体的指令、工具、handoff、guardrail、输出类型和模型配置
Runner src/agents/run.py 执行 Agent 工作流,负责循环、工具调用、handoff、最终输出判断
RunConfig src/agents/run_config.py 提供一次 run 的全局配置,例如模型 provider、tracing、tool 行为、sandbox
RunResult src/agents/result.py 封装最终输出、运行产生的新 item、最后执行的 Agent 等结果
Tool src/agents/tool.py 把函数、MCP、Hosted tools、搜索、代码解释器等能力暴露给 Agent
Handoff src/agents/handoffs 支持 Agent 把任务交给另一个更合适的 Agent
Guardrail src/agents/guardrail.py 在输入或输出阶段执行安全和业务规则校验
Session src/agents/memory 管理自动对话历史和会话状态
Tracing src/agents/tracing 记录模型调用、工具调用、guardrail、handoff 等运行过程
RealtimeAgent src/agents/realtime 面向低延迟 WebSocket、语音和多模态交互
SandboxAgent src/agents/sandbox 面向文件检查、命令执行、补丁应用和长任务工作区

这张表是阅读整个项目的导航。后续如果你在源码中迷路,优先回到这张表判断当前文件属于哪个运行阶段。

一次 Agent run 的高层链路

Runner.run 的 docstring 已经把核心循环讲得很清楚。一次工作流会从 starting agent 开始,循环执行,直到出现最终输出、触发 handoff、执行工具后再次进入模型,或遇到异常。

可以把它理解成下面这条链路:

否,存在工具调用

否,存在 Handoff

用户输入

Runner

Starting Agent

Model Provider

模型输出

是否已经得到最终输出

RunResult

Tool Execution

Next Agent

Guardrails / Session / Tracing

这张图有几个关键点:

  1. Agent 不是直接执行者,它更像是“声明对象”。
  2. Runner 才是运行时入口,负责把 Agent、模型、工具、session 和 tracing 串起来。
  3. 工具调用后通常会再次回到模型,让模型基于工具结果生成最终答案。
  4. handoff 后会切换当前 Agent,但仍在同一次 run 的控制流里。
  5. guardrail、session、tracing 是贯穿执行链路的横切能力。

Agent:声明一个智能体

src/agents/agent.py 中的 Agent 是一个 dataclass。源码注释说明得很明确:Agent 是一个配置了 instructions、tools、guardrails、handoffs 等能力的 AI model。

从当前源码看,Agent 的关键字段包括:

  1. instructions:系统指令,可以是字符串,也可以是根据上下文动态生成的函数。
  2. prompt:面向 OpenAI Responses API 的 prompt 配置。
  3. handoffs:可委派的下游 Agent 或 Handoff 对象。
  4. model:当前 Agent 使用的模型或模型名称。
  5. model_settings:温度、top_p 等模型参数。
  6. input_guardrails:输入阶段的校验规则。
  7. output_guardrails:输出阶段的校验规则。
  8. output_type:结构化输出类型。
  9. tool_use_behavior:工具调用后是否再次调用模型,或直接把工具结果作为最终输出。

这意味着 Agent 不是一个只有 prompt 的薄封装。它把“智能体的职责”和“运行时应该如何对待这个智能体”都描述出来。

一个更接近业务使用的 Agent 可能长这样:

from agents import Agent

support_agent = Agent(
    name="SupportAgent",
    instructions="你是客服助手,只处理订单、退款和账户问题。",
    model="gpt-5.4-mini",
)

后续文章会继续给它增加 tools、handoffs、guardrails 和 session。

Runner:驱动工作流执行

src/agents/run.py 中的 Runner 是 SDK 的执行入口。它提供同步、异步和流式运行方式,其中异步 run 是最核心的形态。

Runner.run 的参数可以看出,它不只是接收一个 Agent 和用户输入,还接收很多运行时上下文:

  1. context:传给工具、handoff 和 guardrail 的业务上下文。
  2. max_turns:限制最多模型调用轮数,避免无限循环。
  3. hooks:生命周期回调。
  4. run_config:全局配置。
  5. error_handlers:运行时错误处理。
  6. previous_response_id / conversation_id:OpenAI Responses API 的会话延续能力。
  7. session:SDK 层面的自动历史管理。

这说明 SDK 的执行模型不是“一次输入一次输出”这么简单。它更像一个受控循环,每一轮都可能发生模型调用、工具调用、handoff、guardrail 检查和状态持久化。

Tool:让 Agent 具备行动能力

如果没有工具,Agent 只能基于已有上下文回答问题。工具系统让 Agent 可以查询外部系统、调用函数、检索文件、执行 MCP 工具或访问 Hosted tools。

最常见的入口是 @function_tool

from agents import Agent, function_tool

@function_tool
def get_order_status(order_id: str) -> str:
    # 示例工具:真实场景中这里会查询订单系统。
    return f"订单 {order_id} 当前状态为已发货。"

agent = Agent(
    name="OrderAgent",
    instructions="你负责回答订单状态问题。",
    tools=[get_order_status],
)

工具系统背后有三件重要工作:

  1. 从 Python 函数签名生成模型可理解的参数 schema。
  2. 在模型请求中暴露工具定义。
  3. 当模型选择调用工具时,执行 Python 函数并把结果回填给模型。

这也是为什么工具系统需要和 Runner 紧密结合。工具不是孤立函数,而是 Agent loop 的一部分。

Handoff:让 Agent 分工协作

当一个 Agent 不应该处理所有事情时,就需要 handoff。比如客服系统里,入口 Agent 可以负责意图识别,然后把任务交给不同专家 Agent:

  1. BillingAgent:处理账单和支付。
  2. RefundAgent:处理退款策略。
  3. TechSupportAgent:处理技术问题。

Handoff 和工具调用的区别在于:

  1. 工具调用是“当前 Agent 调用一个能力”。
  2. Handoff 是“当前 Agent 把控制权交给另一个 Agent”。

这两者都能实现模块化,但适用边界不同。工具适合明确、可执行的动作;handoff 适合职责切换和上下文交接。

Guardrail:把安全和业务边界放进运行时

Guardrail 负责在输入或输出阶段做校验。它不是 prompt 里的“请不要做某事”,而是运行时里的明确检查。

典型场景包括:

  1. 输入中包含不允许处理的主题,直接拦截。
  2. 输出不符合结构化格式,触发错误。
  3. 工具输入缺少必要字段,禁止执行。
  4. 工具输出包含敏感信息,不允许返回给用户。

这类逻辑如果只靠 prompt,稳定性很难保证。放入 guardrail 后,它就变成了可测试、可追踪、可维护的运行时边界。

Session 与 Memory:让多轮对话可持续

很多 Agent 应用不是单轮问答,而是多轮任务。SDK 提供 session 和 memory 相关抽象,用于自动管理会话历史。

当前项目里相关代码主要分布在:

  1. src/agents/memory
  2. src/agents/extensions/memory
  3. src/agents/run_internal/session_persistence.py

内置和扩展能力覆盖 SQLite、SQLAlchemy、Redis、MongoDB、Dapr、加密 session 等。对于业务系统来说,这部分很关键,因为历史状态一旦管理不好,就会出现重复写入、上下文错乱、重试不一致或隐私数据残留等问题。

Tracing:让 Agent 运行过程可观察

Agent 工作流一旦包含工具和 handoff,排障就不能只看最终输出。你需要知道:

  1. 模型被调用了几次。
  2. 每次模型调用用了哪个 Agent。
  3. 模型是否选择了工具。
  4. 工具执行耗时多久。
  5. 是否发生 handoff。
  6. 哪个 guardrail 拦截了请求。
  7. session 是否保存成功。

src/agents/tracing 就是为这些问题服务的。Tracing 不只是调试辅助,它也是生产化 Agent 应用的基础设施。后续文章会专门展开 trace、span、processor 和敏感信息处理。

三种主要运行形态

README 中给出了三种入门方式,它们代表 SDK 的三类典型使用形态。

普通文本 Agent

这是最常见的形态。适合普通问答、结构化输出、工具调用、多 Agent 编排和后台任务。

核心入口:

  1. agents.Agent
  2. agents.Runner
  3. examples/basic

Realtime Agent

Realtime Agent 面向低延迟交互,尤其是 WebSocket、语音和多模态场景。它的核心对象是:

  1. RealtimeAgent
  2. RealtimeRunner
  3. RealtimeSession

相关代码位于 src/agents/realtime,示例位于 examples/realtime

Sandbox Agent

Sandbox Agent 面向长任务工作区。它可以让 Agent 在受控环境里检查文件、运行命令、应用补丁或保留 workspace state。

相关代码位于:

  1. src/agents/sandbox
  2. src/agents/extensions/sandbox
  3. examples/sandbox

如果你把这个 SDK 用在代码分析、数据处理、仓库巡检或自动修复任务上,Sandbox Agent 会是很重要的一条线。

仓库结构怎么读

先看顶层目录:

路径 作用
src/agents SDK 核心实现
examples 官方示例,适合从使用方式切入
docs MkDocs 文档源码
tests 测试套件,适合理解行为边界
pyproject.toml 包配置、依赖、ruff、mypy、pytest、coverage 配置
Makefile 常用开发命令
.agents/references 维护者视角的架构参考
.agents/skills 本仓库自动化工作流说明

再看 src/agents 内部:

路径 建议阅读时机
agent.py 第一优先级,理解 Agent 声明模型
run.py 第一优先级,理解 Runner 入口
run_internal 第二优先级,理解运行时拆分
tool.py 写工具前阅读
guardrail.py / tool_guardrails.py 做安全和业务校验前阅读
handoffs 做多 Agent 编排前阅读
memory / extensions/memory 做多轮对话和持久化前阅读
models 需要切换模型或 provider 时阅读
mcp 接入 MCP server 时阅读
tracing 做排障、审计和可观测性时阅读
realtime 做低延迟交互和语音应用时阅读
voice 做语音输入输出 pipeline 时阅读
sandbox 做长任务、文件操作和命令执行时阅读

推荐源码阅读路线

不要从 src/agents/__init__.py 一路顺序读完整个包。这个文件主要是公共 API re-export,适合查“SDK 暴露了什么”,但不适合作为理解运行时的第一入口。

更实用的阅读顺序是:

  1. README.md:确认项目定位和三类运行形态。
  2. examples/basic:先跑通最小 Agent。
  3. src/agents/agent.py:理解 Agent 可以声明什么。
  4. src/agents/run.py:理解 Runner 如何启动一次 run。
  5. src/agents/run_internal/run_loop.py:理解内部循环。
  6. src/agents/tool.py:理解工具怎么声明和执行。
  7. src/agents/items.py:理解模型输出、工具调用和 handoff 如何被表示。
  8. src/agents/result.py:理解最终结果如何组织。
  9. tests 中对应模块测试:用测试确认行为边界。

这个顺序的好处是先建立外部使用视角,再进入运行时内部,不容易被细节打散。

从应用视角看 SDK 的分层

可以把项目分成四层:

层级 代表模块 说明
用户声明层 AgentToolGuardrailHandoff 开发者声明工作流能力
运行编排层 Runnerrun_internal 驱动模型调用、工具调用、handoff 和结果收敛
模型适配层 modelsextensions/models 屏蔽 Responses、Chat Completions 和第三方 provider 差异
能力扩展层 mcpmemorytracingrealtimevoicesandbox 支撑真实应用中的外部工具、状态、可观测和复杂交互

这个分层不是源码中的强制目录边界,而是理解项目时的工程视角。后续源码解析会不断回到这四层,判断某个类到底承担哪一层职责。

本篇小结

OpenAI Agents Python SDK 的核心不是“帮你少写几行调用模型的代码”,而是提供一套可组合、可观察、可扩展的 Agent runtime。

第一篇需要记住四个结论:

  1. Agent 是声明对象,描述智能体的职责和能力。
  2. Runner 是执行入口,负责驱动完整 Agent loop。
  3. Tools、Handoffs、Guardrails、Sessions、Tracing 是围绕模型调用的关键运行时能力。
  4. Realtime、Voice、Sandbox 是 SDK 面向复杂交互和长任务场景的扩展形态。

下一篇会进入实际编码:从环境准备开始,运行第一个文本 Agent,并观察 RunResult 中到底包含哪些信息。

实践任务

读完本篇后,建议完成三个动作:

  1. 打开 README.md,确认三种官方入门示例:普通文本 Agent、Realtime Agent、Sandbox Agent。
  2. 打开 src/agents/agent.py,找到 Agent dataclass,浏览字段和字段注释。
  3. 打开 src/agents/run.py,找到 Runner.run,阅读 docstring 中关于运行循环的描述。

如果你能用自己的话解释“为什么 Agent 不是 Runner,Runner 也不是 Model Provider”,就已经具备继续阅读后续源码的基础。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐