openai-agents-python-sdk 源码解析 | 第一篇:认识 OpenAI Agents Python SDK:它解决什么问题

发布时间:2026/8/1 13:42:57
openai-agents-python-sdk 源码解析 | 第一篇:认识 OpenAI Agents Python SDK:它解决什么问题 本篇导读如果你已经用过 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 项目要求 Python3.10核心依赖包括openai连接 OpenAI API。pydantic支持结构化输出、参数 schema、类型校验。websockets支撑 Realtime 和 WebSocket 场景。mcp支撑 Model Context Protocol 工具生态。requests、typing-extensions、griffelib分别支撑基础 HTTP、类型兼容和文档能力。README 对它的定位非常直接这是一个用于构建多 Agent 工作流的轻量框架支持 OpenAI Responses API、Chat Completions API也能通过 provider 扩展接入其他模型。更准确地说它不是一个“聊天机器人模板”而是一个 Agent runtime SDK。它关注的是以下问题如何声明一个 Agent 的职责、工具、输出、handoff 和安全边界。如何在一次 run 中协调模型调用、工具调用和 Agent 切换。如何管理上下文、会话历史、流式事件和最终输出。如何让运行过程可观察、可测试、可扩展。如何把 MCP、Realtime、Voice、Sandbox 等能力接入同一套编排模型。为什么不直接调用模型 API直接调用模型 API 的典型流程大致是这样fromopenaiimportOpenAI clientOpenAI()responseclient.responses.create(modelgpt-5.4-mini,input请总结这段文本。,)print(response.output_text)这段代码很清晰适合一次性问答。但真实应用很少停留在这里。比如一个客服 Agent 可能需要识别用户意图。查询订单系统。判断是否需要退款审批。如果是技术问题交给技术支持 Agent。如果用户输入涉及敏感信息提前拦截。保存对话历史下一轮继续处理。在后台记录模型调用、工具调用、耗时和错误。前端需要实时展示模型输出和工具执行进度。如果全部自己手写就会出现大量横切逻辑工具 schema、工具结果回填、错误转换、循环控制、人工审批、上下文裁剪、trace 记录、流式事件合并、重试和取消。这些逻辑和业务代码混在一起后后续维护成本会快速上升。Agents SDK 的价值就在这里它把这些横切逻辑抽象成稳定对象和运行时流程。你仍然需要设计业务 Agent 和工具但不需要从零维护整套 Agent loop。最小使用形态README 中的普通文本 Agent 示例可以简化成下面这样fromagentsimportAgent,Runner agentAgent(nameAssistant,instructions你是一个简洁、准确的技术助手。,)resultRunner.run_sync(agent,解释什么是 Agent runtime。)print(result.final_output)这个例子里出现了两个最重要的对象Agent描述智能体包括名称、指令、模型、工具、guardrails、handoffs、输出类型等。Runner执行智能体工作流把输入交给 Agent并驱动后续模型调用、工具调用或 handoff。从使用体验上看这是一段很短的代码。但从源码视角看它背后已经进入了完整运行时。核心对象地图先把主要概念放在一张表里后续每篇文章会逐个展开。概念主要源码入口解决的问题Agentsrc/agents/agent.py声明智能体的指令、工具、handoff、guardrail、输出类型和模型配置Runnersrc/agents/run.py执行 Agent 工作流负责循环、工具调用、handoff、最终输出判断RunConfigsrc/agents/run_config.py提供一次 run 的全局配置例如模型 provider、tracing、tool 行为、sandboxRunResultsrc/agents/result.py封装最终输出、运行产生的新 item、最后执行的 Agent 等结果Toolsrc/agents/tool.py把函数、MCP、Hosted tools、搜索、代码解释器等能力暴露给 AgentHandoffsrc/agents/handoffs支持 Agent 把任务交给另一个更合适的 AgentGuardrailsrc/agents/guardrail.py在输入或输出阶段执行安全和业务规则校验Sessionsrc/agents/memory管理自动对话历史和会话状态Tracingsrc/agents/tracing记录模型调用、工具调用、guardrail、handoff 等运行过程RealtimeAgentsrc/agents/realtime面向低延迟 WebSocket、语音和多模态交互SandboxAgentsrc/agents/sandbox面向文件检查、命令执行、补丁应用和长任务工作区这张表是阅读整个项目的导航。后续如果你在源码中迷路优先回到这张表判断当前文件属于哪个运行阶段。一次 Agent run 的高层链路Runner.run的 docstring 已经把核心循环讲得很清楚。一次工作流会从 starting agent 开始循环执行直到出现最终输出、触发 handoff、执行工具后再次进入模型或遇到异常。可以把它理解成下面这条链路是否存在工具调用否存在 Handoff用户输入RunnerStarting AgentModel Provider模型输出是否已经得到最终输出RunResultTool ExecutionNext AgentGuardrails / Session / Tracing这张图有几个关键点Agent不是直接执行者它更像是“声明对象”。Runner才是运行时入口负责把 Agent、模型、工具、session 和 tracing 串起来。工具调用后通常会再次回到模型让模型基于工具结果生成最终答案。handoff 后会切换当前 Agent但仍在同一次 run 的控制流里。guardrail、session、tracing 是贯穿执行链路的横切能力。Agent声明一个智能体src/agents/agent.py中的Agent是一个 dataclass。源码注释说明得很明确Agent 是一个配置了 instructions、tools、guardrails、handoffs 等能力的 AI model。从当前源码看Agent的关键字段包括instructions系统指令可以是字符串也可以是根据上下文动态生成的函数。prompt面向 OpenAI Responses API 的 prompt 配置。handoffs可委派的下游 Agent 或 Handoff 对象。model当前 Agent 使用的模型或模型名称。model_settings温度、top_p 等模型参数。input_guardrails输入阶段的校验规则。output_guardrails输出阶段的校验规则。output_type结构化输出类型。tool_use_behavior工具调用后是否再次调用模型或直接把工具结果作为最终输出。这意味着Agent不是一个只有 prompt 的薄封装。它把“智能体的职责”和“运行时应该如何对待这个智能体”都描述出来。一个更接近业务使用的 Agent 可能长这样fromagentsimportAgent support_agentAgent(nameSupportAgent,instructions你是客服助手只处理订单、退款和账户问题。,modelgpt-5.4-mini,)后续文章会继续给它增加 tools、handoffs、guardrails 和 session。Runner驱动工作流执行src/agents/run.py中的Runner是 SDK 的执行入口。它提供同步、异步和流式运行方式其中异步run是最核心的形态。从Runner.run的参数可以看出它不只是接收一个 Agent 和用户输入还接收很多运行时上下文context传给工具、handoff 和 guardrail 的业务上下文。max_turns限制最多模型调用轮数避免无限循环。hooks生命周期回调。run_config全局配置。error_handlers运行时错误处理。previous_response_id/conversation_idOpenAI Responses API 的会话延续能力。sessionSDK 层面的自动历史管理。这说明 SDK 的执行模型不是“一次输入一次输出”这么简单。它更像一个受控循环每一轮都可能发生模型调用、工具调用、handoff、guardrail 检查和状态持久化。Tool让 Agent 具备行动能力如果没有工具Agent 只能基于已有上下文回答问题。工具系统让 Agent 可以查询外部系统、调用函数、检索文件、执行 MCP 工具或访问 Hosted tools。最常见的入口是function_toolfromagentsimportAgent,function_toolfunction_tooldefget_order_status(order_id:str)-str:# 示例工具真实场景中这里会查询订单系统。returnf订单{order_id}当前状态为已发货。agentAgent(nameOrderAgent,instructions你负责回答订单状态问题。,tools[get_order_status],)工具系统背后有三件重要工作从 Python 函数签名生成模型可理解的参数 schema。在模型请求中暴露工具定义。当模型选择调用工具时执行 Python 函数并把结果回填给模型。这也是为什么工具系统需要和 Runner 紧密结合。工具不是孤立函数而是 Agent loop 的一部分。Handoff让 Agent 分工协作当一个 Agent 不应该处理所有事情时就需要 handoff。比如客服系统里入口 Agent 可以负责意图识别然后把任务交给不同专家 AgentBillingAgent处理账单和支付。RefundAgent处理退款策略。TechSupportAgent处理技术问题。Handoff 和工具调用的区别在于工具调用是“当前 Agent 调用一个能力”。Handoff 是“当前 Agent 把控制权交给另一个 Agent”。这两者都能实现模块化但适用边界不同。工具适合明确、可执行的动作handoff 适合职责切换和上下文交接。Guardrail把安全和业务边界放进运行时Guardrail 负责在输入或输出阶段做校验。它不是 prompt 里的“请不要做某事”而是运行时里的明确检查。典型场景包括输入中包含不允许处理的主题直接拦截。输出不符合结构化格式触发错误。工具输入缺少必要字段禁止执行。工具输出包含敏感信息不允许返回给用户。这类逻辑如果只靠 prompt稳定性很难保证。放入 guardrail 后它就变成了可测试、可追踪、可维护的运行时边界。Session 与 Memory让多轮对话可持续很多 Agent 应用不是单轮问答而是多轮任务。SDK 提供 session 和 memory 相关抽象用于自动管理会话历史。当前项目里相关代码主要分布在src/agents/memorysrc/agents/extensions/memorysrc/agents/run_internal/session_persistence.py内置和扩展能力覆盖 SQLite、SQLAlchemy、Redis、MongoDB、Dapr、加密 session 等。对于业务系统来说这部分很关键因为历史状态一旦管理不好就会出现重复写入、上下文错乱、重试不一致或隐私数据残留等问题。Tracing让 Agent 运行过程可观察Agent 工作流一旦包含工具和 handoff排障就不能只看最终输出。你需要知道模型被调用了几次。每次模型调用用了哪个 Agent。模型是否选择了工具。工具执行耗时多久。是否发生 handoff。哪个 guardrail 拦截了请求。session 是否保存成功。src/agents/tracing就是为这些问题服务的。Tracing 不只是调试辅助它也是生产化 Agent 应用的基础设施。后续文章会专门展开 trace、span、processor 和敏感信息处理。三种主要运行形态README 中给出了三种入门方式它们代表 SDK 的三类典型使用形态。普通文本 Agent这是最常见的形态。适合普通问答、结构化输出、工具调用、多 Agent 编排和后台任务。核心入口agents.Agentagents.Runnerexamples/basicRealtime AgentRealtime Agent 面向低延迟交互尤其是 WebSocket、语音和多模态场景。它的核心对象是RealtimeAgentRealtimeRunnerRealtimeSession相关代码位于src/agents/realtime示例位于examples/realtime。Sandbox AgentSandbox Agent 面向长任务工作区。它可以让 Agent 在受控环境里检查文件、运行命令、应用补丁或保留 workspace state。相关代码位于src/agents/sandboxsrc/agents/extensions/sandboxexamples/sandbox如果你把这个 SDK 用在代码分析、数据处理、仓库巡检或自动修复任务上Sandbox Agent 会是很重要的一条线。仓库结构怎么读先看顶层目录路径作用src/agentsSDK 核心实现examples官方示例适合从使用方式切入docsMkDocs 文档源码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 暴露了什么”但不适合作为理解运行时的第一入口。更实用的阅读顺序是README.md确认项目定位和三类运行形态。examples/basic先跑通最小 Agent。src/agents/agent.py理解 Agent 可以声明什么。src/agents/run.py理解 Runner 如何启动一次 run。src/agents/run_internal/run_loop.py理解内部循环。src/agents/tool.py理解工具怎么声明和执行。src/agents/items.py理解模型输出、工具调用和 handoff 如何被表示。src/agents/result.py理解最终结果如何组织。tests中对应模块测试用测试确认行为边界。这个顺序的好处是先建立外部使用视角再进入运行时内部不容易被细节打散。从应用视角看 SDK 的分层可以把项目分成四层层级代表模块说明用户声明层Agent、Tool、Guardrail、Handoff开发者声明工作流能力运行编排层Runner、run_internal驱动模型调用、工具调用、handoff 和结果收敛模型适配层models、extensions/models屏蔽 Responses、Chat Completions 和第三方 provider 差异能力扩展层mcp、memory、tracing、realtime、voice、sandbox支撑真实应用中的外部工具、状态、可观测和复杂交互这个分层不是源码中的强制目录边界而是理解项目时的工程视角。后续源码解析会不断回到这四层判断某个类到底承担哪一层职责。本篇小结OpenAI Agents Python SDK 的核心不是“帮你少写几行调用模型的代码”而是提供一套可组合、可观察、可扩展的 Agent runtime。第一篇需要记住四个结论Agent是声明对象描述智能体的职责和能力。Runner是执行入口负责驱动完整 Agent loop。Tools、Handoffs、Guardrails、Sessions、Tracing 是围绕模型调用的关键运行时能力。Realtime、Voice、Sandbox 是 SDK 面向复杂交互和长任务场景的扩展形态。下一篇会进入实际编码从环境准备开始运行第一个文本 Agent并观察RunResult中到底包含哪些信息。实践任务读完本篇后建议完成三个动作打开README.md确认三种官方入门示例普通文本 Agent、Realtime Agent、Sandbox Agent。打开src/agents/agent.py找到Agentdataclass浏览字段和字段注释。打开src/agents/run.py找到Runner.run阅读 docstring 中关于运行循环的描述。如果你能用自己的话解释“为什么 Agent 不是 RunnerRunner 也不是 Model Provider”就已经具备继续阅读后续源码的基础。