工具调用
工具调用(也称为函数调用)允许模型决定何时使用外部工具,并返回这些工具的结构化参数。当模型需要获取实时数据、查询内部系统、执行计算或在模型本身之外执行操作时,此功能非常有用。
工具调用通过 OpenAI 兼容的 /chat/completions API 支持,在 tools 字段中传递工具定义。
为什么使用工具调用
当模型需要其本身不具备的能力时,工具调用可以提供帮助,例如:
- 检索实时信息
- 调用内部 API 或数据库
- 运行业务逻辑或工作流
- 执行精确计算
- 在外部系统中触发操作
与其让模型猜测,不如让它选择工具并提供结构化参数,由您的应用安全执行。
工作原理
典型的工具调用流程有四个步骤:
- 定义一个或多个工具,包括名称、描述和 JSON Schema 参数。
- 发送带有
tools的聊天补全请求。 - 如果模型决定使用工具,它返回
tool_calls而不是最终答案。 - 在您的应用中执行工具,将工具结果追加到
messages,并发送另一个请求以获取最终响应。
定义工具
每个工具必须定义为一个函数,包含:
name:简短、稳定的函数名称description:清晰说明工具何时应被使用parameters:描述允许参数的 JSON Schema 对象
示例:
[
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to look up, such as San Francisco."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to return."
}
},
"required": ["city"]
}
}
}
]
良好的工具定义很重要。模型依赖您的描述和 schema 来选择正确的工具并生成有效的参数。
基本示例
以下请求为模型提供了一个工具:
curl 'https://api.luchentech.com/inference/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your_token_here>' \
--data '{
"model": "minimax/minimax-m2.5",
"messages": [
{
"role": "user",
"content": "What is the weather in Singapore right now?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to look up."
}
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto",
"temperature": 0.1
}'
如果模型决定需要工具,响应通常会在助手消息中包含 tool_calls:
{
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Singapore\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}
完整工作流
完整的工具调用循环如下:
import json
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.luchentech.com/inference/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to look up."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit."
}
},
"required": ["city"]
}
}
}
]
def get_weather(city: str, unit: str = "celsius"):
return {
"city": city,
"temperature": 29,
"condition": "Partly cloudy",
"unit": unit
}
messages = [
{"role": "user", "content": "What's the weather in Singapore?"}
]
response = client.chat.completions.create(
model="minimax/minimax-m2.5",
messages=messages,
tools=tools,
tool_choice="auto",
temperature=0.1,
)
assistant_message = response.choices[0].message
if assistant_message.tool_calls:
tool_call = assistant_message.tool_calls[0]
tool_args = json.loads(tool_call.function.arguments)
tool_result = get_weather(**tool_args)
messages.append(assistant_message)
messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(tool_result),
}
)
final_response = client.chat.completions.create(
model="minimax/minimax-m2.5",
messages=messages,
tools=tools,
temperature=0.1,
)
print(final_response.choices[0].message.content)
重要提示:通过应用中的显式函数映射执行工具。不要对模型生成的参数或函数名使用 eval。
工具调用的消息模式
模型返回工具调用后,对话历史通常如下:
[
{
"role": "user",
"content": "What's the weather in Singapore?"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Singapore\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_123",
"content": "{\"city\":\"Singapore\",\"temperature\":29,\"condition\":\"Partly cloudy\",\"unit\":\"celsius\"}"
}
]
然后将更新后的 messages 数组发送回模型,使其能够生成最终的自然语言响应。
tool_choice
tool_choice 字段控制模型如何使用工具。
auto:模型决定是调用工具还是直接回答none:不允许模型调用工具required:模型必须至少调用一个工具
一些 OpenAI 兼容实现还支持强制特定函数:
{
"tool_choice": {
"type": "function",
"function": {
"name": "get_weather"
}
}
}
仅当您的工作流需要时才使用强制工具选择。
多个工具
您可以在同一请求中提供多个工具。例如,旅行助手可以提供:
get_weathersearch_hotelssearch_restaurantsget_exchange_rate
模型根据您的工具描述和参数 schema 选择最匹配用户请求的工具。
当多个工具有重叠时,请仔细编写描述以便模型能够区分。
流式工具调用
工具调用也支持 stream=true。在流式模式下,工具调用参数可能会逐步返回,需要在执行前组装。
import json
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.luchentech.com/inference/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "The city to look up."}
},
"required": ["city"]
}
}
}
]
tool_calls = {}
with client.chat.completions.create(
model="minimax/minimax-m2.5",
messages=[{"role": "user", "content": "What's the weather in Singapore?"}],
tools=tools,
stream=True,
temperature=0.1,
) as stream:
for chunk in stream:
choices = getattr(chunk, "choices", None)
if not choices:
continue
choice = choices[0]
delta = getattr(choice, "delta", None)
if delta and getattr(delta, "tool_calls", None):
for tc in delta.tool_calls:
index = tc.index
if index not in tool_calls:
tool_calls[index] = {"id": "", "name": "", "arguments": ""}
if getattr(tc, "id", None):
tool_calls[index]["id"] = tc.id
fn = getattr(tc, "function", None)
if fn and getattr(fn, "name", None):
tool_calls[index]["name"] = fn.name
if fn and getattr(fn, "arguments", None):
tool_calls[index]["arguments"] += fn.arguments
finish_reason = getattr(choice, "finish_reason", None)
if finish_reason == "tool_calls":
break
for tc in tool_calls.values():
try:
args = json.loads(tc["arguments"])
print(f"Call {tc['name']} with {args}")
except json.JSONDecodeError:
print(f"Incomplete tool args for {tc['name']}: {tc['arguments']}")
当模型可能生成大型工具参数或您希望降低感知延迟时,流式输出很有帮助。
工具 Schema 最佳实践
设计良好的 schema 能提高工具准确性。
- 使用具体的函数名称
- 为工具和每个参数编写清晰的描述
- 正确标记必填字段
- 当值来自固定集合时使用
enum - 保持 schema 尽可能简单
- 避免职责模糊的重叠工具
示例:
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, for example San Francisco."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit."
}
},
"required": ["location"]
}
参数建议
工具调用通常在低随机性下效果最佳:
{
"temperature": 0.0,
"top_p": 1.0
}
较低的温度减少了参数值的幻觉,使工具选择更加确定。
安全建议
工具调用会增加现实世界的副作用,因此请将工具执行视为应用安全边界的一部分。
- 执行前验证工具参数
- 将工具限制在所需的最小权限内
- 永远不要直接执行模型输出的任意 shell 命令
- 使用支持的工具名称允许列表
- 在传递给下游系统之前清理外部输入
- 记录工具请求和工具输出以用于调试和审计
常见问题
模型不调用工具
尝试:
- 改进工具描述
- 使用户请求更明确
- 将
tool_choice设置为required - 降低
temperature - 确认所选模型支持工具调用
工具参数缺失或不正确
尝试:
- 添加更好的参数描述
- 对受限值使用
enum - 使必填字段明确
- 降低
temperature
模型直接回答而不是等待工具结果
这通常发生在以下情况:
- 工具描述太模糊
- 模型认为可以从先验知识回答
- 工作流没有正确追加
tool角色消息
确保在请求最终答案之前,助手工具调用和对应的 tool 消息都已包含。
多轮流程中的工具调用变得混乱
保持对话状态清晰:
- 保留包含
tool_calls的助手消息 - 每个工具结果追加一条
tool消息 - 在后续请求中发送完整的更新消息历史