Skip to main content

货币计算器:使用提供的函数工具解决任务

在 Colab 中打开 在 GitHub 上打开

AutoGen 提供了由 LLM、工具或人类驱动的可对话代理,可以通过自动聊天来共同执行任务。该框架通过多代理对话允许工具使用和人类参与。有关此功能的文档,请参阅此处

在本笔记本中,我们演示了如何使用 AssistantAgentUserProxyAgent 来使用 OpenAI 模型的新功能(在模型版本 0613 中)进行函数调用。必须向 AssistantAgent 传递指定的提示和函数配置以初始化代理。相应的函数必须传递给 UserProxyAgent,它将执行 AssistantAgent 进行的任何函数调用。除了需要将描述与函数匹配之外,我们建议检查 AssistantAgent 中的系统消息,以确保指令与函数调用描述相符。

要求

AutoGen 需要 Python>=3.8。要运行此笔记本示例,请安装 pyautogen

pip install pyautogen
# %pip install "pyautogen>=0.2.3"

设置 API 端点

config_list_from_json 函数从环境变量或 json 文件中加载配置列表。

from typing import Literal

from pydantic import BaseModel, Field
from typing_extensions import Annotated

import autogen
from autogen.cache import Cache

config_list = autogen.config_list_from_json(
"OAI_CONFIG_LIST",
filter_dict={"tags": ["3.5-tool"]}, # comment out to get all
)

它首先查找名为 "OAI_CONFIG_LIST" 的环境变量,该变量需要是一个有效的 json 字符串。如果找不到该变量,则会查找名为 "OAI_CONFIG_LIST" 的 json 文件。它通过标签对配置进行过滤(您也可以使用其他键进行过滤)。只有符合过滤条件的配置才会保留在列表中。

配置列表的格式如下:

config_list = [
{
'model': 'gpt-3.5-turbo',
'api_key': '<在此处填入你的 OpenAI API 密钥>',
'tags': ['工具', '3.5-工具'],
},
{
'model': 'gpt-3.5-turbo',
'api_key': '<在此处填入你的 Azure OpenAI API 密钥>',
'base_url': '<在此处填入你的 Azure OpenAI API 基础地址>',
'api_type': 'azure',
'api_version': '2024-02-01',
'tags': ['工具', '3.5-工具'],
},
{
'model': 'gpt-3.5-turbo-16k',
'api_key': '<在此处填入你的 Azure OpenAI API 密钥>',
'base_url': '<在此处填入你的 Azure OpenAI API 基础地址>',
'api_type': 'azure',
'api_version': '2024-02-01',
'tags': ['工具', '3.5-工具'],
},
]

您可以以任何方式设置config_list的值。请参考此notebook中的完整代码示例,了解不同方法的用法。

进行函数调用

在这个例子中,我们演示了使用AssistantAgentUserProxyAgent进行函数调用的执行方式。使用默认的系统提示AssistantAgent,我们允许LLM助手执行带有代码的任务,而UserProxyAgent则会从LLM的响应中提取代码块并执行。通过新的“function_call”功能,我们在AssistantAgent的OpenAI配置中定义函数并指定函数的描述。然后我们在UserProxyAgent中注册这些函数。

llm_config = {
"config_list": config_list,
"timeout": 120,
}

chatbot = autogen.AssistantAgent(
name="chatbot",
system_message="对于货币兑换任务,请仅使用提供的函数。完成任务后,请回复TERMINATE。",
llm_config=llm_config,
)

# 创建一个名为"user_proxy"的UserProxyAgent实例
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
)


CurrencySymbol = Literal["USD", "EUR"]


def exchange_rate(base_currency: CurrencySymbol, quote_currency: CurrencySymbol) -> float:
if base_currency == quote_currency:
return 1.0
elif base_currency == "USD" and quote_currency == "EUR":
return 1 / 1.1
elif base_currency == "EUR" and quote_currency == "USD":
return 1.1
else:
raise ValueError(f"未知货币 {base_currency}, {quote_currency}")


@user_proxy.register_for_execution()
@chatbot.register_for_llm(description="货币兑换计算器。")
def currency_calculator(
base_amount: Annotated[float, "基准货币的金额"],
base_currency: Annotated[CurrencySymbol, "基准货币"] = "USD",
quote_currency: Annotated[CurrencySymbol, "目标货币"] = "EUR",
) -> str:
quote_amount = exchange_rate(base_currency, quote_currency) * base_amount
return f"{quote_amount} {quote_currency}"

装饰器@chatbot.register_for_llm()读取函数currency_calculator的注释签名,并生成以下由OpenAI API使用的JSON模式,以建议调用该函数。我们可以通过以下方式检查生成的JSON模式:

chatbot.llm_config["tools"]
[{'type': 'function',
'function': {'description': '货币兑换计算器。',
'name': 'currency_calculator',
'parameters': {'type': 'object',
'properties': {'base_amount': {'type': 'number',
'description': '基准货币的金额'},
'base_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'USD',
'description': '基准货币'},
'quote_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'EUR',
'description': '报价货币'}},
'required': ['base_amount']}}}]

装饰器 @user_proxy.register_for_execution() 将 OpenAI API 提供的函数名称映射到实际的实现。映射的函数被包装,因为我们还会自动处理函数输出的序列化,具体如下:

  • 字符串保持不变,和

  • Pydantic BaseModel 类型的对象被序列化为 JSON。

我们可以使用包装函数的 ._origin 属性来检查函数映射的正确性,如下所示:

assert user_proxy.function_map["currency_calculator"]._origin == currency_calculator

最后,我们可以使用这个函数来准确计算兑换金额:

with Cache.disk() as cache:
# 开始对话
res = user_proxy.initiate_chat(
chatbot, message="How much is 123.45 USD in EUR?", summary_method="reflection_with_llm", cache=cache
)
user_proxy (to chatbot):

How much is 123.45 USD in EUR?

--------------------------------------------------------------------------------
chatbot (to user_proxy):

***** 建议的工具调用 (call_9ogJS4d40BT1rXfMn7YJb151): currency_calculator *****
参数:
{
"base_amount": 123.45,
"base_currency": "USD",
"quote_currency": "EUR"
}
************************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> 执行函数 currency_calculator...
user_proxy (to chatbot):

user_proxy (to chatbot):

***** 调用工具的响应 (call_9ogJS4d40BT1rXfMn7YJb151) *****
112.22727272727272 EUR
**********************************************************************

--------------------------------------------------------------------------------
chatbot (to user_proxy):

123.45 USD 相当于 112.23 EUR。

--------------------------------------------------------------------------------
user_proxy (to chatbot):



--------------------------------------------------------------------------------
chatbot (to user_proxy):

终止

--------------------------------------------------------------------------------
print("对话摘要:", res.summary)
对话摘要: 123.45 USD 相当于 112.23 EUR。

Pydantic 模型

我们还可以使用 Pydantic 基础模型来重写函数,如下所示:

llm_config = {
"config_list": config_list,
"timeout": 120,
}

chatbot = autogen.AssistantAgent(
name="chatbot",
system_message="对于货币兑换任务,请仅使用您所提供的功能。完成任务后回复 TERMINATE。",
llm_config=llm_config,
)

# 创建一个名为 "user_proxy" 的 UserProxyAgent 实例
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
)


class Currency(BaseModel):
currency: Annotated[CurrencySymbol, Field(..., description="货币符号")]
amount: Annotated[float, Field(0, description="货币数量", ge=0)]


# 另一种注册函数的方法是使用 register_function 而不是 register_for_execution 和 register_for_llm 装饰器
def currency_calculator(
base: Annotated[Currency, "基础货币:数量和货币符号"],
quote_currency: Annotated[CurrencySymbol, "目标货币符号"] = "USD",
) -> Currency:
quote_amount = exchange_rate(base.currency, quote_currency) * base.amount
return Currency(amount=quote_amount, currency=quote_currency)


autogen.agentchat.register_function(
currency_calculator,
caller=chatbot,
executor=user_proxy,
description="货币兑换计算器。",
)
chatbot.llm_config["tools"]
[{'type': 'function',
'function': {'description': '货币兑换计算器。',
'name': 'currency_calculator',
'parameters': {'type': 'object',
'properties': {'base': {'properties': {'currency': {'description': '货币符号',
'enum': ['USD', 'EUR'],
'title': '货币',
'type': 'string'},
'amount': {'default': 0,
'description': '货币金额',
'minimum': 0.0,
'title': '金额',
'type': 'number'}},
'required': ['currency'],
'title': '货币',
'type': 'object',
'description': '基准货币:金额和货币符号'},
'quote_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'USD',
'description': '目标货币符号'}},
'required': ['base']}}}]
with Cache.disk() as cache:
# 开始对话
res = user_proxy.initiate_chat(
chatbot, message="112.23欧元等于多少美元?", summary_method="reflection_with_llm", cache=cache
)
user_proxy (对 chatbot 说):

112.23欧元等于多少美元?

--------------------------------------------------------------------------------
chatbot (对 user_proxy 说):

***** 建议的工具调用 (call_BQkSmdFHsrKvmtDWCk0mY5sF): currency_calculator *****
参数:
{
"base": {
"currency": "EUR",
"amount": 112.23
},
"quote_currency": "USD"
}
************************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> 执行函数 currency_calculator...
user_proxy (对 chatbot 说):

user_proxy (对 chatbot 说):

***** 调用工具的响应 (call_BQkSmdFHsrKvmtDWCk0mY5sF) *****
{"currency":"USD","amount":123.45300000000002}
**********************************************************************

--------------------------------------------------------------------------------
chatbot (对 user_proxy 说):

112.23欧元等于123.45美元。
终止

--------------------------------------------------------------------------------
print("对话摘要:", res.summary)
对话摘要: 112.23欧元等于123.45美元。
with Cache.disk() as cache:
# 开始对话
res = user_proxy.initiate_chat(
chatbot,
message="123.45美元等于多少欧元?",
cache=cache,
)
user_proxy (向chatbot发问):

123.45美元等于多少欧元?

--------------------------------------------------------------------------------
chatbot (回答user_proxy):

***** 推荐的工具调用 (call_Xxol42xTswZHGX60OjvIQRG1): currency_calculator *****
参数:
{
"base": {
"currency": "USD",
"amount": 123.45
},
"quote_currency": "EUR"
}
************************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> 执行函数 currency_calculator...
user_proxy (向chatbot发问):

user_proxy (向chatbot发问):

***** 调用工具的响应 (call_Xxol42xTswZHGX60OjvIQRG1) *****
{"currency":"EUR","amount":112.22727272727272}
**********************************************************************

--------------------------------------------------------------------------------
chatbot (回答user_proxy):

123.45美元等于112.23欧元。

--------------------------------------------------------------------------------
user_proxy (向chatbot发问):



--------------------------------------------------------------------------------
chatbot (回答user_proxy):

终止

--------------------------------------------------------------------------------
print("聊天记录:", res.chat_history)
聊天记录: [{'content': '123.45美元等于多少欧元?', 'role': 'assistant'}, {'tool_calls': [{'id': 'call_Xxol42xTswZHGX60OjvIQRG1', 'function': {'arguments': '{\n  "base": {\n    "currency": "USD",\n    "amount": 123.45\n  },\n  "quote_currency": "EUR"\n}', 'name': 'currency_calculator'}, 'type': 'function'}], 'content': None, 'role': 'assistant'}, {'content': '{"currency":"EUR","amount":112.22727272727272}', 'tool_responses': [{'tool_call_id': 'call_Xxol42xTswZHGX60OjvIQRG1', 'role': 'tool', 'content': '{"currency":"EUR","amount":112.22727272727272}'}], 'role': 'tool'}, {'content': '123.45美元等于112.23欧元。', 'role': 'user'}, {'content': '', 'role': 'assistant'}, {'content': '终止', 'role': 'user'}]