Swarm 是 OpenAI 推出的一个实验性框架,专为帮助开发者高效编排多代理系统(multi-agent systems)而设计。它于 2024 年正式发布,致力于探索简洁、可扩展的方式来管理复杂的 AI 代理交互。

 

本文主要介绍了 OpenAI 推出的实验性框架 Swarm,它是一个多代理编排框架,致力于探索管理复杂 AI 代理交互的方式。文中阐述了 AI 代理的概念、组成及发展方向,强调 Swarm 的作用是协调多代理工作,通过任务分解、动态调度等机制,通过多个代码示例,体现其在复杂任务处理上的优势,还介绍了 Swarm 的核心概念如代理和任务移交,以及通过示例代码展示其关键概念和功能实现,最后深入原理,从 Routine 到 Agent 的转变及 Handoff 功能的运作方式。

引言:揭开 Swarm 的神秘面纱

AI Agent 的出现为人类带来了前所未有的可能性,从简单的任务执行到复杂问题的智能解决,Agent 正在改变我们与技术交互的方式。然而,随着应用需求的增长,单一 Agent 的能力难以满足复杂场景的多样化需求。在许多情况下,解决问题不仅需要单个 Agent 的专业性,还需要多个 Agent 的协作,彼此分工明确、紧密配合,才能高效完成任务。如何协调和管理多个 Agent,让它们各司其职又能无缝衔接,成为一个新的问题。

为此,OpenAI 提出了 Swarm :多 Agent 协作架构,通过定义统一的智能体行为规范和动态任务转交机制,为复杂场景中的 Agent 协作提供了解决方案。在接下来的内容中,我们将深入探索这一架构,通过理论描述和代码实践的方式,揭示 Swarm 的设计理念与运作原理。

什么是 Swarm?

Swarm 是 OpenAI 推出的一个实验性框架,专为帮助开发者高效编排多代理系统(multi-agent systems)而设计。它于 2024 年正式发布,致力于探索简洁、可扩展的方式来管理复杂的 AI 代理交互。Swarm 是开源的,托管在 GitHub 平台上,开发者可以轻松获取、尝试和贡献。

在本质上,Swarm 是一个多代理编排框架,旨在让代理间的协调变得轻量化、可定制且易于测试。通过 Swarm,开发者可以构建、组织并管理多个 AI 代理(AI Agent),这些代理之间可以传递任务控制权,以共同完成复杂的工作流程。

各位看到这里就需要划重点了, Swarm的作用是构建、组织并管理多个AI Agent,说白了,Swarm的作用就是协调多代理工作。

既然如此,为了搞懂Swarm 是个啥,我们就要先了解 AI 代理(AI Agent)。

如下图所示,AI 代理(AI Agent)是能够自主感知环境、做出决策并采取行动的系统,旨在实现更高层次的人工智能能力。在 AI 发展路径中,AI 代理从解决单一任务(如生成文字、图片、语音或视频)逐步发展到能够处理复杂任务(如金融投资、建筑设计或诗歌创作),最终朝着通用人工智能(AGI)的方向迈进,其目标是具备类似人类思考和行动的能力,能够应对多样化环境和复杂问题。

AI 代理的核心概念包括:

  • 状态(State):代理在环境中所处的当前状况。
  • 智能体(Agent):基于状态信息选择并执行行动(Action)。
  • 奖励(Reward):根据代理行为对目标的影响、环境给予的反馈。

AI 代理的组成主要包括:

  • LLM(大语言模型):作为智能的核心,提供强大的语言理解和生成能力。
  • 记忆:包括短期和长期记忆,用于跟踪任务状态和历史数据。
  • 工具:涵盖代码执行、搜索引擎、API 调用等功能模块。
  • 规则:定义代理行为的边界,包括反思、自我批评和思维链条。

这种设计使得 AI 代理能够在复杂环境中模拟人类决策过程,完成多样化任务,并为通用人工智能的实现奠定基础。

换句话说,AI 代理(Agent)也就是我们常说的智能体,指的是能够执行特定任务或功能的独立单位。每个代理通常具备某种能力或工具,能够根据输入进行处理,并输出结果或执行某些操作。AI 代理不仅能够根据预定规则和任务指令工作,还能够在复杂的动态环境中做出决策、进行交互、协调和任务分配。

而Swarm 是一种让智能体协作的工作方式,它让每个智能体各司其职的同时,还能让他们相互协作完成更加复杂的任务。OpenAI 推出Swarm的目的也是为大家在出一些复杂任务时具备一些“解题思路”。

比如说,有一家在线零售企业,客户经常遇到多种问题,如咨询产品信息、查询订单状态以及申请退换货等。这些需求往往需要不同的专属服务,而传统客服系统难以高效处理多样化问题。通过 Swarm 框架,客服系统可以拆解任务并分配给多个专属 AI 智能体。例如,当客户咨询产品信息时,推荐代理可以提供精确的产品推荐;当客户查询订单时,订单代理可以快速返回订单状态;如果客户申请退货,退货代理能够解释政策并发起流程。Swarm架构就是让这些智能体高效协作的实践方法。

目前,Swarm是一个实验性示例框架,用来探索多智能体系统的最佳实践,为多智能体协作提供基础研究。

在官方的介绍文档中提到了Swarm 的两个核心概念:代理(Agent)与任务移交(Handoff)。

  • 代理(Agent):代表执行特定任务或功能的单位,可以是具备特定技能或工具的独立实体。
  • 任务移交(Handoff):允许一个代理根据当前上下文将任务委派给另一个更合适的代理。

这种任务的移交需要在生命代理之初就进行定义,除了移交以外,在初始化代理的时候还可以定义代理所具备的能力,包括函数或工具调用等。

为什么需要 Swarm?

Swarm 的核心价值在于其强大的任务分解能力、动态调度机制和多场景适配性,使其成为解决复杂问题的理想框架。对于人工智能系统而言,许多任务并非单一流程可以完成,而是由多个子任务组成。Swarm 的设计理念将复杂问题拆解为若干小任务,通过分工和动态任务调度,让这些子任务相互衔接。

这种机制不仅提高了解决问题的效率,还大幅减少了上下文信息的冗余传播。在此基础上,Swarm 提供了强大的灵活性,可以适配从文档分析到多模型协作的多种应用场景。这种能力的实现基于每个子智能体(Agent)专注于特定领域或任务,其运行严格遵循明确的策略与规则,同时主智能体负责协调和调度整个流程。

这么说可能太抽象,我们以航空公司客户服务为例给大家说明。如下图所示,当服务接收到客户请求时,主智能体(Triage Agent)首先分析用户输入,并结合客户上下文和航班信息,判断问题的类型。例如,如果客户询问如何更改航班,主智能体会将任务传递给专注于航班修改的智能体(Flight Modification Agent)。该智能体进一步对问题进行细化,判断用户的需求是取消航班还是改签航班。如果用户希望取消航班,它会将任务传递给取消航班智能体(Flight Cancel),负责处理退款或生成积分的具体操作;如果用户需要改签航班,任务会被传递给改签智能体(Flight Change),完成航班改签流程。如果在改签和取消航班时遇到问题,智能体还可以将请求再交回给主智能体进行处理,在图中可以看到红线的部分就是交回请求。

在另一个场景中,如果客户报告行李丢失,主智能体会将问题转交给行李管理智能体(Lost Baggage),该模块会立即启动行李搜索流程。如果找到行李,系统会安排将其送达客户地址;如果未能找到,也可以通过红线将请求交回给主智能体。

这种分工明确的设计确保了每个问题都由最适合的模块来处理,而动态调度机制则使得任务能够以最短路径被解决。同时,也体现了 Swarm 的核心优势:通过任务分解,系统将复杂的客户服务流程划分为一个个小模块;通过动态调度,主智能体和子智能体之间的任务交接变得高效流畅;通过策略化引导,子智能体在完成特定任务时能够严格遵循规则,确保用户体验的一致性与任务的准确性。每个子任务的独立性使得系统易于扩展,当新的需求出现时,只需添加对应的子智能体即可,而无需改动现有架构。这不仅降低了系统的复杂性,还显著提高了可维护性。

Swarm 的实战

前面对Swarm 进行简单介绍之后,我们来尝试安装Swarm 并通过实例体验一下它的“魅力”。通过如下指令安装Swarm:

复制

pip install git+ssh://git@github.com/openai/swarm.git

  • 1.

接着,通过一个简单代码来看看它是如何让Agent 工作的。

如下图所示,该示例展示了多语言代理切换功能,具体而言实现了英语、西班牙语和中文三种语言代理之间的智能切换。英语代理作为主代理接受用户的请求,当发现用户请求的内容是中文的时候,转交给中文代理进行处理。需要注意的是,这里的请求移交是通过两个预定义函数完成的,分别是transfer_to_chinese_agent 将请求转交给中文代理,以及transfer_to_spanish_agent 将请求转交给西班牙语代理。

详细代码如下:

复制

from swarm import Swarm, Agent # 创建Swarm客户端实例 client = Swarm() # 创建英语代理实例 english_agent = Agent( # 设置代理的名称为”English Agent” name=”English Agent”, # 设置代理的指令 – 只使用英语交流 instructions=”You only speak English.”, ) # 创建西班牙语代理实例 spanish_agent = Agent( name=”Spanish Agent”, # 设置代理只使用西班牙语交流 instructions=”You only speak Spanish.”, ) # 创建中文代理实例 chinese_agent = Agent( name=”Chinese Agent”, # 设置代理只使用中文交流 instructions=”You only speak Chinese.”, ) # 定义转移到西班牙语代理的函数 def transfer_to_spanish_agent(): “””Transfer spanish speaking users immediately.””” return spanish_agent # 定义转移到中文代理的函数 def transfer_to_chinese_agent(): “””Transfer chinese speaking users immediately.””” return chinese_agent # 将转移函数添加到英语代理的功能列表中 english_agent.functions.append(transfer_to_spanish_agent) english_agent.functions.append(transfer_to_chinese_agent) # 创建用户消息 – 这里使用中文进行测试 messages = [{“role”: “user”, “content”: “你好, 你是谁?”}] # 中文测试消息 # 运行代理并获取响应 response = client.run(agent=english_agent, messages=messages) # 打印最后一条响应消息 print(response.messages[-1][“content”])

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

重点代码解析如下:

1. 代理创建部分

复制

english_agent = Agent( name=”English Agent”, instructions=”You only speak English.”, )

  • 1.
  • 2.
  • 3.
  • 4.

创建了一个英语代理,通过instructions指令,利用提示词工程使大模型扮演说英语的代理角色,负责使用英语与用户交流。中文和西班牙语的代理创建也是采用相同模式。

2. 切换函数定义

复制

def transfer_to_chinese_agent(): “””Transfer chinese speaking users immediately.””” return chinese_agent

  • 1.
  • 2.
  • 3.

该函数实现了向中文代理的移交请求功能,当系统检测到用户使用中文时会触发此函数。与之相同的还有一个transfer_to_spanish_agent,它负责移交请求给西班牙语代理。

3. 功能注册

复制

english_agent.functions.append(transfer_to_spanish_agent) english_agent.functions.append(transfer_to_chinese_agent)

  • 1.
  • 2.

由于我们假设英文代理作为主代理,它负责用户请求的转交,当发现是英语请求的时候它会自己处理,如果发现是其他两种语言的时候,通过预定义的函数功能实现请求转交。这段代码将请求转交功能注册到英语代理中。

4. 测试代码

复制

# 创建用户消息 – 这里使用中文进行测试 messages = [{“role”: “user”, “content”: “你好, 你是谁?”}] # 中文测试消息 # 运行代理并获取响应 response = client.run(agent=english_agent, messages=messages)

  • 1.
  • 2.
  • 3.
  • 4.

接着,使用Swarm实例化的客户端 client进行测试,我们输入中文”你好, 你是谁?”并通过Swarm类的run方法传入主代理english_agent 和messages,通过response返回测试结果如下:

复制

你好,我是一个智能助手,可以帮助你解决各种问题。你有什么需要帮助的吗?

  • 1.

显然,英语代理识别出中文输入,并将请求转交给中文代理执行。

Swarm 核心概念

通过上面Swarm 示例代码,可以理解 Swarm 的关键概念及功能实现:

1. client.run() 方法

client.run() 是 Swarm 中的核心方法,类似于 OpenAI 的 chat.completions.create() 方法。它接受消息输入并返回消息输出,同时在多轮调用之间不保存状态。除了处理消息对话,还支持以下功能:

  • 执行 Agent 的函数调用并追加结果。
  • 在任务完成后转交给其他 Agent(handoffs)。
  • 动态更新上下文变量(context variables)。
  • 在必要时支持多轮对话再返回结果。

例如,在代码中,我们通过 client.run() 将初始用户消息传递给英语代理(English Agent)。当系统检测到输入的语言不符合代理的要求时,会调用代理函数,切换到适合语言的代理,如 Spanish Agent 或 Chinese Agent。

2. Agents(代理)

Agent 是任务执行的基本单元。它可以被看作一个封装了特定指令(instructions)和功能(functions)的“智能体”。Agent 的核心字段包括:

  • name:代理的名称,用于标识。
  • instructions:代理的指令,决定代理的行为方式。
  • functions:代理可以调用的一组 Python 函数,用于执行特定任务。
  • handoff:代理可以通过函数切换到其他代理。

代码中,我们创建了三个代理:English Agent、Spanish Agent 和 Chinese Agent,它们分别按照语言设置了特定的指令。代理通过 instructions 告知系统其行为规范,例如仅使用某种语言交流。

3. Functions(函数)

Swarm 的代理支持直接调用 Python 函数执行任务。函数通常返回一个字符串(str),也可以通过返回一个代理(Agent)实现代理之间的切换,或通过修改上下文变量(context_variables)来动态改变对话状态。

在示例中,transfer_to_spanish_agent 和 transfer_to_chinese_agent 是两个函数,它们的作用是根据用户的语言输入,将当前任务切换到对应的语言代理。

如果一个代理调用了多个函数,Swarm 会按照顺序依次执行它们。如果函数出现错误(如参数缺失或类型错误),系统会生成一个错误响应,并尝试从错误中恢复。

4. Handoffs and Updating Context Variables(代理切换和上下文变量更新)

代理转交(Handoff)在代理无法完成任务时,可以将任务交接给其他代理。例如,English Agent 调用 transfer_to_spanish_agent 函数后,返回了 Spanish Agent,实现了从英语代理到西班牙语代理的切换。

此外,Swarm 还支持动态更新上下文变量。通过返回一个 Result 对象,函数可以同时更新返回值、切换代理和修改上下文变量。这种能力确保了复杂任务流程中每个步骤的信息传递和状态保持一致。

5. Function Schemas(函数模式)

Swarm 能够自动将函数转换为 JSON Schema,以便代理理解函数的功能和参数需求:

  • 函数的文档字符串(docstring)会转化为函数的描述信息。
  • 参数的类型提示(type hints)会映射到 JSON Schema 的字段类型。
  • 如果函数定义了必需参数,则会自动标记为 required。

Swarm 是如何运作的 ?

Swarm 的运作核心在于通过多个智能体(Agent)的协同工作,实现复杂任务的高效处理。为了让大家对这个过程有深入的了解,接下来,我们会从Routine 概念开始,逐步演化为具备智能能力的 Agent,并最终依靠 Handoff 功能实现动态任务分配。

Routine 是 Swarm 的基础单元,由预定义的指令和工具/函数组成,负责描述任务的逻辑流程及完成任务所需的工具。而 Agent 是一种强化版的 Routine,通过结合大语言模型(LLM),赋予其智能理解和决策能力,使其不仅能够执行预定义任务,还能灵活应对复杂的用户需求。在此基础上,Swarm 的 Handoff 功能让不同的 Agent 能够根据请求的内容动态协作,将用户的任务无缝转交给更适合的 Agent 处理,并完整保留对话上下文,避免用户重复输入。

什么是 Routine?

简单来说,Routine 是一组预定义的指令与相应工具的组合,旨在完成特定任务。它不仅是一个执行步骤的计划,还包含完成任务所需的资源和工具。我们可以简单理解Routine 就是Agent(代理)的雏形,它描述了代理需要完成的任务,同时还赋予它对应的工具/函数,只是Agent 本身还具备大模型的能力还可以进行“思考”。

如下图所示,Routine可以拆解为两部分:

  • 指令(Instructions):以自然语言或系统提示的形式描述的任务执行步骤。
  • 工具/函数(Tools/function):完成这些步骤所需的工具或函数。需要说明的是,无论是调用工具或者函数都会通过函数调用的方式,也就是function call的方式完成。

说白了,Routine就是系统提示:描述任务的逻辑流程(比如询问问题、搜索信息或处理用户请求),加上可调用的工具/函数(用来辅助完成这些任务)。

来个具体的例子,我们为客户服务代理定义了一个例程,指示其对用户问题进行分类,然后建议修复或提供退款。同时定义函数execute_refund和look_up_item 作为外部工具协助完成退货以及查找订单的工作。下面就是客户服务例程的代码:指令和工具/函数。

复制

system_message = ( “你是一名 ACME Inc. 的客户服务代理,以下是你的工作流程:\n” “1. 首先,向用户询问更多信息以理解他们的问题(如果问题未明确)。\n” “2. 提出一个解决方案。\n” “3. 如果用户不满意,提供退款。\n” “4. 如果接受退款,查找物品 ID 并执行退款操作。” ) def look_up_item(search_query): “””Use to find item ID. Search query can be a description or keywords.””” # return hard-coded item ID – in reality would be a lookup return “item_132612938″ def execute_refund(item_id, reason=”not provided”): print(“Summary:”, item_id, reason) # lazy summary return “success”

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

如何执行 Routine?

为了执行 Routine,需要实现从用户交互到模型调用、工具执行的完整闭环。以下是几个关键部分:

1.函数定义(Function Definition)

函数是 Routine 的核心工具。它们可以是具体的业务逻辑实现,例如处理退款或查询信息。这也就是前面描述的execute_refund和look_up_item 两个函数的定义,代码在上面已经展示过了, 这里就不赘述了。需要说明的是,look_up_item 执行订单查询,execute_refund 负责退款操作。

2.函数接口(Function Schema)

当语言模型接到用户请求的时候,需要调用函数返回对应的结果,调用函数时需要使用Function Schema。它包括:函数的名称、参数及其类型等信息。为此需要将 Python 函数定义转化为标准化的 Schema(模式)。为了实现从函数到函数接口的转换需要实现如下代码:

复制

import inspect def function_to_schema(func) -> dict: “””将函数定义转化为 Schema 格式。””” type_map = { str: “string”, int: “integer”, float: “number”, bool: “boolean”, list: “array”, dict: “object”, type(None): “null”, } # 获取函数签名 signature = inspect.signature(func) parameters = {} for param in signature.parameters.values(): param_type = type_map.get(param.annotation, “string”) parameters[param.name] = {“type”: param_type} required = [ param.name for param in signature.parameters.values() if param.default == inspect._empty ] return { “type”: “function”, “function”: { “name”: func.__name__, “description”: (func.__doc__ or “”).strip(), “parameters”: { “type”: “object”, “properties”: parameters, “required”: required, }, }, }

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.

这个代码主要通过输入函数句柄,提取函数名称、描述、输入参数等信息,从而生成函数接口(Function schema)。我们可以用execute_refund 函数测试其效果。代码如下:

复制

# 示例输出 schema = function_to_schema(execute_refund) print(schema) 结果: { “type”: “function”, “function”: { “name”: “execute_refund”, “description”: “执行退款操作。”, “parameters”: { “type”: “object”, “properties”: { “item_id”: { “type”: “string” }, “reason”: { “type”: “string” } }, “required”: [“item_id”] } } }

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  1. 函数调用(Function Call)

完成函数定义和调用函数接口之后,接下来就是利用函数接口去调用对应的函数。需要将 Schema 注册为工具,供模型生成调用指令。然后,根据调用结果执行对应函数,最后将结果返回给模型。执行代码如下:

复制

# 定义可用的工具函数列表 tools = [execute_refund, look_up_item] def run_full_turn(system_message, tools, messages): # 记录初始消息数量 num_init_messages = len(messages) # 复制消息列表以避免修改原始数据 messages = messages.copy() while True: # 将Python函数转换为OpenAI工具模式 tool_schemas = [function_to_schema(tool) for tool in tools] # 创建工具名称到函数的映射字典 tools_map = {tool.__name__: tool for tool in tools} # 调用OpenAI API获取回复 response = client.chat.completions.create( model=”gpt-4o-mini”, messages=[{“role”: “system”, “content”: system_message}] + messages, tools=tool_schemas or None, ) # 获取AI助手的回复 message = response.choices[0].message # 将助手回复添加到消息历史 messages.append(message) # 如果有文本回复则打印 if message.content: print(“Assistant:”, message.content) # 如果没有工具调用请求则结束循环 if not message.tool_calls: break # 处理工具调用 for tool_call in message.tool_calls: # 执行工具调用并获取结果 result = execute_tool_call(tool_call, tools_map) # 将工具调用结果添加到消息历史 result_message = { “role”: “tool”, “tool_call_id”: tool_call.id, “content”: result, } messages.append(result_message) # 返回新增的消息 return messages[num_init_messages:] def execute_tool_call(tool_call, tools_map): # 获取要调用的函数名 name = tool_call.function.name # 解析函数参数 args = json.loads(tool_call.function.arguments) # 打印调用信息 print(f”Assistant: {name}({args})”) # 执行函数调用并返回结果 return tools_map[name](**args) # 主循环 messages = [] while True: # 获取用户输入 user = input(“User: “) # 添加用户消息到历史 messages.append({“role”: “user”, “content”: user}) # 执行一轮对话并获取新消息 new_messages = run_full_turn(system_message, tools, messages) # 将新消息添加到历史中 messages.extend(new_messages)

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.

在这段代码中,通过大模型和Routine构建了一个交互系统,用来让客服代理与用户进行对话。我们截取部分重要段落给大家进行拆解如下:

首先,定义一组工具函数(如 execute_refund 和 look_up_item),这些工具提供了解决具体业务需求的能力。它们被集中存储在一个列表中,随后通过工具模式(Schema)转化为模型可以识别和调用的接口描述,从而成为语言模型的可用扩展。

复制

tools = [execute_refund, look_up_item] tool_schemas = [function_to_schema(tool) for tool in tools]

  • 1.
  • 2.

function_to_schema 方法将 Python 函数转换为模型可理解的工具描述,方便系统动态调用这些函数。

对话流程的核心由 run_full_turn 函数实现,它负责完成一轮从用户输入到工具调用再到生成助手回复的整个逻辑。其实现的关键在于利用 OpenAI 模型生成回复并解析是否需要工具调用。每次交互开始时,系统会加载当前的消息历史以及可用工具的模式列表,然后通过调用模型接口获取助手的回复。如果模型未请求调用工具,则直接返回助手的回复;否则系统将根据工具调用的描述执行相应的函数。

复制

response = client.chat.completions.create( model=”gpt-4o-mini”, messages=[{“role”: “system”, “content”: system_message}] + messages, tools=tool_schemas or None, )

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

工具调用的具体执行逻辑由 execute_tool_call 函数实现。每当模型发出工具调用请求时,该函数会根据请求中描述的工具名称和参数,查找与之对应的 Python 函数并执行操作。例如,若助手要求退款操作,则函数会解析出对应的函数名称和参数,然后调用 execute_refund 完成任务,返回结果后更新对话历史。

复制

def execute_tool_call(tool_call, tools_map): name = tool_call.function.name args = json.loads(tool_call.function.arguments) return tools_map[name](**args)

  • 1.
  • 2.
  • 3.
  • 4.

最后,通过一个主循环实现用户与助手的持续交互。用户的输入被实时加入消息历史,随后调用 run_full_turn 生成助手回复,并在必要时调用外部工具函数。所有新增的消息和工具调用结果都会被动态更新到对话历史中,保证了上下文的连贯性。

复制

while True: user = input(“User: “) messages.append({“role”: “user”, “content”: user}) new_messages = run_full_turn(system_message, tools, messages) messages.extend(new_messages)

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

从Routine到Agent

到目前为止,我们得到了Routine,它可以理解为指令和工具的集合,为了让它独立工作还需要加入大语言模型(LLM),这样才能过渡到Swarm中的Agent形态。这里我们将智能体(Agent)理解为一种强化版的 Routine,即 Routine 加上了语言模型(LLM)的智能能力。Routine 负责定义工具和执行步骤,而 Agent 则通过结合 LLM 具备了智能理解和处理能力。具体来说,Agent 包括以下几个核心要素:

  • 名称(Name):用于标识 Agent 的职责。
  • 模型(Model):用来理解用户请求,处理工具函数调用,并给予用户反馈。
  • 指令(Instructions):定义 Agent 如何执行其任务。
  • 工具(Tools):该 Agent 可以调用的一组函数。

我们可以通过如下代码来定义Agent:

复制

class Agent(BaseModel): name: str = “Agent” model: str = “gpt-4o-mini” instructions: str = “You are a helpful Agent” tools: list = []

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

顺着这个思路,我们可以定义更多的代理如下:

复制

def execute_refund(item_name): return “success” refund_agent = Agent( name=”Refund Agent”, instructions=”You are a refund agent. Help the user with refunds.”, tools=[execute_refund], ) def place_order(item_name): return “success” sales_assistant = Agent( name=”Sales Assistant”, instructions=”You are a sales assistant. Sell the user a product.”, tools=[place_order], )

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

上面代码定义了退货和销售代理,分别针对两个代理都定义了工具/函数,协助他们完成工作。

Handoff转交功能

好!目前,我们已经理解了Routine 并且顺利从Routine的概念过渡到了Agent,还记得我们在“什么是Swarm”章节中介绍Swarm结构的核心就是Agent和Handoff, 接着我们就来介绍Handoff 功能。前面的内容中也提到了, 在当前代理无法处理对应请求的时候,该代理会将请求转交给其他代理处理。

于是,我们修改执行代码如下:

复制

def run_full_turn(agent, messages): # 初始化当前智能体为传入的 agent current_agent = agent # 记录初始消息数量,用于之后返回新增消息 num_init_messages = len(messages) # 复制消息列表,防止对原始消息数据造成影响 messages = messages.copy() while True: # 将当前智能体的工具列表转化为工具模式(schemas),用于 API 调用 tool_schemas = [function_to_schema(tool) for tool in current_agent.tools] # 构造工具名称到工具函数的映射 tools = {tool.__name__: tool for tool in current_agent.tools} # === 1. 调用 OpenAI 接口生成回复 === response = client.chat.completions.create( model=agent.model, # 当前智能体使用的模型 messages=[{“role”: “system”, “content”: current_agent.instructions}] + messages, # 包括系统消息和历史对话内容 tools=tool_schemas or None, # 提供工具的模式定义 ) # 获取生成的消息 message = response.choices[0].message # 将回复消息添加到历史记录中 messages.append(message) # 如果消息包含文本内容,则打印当前智能体的回复 if message.content: print(f”{current_agent.name}:”, message.content) # 如果没有工具调用请求,则退出循环 if not message.tool_calls: break # === 2. 处理工具调用 === for tool_call in message.tool_calls: # 执行工具调用,并返回结果 result = execute_tool_call(tool_call, tools, current_agent.name) # 如果工具调用结果是一个新的智能体对象,则进行切换 if type(result) is Agent: current_agent = result # 更新当前智能体为新的智能体 result = ( f”Transfered to {current_agent.name}. Adopt persona immediately.” ) # 生成切换通知 # 将工具调用的结果作为消息添加到历史记录中 result_message = { “role”: “tool”, “tool_call_id”: tool_call.id, “content”: result, } messages.append(result_message) # ==== 3. 返回最后使用的智能体和新增的消息记录 ==== return Response(agent=current_agent, messages=messages[num_init_messages:]) def execute_tool_call(tool_call, tools, agent_name): # 提取工具名称 name = tool_call.function.name # 解析工具调用的参数 args = json.loads(tool_call.function.arguments) # 打印工具调用的详细信息 print(f”{agent_name}:”, f”{name}({args})”) # 调用对应的工具函数并返回其结果 return tools[name](**args)

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.

我们把目光放到与Handoff 相关的细节上,工具调用返回智能体对象。在处理工具调用时,execute_tool_call 的返回结果是 Agent 对象,说明该工具无法完成用户的请求,通过返回Agent的方式让请求切换到其他Agent中去。这里需要注意的是,我们将Handoff的动作也封装成了函数,该函数会直接返回要切换到的Agent对象,他的具体应用就在此处。

在run_full_turn函数中通过 type(result) 判断,如果返回的是 Agent 类型,则说明需要进行智能体切换。

复制

# 执行工具调用,并返回结果 result = execute_tool_call(tool_call, tools, current_agent.name) if type(result) is Agent: # 如果工具调用返回一个新的 Agent current_agent = result # 更新当前智能体 result = ( f”Transfered to {current_agent.name}. Adopt persona immediately.” ) # 通知用户智能体切换

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

除此之外,我们还需要动态更新 current_agent 的工具和说明,确保切换后的行为符合目标智能体的能力。为了让对话记录延续,需要通过消息列表的复制和扩展(messages.copy()),保留了所有上下文信息。

总结

Swarm 作为 OpenAI 的实验性框架,旨在解决复杂场景下多代理协作问题。AI 代理具备自主感知、决策和行动能力,Swarm 则让多个代理协同工作。其优势在于强大的任务分解和动态调度,适用于多种场景,如航空公司客户服务等。在实战示例中,通过代码展示了多语言代理切换功能,体现了 Swarm 的核心方法、代理、函数等概念及功能。深入原理部分,Routine 是基础单元,执行 Routine 需实现函数定义、接口和调用等环节,Agent 是强化版 Routine,结合了大语言模型的智能能力,Handoff 功能可在代理无法处理请求时进行任务转交,通过一系列操作确保对话上下文延续及智能体切换后的行为符合要求。

文章来自:51CTO

Loading

作者 yinhua

发表回复