Python调用OpenAI Agents SDK打造一个多智能体系统
作者:Halcyon.平安

引言
2025年初,OpenAI发布了 Agents SDK(openai-agents),一个专为Python开发者设计的多智能体框架。与LangGraph的图抽象、CrewAI的角色编排不同,Agents SDK走了一条更直觉的路线:纯Python、零DSL、开箱即用。
截至目前,该SDK在GitHub上已获得超过 23,000 Stars,版本迭代至 v0.14.2,成为2026年增长最快的Agent框架之一。
本文将带你从零开始,用Agents SDK构建一个完整的智能购物助手——包含路由分诊、专家协作、安全护栏、运行追踪等完整功能。
一、核心架构概览
Agents SDK 的九大核心概念
在开始编码之前,先理解SDK的设计哲学。Agents SDK围绕9个核心概念构建:

三种多智能体编排模式
SDK提供了三种编排多Agent的模式,适用于不同场景:

| 模式 | 适用场景 | 特点 | 控制权 |
|---|---|---|---|
| Manager | 需要汇总多个Agent结果 | 中心化协调 | Manager持有 |
| Handoff | 专家应直接面对用户 | 去中心化交接 | 转移给专家 |
| Code Orchestration | 确定性流程控制 | Python代码编排 | 开发者控制 |
二、环境搭建
安装SDK
# 创建虚拟环境 python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 安装 Agents SDK pip install openai-agents # 验证安装 python -c "import agents; print(agents.__version__)" # 输出: 0.14.2
配置API Key
import os # 方式1: 环境变量 os.environ["OPENAI_API_KEY"] = "sk-your-api-key-here" # 方式2: .env 文件(推荐) # 在项目根目录创建 .env 文件: # OPENAI_API_KEY=sk-your-api-key-here
最简示例:Hello Agent
在深入复杂场景之前,先跑通最简单的例子:
import asyncio
from agents import Agent, Runner
async def main():
# 创建一个Agent —— 就这么简单
agent = Agent(
name="Haiku Master",
instructions="你只使用俳句格式回答问题。俳句是5-7-5音节的三行诗。",
)
# 运行Agent
result = await Runner.run(agent, "用Python写递归是什么感觉?")
print(result.final_output)
# 输出:
# 函数调自身,
# 分解问题为小块,
# 无尽由设计。
if __name__ == "__main__":
asyncio.run(main)
Agent执行循环:Runner.run() 启动后,SDK会执行一个循环——调用LLM、处理工具调用、处理交接,直到LLM产生最终输出或达到最大轮次。
三、实战:构建智能购物助手
现在进入正题。我们将构建一个包含以下功能的智能购物助手:

Step 1: 定义共享上下文
所有Agent共享同一个上下文对象,用于传递状态:
from pydantic import BaseModel
class ShoppingContext(BaseModel):
"""购物助手的共享上下文"""
customer_id: str | None = None
customer_name: str | None = None
order_id: str | None = None
cart_items: list[str] = []
is_premium_user: bool = False
Step 2: 定义工具(Tools)
工具是Agent的"手"——让它能与外部世界交互:
import random
from agents import RunContextWrapper, function_tool
# ===== 商品相关工具 =====
@function_tool
async def search_products(query: str) -> str:
"""搜索商品。query是搜索关键词。"""
# 实际项目中这里连接搜索引擎或数据库
mock_products = {
"手机": "iPhone 16 Pro (¥8,999), Samsung S26 (¥6,999), Xiaomi 16 (¥3,499)",
"笔记本": "MacBook Pro M5 (¥14,999), ThinkPad X1 (¥9,999), Surface Laptop (¥8,999)",
"耳机": "AirPods Pro 3 (¥1,899), Sony WH-1000XM6 (¥2,499), Bose QC Ultra (¥2,299)",
}
for keyword, products in mock_products.items():
if keyword in query:
return f"找到以下商品: {products}"
return f"未找到与 '{query}' 相关的商品,试试其他关键词?"
@function_tool
async def get_product_detail(product_name: str) -> str:
"""获取商品详情。product_name是商品名称。"""
details = {
"iPhone 16 Pro": "A20芯片 | 6.3英寸 | 4800万像素 | 256GB起 | 电池续航30小时",
"MacBook Pro M5": "M5芯片 | 16英寸 | 36GB内存 | 512GB SSD | 续航24小时",
}
return details.get(product_name, f"商品 '{product_name}' 详情: 评分4.8 | 月销10000+ | 好评率98%")
@function_tool
async def add_to_cart(
context: RunContextWrapper[ShoppingContext],
product_name: str,
quantity: int = 1
) -> str:
"""将商品加入购物车。"""
context.context.cart_items.append(f"{product_name} x{quantity}")
return (f"已将 {product_name} x{quantity} 加入购物车。"
f"当前购物车: {', '.join(context.context.cart_items)}")
# ===== 订单相关工具 =====
@function_tool
async def check_order_status(
context: RunContextWrapper[ShoppingContext],
order_id: str
) -> str:
"""查询订单状态。order_id是订单号。"""
context.context.order_id = order_id
statuses = ["已发货", "运输中", "派送中", "已签收"]
status = random.choice(statuses)
return f"订单 {order_id} 状态: {status}。预计到达: 明天下午。"
@function_tool
async def process_refund(
context: RunContextWrapper[ShoppingContext],
order_id: str,
reason: str
) -> str:
"""处理退款。order_id是订单号,reason是退款原因。"""
if context.context.is_premium_user:
return f"VIP用户优先退款已提交!订单 {order_id},原因: {reason}。退款将在1-2个工作日内到账。"
return f"退款已提交!订单 {order_id},原因: {reason}。退款将在3-5个工作日内到账。"
@function_tool
async def track_package(order_id: str) -> str:
"""追踪包裹物流。"""
locations = ["北京分拣中心", "上海转运站", "杭州配送站", "客户所在城市"]
location = random.choice(locations)
return f"订单 {order_id} 最新位置: {location}。更新时间: 10分钟前。"
Step 3: 定义安全护栏(Guardrails)
护栏是Agent的"安全带"——防止越界行为:
from pydantic import BaseModel, Field
from agents import (
GuardrailFunctionOutput, InputGuardrailTripwireTriggered,
RunContextWrapper, TResponseInputItem, Agent, Runner,
input_guardrail,
)
# ===== 输入护栏: 检查是否为购物相关问题 =====
class RelevanceCheck(BaseModel):
is_shopping_related: bool = Field(description="是否与购物/商品/订单相关")
reasoning: str = Field(description="判断理由")
guardrail_agent = Agent(
name="Relevance Guard",
instructions="""判断用户输入是否与以下领域相关:
- 商品搜索与推荐
- 订单查询与物流
- 退款与售后
- 购物咨询
如果完全无关,标记为不相关。""",
output_type=RelevanceCheck,
)
@input_guardrail
async def shopping_relevance_guardrail(
ctx: RunContextWrapper[None],
agent: Agent,
input: str | list[TResponseInputItem]
) -> GuardrailFunctionOutput:
"""确保Agent只处理购物相关问题"""
result = await Runner.run(guardrail_agent, input, context=ctx.context)
check = result.final_output_as(RelevanceCheck)
return GuardrailFunctionOutput(
output_info=check.model_dump(),
tripwire_triggered=not check.is_shopping_related,
)
Step 4: 创建三个核心Agent
from agents import Agent, handoff
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
# ===== Agent 1: 商品专家 =====
product_agent = Agent[ShoppingContext](
name="Product Specialist",
handoff_description="处理商品搜索、推荐、详情查询和加购。",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
你是一个热情的商品专家,名叫小商。
## 你的职责
- 帮助用户搜索和推荐商品
- 提供商品详细信息
- 协助用户将商品加入购物车
## 工作流程
1. 理解用户的购物需求
2. 使用 search_products 搜索相关商品
3. 如果用户想了解某个商品,使用 get_product_detail
4. 如果用户决定购买,使用 add_to_cart
## 规则
- 推荐时优先考虑性价比
- 如果用户的需求超出了商品范围(如查订单、退款),交接给订单专家
- 保持友好专业的语气
""",
tools=[search_products, get_product_detail, add_to_cart],
)
# ===== Agent 2: 订单专家 =====
order_agent = Agent[ShoppingContext](
name="Order Specialist",
handoff_description="处理订单查询、物流追踪和退款处理。",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
你是一个耐心的订单专家,名叫小单。
## 你的职责
- 查询订单状态
- 追踪包裹物流
- 处理退款请求
## 工作流程
1. 确认用户的订单号(如果没有,先询问)
2. 根据需求使用对应工具:
- 查状态 → check_order_status
- 查物流 → track_package
- 退款 → process_refund
## 规则
- 处理退款时务必确认订单号和退款原因
- VIP用户享有优先退款
- 如果用户想继续购物,交接给商品专家
- 保持耐心和同理心
""",
tools=[check_order_status, track_package, process_refund],
)
# ===== Agent 3: 分诊路由 =====
triage_agent = Agent[ShoppingContext](
name="Shopping Triage",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
你是一个智能购物助手的接待员。
## 你的职责
判断用户的需求类型,将其路由到正确的专家:
- 商品搜索/推荐/购买 → 商品专家 (Product Specialist)
- 订单查询/物流/退款 → 订单专家 (Order Specialist)
## 规则
- 简单打招呼由你自己回复
- 无法判断时,优先交给商品专家
- 用一句话简单介绍自己后立即路由
""",
input_guardrails=[shopping_relevance_guardrail],
handoffs=[
handoff(agent=product_agent),
handoff(agent=order_agent),
],
)
# 允许专家之间互相交接
product_agent.handoffs.append(handoff(agent=order_agent))
order_agent.handoffs.append(handoff(agent=product_agent))
# 允许专家回到分诊
product_agent.handoffs.append(handoff(agent=triage_agent))
order_agent.handoffs.append(handoff(agent=triage_agent))
Step 5: 主循环 + 运行追踪
import uuid
from agents import (
Runner, trace, HandoffOutputItem, ItemHelpers,
MessageOutputItem, ToolCallItem, ToolCallOutputItem,
)
async def main():
current_agent = triage_agent
input_items: list = []
context = ShoppingContext(is_premium_user=True) # 模拟VIP用户
conversation_id = uuid.uuid4().hex[:16]
print("=" * 60)
print(" 欢迎使用智能购物助手!")
print(" 输入 'quit' / 'exit' / 'bye' 退出")
print("=" * 60)
while True:
user_input = input("\n🧑 你: ").strip()
if not user_input:
continue
if user_input.lower() in ("quit", "exit", "bye"):
print("👋 感谢使用,再见!")
break
input_items.append({"content": user_input, "role": "user"})
try:
with trace("Shopping Assistant", group_id=conversation_id):
result = await Runner.run(
current_agent,
input_items,
context=context,
)
# 打印详细的执行过程
for new_item in result.new_items:
agent_name = new_item.agent.name
if isinstance(new_item, MessageOutputItem):
text = ItemHelpers.text_message_output(new_item)
if text:
print(f"\n🤖 [{agent_name}]: {text}")
elif isinstance(new_item, HandoffOutputItem):
print(f" 🔄 [交接] {new_item.source_agent.name} "
f"→ {new_item.target_agent.name}")
elif isinstance(new_item, ToolCallItem):
print(f" 🔧 [{agent_name}]: 正在调用工具...")
elif isinstance(new_item, ToolCallOutputItem):
print(f" 📋 [工具结果]: {str(new_item.output)[:100]}...")
input_items = result.to_input_list()
current_agent = result.last_agent
except InputGuardrailTripwireTriggered as e:
message = "抱歉,我只能帮助处理购物相关问题(商品、订单、退款等)。请换个问题试试?"
print(f"\n🛡️ [护栏触发]: {message}")
input_items.append({"role": "assistant", "content": message})
if __name__ == "__main__":
asyncio.run(main())
运行效果演示
============================================================ 欢迎使用智能购物助手! 输入 'quit' / 'exit' / 'bye' 退出 ============================================================ 🧑 你: 你好,我想买个手机 🤖 [Shopping Triage]: 你好!我是智能购物助手,马上为你找商品专家! 🔄 [交接] Shopping Triage → Product Specialist 🤖 [Product Specialist]: 你好!我是商品专家小商 🎉 来帮你挑手机! 🔧 [Product Specialist]: 正在调用工具... 📋 [工具结果]: 找到以下商品: iPhone 16 Pro (¥8,999), Samsung S26 (¥6,999), Xiaomi 16 (¥3,499)... 🤖 [Product Specialist]: 我为你找到了几款热门手机: - iPhone 16 Pro - ¥8,999 - Samsung S26 - ¥6,999 - Xiaomi 16 - ¥3,499 你预算大概多少?我可以进一步推荐! 🧑 你: iPhone 16 Pro 怎么样? 🔧 [Product Specialist]: 正在调用工具... 📋 [工具结果]: A20芯片 | 6.3英寸 | 4800万像素 | 256GB起 | 电池续航30小时 🤖 [Product Specialist]: iPhone 16 Pro 是今年的旗舰款,配置非常强: - A20芯片,性能提升40% - 4800万像素主摄 - 电池续航长达30小时 要加入购物车吗? 🧑 你: 好的,加一辆 🔧 [Product Specialist]: 正在调用工具... 📋 [工具结果]: 已将 iPhone 16 Pro x1 加入购物车... 🤖 [Product Specialist]: 已加入购物车!还需要别的吗?或者我可以帮你查一下订单? 🧑 你: 帮我查一下我之前的订单 20260315001 🔄 [交接] Product Specialist → Order Specialist 🔧 [Order Specialist]: 正在调用工具... 📋 [工具结果]: 订单 20260315001 状态: 运输中。预计到达: 明天下午。 🤖 [Order Specialist]: 你的订单 20260315001 正在运输中,预计明天下午就能收到啦! 🧑 你: 天气怎么样? 🛡️ [护栏触发]: 抱歉,我只能帮助处理购物相关问题(商品、订单、退款等)。请换个问题试试?
四、深入理解:Agent执行流程
Runner的执行循环
当你调用 Runner.run() 时,SDK内部执行如下循环:

护栏的执行时机
护栏不是在所有Agent上都运行,而是有明确的边界:

| 护栏类型 | 执行时机 | 触发效果 |
|---|---|---|
| Input Guardrail | 链中首个Agent收到输入时 | 抛出异常,阻止执行 |
| Output Guardrail | 最终Agent产生输出时 | 抛出异常,阻止输出 |
| Tool Guardrail | 每次函数工具调用时 | 拒绝内容或抛出异常 |
五、进阶:Agents as Tools 模式
Handoff模式适合"接力赛"场景,但当你需要一个Agent汇总多个Agent的结果时,应该使用 Agents as Tools 模式:
# ===== Agents as Tools 模式 =====
# 场景: 内容创作流水线 —— 一个Manager Agent协调调研、写作、审核
from agents import Agent, Runner, trace
# 专家Agent
researcher = Agent(
name="Researcher",
instructions="你是一个调研专家。对给定主题进行深度调研,输出结构化的调研报告。",
)
writer = Agent(
name="Writer",
instructions="你是一个资深技术写手。基于调研报告撰写高质量的技术文章。",
)
reviewer = Agent(
name="Reviewer",
instructions="""你是一个严格的审核编辑。从以下维度审核文章:
1. 技术准确性 (0-10)
2. 可读性 (0-10)
3. 完整性 (0-10)
输出JSON格式的评分和修改建议。""",
output_type=dict, # 结构化输出
)
# Manager Agent —— 把专家当作工具使用
manager = Agent(
name="Content Manager",
instructions="""你是一个内容管理Agent,负责协调一篇文章的创作。
工作流程:
1. 先用 research 工具调研主题
2. 再用 write 工具基于调研结果撰写文章
3. 最后用 review 工具审核文章质量
4. 如果评分低于8分,根据意见修改后重新审核
""",
tools=[
researcher.as_tool(
tool_name="research",
tool_description="对指定主题进行深度调研,返回调研报告"
),
writer.as_tool(
tool_name="write",
tool_description="基于调研报告撰写技术文章"
),
reviewer.as_tool(
tool_name="review",
tool_description="审核文章质量,返回评分和修改建议"
),
],
)
async def create_article(topic: str) -> str:
with trace("Content Creation Pipeline"):
result = await Runner.run(
manager,
f"请创作一篇关于 '{topic}' 的技术文章"
)
return result.final_output
两种模式的对比

| 特性 | Handoff | Agents as Tools |
|---|---|---|
| 用户交互 | 专家直接面对用户 | 只与Manager交互 |
| 上下文 | 完整传递 | 工具输入/输出 |
| 适合场景 | 客服、路由 | 内容创作、分析 |
| 复杂度 | 低 | 中 |
六、Tracing:调试与监控
SDK内置了完整的Tracing系统,可以追踪每一次Agent运行、工具调用、交接和护栏检查:
from agents import Agent, Runner, trace
# 方式1: 自动Tracing(默认开启)
result = await Runner.run(agent, "Hello")
# 自动在 OpenAI Dashboard 中创建 trace
# 方式2: 手动创建 trace(跨多个 run)
with trace("复杂工作流", group_id="session-123"):
result1 = await Runner.run(agent1, "步骤1")
result2 = await Runner.run(agent2, f"基于上一步: {result1.final_output}")
result3 = await Runner.run(agent3, f"最终处理: {result2.final_output}")
# 方式3: 关闭 Tracing
from agents import set_tracing_disabled
set_tracing_disabled(True)
集成外部监控
# 集成 LangSmith / Weights & Biases / MLflow 等 from agents import add_trace_processor # 方式1: 添加自定义处理器(保留OpenAI后端) add_trace_processor(my_custom_processor) # 方式2: 完全替换处理器 from agents import set_trace_processors set_trace_processors([langsmith_processor, wandb_processor])
长时间运行的任务
from agents import Runner, trace, flush_traces
async def background_agent_task(prompt: str):
try:
with trace("background_task"):
result = await Runner.run(agent, prompt)
return result.final_output
finally:
# 确保在Celery/FastAPI等场景中刷新trace
flush_traces()
七、与其他框架的对比

| 维度 | OpenAI Agents SDK | LangGraph | CrewAI |
|---|---|---|---|
| 学习曲线 | 低(纯Python) | 中-高(图抽象) | 低-中 |
| 护栏 | 内置三重护栏 | 手动实现 | 有限 |
| Tracing | 免费内置 | 需LangSmith | 有限 |
| Human-in-the-Loop | 内置 | 通过图中断 | 基本 |
| LLM支持 | OpenAI原生,也支持100+ | 任意LLM | 任意LLM |
| MCP支持 | 内置 | 需集成 | 有限 |
| 语音Agent | 支持 | 不支持 | 不支持 |
| 沙盒Agent | 支持(Docker) | 不支持 | 不支持 |
| 适用场景 | 快速多Agent应用 | 复杂有状态工作流 | 快速原型 |
选择建议

八、最佳实践总结
DO ✅
| 实践 | 说明 |
|---|---|
使用 RECOMMENDED_PROMPT_PREFIX | 官方推荐的交接提示前缀,能显著提升交接质量 |
| 每个Agent职责单一 | "一个Agent只做一件事"比"全能Agent"效果好得多 |
| 使用结构化输出 | 用Pydantic模型定义 output_type,提高结果可靠性 |
| 启用护栏 | 即使是Demo,也加上输入护栏,养成习惯 |
| 使用Tracing | 调试多Agent系统没有Tracing等于盲人摸象 |
| 动态指令 | 用回调函数代替静态字符串,实现上下文感知的指令 |
DON’T ❌
| 反模式 | 原因 |
|---|---|
| 给Agent太多工具 | 5个以上的工具会降低LLM选择准确率 |
| 过深的交接链 | 超过3层交接会导致上下文丢失 |
忽略 max_turns | 必须设置上限防止无限循环 |
| 在护栏中使用强模型 | 护栏用 gpt-4o-mini 即可,省钱且够用 |
| 不处理护栏异常 | GuardrailTripwireTriggered 必须被优雅处理 |
结语
OpenAI Agents SDK用最Pythonic的方式解决了多智能体系统的构建问题——没有DSL,没有复杂的图抽象,只有你熟悉的Python代码。
它的核心设计哲学可以概括为三点:
- Agent即配置:一个字典式的配置对象就是一个Agent
- Handoff即工具:交接对LLM来说就是一个特殊的工具调用
- Guardrails即安全网:三重护栏让Agent行为可预测
2026年,AI Agent不再是实验室的玩具。选择合适的框架,从第一个多智能体系统开始,这是每个Python开发者的必修课。
以上就是Python调用OpenAI Agents SDK打造一个多智能体系统的详细内容,更多关于Python Agents SDK多智能体系统的资料请关注脚本之家其它相关文章!
