【学习记录】Function Call 完全指南:让大模型从"聊天"到"行动"
Function Call(函数调用)是大语言模型从"只会聊天"升级为"能行动"的核心机制。它让 LLM 能够主动请求调用外部工具------查询实时天气、操作数据库、发送邮件、执行计算......本文从原理到代码,带你完整掌握 Function Call 的全链路开发。
📌 为什么需要 Function Call?
| 痛点 | 说明 | Function Call 解决方案 |
|---|---|---|
| 知识截止 | LLM 训练数据有截止日期 | 调用实时天气、股票、新闻 API |
| 无法执行计算 | 复杂的数学、单位换算容易出错 | 调用计算器、单位转换函数 |
| 不能操作数据库 | 无法查询或更新私有数据库 | 调用数据库查询函数,返回结构化结果 |
| 不能执行业务逻辑 | 无法发送邮件、创建工单 | 调用业务 API,完成实际操作 |
| 需要确定性输出 | LLM 自由生成的字段名不固定 | 强制通过函数签名返回严格结构的 JSON |
一句话:Function Call = 让 LLM 拥有手脚。
一、Function Call 完整流程
外部函数/API 系统/应用程序 大语言模型 User 外部函数/API 系统/应用程序 大语言模型 User alt [需要调用函数] [不需要调用函数] 用户提问 发送提示词 + 可用函数定义 判断是否需要调用函数 返回函数调用 JSON 执行实际函数 返回执行结果 发送函数结果 基于结果生成自然语言回答 最终回复 直接生成回答 最终回复
二、详细步骤与代码实现
2.1 定义函数及 JSON Schema
在系统中预先定义可被调用的函数,并用 JSON Schema 描述其功能、参数、必填项。
python
import json
from openai import OpenAI
# 模拟一个查询天气的真实函数
def get_current_weather(latitude: float, longitude: float):
"""实际可替换为真实 API 请求"""
return f"当前坐标 ({latitude}, {longitude}) 的温度是 22°C,晴天"
# 定义函数的 JSON Schema(OpenAI 格式)
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "获取指定经纬度的当前天气",
"parameters": {
"type": "object",
"properties": {
"latitude": {
"type": "number",
"description": "纬度,范围 -90 到 90"
},
"longitude": {
"type": "number",
"description": "经度,范围 -180 到 180"
}
},
"required": ["latitude", "longitude"],
"additionalProperties": False
},
"strict": True
}
}
]
2.2 调用 LLM,并传入函数定义
python
client = OpenAI(api_key="your-api-key")
messages = [
{"role": "user", "content": "北京今天的天气怎么样?"}
]
# 第一次调用:模型判断是否需要调用函数
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools, # 提供可用函数
tool_choice="auto" # 让模型自动决定是否调用
)
message = response.choices[0].message
2.3 处理函数调用并执行实际函数
python
# 如果模型决定调用函数
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
# 根据函数名执行对应的 Python 函数
if function_name == "get_current_weather":
result = get_current_weather(**arguments)
# 将函数执行结果以 tool 消息追加到对话历史
messages.append(message) # 添加模型的 function call 消息
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
# 第二次调用:让模型基于函数结果生成最终回答
second_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
final_answer = second_response.choices[0].message.content
print(final_answer)
else:
# 模型直接回答
print(message.content)
2.4 完整封装示例(可直接运行)
python
import json
from openai import OpenAI
class FunctionCallAgent:
def __init__(self, api_key: str, model: str = "gpt-4o"):
self.client = OpenAI(api_key=api_key)
self.model = model
self.functions = {} # 存储函数名 -> 实际函数
self.tools = [] # 存储 JSON Schema
def register_function(self, func, schema: dict):
"""注册一个可调用函数"""
func_name = func.__name__
self.functions[func_name] = func
self.tools.append({
"type": "function",
"function": schema
})
def chat(self, user_message: str) -> str:
messages = [{"role": "user", "content": user_message}]
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
tools=self.tools,
tool_choice="auto"
)
msg = response.choices[0].message
if msg.tool_calls:
messages.append(msg)
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
if func_name in self.functions:
result = self.functions[func_name](**args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
final = self.client.chat.completions.create(
model=self.model,
messages=messages,
tools=self.tools
)
return final.choices[0].message.content
else:
return msg.content
# 使用示例
def get_stock_price(symbol: str):
"""模拟获取股价"""
prices = {"AAPL": 175.32, "GOOGL": 138.45, "TSLA": 245.60}
return prices.get(symbol.upper(), "未知")
stock_schema = {
"name": "get_stock_price",
"description": "获取美股实时股价",
"parameters": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "股票代码,如 AAPL"}
},
"required": ["symbol"],
"additionalProperties": False
},
"strict": True
}
agent = FunctionCallAgent(api_key="your-key")
agent.register_function(get_stock_price, stock_schema)
print(agent.chat("苹果公司今天的股价是多少?"))
三、函数定义的关键要素(JSON Schema)
| 字段 | 说明 | 示例 |
|---|---|---|
name |
函数名称,须与代码函数名一致 | "get_current_weather" |
description |
告诉模型该函数的作用,影响决策准确性 | "获取指定位置的天气" |
parameters.type |
固定为 "object" |
|
parameters.properties |
列出每个参数的名称、类型、描述 | {"latitude": {"type": "number"}} |
parameters.required |
必填参数列表 | ["latitude", "longitude"] |
additionalProperties |
设为 false 增强严格性 |
false |
strict |
要求模型严格遵循 schema(部分 API 支持) | true |
四、常见应用场景
| 场景 | 函数示例 |
|---|---|
| 实时信息 | 查询天气、股票、新闻、汇率 |
| 数学计算 | 计算器、方程求解、单位换算 |
| 数据库操作 | 查询 SQL、插入记录、生成报表 |
| 第三方 API | 发送邮件、创建日历事件、发短信 |
| 业务逻辑 | 预订机票、计算运费、库存检查 |
| 代码执行 | 运行 Python 代码、解析表达式 |
五、注意事项
- 函数参数命名:要与 JSON Schema 中完全一致,否则 LLM 生成的可能无法匹配。
- 结果长度:函数返回的内容不宜过长(建议 < 1000 token),否则模型可能截断或混淆。
- 错误处理:如果函数执行失败,应返回明确的错误信息,模型会据此告知用户。
- 多次调用 :一个请求中可以包含多个
tool_calls,需循环处理并返回多个结果。 - 不同 API 的差异 :
- OpenAI:使用
tools参数,函数调用返回tool_calls - Anthropic Claude:使用
tools,返回tool_use - 国产模型(DeepSeek、Qwen、智谱)也支持类似格式,略有差异。
- OpenAI:使用
🎯 总结
| 核心概念 | 说明 |
|---|---|
| Function Call | LLM 主动请求调用外部函数的机制 |
| JSON Schema | 函数的"说明书",描述名称、参数、类型 |
| tool_choice | 控制模型是否/何时调用函数(auto / none / 强制指定) |
| 多次调用 | 模型可在一个回答中请求多个函数,需依次执行并返回结果 |
Function Call 是构建 AI Agent 的核心基础设施。它将大语言模型从"嘴炮"升级为"实干家"------不仅能说,还能做。掌握它,你就能构建出能查天气、订机票、操作数据库的真正智能体。