使用 OpenAI Agents SDK 构建智能体——多智能体系统与交接

115 阅读24分钟

有些任务并非单个人类就能完成,而需要一个由多人组成的组织(团队) 。想想任何一家大型公司:它之所以能实现目标,是因为不同专长的人协同合作。同理,单智能体系统(one-agent)能力有限;而多智能体系统几乎无所不能。

单个 Agent 即便很强,仍有天然边界:当问题跨越多个领域、需要多元专长或需要并行处理时,一个 Agent 往往吃力。比如客服 Agent 处理简单咨询没问题,但若任务牵涉财务分析、法律推理或技术排障,它就可能捉襟见肘。将职责分配给多个专长 Agent,能获得比任何单体更高的准确性、可扩展性与韧性

本章将介绍如何构建多智能体系统——让多个 Agent 协同工作的系统。无论是简单的路由器还是复杂的组织层级,理解 Agent 之间交互、委派与协作的方式,都是释放 Agent 全部潜力的关键。OpenAI Agents SDK 提供的核心原语之一——handoff(交接) ,正是实现多智能体的关键。

你将学到:

  • 编排类型:对比两种多智能体编排策略——确定式(硬编码)动态式(系统驱动) ,并分别示例讲解。
  • 交接(Handoffs) :学习如何使用 SDK 的 handoffs 功能在 Agent 间移交控制权,让 Agent 在保持上下文的同时进行任务委派。
  • 多智能体模式:探讨多种体系结构(集中式、去中心化、分层式、群体式),并展示在 SDK 中如何实现。

章节末,你将能设计与实现像真实团队那样协作的多智能体系统。

技术准备

请先按照第 3 章完成环境配置。
本书各章的示例与完整代码均在仓库:github.com/PacktPublis…
建议你克隆仓库、复用与改造示例代码,并在学习过程中随用随查。

多智能体编排(orchestration)

构建多 Agent 系统时,核心决策之一是:如何在 Agent 之间管理信息与任务的流动。总体有两种策略:

  • 确定式编排:你亲自写明交互逻辑,显式控制 Agent 如何互动(见图 6.1)。

image.png

  • 动态式编排:把流程决策交给另一套系统(如 LLM),使其能即时自适应(见图 6.2)。

image.png

很多系统其实会混合两者:某些环节用确定式保证可控与合规,其他环节用动态式更好地应对不确定性与歧义。

确定式编排

确定式编排就是把 Agent 之间的交互流程硬编码出来。它的优势是可预测、好测试、易审计:同样输入总走同样路径,调用次数、成本与时延都容易预估,特别适合需要稳定、可复现结果的系统。

缺点是灵活性不足:一旦出现未覆盖的请求或要新增步骤,你就得改代码并重新部署。随着流程复杂度增加,维护分支与路径会变重。

示例:两个客服 Agent 之间用硬编码路由,演示确定式委派的可控与局限。创建 deterministic_approach.py 并运行:

from agents import Agent, Runner

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions="Handle any customer complaints with empathy and clear next steps."
)
inquiry_agent = Agent(
    name="General Inquiry Agent",
    instructions="Answer general questions about our services promptly."
)

# Create orchestration
def orchestrate(user_message: str):
    # Deterministically delegates requests to the right customer service agent.
    if ("complaint" in user_message.lower() 
            or "problem" in user_message.lower()):
        print('Redirecting you to the Complaints agent')
        chosen_agent = complaints_agent
    else:
        print('Redirecting you to the Inquiry agent')
        chosen_agent = inquiry_agent
    result = Runner.run_sync(chosen_agent, user_message)
    return result.final_output

while True:
    question = input("You: ")
    result = orchestrate(question)
    print("Agent: ", result)

要点:

  • 可控、可测,但缺乏弹性:若用户不使用关键词“complaint/problem”,可能被误路由。
  • 路由逻辑集中在 orchestrate 函数内,以固定规则选择 Agent,因此总是同词同路。

示例交互:

You: I have a complaint, my meal was too hot 
Redirecting you to the Complaints agent
Agent:  I'm really sorry to hear that your meal was too hot. ...

但若用户没说“complaint”:

You: my meal is too hot
Redirecting you to the Inquiry agent
Agent: Try eating in smaller bites.

可见误判风险。

动态式编排

动态式编排把 Agent 间的流程交互交给外部系统(此处通常是 LLM)自主决策。这类编排更灵活:由一个“分诊(triage)”Agent 实时理解请求,再决定调用哪一个专长 Agent / 工具。在本书此前的大多数示例里,我们实际上都运用了这种模式(Agent 自主决定是否/何时调用工具、调用哪个工具等)。

优点与确定式互补:强灵活性与泛化能力,对开放式任务(客服、销售分流等)尤其适合。缺点是路径与成本不那么可预测:走哪条分支、调用几次模型,事先不一定知道。

我们把上例改成动态式:先创建一个分诊 Agent,根据用户请求选择要调用的 Agent。创建并运行 dynamic_approach.py

from agents import Agent, Runner

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions="Handle any customer complaints with empathy and clear next steps."
)
inquiry_agent = Agent(
    name="General Inquiry Agent",
    instructions="Answer general questions about our services promptly."
)

triage_agent = Agent(
    name="Triage Agent",
    instructions="Triage the user's request and call the appropriate agent",
    tools=[
        complaints_agent.as_tool(
            tool_name="ComplaintsAgent",
            tool_description="Introduce yourself as the Complaints agent. Handle any customer complaints with empathy and clear next steps."
        ),
        inquiry_agent.as_tool(
            tool_name="GeneralInquiryAgent",
            tool_description="Introduce yourself as the General Inquiry agent. Answer general questions about our services promptly."
        )]
)

while True:
    question = input("You: ")
    result = Runner.run_sync(triage_agent, question)
    print("Agent: ", result.final_output)

试一个不含“complaint”字样、但应被识别为投诉的提示:

You: My meal is too hot
Agent:  I'm sorry to hear about your meal. ...

Traces 中可验证确实路由到投诉 Agent:

image.png

图 6.3:上述示例的 Trace

这样,我们把决策权交给了分诊 Agent,而不是提前硬编码路由。它能理解意图动态选择合适 Agent,避免用大量 if-else 处理各种变体。

另一优势是能一次处理多个请求。比如:

You: My meal is too hot, and how do I get my receipt?
Agent:  Here's how I can assist you:
**For the hot meal:**
- ...
**For the receipt:**
- ...

对应的 Traces(图 6.4)会显示它在一次对话中同时调用了两个 Agent

image.png

这一切都发生在 Agent 的推理过程中,而非固定代码分支里。我们只负责定义各 Agent 及其能力;由分诊 Agent 的 LLM 来做路由决策

OpenAI Agents SDK 中的交接(Handoffs)

了解了多智能体系统的不同编排方式后,我们来看看 OpenAI Agents SDK 提供的、让这些方式成为可能的构造。其中最重要的原语之一就是 handoffs(交接)

交接是一个 Agent 将控制权移交给另一个 Agent 的机制。它等价于一个 Agent 说:“这事儿你更擅长,我把任务和全部细节交给你。”在多智能体系统中,交接是把不同 Agent 连接起来的关键一层。

注意
Agent 之间通常有两种交互方式,其中一种我们在第 4 章已详细介绍:as_tool()

  • as_tool() 让一个 Agent 变成工具并被另一个 Agent 调用。好比主 Agent 暂时请教一个子 Agent,拿到输入或决策后主 Agent 继续掌控对话。这在主 Agent 需要专业意见但不想放弃流程控制时很有用。
  • 本节讨论的 handoff(交接) 则是彻底移交控制权:一个 Agent 将对话交给另一个 Agent,由后者全权接管;原来的 Agent 不再参与。

下图给出了两种方式的可视化示例。Agent-as-tool 模式中,编排/主控 Agent 始终掌控整体工作流,只是调用其他 Agent 完成子任务(图 6.5):

image.png

图 6.5:Agent-as-tool 模式

交接模式中,一个 Agent 将控制权完全交给另一个 Agent(图 6.6):

image.png

图 6.6:Handoff 模式

本节将介绍如何设置交接、如何定制其行为、交接时传递哪些信息、如何过滤/修改这些信息,以及如何处理错误或多步交接。随后,我们将用交接来构建不同的多智能体系统。

交接入门

定义交接非常简单:实例化 Agent 时,传入一个名为 handoffs 的参数即可。它接收一个已构建的其他 Agent 列表。列表中的每个 Agent 都是潜在的交接目标

我们直接上手,用交接搭一个多智能体系统。基于前面的示例,把 tools 改成 handoffs,并去掉 as_tool()。创建 basic_handoff.py

from agents import Agent, Runner

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions="Handle any customer complaints with empathy and clear next steps."
)
inquiry_agent = Agent(
    name="General Inquiry Agent",
    instructions="Answer general questions about our services promptly."
)

# Create the triage agent with handoffs
triage_agent = Agent(
    name="Triage Agent",
    instructions="Triage the user's request and call the appropriate agent",
    handoffs=[complaints_agent, inquiry_agent]
)

while True:
    question = input("You: ")
    result = Runner.run_sync(triage_agent, question)
    print("Agent: ", result.final_output)

这里,triage_agent 有两个可交接的目标:complaints_agentinquiry_agent。类比为:前台(triage_agent)接待来访者,再把人带到合适的同事那里。

分诊 Agent 如何知道交给谁?和工具原语类似,Handoff 原语会向分诊 Agent 暴露子 Agent 的 name 与 instructions,因此它能根据各自职责判断是否交接。

试运行并验证交接:

You: My meal is too hot
Agent:  Hi there, I'm sorry to hear that your meal is too hot. ...

在 Traces 模块里可确认 triage_agent 把任务移交给了 complaints_agent

image.png

图 6.7:从一个 Agent 交接到另一个 Agent

Traces 显示向 complaints_agent 的转移,之后由 complaints_agent 全权处理

多 Agent 切换

注意:complaints_agent 本身也是一个 Agent,它也可以拥有自己的工具与交接。当前,一旦 complaints_agent 接管,就不能再转给其他 Agent。为了解决这个问题,我们给 complaints_agentinquiry_agent 也配置 handoffs,并让 Runner 从上次响应的 Agent 继续对话,而不是每次都回到 triage_agent。再把对话改为多轮。

创建 multi_agent_switching.py

from agents import Agent, Runner, SQLiteSession, trace

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions="Introduce yourself as the complaints agent. Handle any customer complaints with empathy and clear next steps."
)
sales_agent = Agent(
    name="Sales Agent",
    instructions="Introduce yourself as the sales agent. Answer general questions about our services promptly."
)

# Create the triage agent with handoffs
triage_agent = Agent(
    name="Triage Agent",
    instructions="Answer general questions. Triage the user's request and call the appropriate agent",
)

# Handoff all agents with each other
complaints_agent.handoffs = [sales_agent, triage_agent]
sales_agent.handoffs = [complaints_agent, triage_agent]
triage_agent.handoffs = [complaints_agent, sales_agent]

# Create a session
session = SQLiteSession("first_session")
last_agent = triage_agent

with trace("Multi-agent system"):
    while True:
        question = input("You: ")
        result = Runner.run_sync(last_agent, question, session=session)
        print("Agent: ", result.final_output)
        last_agent = result.last_agent

关键点:

  • 建立三方互相可交接的关系。此前一旦二级 Agent(如 complaints_agent)接管,之后就被“锁定”。现在明确给每个 Agent 指定其他 Agent 为 handoffs,任何 Agent 都能再交接到任何一个,包括回到 triage_agent
  • 使用 SQLiteSession 持久化多轮会话状态;配合 trace() 记录全流程。
  • last_agent 记录最近在处理的 Agent;每轮调用 Runner.run_sync(last_agent, ...),确保当前掌权的 Agent 接收用户新输入。完成响应后用 result.last_agent 更新,从而实现顺滑交接

示例对话(根据上下文无缝切换不同 Agent):

You: Hi, I'm Henry
Agent:  Hello Henry! How can I assist you today?
You: Transfer me to the complaints agent - My meal is too hot
Agent:  Hello Henry, I'm the complaints agent here to assist you. ...
You: I have a general inquiry - how do I get my receipts?
Agent:  For receipt inquiries, you typically have a few options …

Traces 如下:

image.png

图 6.8:本例的 Traces

这种结构让多智能体对话真正动态化:Agent 不仅能轮流,还能智能决定何时把控制权交给他人。

定制交接

OpenAI Agents SDK 允许定制交接属性,在很多场景非常实用。SDK 提供了构造 handoff 对象 的方式,可配置下列属性:

  • agent:要交接到的 Agent。
  • tool_name_override / tool_description_override:覆盖 Traces 中显示的交接描述(默认是“transfer to X”)。
  • on_handoff:交接发生时触发的函数。可用于提醒用户、日志记录等。SDK 会把会话历史传给你的回调。
  • input_type / input_filter:细化交接时输入内容。例如让 LLM 传入已总结的会话概览,或只保留最近 5 条消息。

注意
交接中的关键考虑是:传递多少上下文给新 Agent。默认情况下,SDK 会将交接前的完整会话历史自动转移——包括用户输入、系统指令、上一 Agent 的消息与动作(也就是原 Agent 能看到的一切)。对用户而言,不需要重复信息。

下面定制一个我最常用的属性:on_handoff。定义一个函数,在交接发生时打印日志。创建 handoff_customization.py

from agents import Agent, Runner, SQLiteSession, trace, handoff
from pydantic import BaseModel
import os

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions="Introduce yourself as the complaints agent. Handle any customer complaints with empathy and clear next steps."
)
sales_agent = Agent(
    name="Sales Agent",
    instructions="Introduce yourself as the sales agent. Answer general questions about our services promptly."
)

# Create the triage agent with handoffs
triage_agent = Agent(
    name="Triage Agent",
    instructions="Answer general questions. Triage the user's request and call the appropriate agent",
)

接着定义模型与日志函数,并创建 handoff 对象:

class NameOfAgentToBeHandedOff(BaseModel):
    name_of_agents_to_be_handed_off: str

# Create logging function
def log(ctx, name_of_agent):
    msg = f"The system has transferred you to another agent: {name_of_agent.name_of_agents_to_be_handed_off}"
    print(msg)

# Create custom handoff
complaints_handoff = handoff(agent=complaints_agent, on_handoff=log, input_type=NameOfAgentToBeHandedOff)
sales_handoff = handoff(agent=sales_agent, on_handoff=log, input_type=NameOfAgentToBeHandedOff)
triage_handoff = handoff(agent=triage_agent, on_handoff=log, input_type=NameOfAgentToBeHandedOff)

# Handoff all agents with each other
complaints_agent.handoffs = [sales_handoff, triage_handoff]
sales_agent.handoffs = [complaints_handoff, triage_handoff]
triage_agent.handoffs = [complaints_handoff, sales_handoff]

# Create a session
session = SQLiteSession("first_session")
last_agent = triage_agent

with trace("Multi-agent system"):
    while True:
        question = input("You: ")
        result = Runner.run_sync(last_agent, question, session=session)
        print("Agent: ", result.final_output)
        last_agent = result.last_agent

要点说明:

  • 不再直接把 Agent 填进 .handoffs,而是用 SDK 的 handoff() 构造可定制的交接对象,例如给每次交接挂上 on_handoff 日志回调。
  • log() 函数接收交接上下文 ctx 与模型输入 name_of_agent,打印转移到哪个 Agent。
  • 用 Pydantic 定义 NameOfAgentToBeHandedOff,确保 on_handoff 的输入有结构、可校验
  • 给每个交接都应用这个结构,便于统一跟踪与调试
  • 最终把 handoff 对象而非裸 Agent 赋给 .handoffs,从而获得完整的过渡控制,可加日志、审计、乃至动态改写上下文。

运行后,发生交接会打印:

You: I want to make a complaint
The system has transferred you to another agent: Complaints Agent
Agent:  Hello, I'm the Complaints Agent, and I'm here to help. ...

这就为简单的“委派”加入了可编程钩子,方便在真实生产中做日志/审计/规则等。

交接提示(prompting)

交接的效果取决于你给每个 Agent 的指令。涉及交接的 Agent 应有清晰的何时、如何交接以及交接后怎么做的说明。为此,OpenAI Agents SDK 提供了一个推荐的提示前缀可加入到每个 Agent 的 instructions 中:

from agents import Agent, Runner
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX

print(RECOMMENDED_PROMPT_PREFIX)

# Create two agents
complaints_agent = Agent(
    name="Complaints Agent",
    instructions=f"{RECOMMENDED_PROMPT_PREFIX}. Introduce yourself as the complaints agent. Handle any customer complaints with empathy and clear next steps."
)
inquiry_agent = Agent(
    name="General Inquiry Agent",
    instructions=f"{RECOMMENDED_PROMPT_PREFIX}. Introduce yourself as the inquiry agent. Answer general questions about our services promptly."
)

# Create the triage agent with handoffs
triage_agent = Agent(
    name="Triage Agent",
    instructions=f"{RECOMMENDED_PROMPT_PREFIX}. Triage the user's request and call the appropriate agent",
    handoffs=[complaints_agent, inquiry_agent]
)

while True:
    question = input("You: ")
    result = Runner.run_sync(triage_agent, question)
    print("Agent: ", result.final_output)

RECOMMENDED_PROMPT_PREFIX 是一段系统级前缀,例如:

# System context
You are part of a multi-agent system called the Agents SDK, designed to make agent coordination and execution easy. Agents uses two primary abstraction: **Agents** and **Handoffs**. An agent encompasses instructions and tools and can hand off a conversation to another agent when appropriate. Handoffs are achieved by calling a handoff function, generally named `transfer_to_<agent_name>`. Transfers between agents are handled seamlessly in the background; do not mention or draw attention to these transfers in your conversation with the user.

这段前缀向模型明确:它身处多智能体环境中,并且如何处理交接(例如交接在后台无缝进行、不要向用户透露)。该前缀会随 SDK 更新而更新。把它放在系统提示开头(尤其是编排/分诊 Agent)能显著提升与交接系统的配合。

其他提示建议:

  • 显式的交接条件:在 Agent 的系统提示中写清楚何时应交接,比如“涉及销售问题就路由给销售 Agent”。规则越明确,系统越稳定。
  • 明确的 Agent 职责:清楚界定每个 Agent 的用途和适用场景,帮助分诊/主控 Agent 做出正确路由。

了解了 handoffs 的使用方法,接下来我们将学习不同的多智能体架构模式,以及如何用交接来实现它们。

多智能体模式(Multi-agent patterns)

描述多个 Agent 如何组织与构成,就是在讨论它们的架构模式。本节将介绍两种主要的多智能体架构模式、各自的优缺点,以及如何用 OpenAI Agents SDK 实现它们。

两种架构模式如下:

  • 集中式系统(Centralized system)
  • 分散式系统(Decentralized system)

下面依次说明。

集中式系统

集中式系统是指由一个中心 Agent 将请求路由到其他合适的 Agent。这是最常见的架构模式。中心 Agent 通常被称为“经理(manager)”“编排器(orchestrator)”或“分诊(triage)”Agent,其余则是“专业(specialized)”Agent。中心 Agent 负责分配用户请求,而专业 Agent 各自擅长某项职能。

优势在于组织清晰、职责分明:中心 Agent 专注做路由;专业 Agent 通过提示词、工具选择、模型选择,甚至真正的微调权重,来针对特定目标发挥专长。
拥有多个专业 Agent 的结构通常优于一个 Agent 包打天下——就像公司里 HR、销售、工程各司其职一样;而且新增专业 Agent 也很容易。

劣势在于系统对中心 Agent 的依赖极大:若中心 Agent 路由失误,整体就会失灵。通常这种结构下各专业 Agent 彼此不直接沟通,而是各自成“孤岛”;当任务需要跨域互动与团队协作时,这并不理想。

适用场景:天然“自上而下”的架构。例如客服机器人:用户先向分诊 Agent 描述问题,再被交接到正确的专业 Agent。又如企业内部助手:员工描述 HR/IT/行政诉求后,由中心助手路由到对应部门 Agent。这与现实中的工单系统非常相似。

注:本章前面的示例基本都属于集中式系统——有一个集中式分诊 Agent,再把请求路由给其他专业 Agent。

分层(层级)系统(Hierarchical system)

分层系统是集中式系统的一个子集,但具有多级层次(可以想象为一个逐层细化的金字塔)。这很像现实中的组织:顶部是 CEO(顶层编排者),其下有 CFO/COO/CHRO 等“经理”层,再往下是各自的专业团队。分层系统中的中间层 Agent会进一步划分任务,并为其下属的专业 Agent 提供上下文/指令。

优势:擅长将复杂任务层层拆解为可管理的子任务并复用共性子任务,让每个 Agent 的职责域保持聚焦。
劣势:当任务并不复杂时,层级会带来额外开销——更多层意味着更多成本、延迟、失败点与沟通复杂度;层级管理不善也容易造成信息失真或混乱,调试会非常困难。

最佳场景:处理大型、复杂的问题,比如深度研究

下面我们用一个层级系统来回答复杂的研究类问题。我们会创建一个集中式分诊 Agent、两个“经理”Agent(分别管理科学和历史问题),以及一组专业 Agent(每个经理下面各 3 个子领域 Agent)。

创建 hierarchical.py 并运行以下代码:

from agents import Agent, Runner, SQLiteSession, trace

# 创建我们的代理
# 科学领域的专业代理
physics_agent = Agent(name="Physics Agent", instructions="Answer questions about physics.")
chemistry_agent = Agent(name="Chemistry Agent", instructions="Answer questions about chemistry.")
medical_agent = Agent(name="Medical Agent", instructions="Answer questions about medical science.")

# 历史领域的专业代理
politics_agent = Agent(name="Politics Agent", instructions="Answer questions about political history.")
warfare_agent = Agent(name="Warfare Agent", instructions="Answer questions about wars and military history.")
culture_agent = Agent(name="Culture Agent", instructions="Answer questions about cultural history.")

# 经理代理:把问题路由到各自的子领域
science_manager = Agent(
    name="Science Manager",
    instructions="Manage science-related queries and route them to the appropriate subdomain agent.",
    handoffs=[physics_agent, chemistry_agent, medical_agent]
)
history_manager = Agent(
    name="History Manager",
    instructions="Manage history-related queries and route them to the appropriate subdomain agent.",
    handoffs=[politics_agent, warfare_agent, culture_agent]
)

# 顶层分诊代理
triage_agent = Agent(
    name="Research Triage Agent",
    instructions="Triage the user's question and decide whether it's science or history related, and route accordingly.",
    handoffs=[science_manager, history_manager]
)

# 创建会话
session = SQLiteSession("hierarchy")
last_agent = triage_agent

with trace("Hierarchical system"):
    while True:
        question = input("You: ")
        result = Runner.run_sync(last_agent, question, session=session)
        print("Agent: ", result.final_output)
        last_agent = result.last_agent

试运行并查看日志:

You: Which war after the year 1600 led to the greatest death toll?
Agent:  The war after 1600 that led to the greatest death toll is World War II. It is estimated to have caused the deaths of approximately 70 to 85 million people, including military personnel and civilians.

在 Traces 模块中可以看到类似如下链路(示意图 6.9):

image.png

图 6.9:本示例的 Traces 视图

发生了什么?
  • 用户问题首先到达顶层分诊 Agent(Research Triage Agent),它判断问题是历史相关,于是交接给 History Manager
  • History Manager 进一步检查主题,选择最合适的专业 Agent。问题与战争与死亡人数有关,于是路由到 Warfare Agent
  • Warfare Agent 作为军事史领域专家,生成答案并返回给用户。

这种分层委派让每个 Agent 都在清晰的职责边界内工作,像组织中处理复杂任务的方式一样逐层拆解。对用户而言,整个过程是无缝的一次交互

Traces 中也能清楚看到:分诊 Agent → History Manager → Warfare Agent。因为用户的问题与战争相关,最终由 Warfare Agent 直接作答。

在更加贴近实战的例子里,各专业 Agent 往往会拥有自己的工具与知识库:

  • Warfare Agent 可以接入历史冲突数据库查询工具,或访问全球战争研究文档;
  • Chemistry Agent 可以配备科学论文摘要器或元素/化学式计算工具;
  • 以此类推,让每个专业 Agent 的能力真正面向其领域

去中心化系统(Decentralized system)

去中心化系统与集中式系统正好相反。这里没有单一的分诊(triage)Agent;而是由多个 Agent 直接协作来响应用户请求。在这种系统中不存在孤岛,所有 Agent 都可以彼此沟通。更贴切的类比是圆桌讨论:没有主持人,所有 Agent 一起给出最终答案。

这种模式的优势在于能激发创造力,非常适合头脑风暴、创意发散或辩论等场景。Agent 之间通过迭代对话或观点交换来共同改进方案(类似部分“自博弈”研究,如 Google AlphaZero)。去中心化系统让 Agent 能从不同角度切入问题。

显著的劣势缺乏统一的协调。在 OpenAI Agents SDK 中,要管理去中心化对话流,通常需要确定性编排(即硬编码控制逻辑,也带来相应缺点),因为 SDK 本身并不直接支持这种自组织的对话管理。

因此,最佳用例是需要创意与新颖思考的任务:头脑风暴、创意生成、谈判、辩论等。

下面通过一个示例演示:我们创建两个立场相反的专家 Agent——一个代表房东,另一个代表租客;让他们围绕争议话题(如“是否应实施租金管制”)进行数轮交锋。最后将对话历史交给第三个 Agent,总结双方要点并返回结果。

创建 decentralized.py 并运行以下代码:

from agents import Agent, Runner, SQLiteSession, trace

# 创建三个代理
landlord_agent = Agent(
    name="Landlord Agent",
    instructions="Argue against rent control from the perspective of a landlord. Present strong economic and property-rights arguments."
)
tenant_agent = Agent(
    name="Tenant Agent",
    instructions="Argue in favor of rent control from the perspective of a tenant. Emphasize affordability, housing rights, and tenant protections."
)
summarizer_agent = Agent(
    name="Summarizer Agent",
    instructions="Summarize the main arguments presented by both the landlord and tenant agents in a neutral and concise way."
)

# 会话
session = SQLiteSession("decentralized")
landlord_turn = True
conversation_history = []

with trace("Decentralized system"):
    print("Topic: Should there be rent control?")
    for _ in range(6):  # 往返 6 轮
        if landlord_turn:
            agent = landlord_agent
        else:
            agent = tenant_agent

        prompt = "\n".join([f"{msg['role']}: {msg['content']}"
                            for msg in conversation_history])

        response = Runner.run_sync(agent,
                                   prompt or "Debate starting now.",
                                   session=session)

        print(f"{agent.name}: {response.final_output}")
        conversation_history.append({"role": agent.name,
                                     "content": response.final_output})
        landlord_turn = not landlord_turn

    # 交给总结代理
    summary_prompt = "\n".join([f"{msg['role']}: {msg['content']}"
                                for msg in conversation_history])
    result = Runner.run_sync(summarizer_agent, summary_prompt,
                             session=session)

    print("\nSummary of the Debate:")
    print(result.final_output)

在这个脚本中,我们创建了两个对立的 Agent(Landlord/房东 与 Tenant/租客),分别被指示从各自立场为争议问题辩护。它们不通过分诊或经理 Agent 编排,而是轮流发言,模拟一场辩论。

这展示了无需中心决策者也能形成的多 Agent 动态交互。每个 Agent 都是自治的,同时又建立在他者贡献之上。对话通过涌现行为渐进演化,而非依赖刚性的编排。

运行程序后,你能在对话历史中看到完整的往返,并获得如下总结示例(节选):

在关于租金管制的辩论中,房东代理认为:租金上限压制维护投资、抑制新增供给、造成与供需不匹配的市场扭曲、降低租户流动性,并侵犯产权、偏袒长期租户、增加行政负担、削弱对房东的公平补偿。
相反,租客代理支持租金管制以稳定租金、降低经济焦虑、促进住房安全与公平可得;强调保护租户免受剥削、维护社区纽带,主张将租金管制作为更广泛住房政策的一部分以促进稳定与公平。

你也可以在 Traces 模块中看到双方往返交锋(图 6.10)。

image.png

总体而言,该模式非常适合依赖观点多样性与交流的场景。

蜂群系统(Swarm system)

蜂群系统是去中心化系统的一个子集:由大量相对简单的 Agent(通常并行)协同产出答案。其背后依赖“涌现属性”——大量简单个体协作可形成复杂智能。类比:人体的细胞各自简单,但合在一起形成智能的整体;或机器学习中的随机森林——数百个弱学习器组合成强模型。

优点:能够产生新颖创意,可并行分工、具备良好扩展性;且没有单点故障(部分 Agent 失败无妨)。
缺点管理开销大(成本、调度复杂度显著);并非总能出现涌现智能,可能白白消耗时间与金钱。

适用场景:需要探索性的任务,如创意生成、优化、求解多路径问题。常见做法是批量生成多种候选,再汇总/筛选

下面示例:我们并行启动 10 个各司其职的城市角色 Agent(医生、技工、厨师等),都回答同一个问题:“如果从零设计一座梦想之城,它应该具备什么?” 然后把它们的回答交给一个汇总 Agent,合成为最终方案。

创建 swarm.py 并输入:

from agents import Agent, Runner, SQLiteSession, trace
import concurrent.futures

# 角色列表
roles = [
    "Urban Planner", "Artist", "Chef", "Engineer", "Teacher",
    "Doctor", "Mechanic", "Lawyer", "Historian", "Environmentalist"
]

city_agents = [
    Agent(
        name=f"{role} Agent",
        instructions=(f"You are a {role.lower()}. Answer the question: "
                      f"'If you were to design your dream city from scratch, what would it have?' "
                      f"Be creative and imaginative, but concise")
    )
    for role in roles
]

# 汇总代理
summary_agent = Agent(
    name="City Design Aggregator",
    instructions=("You are a city designer. You've just received 10 creative responses from different citizens. "
                  "Read all of their responses and consolidate them into a cohesive, imaginative, and well-rounded city plan.")
)

# 会话
session = SQLiteSession("swarm")
conversation_history = []

with trace("Swarm system"):
    prompt = "Design your dream city from scratch. What would it have?"

    # 收集各代理回答(可串行,也可用并行池)
    for agent in city_agents:
        result = Runner.run_sync(agent, prompt, session=session)
        print(f"{agent.name}: {result.final_output}\n")
        conversation_history.append(f"{agent.name}: {result.final_output}")

    # 汇总
    combined_responses = "\n\n".join(conversation_history)
    final_result = Runner.run_sync(summary_agent, combined_responses, session=session)

    print("\nFinal City Design Summary:")
    print(final_result.final_output)

这里我们定义了 10 个“蜂群”Agent,每个都按自身角色身份给出创意视角;随后把所有回答交给 summary_agent 进行综合,得到一份统一的城市方案。该结果体现了多主体独立思考后的涌现合力。

小结

OpenAI Agents SDK 足够灵活,可以实现多种多智能体架构模式。正如本节所示,每种模式都能用独立脚本实现:创建 Agent、设置 handoff、管理记忆,就能拼装出集中式、层级式、去中心化与蜂群式等不同系统。下一章我们将学习如何管理多智能体系统的“发动机”——LLM 本身。