Tool Calling 函数调用
什么是 Tool Calling
Tool Calling(函数调用)允许模型识别何时需要使用外部工具或函数,并生成符合工具 schema 的输出。通过函数调用,可以让模型与外部系统、API、数据库等进行交互。
工作原理
┌─────────────────────────────────────────────────────────────────┐
│ Tool Calling 流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 用户请求 ──┐ │
│ ▼ │
│ ┌──────────────┐ │
│ │ LLM │ │
│ │ 识别需要工具 │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 返回函数调用 │ ← {name: "get_weather", args: {city: "北京"}} │
│ │ 请求 │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 执行外部函数 │ ← 调用天气 API │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 返回结果给 LLM│ ← "北京今天晴,温度 25°C" │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 最终回复用户 │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘定义工具
工具 schema 示例
json
{
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如:北京、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,默认为 celsius"
}
},
"required": ["city"]
}
}
}
]
}完整调用示例
Python 示例
python
from openai import OpenAI
client = OpenAI(
base_url="https://ai-tokenhub.com/v1",
api_key="your_api_key"
)
# 定义工具
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
}
]
# 发送请求
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "北京今天天气怎么样?"}
],
tools=tools,
tool_choice="auto"
)
# 处理工具调用
tool_calls = response.choices[0].message.tool_calls
if tool_calls:
for call in tool_calls:
function_name = call.function.name
arguments = json.loads(call.function.arguments)
print(f"调用函数: {function_name}")
print(f"参数: {arguments}")
# 执行函数并获取结果
if function_name == "get_weather":
result = get_weather(arguments["city"])
# 将结果返回给模型
result_response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "北京今天天气怎么样?"},
{"role": "assistant", "content": None, "tool_calls": tool_calls},
{
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result)
}
]
)
print(result_response.choices[0].message.content)常用工具场景
1. 天气查询
python
def get_weather(city: str, unit: str = "celsius"):
"""获取天气信息"""
return {
"city": city,
"weather": "晴天",
"temperature": 25,
"unit": unit
}2. 搜索功能
python
def web_search(query: str, limit: int = 5):
"""网络搜索"""
results = search_api(query, limit)
return {
"query": query,
"results": results
}3. 数据库查询
python
def query_database(sql: str):
"""执行 SQL 查询"""
result = db.execute(sql)
return {
"columns": result.columns,
"rows": result.data
}4. 发送邮件
python
def send_email(to: str, subject: str, body: str):
"""发送邮件"""
mail.send(to=to, subject=subject, body=body)
return {"status": "sent", "message_id": "xxx"}工具调用参数
tool_choice 参数
| 值 | 说明 |
|---|---|
auto | 模型自动决定是否调用工具 |
none | 禁止调用工具,直接生成文本 |
{"type": "function", "function": {"name": "get_weather"}} | 强制调用指定工具 |
parallel_tool_calls 参数
控制是否允许并行调用多个工具:
python
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "查一下北京和上海的天气"}],
tools=tools,
parallel_tool_calls=True # 允许并行调用
)最佳实践
1. 清晰的工具描述
json
{
"name": "calculate",
"description": "使用 Python 计算器进行数学运算,支持加减乘除、指数、开方等。输入应为标准的数学表达式,如 '2+2'、'sqrt(16)'、'10**2'"
}2. 严格的参数校验
json
{
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "日期格式:YYYY-MM-DD"
}
}
}
}3. 错误处理
python
try:
result = execute_tool(function_name, arguments)
except ToolExecutionError as e:
return {"error": str(e), "fallback": "无法执行该操作,请稍后重试"}常见问题
Q: 模型不调用工具?
可能原因:
- 提示词不够明确
- 工具描述不清晰
- 设置了
tool_choice="none"
Q: 如何强制使用工具?
python
tool_choice = {"type": "function", "function": {"name": "get_weather"}}Q: 工具调用超时怎么办?
设置超时机制:
python
import signal
def timeout_handler(signum, frame):
raise TimeoutError("工具执行超时")
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(30) # 30秒超时
try:
result = execute_tool(...)
finally:
signal.alarm(0)