LLM 函数调用¶
继续我们在基础用法中的简单数学示例,本文档解释如何将工具注册表与 OpenAI API 一起使用。请注意,您可以将 OpenAI 客户端与任何提供 OpenAI 兼容 API 的 API 提供者一起使用。在本指南中,我们将使用 DeepSeek 作为示例。
回想一下,我们使用 registry.get_schemas() 获得了两个数学函数的 JSON 模式:
[
{
"type": "function",
"function": {
"name": "add",
"description": "将两个数字相加。",
"parameters": {
"properties": {
"a": {
"title": "A",
"type": "number"
},
"b": {
"title": "B",
"type": "number"
}
},
"required": ["a", "b"],
"title": "addParameters",
"type": "object"
}
}
},
{
"type": "function",
"function": {
"name": "subtract",
"description": "从第一个数字中减去第二个数字。",
"parameters": {
"properties": {
"a": {
"title": "A",
"type": "integer"
},
"b": {
"title": "B",
"type": "integer"
}
},
"required": ["a", "b"],
"title": "subtractParameters",
"type": "object"
}
}
}
]
提供带工具的聊天查询¶
将工具 JSON 模式提供给 OpenAI 客户端的聊天完成接口:
import os
from dotenv import load_dotenv
from openai import OpenAI
# 从 .env 文件加载环境变量
load_dotenv()
# 配置 OpenAI 客户端
client = OpenAI(
api_key=os.getenv("API_KEY", "your-api-key"),
base_url=os.getenv("BASE_URL", "https://api.deepseek.com/"),
)
messages = [
{
"role": "user",
"content": "我有 15 个栗子。Joe 吃了 3 个。我还剩多少个栗子?",
}
]
# 发送聊天完成请求
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
tools=registry.get_schemas(), # 这里我们提供模式
tool_choice="auto",
)
什么是 tool_calls?¶
如果模型(LLM)决定使用工具,它将在响应消息中返回 tool_calls:
if response.choices[0].message.tool_calls:
tool_calls = response.choices[0].message.tool_calls
print(tool_calls)
[ChatCompletionMessageToolCall(id='call_egkg4evbb19d8012bex83v8a', function=Function(arguments='{"a":15,"b":3}', name='subtract'), type='function', index=0)]
tool_calls 对象是 ChatCompletionMessageToolCall 对象的 List。以下属性特别有用:
id:这是我们将结果反馈给 LLM 时需要的function:这是核心,包含目标函数的参数和名称index:在非流模式下不太有用,但如果您流式传输聊天结果,这是组合完整 tool_calls 信息的关键
执行工具调用¶
使用 ToolRegistry,您可以轻松处理来自所有 tool_calls 的结果。请注意,有时 LLM 可能决定同时调用多个工具。
注册表的工具执行结果作为 Python 字典返回,将 tool_call_id 映射到结果:
将结果反馈给 LLM¶
执行工具调用后,我们仍需要在 LLM 能够回答原始问题之前告知它结果。
我们需要构造工具结果消息并将它们包含在聊天历史中,以便 LLM 能够理解上下文:
# 构造带结果的助手消息
assistant_tool_messages = registry.build_tool_call_messages(
tool_calls, tool_responses
)
print(assistant_tool_messages)
为了维护后续 LLM 交互的工具调用上下文,我们需要重构:
- 助手做出
tool_calls的决定 - 实际的
tool_calls结果
[
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_0_bfa567b8-2f10-4113-953a-56e87b664e0f",
"type": "function",
"function": {
"name": "subtract",
"arguments": "{\"a\":15,\"b\":3}"
}
}
]
},
{
"role": "tool",
"content": "subtract --> 12",
"tool_call_id": "call_0_bfa567b8-2f10-4113-953a-56e87b664e0f"
}
]
然后我们用这些重构的消息扩展之前发送给第一个 LLM 的消息。
messages.extend(assistant_tool_messages)
# 将结果发送回模型
second_response = client.chat.completions.create(
model="deepseek-chat", messages=messages
)
# 打印最终响应
print(second_response.choices[0].message.content)
最终结果和注意事项¶
LLM 在处理工具执行结果后将返回最终答案:
重要实现注意事项¶
实现应该处理连续函数调用,因为对话可能需要多轮工具调用,LLM 的每个响应都可能触发新的工具调用。
错误处理至关重要;在执行前始终验证工具调用参数,ToolRegistry 会为您执行此操作。处理工具可能失败或返回错误的情况,并考虑长时间运行操作的超时机制。
状态管理涉及维护对话历史,包括所有工具调用和响应,跟踪工具执行序列以进行调试,并考虑对话状态持久化。
性能考虑包括最小化不必要的工具调用,在适当时缓存频繁的工具响应,以及监控和优化工具执行时间。
完整的 Python 脚本¶
以下是本演示中使用的完整脚本。
import json
import os
from dotenv import load_dotenv
from openai import OpenAI
from toolregistry import ToolRegistry
# 从 .env 文件加载环境变量
load_dotenv()
registry = ToolRegistry()
@registry.register
def add(a: float, b: float) -> float:
"""将两个数字相加。"""
return a + b
@registry.register
def subtract(a: int, b: int) -> int:
"""从第一个数字中减去第二个数字。"""
return a - b
# 设置 OpenAI 客户端
client = OpenAI(
api_key=os.getenv("API_KEY", "your-api-key"),
base_url=os.getenv("BASE_URL", "https://api.deepseek.com/"),
)
messages = [
{
"role": "user",
"content": "我有 15 个栗子。Joe 吃了 3 个。我还剩多少个栗子?",
}
]
# 发出聊天完成请求
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
tools=registry.get_schemas(),
tool_choice="auto",
)
# 使用 ToolRegistry 处理工具调用
if response.choices[0].message.tool_calls:
tool_calls = response.choices[0].message.tool_calls
print(tool_calls)
# 执行工具调用
tool_responses = registry.execute_tool_calls(tool_calls)
print(tool_responses)
# 构造带结果的助手消息
assistant_tool_messages = registry.build_tool_call_messages(
tool_calls, tool_responses
)
print(assistant_tool_messages)
messages.extend(assistant_tool_messages)
# 将结果发送回模型
second_response = client.chat.completions.create(
model="deepseek-chat", messages=messages
)
# 打印最终响应
print(second_response.choices[0].message.content)
参见¶
- OpenAI Chat Completion 集成 -- OpenAI Chat Completion API 分步指南
- OpenAI Responses 集成 -- OpenAI Responses API 指南
- Anthropic 集成 -- Anthropic Claude 模型指南
- Gemini 集成 -- Google Gemini 模型指南