项目链接:

https://github.com/openai/swarm

1.指令(Instruction)参数

智能体的指令将直接转化为对话的系统提示(也可以理解为它是LLM接受到的第一条消息)。

在任何时候,只有当前活跃Agent的指令会存在(例如,如果发生智能体交接,系统体会会跟随Agent变化而发生改变,但是聊天记录则不会)。

举个简单的例子:

from openai import OpenAI
from swarm import Swarm, Agent

# 设置API密钥和基础URL
api_key = "API_KEY" 
base_url = "BASE_URL"

# 实例化OpenAI客户端和Swarm客户端
client = OpenAI(api_key=api_key, base_url=base_url)
swarm_client = Swarm(client)


# 创建Agent A,设置其名称、指令
agent_a = Agent(
    name="Agent A",
    instructions="无论用户发送的消息是什么语言,请用英文回答。",
)

# 创建Agent B,设置其名称和指令
agent_b = Agent(
    name="Agent B",
    instructions="无论用户发送的消息是什么语言,请用中文回答。",
)

test_message = {"role": "user", "content": "你好,请介绍一下你自己。"}

response_a = swarm_client.run(
    agent=agent_a,
    messages=[test_message],
)

response_b = swarm_client.run(
    agent=agent_b,
    messages=[test_message],
)

print(response_a.messages[-1]["content"])
print(response_b.messages[-1]["content"])

最终得到的回复如下:

Hello! I'm an AI language model developed by OpenAI. I'm designed to assist with a wide range of inquiries by providing information, answering questions, and generating text based on the input I receive. My knowledge is based on data up to October 2023. If you have any questions or need assistance, feel free to ask!
你好!我是一个人工智能助手,旨在提供信息和帮助,回答各种问题。从基本知识到复杂信息领域,我都会尽力提供准确和有用的答案。如果你有任何问题或者需要帮助,随时告诉我!

Instructions是能够长期影响每一个Agent的行为的。

值得注意的是,Instructions可以是普通的str字符串,也可以是返回字符串的函数。该函数可以选择接受一个context_variables参数,context_variables将由传递给client.run()的上下文变量进行填充。

举个简单的例子:

def instructions(context_variables):
    user_name = context_variables["user_name"]
    return f"用户的昵称是{user_name}。"

test_message_name = {"role": "user", "content": "你好,请问你知道我的昵称么?"}

agent = Agent(
    instructions=instructions,
)

response = swarm_client.run(
    agent=agent,
    messages=[test_message_name],
    context_variables={"user_name": "ArtemisYi"}
)

print(response.messages[-1]["content"])

得到的回复如下:

你好,你的昵称是ArtemisYi。有什么我可以帮助你的吗?

也就是说,实际编写程序时,可以把context_variables直接写到.run中进行定义。这一功能非常实用,方便开发者在编写.run时统一管理传入的参数。

2.外部函数(Functions)参数

2.1 什么是Function Calling

OpenAI在0613的更新中为目前最先进的Chat类模型增加了Function Calling的功能,该功能的本质是让大语言模型拥有调用外部函数的能力。

这个能力和ChatGPT插件功能有些类似,就是告诉ChatGPT怎么调用你的接口,以及这些接口都能做什么,那么当用户在使用ChatGPT的时候,如果ChatGPT认为用户提的某些问题利用插件能够更好的解决,那么ChatGPT就会直接去调用插件的接口。

Function Calling其实就是把这个过程API化,模型不再仅仅根据自身的数据库知识进行问答,而是可以额外挂载一个函数库,然后根据用户提问进行数据库检索,根据实际需求调用外部函数并获取函数运行结果,再基于函数运行结果进行回答。

image
image

Function Calling的功能与LLM本身的能力息息相关。当LLM的能力越强,越能清晰地判断如何调用各类函数来完成用户的需求。如果能力不足,比较容易出现下述情况:

  • 有相关的外部函数可以调用却没有调用。
  • 不需要调用外部函数的时候却调用了,造成计算资源的浪费。

2.2 快速实现

Swarm智能体可以直接调用Python函数。在通常情况下,函数应该返回一个str字符串(Swarm会尝试将返回值转换为字符串)。如果函数返回的是一个智能体(Agent),执行将转移到该智能体。如果函数定义了一个context_veriables参数,它将由传递给client.run()的上下文变量填充。

举个简单的例子:

def get_date():
    return "今天是星期一"

agent_weather = Agent(
    functions=[get_date]
)

response = swarm_client.run(
    agent=agent_weather,
    messages=[{"role": "user", "content": "你好,今天是星期几?"}]
)

print(response.messages[-1]["content"])

最终返回的结果如下:

今天是星期一。

如果想看到完整的流程,可以返回response.messages(用json格式化后的结果):

[
    {
        "content": null,
        "refusal": null,
        "role": "assistant",
        "audio": null,
        "function_call": null,
        "tool_calls": [
            {
                "id": "call_YVWrIOGisdOcSPU3lxKAmOxQ",
                "function": {
                    "arguments": "{}",
                    "name": "get_date"
                },
                "type": "function"
            }
        ],
        "sender": "Agent"
    },
    {
        "role": "tool",
        "tool_call_id": "call_YVWrIOGisdOcSPU3lxKAmOxQ",
        "tool_name": "get_date",
        "content": "今天是星期一"
    },
    {
        "content": "今天是星期一。",
        "refusal": null,
        "role": "assistant",
        "audio": null,
        "function_call": null,
        "tool_calls": null,
        "sender": "Agent"
    }
]

2.3 Swarm的优势

Swarm-01-初体验中,曾经提到过“用AI来开发AI”。这句话在Function Calling环节得到了充分体现。

这里直接用一个完整的案例来展示比较好,现在让LLM接入天气查询的API。

首先,注册OpenWeather(一个有免费调用次数的天气查询API,注册无需魔法),获取API。

image
image
image
image

接下来从头走一遍标准流程。

from openai import OpenAI
from swarm import Swarm, Agent
import json
import requests
# 设置API密钥和基础URL
api_key = "API_KEY" 
base_url = "BASE_URL"

# 实例化OpenAI客户端和Swarm客户端
client = OpenAI(api_key=api_key, base_url=base_url)
swarm_client = Swarm(client)

重点在于,创建查询即时天气的函数:

def get_weather(loc):
    """
    查询即时天气的函数
    :param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称。
    注意,中国的城市需要用对应的英文名称,例如如果查询北京的天气,则loc参数需要输入"Beijing"
    :return:API查询即使天气的结果,具体的请求地址为https://api.openweathermap.org/data/2.5/weather
    返回结果对象类型为解析之后的JSON格式对象,并用字符串形式进行标识,其中包含了全部重要的天气信息。
    """
    url = "https://api.openweathermap.org/data/2.5/weather"
    params = {
        "q": loc,
        "appid": "WEATHER_API_KEY",
        "lang": "zh_cn",
        "units": "metric"
    }
    response = requests.get(url, params=params)
    data = response.json()
    return json.dumps(data, indent=4, ensure_ascii=False)

在这个函数中需要做的事情主要包括以下两点:

  • 完整的描述该函数的功能,包括对输入参数与返回参数的说明。
  • 通过URL与API获取目标城市的天气信息。

最后,创建可以调用这个函数的智能体,获取回复:

agent = Agent(
    functions=[get_weather]
    instructions="用Markdown格式,分点结构化输出回复。"
)

response = swarm_client.run(
    agent=agent,
    messages=[{"role": "user", "content": "请问北京现在天气如何?"}],
)

print(response.messages[-1]["content"])

最后的结果如下:

image
image

在终端内无法看到完整效果,如果是在支持MD格式的软件或者Jupyter内调用display命令则效果更好

image
image

通过这个案例,充分体现了Swarm框架的能力:不需要编写繁杂的代码,只需要用自然语言描述清楚函数的参数与功能,加上一个特征明显的函数名,就可以轻松实现Function Calling。

此外,LLM的纠错能力也能在此处得到体现:

response = swarm_client.run(
    agent=agent,
    messages=[{"role": "user", "content": "请问商嗨现在天气如何?"}],
)

模型的回复:

image
image