☰
OpenAI Agents SDK 实战:多智能体编排与工具调用核心要点解析
2026/10/1 4:49:32 网站建设 项目流程

2. 核心细节解析与实操要点

不要急着一上来就堆代码。OpenAI Agents SDK 整个设计里,有不少细节是文档里一笔带过、但在实际工程里非常影响体验的。我先挑几个最关键的说一下。

2.1 为什么是“Agent”而不是纯“Function Call”

如果你以前接过 OpenAI 的 API,可能用过 function calling。说白了就是给模型一张函数清单,模型看着任务选出合适的函数调用,然后你当作工具函数执行,把结果回填给模型。这套流程本身没什么问题,但一旦任务复杂起来,你会发现自己在“手写循环”这件事上花的时间越来越多,比如:

  • 维护对话历史轮次;
  • 判断模型什么时候该结束、什么时候该继续调工具;
  • 自己拼 system prompt,反复强调“你要用工具、你要一步步思考”;
  • 自己处理函数返回结果的异常情况;
  • 多个工具互相依赖,还要设计一个复杂的有限状态机去推动。

Agents SDK 本质上把这套过程全部封装了。你在代码里定义一个 Agent,也就是一个带有 system prompt、可用的 tool 列表、以及模型配置的“智能体实体”。当用户输入进来,SDK 内部会帮你跑一个循环:模型生成文本或调用工具 → 如有工具调用就执行对应函数 → 把工具结果再交还给模型 → 直到模型给出最终回复或达到限制条件。开发者只需要关心“每个 tool 的函数是什么”,不用再写状态机。

这就像一个餐厅老板不用自己去后厨盯每一道菜的火候,只要把菜单(工具清单)交给厨师(Agent),厨师自然会统筹全局。手写 function calling 相当于老板自己端个锅在那里翻炒,不仅累,菜多了绝对翻车。

2.2 三种构建模式的取舍

我翻了不少资料,也在自己项目里试过,目前主流的构建方式有三类。我把它们的差异整理成了一张表,方便你按项目情况选:

模式适用场景优点缺点
单个 Agent + 多个工具任务清晰、领域单一开发量最小,调试容易,响应速度有保障功能一旦变多,prompt 越来越长,容易混乱
多 Agent 协作(Router + 子 Agent)任务横跨多个子领域,需要分工各 Agent prompt 专注、职责单一,扩展性强编排逻辑复杂,上下文管理要仔细设计
嵌套 Agent(工具化子 Agent)某一个环节是完整子流程,需要独立决策隔离性好,子流程变更不影响主流程多一层调度耗时,必须设置合理的迭代上限

我个人的建议是:先从单 Agent 开始跑通流程,等发现 prompt 已经膨胀到不好维护,再拆多 Agent。不要一开始就为了“架构好看”堆出十多个 Agent,不然调试的时候你会怀疑人生。

2.3 配置模型与 API Key 时容易踩的坑

这个系列前面几篇肯定已经提过环境配置的事情,我这里补充三个容易踩的坑:

第一,模型名称别写错。使用 Agents SDK 时,OpenAI 官方模型建议使用gpt-4o、gpt-4o-mini、gpt-4.1这类精确名称,不要带“-turbo”或者空格。写错模型名,openai 接口会直接给一个 model not found 的异常,但 SDK 的报错未必第一时间就让你看出来,有时候会被包在 stream 中间,让你误以为是网络问题。

第二,API Key 不要硬编码。很多教程示例里会写“直接把 key 塞到代码里”,为了跑通没问题,但只要是准备长期维护的项目,建议用环境变量或者本地配置文件管理。之前见过有同学把一个包含了真实 key 的 jupyter notebook 直接提交到公开仓库,几分钟内账号就被盗刷了。做开源项目或者教程演示时,务必用.env文件加.gitignore屏蔽掉。

第三,代理与超时问题。使用 OpenAI 服务时,网络连通性、超时设置是很多初学者卡壳的地方。你要是调用量不大,SDK 默认超时一般够用,但如果你在代码里做批量任务,建议显式设置超时和重试策略。关于访问 OpenAI 的基础网络条件这里不做展开,你需要确保运行环境本身能够正常访问相关的 API 服务即可。

3. 实操过程与核心环节实现

这一部分我带大家完整跑通两个实战场景:第一个是“多 Agent 协作的智能体”,第二个是“带生命周期事件监控的 Agent”。这两个案例覆盖了编排、工具调用、事件监听等核心环节,你跟着做一遍,基本就能把这套 SDK 的套路摸个七八成。

3.1 实战一:多 Agent 协作编排

先看需求。我们做一个“智能客服助手”,面对用户提问时,系统需要先识别这个问题属于“订单咨询”还是“商品推荐”,然后分发给专门的子 Agent 处理。传统单 Agent 做法是把所有能力全塞到一个 prompt,但那样回复质量不稳定。所以我们这里用主 Agent 做路由,两个子 Agent 各管一块。

主 Agent 的 system prompt 大约长这样:

你是一个智能客服调度员。你的职责是根据用户的问题,选择调用合适的处理 Agent 来响应用户。 当用户询问订单相关问题时,调用 order_agent; 当用户询问商品推荐问题时,调用 recommendation_agent; 如果用户的问题不在上述范围内,你可以直接礼貌地回复无法处理。

这个 prompt 本质上是在告诉主 Agent 什么时候应该把控制权交出去。接下来在代码里,我们把两个子 Agent 用handoffs参数挂到主 Agent 上。

import asyncio from agents import Agent, Runner order_agent = Agent( name="order_agent", instructions="你是订单处理专员。你可以查询订单状态、修改订单、处理退换货。回答专业简洁。", tools=[query_order_tool, cancel_order_tool], ) recommendation_agent = Agent( name="recommendation_agent", instructions="你是商品推荐专员。根据用户的兴趣和预算推荐合适的商品。", tools=[search_product_tool], ) triage_agent = Agent( name="triage_agent", instructions="你是智能客服调度员。根据用户的问题选择将对话移交给合适的专员。", handoffs=[order_agent, recommendation_agent], ) async def main(): result = await Runner.run( triage_agent, "你好,我想查一下昨天买的手机现在送到哪里了?", ) print(result.final_output) if __name__ == "__main__": asyncio.run(main())

这套代码跑起来之后,你会看到流程大致是:

用户提问 → 主 Agent 接住 → 判断属于订单类问题 → 转交 order_agent → order_agent 调用查询工具 → 拿到物流信息 → 回复用户。

整个调度过程对用户来说是无感的,但每个子 Agent 的 prompt 都保持了足够的专注度。订单 Agent 不需要关心推荐算法,推荐 Agent 也不需要关心订单表结构。

这里有一个经验:子 Agent 的描述(name 和 instructions)一定要写得口语化、意图明确,因为主 Agent 决定“交给谁”时,看的不是函数名,而是这套描述。很多人最初会把子 Agent 的 instructions 写成“你是订单处理专员,负责查询订单”,但主 Agent 对这个职位的业务边界理解不深,就可能导致路由不准。更好的写法是描述这个 Agent 擅长接收什么类型的任务,比如:

“当用户想查询订单状态、修改配送地址、申请退款时,优先使用该 Agent。”

这种写法,主 Agent 更容易把握。

3.2 实战二:配置生命周期事件监听

很多时候我们需要知道 Agent 内部到底发生了什么,尤其是调用工具这个过程,调试时两眼一抹黑非常痛苦。Agents SDK 提供了事件监听机制,你可以拿到智能体运行过程中的每一个关键节点。

下面这段代码演示了如何监听工具调用事件和智能体更新事件:

from agents import Agent, Runner, AgentHooks, ToolCallItem class DebugHooks(AgentHooks): async def on_agent_start(self, agent, input): print(f"[Agent 开始] {agent.name} 收到输入: {input}") async def on_tool_call(self, agent, tool_call: ToolCallItem): print(f"[工具调用] {agent.name} 调用工具: {tool_call.tool_call.function.name}") async def on_tool_response(self, agent, tool_call: ToolCallItem, response): print(f"[工具返回] {agent.name} 收到返回: {str(response)[:100]}") agent = Agent( name="debug_agent", instructions="你是一个测试 Agent。", tools=[get_weather], hooks=DebugHooks(), ) result = await Runner.run(agent, "北京今天天气怎么样?")

加了 hooks 之后,每次 Agent 运行时都会输出各个阶段的日志。这在排查“为什么 Agent 没有调用工具”或者“工具返回后模型没有正确使用结果”时,价值非常高。

比如你发现工具明明被调用了,但最终输出却没有使用工具结果。这时候你看 on_tool_response 里返回的内容,如果返回内容过长被截断,模型可能没有拿到完整信息。这时候你就需要优化工具返回内容的长度,而不是怀疑模型变笨了。

3.3 关键参数选择与计算

跑 Agent 的时候,有几个参数直接影响运行效果:

  • 模型温度(temperature):控制输出的随机性。如果你做的是客服、代码生成这种追求准确度的场景,建议设置在 0.2 左右。如果做文案创意,可以拉到 0.7 ~ 0.9。默认值往往是 1.0,对很多业务场景来说过于自由了。

  • 最大迭代次数(max_turns):这代表 Agent 一轮运行中,最多可以执行多少轮工具调用和模型生成。设得太小容易截断复杂任务,设得太大可能进入工具循环死循环。我一般从 5 起步,复杂任务再调高到 10。特别注意,嵌套 Agent 调用时,这个参数要分开设,主 Agent 转交流程也要消耗轮次。

  • 上下文预算(context_length):如果你的工具返回结果都很大,建议在工具内部先做截断或摘要,而不是直接塞给模型。之前处理一个内部数据查询工具时,原始接口返回有 20000 多 token,直接传给模型,不仅慢,还挤占了输出空间。后来我在工具函数里做了 JSON 精简摘要,整个 Agent 的响应速度提升了几倍。

4. 常见问题与排查技巧实录

4.1 排查思路:从报错信息倒推

我在使用这套 SDK 的过程中,见过最多的三类报错,先列出来:

第一类:model not found。这通常是模型名写错了,或者运行环境无法访问指定模型。解决办法是先单独用 openai 官方客户端测试一下给定的模型名能否出结果,再回到 SDK 排查。

第二类:tool_call_id mismatch。这类报错一般出现在你手动拼接工具调用上下文的时候。正常情况下 SDK 会自动处理,如果你非要自己组装 message,就很容易把 id 对不上。

第三类:迭代上限触发(max_turns reached)。代表 Agent 在达到最大迭代轮数时还没有得出结论。这不一定意味着失败,有时只是任务太重。你可以提高轮数,也可以精简工具数量,让模型更快聚焦。

4.2 工具函数返回内容过长的处理

工具函数返回给模型的内容,会整体被纳入上下文。有些工具爱返回超长 JSON,然后模型会出现两种问题:一是丢失重点信息,二是响应超时。

我的做法是设计一套“摘要优先”策略:

async def query_order_tool(order_id: str) -> str: """查询订单详情,返回摘要。""" raw_data = await fetch_order_raw(order_id) # 原始数据可能是全量 JSON summary = { "order_id": raw_data.get("order_id"), "status": raw_data.get("status"), "logistics": raw_data.get("logistics", {}).get("current_location"), "eta": raw_data.get("logistics", {}).get("estimated_time"), } return json.dumps(summary, ensure_ascii=False)

这样模型拿到的全是有用的信息。如果模型后续还追问“配送员电话”,你可以在函数里判断请求参数再补充返回。

4.3 Agents SDK 常见问题速查表

问题现象可能原因解决办法
Agent 调用工具后直接结束,没有用结果工具返回内容过长被截断精简返回内容,使用摘要优先策略
多 Agent 协作时路由不准确子 Agent instructions 描述不够明确在 instructions 里写明触发场景
一直循环调用同一个工具模型无法从工具结果中找到目标信息检查工具返回是否有遗漏字段
事件监听没有输出hooks 挂错对象将 hooks 挂在具体的 Agent 实例上,而不是 Runner
使用本地模型时报错兼容层配置问题不展开,建议优先使用官方兼容方案

4.4 调试技巧:把 prompt 当作日志打出来

最后分享一个我自己的调试习惯。排查 Agent 行为问题时,我喜欢在事件回调里把每个关键时刻的 prompt 和输入打印出来。这样做的好处是,你能确切地看到模型每轮看到的上下文,而不仅仅是猜测。

比如我遇到过一个问题:主 Agent 在路由时经常把商品咨询订单也转给订单 Agent。我一开始以为是 instructions 写得不够详尽,后来通过 hook 打出主 Agent 收到的完整上下文才发现,是因为多轮对话时历史消息里先出现了“我想退货”,导致模型产生了先入为主的判断。这种情况靠调整 prompt 很难解决,我最后是把话题分类逻辑改成了先调用一个意图识别工具,再把结果作为上下文传给主 Agent。问题立即解决了。

如果你想深入排查这类与历史意图相关的问题,建议养成记录对话历史的习惯,在每次路由前打印出最近几轮的消息摘要,很快可以定位到模型做判断的“有效上下文”到底是什么。

5. 从 Demo 到可维护工程的进阶思考

把 Demo 跑通和把项目上线之间,隔着一条很深的河。如果你只是个人实验,上文的内容已经足够。但如果想把这个智能体接到实际业务里,还有几个方向值得投入精力。

5.1 Prompt 管理服务化

不要把所有 Agent 的 instructions 都硬编码在代码中。我的做法是放一个配置中心或 JSON 配置文件,每个 Agent 的 name、instructions、模型参数都抽离出来。这样产品经理直接改配置就能调整话术,不用每次改动都发版本。

配置文件大致长这样:

{ "agents": [ { "name": "order_agent", "instructions": "你是订单处理专员,擅长查询订单、处理退款...", "model": "gpt-4o", "temperature": 0.2 } ] }

代码加载配置后动态创建 Agent:

def create_agent_from_config(config): return Agent( name=config["name"], instructions=config["instructions"], model=config["model"], model_settings={"temperature": config["temperature"]}, )

这样一来,“改 prompt”和“改代码”彻底分开了。对非技术背景的同事非常友好。

5.2 可观测性与日志系统

上文讲过 hooks 回调,这不仅是调试工具,更是生产环境的日志系统。你可以把每个事件上报到日志平台,包括:

  • 每次 Agent 运行的输入与输出;
  • 每次工具调用的耗时和返回大小;
  • 每次转交路由的关键路径;
  • 每次模型响应延迟。

这些数据积累起来后,你可以进一步分析用户提问的意图分布、工具的失败率、模型的响应延迟趋势。有了数据,后续做性能优化和体验迭代就心里有数了。这里顺便提一句:很多真实项目中,“智能体效果不好”其实并不是模型能力差,而是工具调用链路不够稳定。先观测,再优化,顺序千万不要反过来。

5.3 多 Agent 协作的几条铁律

我自己在实际项目中总结了几条经验,算不上什么高深理论,但确实能帮你少走弯路。

第一条:子 Agent 职责要正交。不要让订单 Agent 和商品 Agent 都能调用同一个“查询订单”工具。职责交叉会让主 Agent 的决策注意力被分散,路由就不稳定。你希望每一步决策都尽可能无歧义。

第二条:主 Agent 的 prompt 不需要写太多业务规则,重点是“何时转交”和“何时直接回复”。很多调度的细节,子 Agent 内部自然会处理。主 Agent 就像一个客服前台,只需要知道找谁,不需要知道具体怎么解决问题。

第三条:嵌套 Agent 的层数不要超过三层。层数越深,单次请求的耗时越长,出问题的概率也越高。如果你发现需要四层以上的嵌套,优先检讨是不是职责划分出了问题。

第四条:给 Agent 设置合理的 max_turns,防止子 Agent 在某一步沦入反复调工具的死循环。这个问题我在生产环境里真正遇到过,一开始排查方向错了,以为是工具函数并行问题,后来发现其实就是模型在情绪化地反复重试。加上迭代上限之后,整个链路的稳定性提升非常明显。

6. 工具选型与扩展能力分析

6.1 如何选择模型与参数

有人问:我应该全用 gpt-4o 还是采用混合配置?我的答案是看你每个环节对延迟和质量的敏感度。

角色推荐模型温度原因
主路由 Agentgpt-4o-mini0.0路由判断不需要想象力,低延迟优先
专业处理 Agentgpt-4o0.2 ~ 0.4需要一定的推理深度和工具结果准确性
创意文案 Agentgpt-4o 或带视觉能力模型0.7 ~ 0.9让模型有更多表达空间

上面这个表是团队项目里常用的默认配置。如果你手里的预算有限,路由 Agent 用 mini 版本能省很多成本,毕竟它的任务最轻,大多只是输出一个选择结果。真正贵的是专业处理 Agent,因为工具调用会消耗较多 token。合理分配模型资源,对整体成本的影响非常可观。

6.2 Agent 与 Coding Agent 的叠加

如果你本身就是程序员,还可以把 Agent 构建这件事和编码工具组合使用。比如在构建一个复杂的 Agent 应用时,先用现成的命令行编程助手快速生成脚手架,再手动修改业务逻辑。两者各管一段:Coding Agent 负责写代码模板,你自己的编排负责业务正确性。这种工作流是我目前觉得效率最高的方式,但注意别把 Coding Agent 生成的代码直接当作最终交付,一定要过一遍 code review。

6.3 生态扩展能力速查

需求可用方向
工具调用SDK 原生工具函数、MCP 集成、WebSearch 工具
多模型支撑通过兼容层接入本地模型或闭源大模型
长期记忆外部向量数据库 + 对话摘要机制
视觉理解支持图像输入的多模态模型
语音对话结合实时语音识别与文本大模型

这个生态里,我认为最值得关注的是 MCP 集成。它相当于给 Agent 提供了一个标准化的“接入总线”,理论上企业内部已有的服务都可以通过 MCP 描述给模型。SDK 对 MCP 的关照程度不低,如果你准备在企业内部落地智能体,这个方向迟早要研究。

6.4 适合延伸的方向

最后说两个我觉得很有前景的延伸方向:

一个是“主动型 Agent(Proactive Agent)”。之前的智能体大多是“你问我答”的被动响应,但在企业场景里,Agent 其实可以主动扫描工单、检测异常、推送提醒。这类使用方式需要把事件驱动架构和 Agent 运行机制结合起来,SDK 的生命周期回调正好提供了切入点。

另一个是“群组协作智能体(Group Agents)”。单个 Agent 遇到超大型任务时,可以让多个 Agent 并行执行不同模块,最后统一汇总。这非常考验消息传递和状态管理,但一旦跑通,产能提升是质的飞跃。如果你准备向这个方向探索,建议先把本文讲到的多 Agent 路由和工具内聚稳扎稳打地练好,再谈并行协作,不要一上来就把系统搞得太复杂。

我现在正在自己的开源项目里实践“事件总线 + 群组 Agent”的架构,等有阶段性成果了,再来给大家更新这个系列的第五篇。回见。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询