ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenAI Agents SDK实战:从零构建智能体编排与多Agent协作

OpenAI Agents SDK实战:从零构建智能体编排与多Agent协作 说实话当我第一次听到“OpenAI Agents SDK”这个名字的时候我心里想的是又来一个框架LangChain还没学明白AutoGen也没怎么用熟现在官方又甩出一个SDK学得过来吗但真正花时间把它跑通之后我发现自己之前的判断错了。OpenAI Agents SDK和市面上那些“全家桶”式框架不一样它一上来就不想让你折腾Agent的外壳而是把智能体编排拆成了几个极其清爽的零件装上就能跑。这篇是“构建指南”系列的第一篇我打算把它当作一份基础实操笔记来写直接把从零到第一个Agent跑通的全过程、里面每个核心概念的真正含义、以及我实测过程中踩到的坑一起讲清楚。如果你正准备开始接触官方这套Agent开发工具这篇文章应该能帮你省下不少瞎琢磨的时间。1. 从Function Calling到Agent编排OpenAI Agents SDK到底解决了什么问题先把背景交代清楚。很多人可能已经有这样的经验用Chat Completions接口写单轮对话没问题但一旦要做“多步骤任务”——比如让模型先查一下用户的订单状态再根据状态决定要不要调用退款接口最后还要生成一封回复邮件——代码就开始变得很痛苦。你需要在主循环里维护一个所谓的“当前状态”判断模型返回的是普通文本、函数调用、还是想结束任务你要自己处理上一轮工具返回的数据怎么塞回下一轮请求遇到多个任务要串行或者并行执行时你得写一堆if-else去编排。说实话这些代码本身不难但写多了容易乱而且每个项目都要重写一遍。我去翻了不少开源项目发现大家的实现思路其实都差不多无非是建一个循环、收集工具结果、再发给模型。问题不在于“能不能写出来”而在于“能不能把这个模式抽象成公共能力”。OpenAI Agents SDK想解决的正是这件事。它是OpenAI官方推出的智能体编排框架核心思路很直接把Agent当成一个带有指令、模型和工具的执行单元然后通过内置的循环机制去跑任务你不需要关心工具调用过程中的状态管理也不需要自己写循环去一直问模型“你现在是要调工具还是给最终答案”。与此同时它借鉴了早期Swarm项目的实验思路把多Agent之间的协作简化成了所谓的“Handoff”也就是不同Agent之间直接交接而不是靠外部流程引擎去硬编。说白了这个SDK就是在告诉你Agent编排不该靠一堆胶水代码去堆而应该把“智能体本身”、“它能用哪些工具”、“问题怎么在智能体之间流转”这三件事变成声明式的配置和轻量级的运行时。我在实际体验里的感觉是如果你只有一个单Agent、单次调用的简单需求其实用原生的Responses API就够了但只要你开始考虑把多个工具组合在一起做复杂任务或者希望不同的业务领域由不同的Agent分别接管Agents SDK立刻就能体现出价值。它给你的不是一层更厚的包装而是一个比手写更规范、比LangChain更克制的中间层——这不是夸大而是我对比过代码结构之后比较客观的结论。2. 五个核心概念逐个拆解Agent、Handoff、Guardrail、Session与Execution2.1 Agent不只是“提示词加模型”这是整个SDK最基础也最核心的概念。一个Agent实例可以简单理解成一个带有专属指令和工具列表的“员工”。你在初始化的时候需要给它指定用哪个模型、系统指令是什么、它能调用哪些工具。官方SDK里的Agent还有可选的name和description字段名字别说description在多Agent协作的时候非常关键因为系统依赖它来决定把任务转给谁。很多人把它理解为“包装好的Prompt模板”这个理解不算错但不够准确。Agent实际上承担了任务执行循环你调用Agent的run方法后SDK会在内部不断检查模型输出如果是文本就返回结果如果触发工具调用就自动执行工具并把结果传回模型。这个过程你不用写任何while循环SDK的Runner模块替你把这件事做了。举个我自己写的例子这个Agent负责处理用户的订单查询请求from agents import Agent, Runner order_agent Agent( name订单助手, instructions你是电商平台的订单客服助手负责查询订单状态。 回答时应先调用查询工具拿到真实结果后再回复用户。 如果订单号格式不对请让用户提供正确的订单号。, modelgpt-4o-mini, tools[get_order_status], ) result Runner.run_sync( starting_agentorder_agent, input订单号10086现在是什么状态 ) print(result.final_output)这个Agent里面注入了工具函数get_order_statusSDK在识别到调用意图后会自动执行然后把结果回传给模型继续推理。整段代码的核心工作就是把“工具调用循环”藏了起来而这也正是它最大的价值让你的业务逻辑和模型交互逻辑彻底解耦。2.2 Handoff多Agent协作的关键机制Handoff是我最开始看文档时觉得有点抽象、实际跑通后觉得特别巧妙的一个机制。大致含义是当前Agent发现自己不适合处理某个任务时可以主动“交接”给另一个Agent。这不是简单的函数调用而是一种语义级的任务转移——Agent可以根据用户在对话中表达的需求自己判断把控制权交给哪个更合适的Agent。这种机制和传统的“路由”有本质区别。路由是预先写死规则——“如果用户说退款就跳到退款Agent”但Handoff是让模型根据上下文自主选择交接目标。它不只是分发请求还会把当前对话上下文一并带过去下一个Agent可以无缝接着处理。这个设计理念很贴近人类团队协作方式一个小助理发现自己不熟悉某个问题主动把客户转给相应同事同时说明一下情况而不是让客户换个窗口重新描述一遍。2.3 Guardrail给Agent加上安全检查用过Agent的开发朋友肯定有共鸣模型在复杂的多轮任务里经常会出现“跑偏”的情况比如突然回答起与当前场景无关的问题或者在执行某个关键动作前缺乏必要的校验。Agents SDK里的Guardrail就是专门针对这个问题的内置机制。它分为输入Guardrail和输出Guardrail两种。输入Guardrail在Agent正式处理之前先做一轮内容审核输出Guardrail在Agent生成最终答案之前做一次质量把关。这个机制特别适合用在“客服场景”——用户在对话开始前如果已经带有恶意意图你完全可以在输入Guardrail阶段就拦截或者用规则约束不让Agent访问某些敏感能力。用一个不太恰当的比喻Guardrail就像给Agent装了一道安检门不是每个问题都能直接走到模型面前。2.4 Session对话上下文的透明管理做Agent应用的人都知道上下文管理是最容易出问题的环节。会话太长会导致Token超限太短又容易丢失关键信息。Agents SDK引入Session来做状态管理一个Session里可以包含多轮对话的完整历史你可以把它理解为“一段有记忆的对话周期”。它把Chat Completions时代必须自己管理的messages数组、历史截断和上下文窗口策略都交给SDK来处理了。这个设计直接催生了另一梯队的能力——现在可以按Session维度做会话持久化与恢复这在多轮真实业务场景里非常实用。2.5 Execution一套完整运行追踪体系最后要提的是Execution层。如果你调试过复杂的Agent应用一定体会过“整个过程是个黑盒”的崩溃感——模型明明调了好几次工具每次调用的参数是什么、返回了什么你根本看不到。Agents SDK内置了Tracing机制跑完一次任务之后你能在官方Dashboard上看到完整的执行轨迹模型推理了哪几步、调用了哪些工具、每步耗时多少、有没有报错。对开发者调试复杂链路来说这个特性带来的收益比我预期大得多。3. 环境准备与第一个Agent的完整落地3.1 安装与版本选择别用太旧的Python我在写这篇文章的时候openai-agents这个Python包已经可以在PyPI上直接安装。先说明一下官方建议使用Python 3.9及以上版本但我个人更推荐直接用3.11或3.12主要是因为新版SDK迭代比较快有些内部依赖对老版本Python的支持越来越弱。装包的命令很简单pip install openai-agents如果你在用uv或者poetry直接用你习惯的方式加依赖就行。最稳妥的确认方式是在终端跑一下python -c import agents; print(agents.__version__)能正常输出版本号就说明安装成功了。这里提醒一句这个SDK还在快速迭代阶段小版本之间偶尔会有API变动所以如果你是照着网上的旧教程写代码发现报错先去查一下版本更新日志很多时候不是你的代码写错了是API改了名字。3.2 API Key配置开发环境的正确姿势这个步骤比较基础但很多人仍会踩坑。Agents SDK底层依赖OpenAI的API所以你需要一个有效的API Key。一些朋友喜欢直接在代码里写key我必须强调这样一点都不安全哪天仓库传到GitHub上密钥泄露了你就知道疼了。更规范的做法是设置环境变量export OPENAI_API_KEYsk-...代码内部会自动读取这个环境变量不需要你显式传入。如果你用的是兼容接口的国产模型或私有化部署端点也可以单独设置base_url之类的参数。这属于进阶玩法我们在后面具体场景里再展开。3.3 写一个真实的Agent把工具调用跑起来环境准备完毕我直接写一个复杂度恰到好处的示例——一个能查天气并能根据结果给出出行建议的Agent。它要调用一个模拟的天气API工具然后把原始天气数据加工成用户能看懂的出行建议。工具函数长这样import asyncio from typing import Literal from agents import Agent, Runner, function_tool function_tool async def get_weather(city: str) - dict: 获取指定城市的当前天气状况 # 这里应该是真实天气API的调用 # 为了演示方便直接返回模拟数据 weather_map { 北京: {temperature: 32, condition: 晴, humidity: 40}, 上海: {temperature: 28, condition: 小雨, humidity: 75}, 广州: {temperature: 30, condition: 多云, humidity: 65}, } return weather_map.get(city, {temperature: 25, condition: 未知, humidity: 50})然后定义一个带这个工具的Agenttravel_agent Agent( name出行助手, instructions你是一个贴心的出行建议助手。收到天气数据后 要结合温度、降水等情况给出简洁的出行建议 例如是否建议带伞、时间安排等。, modelgpt-4o-mini, tools[get_weather], ) async def main(): result await Runner.run( starting_agenttravel_agent, input{query: 上海今天天气怎么样适合出门吗}, ) print(result.final_output) if __name__ __main__: asyncio.run(main())第一次跑通这段代码的感觉说句实话有点微妙——就是那种“诶这就完了不用写循环”的体验。模型自己去调工具、自己去总结、自己生成最终答案。你可以对比一下自己之前用Completions接口写的工具调用代码那种喜悦感会更明显。3.4 同步还是异步按你项目的需要来上面代码里用到了asyncio.run和Runner.run这是异步接口。SDK同时提供了同步版本Runner.run_sync。在大多数Web服务的场景我推荐直接用异步版本配合FastAPI这类异步框架不会阻塞事件循环但你如果只是在Jupyter Notebook里做实验用run_sync更方便。还有一个经验如果Agent链路里涉及多个外部API请求尽量不要在工具函数里用阻塞式的requests库用httpx的async版本会合适得多整体性能差距在并发场景下非常明显。4. Handoff与Session多Agent协作与状态流转的正确姿势4.1 用Handoff搭一个客服中心从单Agent扩展到多Agent单Agent写通了立刻要面对的问题是真实业务往往不是一个人能搞定的。我在一个电商客服Demo里试过这样的场景用户既想问订单又想退货还突然关心物流配送进度。如果让一个Agent处理所有问题指令会越来越长还容易混乱如果写一堆规则去路由维护成本又很高。这时Handoff就是最合理的解法。我创建了三个Agent每个负责一个业务域然后让一个“客服接待”Agent根据用户的意图主动把会话转移给对应专员from agents import Agent, Runner, handoff order_agent Agent( name订单专员, instructions你负责查询订单状态、修改收货地址等订单类问题。, tools[get_order_status, update_address], ) refund_agent Agent( name退款专员, instructions你负责处理退款申请、退货进度查询等售后问题。, tools[apply_refund, get_refund_progress], ) logistics_agent Agent( name物流专员, instructions你负责查询物流轨迹、预计送达时间等问题。, tools[get_logistics_info], ) triage_agent Agent( name客服接待, instructions你是客服总入口。先判断用户的诉求归属 订单问题转给订单专员售后退款转给退款专员 物流问题转给物流专员。, handoffs[order_agent, refund_agent, logistics_agent], )这里的关键在于客服接待Agent的handoffs参数里声明了三个可用的交接目标。SDK在对话循环中会把“当前话题是否应该由另一个Agent处理”的判断交给模型模型自己决定什么时候发起Handoff。我在跑这个Demo的时候测试了十几条不同类型的用户消息除了个别语义模糊的长句外大部分路由判断都比较准确。相比我过去写if-else规则去匹配关键词这种基于模型语义理解的路由方式明显更接近“智能客服”该有的样子。4.2 Session到底怎么用维护多轮对话记忆Session是另一个值得单独强调的概念。我之前在做多轮客服项目时最头疼的就是怎么跨轮次保存用户意图。自己存messages数组的话每轮都要手动拼接历史Token一长还要自己实现截断策略。Agents SDK把这件事简化为Session对象的存取。当你在Web服务里集成时可以在每次新用户请求里手动构建Session并传入之前保存的Session ID也可以基于Session生命周期做持久化。这里有个非常重要的建议不要把所有东西都往Session里塞。Session存在的意义是把多轮上下文理顺不是当垃圾桶。无关的缓存数据、大段日志、临时变量都塞进去不仅增加Token消耗还会干扰模型对当前意图的判断。我在项目里一般只把用户-助手交替的对话消息和必要的业务标识放进去。4.3 多Agent协作的两种典型模式用了一段时间下来我总结出两种比较典型的多Agent组织模式你也可以按这个思路去设计自己的Agent架构路由模式一个总入口Agent负责判断用户诉求再通过Handoff转给不同的领域Agent。各领域Agent相互独立互不感知。适合客服、工单分类这种“多个垂直领域并行”的业务。流水线模式多个Agent按固定顺序接力处理同一个任务。前一个Agent的输出作为后一个Agent的输入。适合内容生产类流程比如先由策划Agent生成大纲然后交给写作Agent展开成文最后由校对Agent润色。流水线模式在Agents SDK里没有专门的关键字但你可以用函数编排的方式把多次Runner.run接起来等于是用代码做流程编排。就我的感受而言路由模式是Agents SDK最有代表性的天然优势因为它内建了Handoff机制根本不用自己写分支判断。流水线模式反而是任何框架都能做的事区别只在于你愿不愿意多写几行代码。5. 两轮实测下来必须提醒的坑与优化思路5.1 模型选择别一上来就上旗舰模型这是第一个坑也是我见过最多人踩的。很多新手拿到SDK就默认用gpt-4o其实很多Agent任务用gpt-4o-mini就能跑得又快又稳尤其是在Agent内部单次“推理工具选择”都不复杂的情况下。如果你的Agent主要做路由判断、简单工具调用、格式化输出mini模型足够只有涉及复杂逻辑推理、长文档总结、多步规划时才值得上更强模型。这个建议背后是实打实的经济账Agent任务和单次Chat Completion不一样它内部会跑好几轮模型推理每调用一次工具就多一轮Token消耗是肉眼可见的速度增长。选错模型不只是变慢账单数字也起得飞快。5.2 API版本锁定SDK快速迭代期的重要经验我第一轮跑通以后隔了一周再去更新依赖发现个别接口签名已经变了原本的写法开始报警告。这也侧面说明这个SDK确实还在快速演进期。在正式项目里我会在requirements.txt里直接锁死版本号比如openai-agents0.0.x而不是用这种宽松写法。否则哪天CI/CD流水线重新装依赖直接给你装出一个不兼容的新版本整个服务原地爆炸。升级当然要升但该在你可控的窗口里主动去升而不是被动地被依赖解析出问题。5.3 Guardrail别只防外部攻击更要管住Agent自己很多人觉得Guardrail是安全组件用来防恶意用户的。这个理解没问题但它同时也是一个“行为纠正器”。在实际项目中我发现输出Guardrail更适合用来约束Agent的自我发挥空间。比如我们规定Agent只能使用规定的工具、只能在拿到真实查询结果后才能回答超出这些边界就判定为不合格输出并触发一次重新生成。这比你在instructions里反复强调要可靠得多——模型确实会遗忘你说的“规则”但Guardrail是代码层面的硬约束它不会忘。5.4 工具函数的输入参数越严格越好最后还想提醒一个特别容易被忽视的点工具函数的类型注解和docstring直接决定了模型能不能正确调用工具。我实测下来如果get_weather这个函数的参数类型写成str模型倒也不会出错但如果你的参数是一个复杂结构比如嵌套的dict而你没有把字段结构写清楚模型调用时大概率会传错字段名然后得到一个莫名其妙的报错。比较好的做法是能用简单类型就用简单类型需要传JSON对象时就用Pydantic定义一个输入模型。这让模型对参数结构的理解变得更准确从“靠猜”升级为“照着说明书做”。工具调用出错很多时候真的不是模型不行而是你给它的工具说明书写得太敷衍了。从决定All in这个SDK到把第一版Demo跑起来前后我大概花了一个多星期。印象最深的一点是OpenAI设计这套SDK时是真的站在了“开发者日常开发流程中会抱怨什么”的角度把状态循环、会话管理、Agent交接这些被重复处理了无数遍的事情抽了出来。但工具终究只是工具它能帮你省掉样板代码却不能替你设计Agent的策略组合。搭好脚手架的下一步就是在上面盖出真正适配你业务的房子。系列第二篇我打算重点聊聊Agent的工具编排和外部API接入实战比如怎么给Agent设计一套能处理复杂业务参数的Tool接口、怎么样用更结构化的方式组织多Agent协作的上下文——这些才是把SDK用出生产力的地方。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进