Function Calling实战:让大模型学会调用你的API(完整项目)
·
你有没有想过,为什么 ChatGPT 能帮你查天气、写代码、操作文件?它不是凭空做到的——背后靠的就是 Function Calling。今天从原理到实战,用一个完整项目让你彻底搞懂 Function Calling。
一、Function Calling 是什么?
一句话解释:Function Calling 让大模型能够"调用你定义的函数",从而获取实时数据、操作外部系统。
┌──────────────────────────────────────────────────────────┐
│ 没有 Function Calling: │
│ 用户:今天北京天气怎么样? │
│ AI:抱歉,我的知识截止到2025年,无法查询实时天气。 │
│ │
│ 有 Function Calling: │
│ 用户:今天北京天气怎么样? │
│ AI:我来帮你查一下 → 调用 get_weather("北京") → 返回数据 │
│ AI:今天北京晴,最高温28°C,最低温18°C,建议带件外套。 │
└──────────────────────────────────────────────────────────┘
工作流程
用户提问
│
▼
大模型分析 → 需要"查天气"? → 返回函数调用请求(不直接执行!)
│ {function: "get_weather", args: {city: "北京"}}
▼
你的代码接收 → 解析函数名和参数 → 实际调用函数 → 得到真实结果
│ {temp: 28, weather: "晴"}
▼
把结果返回给大模型 → 大模型用自然语言总结 → 回复用户
│ "今天北京晴,最高温28°C..."
▼
用户收到回答
关键点:大模型不直接执行函数,它只告诉你"我想调用这个函数,参数是这些"。真正执行的是你的代码。这保证了安全性。
二、与 MCP 的关系
┌────────────────────────────────────────────────────────┐
│ Function Calling vs MCP │
├──────────────┬─────────────────────────────────────────┤
│ │ │
│ Function │ 底层协议,AI模型直接支持 │
│ Calling │ 每次对话都要声明可用的函数 │
│ │ 适合简单场景(几个函数) │
│ │ │
├──────────────┼─────────────────────────────────────────┤
│ │ │
│ MCP │ 在 Function Calling 之上的标准化框架 │
│ (Model │ 统一工具定义格式 │
│ Context │ 支持 Server/Client 架构 │
│ Protocol) │ 一次开发,所有AI平台可用 │
│ │ 适合复杂场景(几十个工具) │
│ │ │
└──────────────┴─────────────────────────────────────────┘
关系:MCP 底层就是基于 Function Calling 的扩展和标准化。
先搞懂 Function Calling,再学 MCP 就很容易理解。
三、DeepSeek vs Claude Function Calling 对比
| 对比项 | DeepSeek | Claude |
|---|---|---|
| API 格式 | 兼容 OpenAI 格式 | Anthropic 格式 |
| 函数定义 | tools 参数 | tools 参数 |
| 并行调用 | 支持 | 支持 |
| 多轮对话 | ✅ | ✅ |
| 中文能力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 价格 | ¥1/百万token | ¥24/百万token |
| 适合场景 | 国内项目、成本敏感 | 代码质量要求高 |
本教程用 DeepSeek(兼容 OpenAI 格式,上手最快)。
四、实战项目:AI智能助手(查天气+查快递+查日程)
4.1 系统架构
┌──────────────────────────────────────────────────────┐
│ 用户输入 │
│ "帮我查一下北京天气,顺便看看我的日程" │
└─────────────────────┬────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ DeepSeek API │
│ 分析用户意图 → 决定调用哪些函数 │
│ 返回: [ │
│ {function: "get_weather", args: {city:"北京"}│
│ {function: "get_schedule", args: {date:"今天"}}│
│ ] │
└─────────────────────┬────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ 你的 Python 代码 │
│ 1. 解析函数调用请求 │
│ 2. 调用对应的本地函数 │
│ 3. 收集所有函数的结果 │
└──────┬───────────┬───────────┬────────────────────────┘
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│get_weather│ │get_schedule│ │get_express│
│(模拟API) │ │(模拟数据) │ │(模拟数据) │
└────┬─────┘ └────┬──────┘ └────┬──────┘
▼ ▼ ▼
└───────────┴──────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ 结果返回 DeepSeek │
│ "北京今天晴,最高28°C。你今天下午2点有一个..." │
└──────────────────────────────────────────────────────┘
五、完整代码实现
5.1 函数定义
# functions.py
import json
from datetime import datetime
# ====== 函数定义(告诉AI有哪些函数可用) ======
FUNCTIONS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如:北京、上海、广州"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "get_schedule",
"description": "查询指定日期的日程安排",
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"description": "日期,如:今天、明天、2026-05-01"
}
},
"required": ["date"]
}
}
},
{
"type": "function",
"function": {
"name": "get_express",
"description": "查询快递物流信息",
"parameters": {
"type": "object",
"properties": {
"tracking_number": {
"type": "string",
"description": "快递单号"
}
},
"required": ["tracking_number"]
}
}
}
]
# ====== 函数实现(模拟) ======
def get_weather(city: str) -> dict:
"""查询天气(模拟数据)"""
weather_data = {
"北京": {"temp": 28, "weather": "晴", "humidity": 45},
"上海": {"temp": 25, "weather": "多云", "humidity": 65},
"广州": {"temp": 32, "weather": "雷阵雨", "humidity": 80},
"深圳": {"temp": 31, "weather": "阵雨", "humidity": 75},
}
data = weather_data.get(city, {"temp": 22, "weather": "未知", "humidity": 50})
return {
"city": city,
"temperature": f"{data['temp']}°C",
"weather": data["weather"],
"humidity": f"{data['humidity']}%"
}
def get_schedule(date: str) -> dict:
"""查询日程(模拟数据)"""
today = datetime.now().strftime("%Y-%m-%d")
schedules = {
"今天": [
{"time": "09:00", "event": "晨会", "duration": "30min"},
{"time": "14:00", "event": "技术评审", "duration": "1h"},
{"time": "16:30", "event": "1v1 周报", "duration": "30min"},
],
"明天": [
{"time": "10:00", "event": "产品需求评审", "duration": "2h"},
],
}
events = schedules.get(date, [{"time": "无日程", "event": "空闲", "duration": ""}])
return {"date": date, "schedules": events}
def get_express(tracking_number: str) -> dict:
"""查询快递(模拟数据)"""
return {
"tracking_number": tracking_number,
"status": "运输中",
"location": "北京转运中心",
"update_time": "2026-04-28 15:30",
"estimated_delivery": "2026-04-30"
}
# 函数名 → 实际函数的映射
FUNCTION_MAP = {
"get_weather": get_weather,
"get_schedule": get_schedule,
"get_express": get_express,
}
5.2 核心调用逻辑
# main.py
import json
import httpx
from functions import FUNCTIONS, FUNCTION_MAP
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.deepseek.com"
MODEL = "deepseek-chat"
def call_deepseek(messages, tools=None):
"""调用 DeepSeek API"""
payload = {
"model": MODEL,
"messages": messages,
"temperature": 0.3, # 低温度,让函数调用更稳定
}
if tools:
payload["tools"] = tools
response = httpx.post(
f"{BASE_URL}/v1/chat/completions",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=30.0,
)
return response.json()
def execute_function(name: str, arguments: dict) -> str:
"""执行函数并返回结果"""
func = FUNCTION_MAP.get(name)
if not func:
return json.dumps({"error": f"未知函数: {name}"})
try:
result = func(**arguments)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": str(e)})
def chat(user_input: str) -> str:
"""完整对话流程(支持多轮 Function Calling)"""
messages = [
{
"role": "system",
"content": "你是一个智能助手,可以帮用户查天气、查日程、查快递。"
"根据用户需求调用相应函数获取信息。"
},
{"role": "user", "content": user_input},
]
# 可能需要多轮函数调用(AI可能一次想调用多个函数)
max_rounds = 5 # 防止无限循环
for round in range(max_rounds):
response = call_deepseek(messages, tools=FUNCTIONS)
choice = response["choices"][0]
message = choice["message"]
# 情况1:AI 直接回复文本(不需要调用函数)
if not message.get("tool_calls"):
return message["content"]
# 情况2:AI 要求调用函数
# 把AI的函数调用请求加入消息历史
messages.append(message)
# 执行所有函数调用
for tool_call in message["tool_calls"]:
func_name = tool_call["function"]["name"]
func_args = json.loads(tool_call["function"]["arguments"])
print(f" 🔧 调用函数: {func_name}({func_args})")
# 执行函数
result = execute_function(func_name, func_args)
# 把函数结果加入消息历史
messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"content": result,
})
return "抱歉,处理超时,请重试。"
# ====== 测试 ======
if __name__ == "__main__":
print("=" * 50)
print("AI智能助手(Function Calling Demo)")
print("=" * 50)
test_cases = [
"帮我查一下北京今天天气怎么样",
"我今天的日程是什么?",
"帮我查一下快递单号 SF1234567890 到哪了",
"查一下上海天气和我明天的日程",
]
for question in test_cases:
print(f"\n👤 用户: {question}")
answer = chat(question)
print(f"🤖 助手: {answer}")
print("-" * 50)
5.3 运行效果
==================================================
AI智能助手(Function Calling Demo)
==================================================
👤 用户: 帮我查一下北京今天天气怎么样
🔧 调用函数: get_weather({'city': '北京'})
🤖 助手: 北京今天的天气情况:
- 🌡️ 温度:28°C
- ☀️ 天气:晴
- 💧 湿度:45%
天气不错,适合出行!
--------------------------------------------------
👤 用户: 查一下上海天气和我明天的日程
🔧 调用函数: get_weather({'city': '上海'})
🔧 调用函数: get_schedule({'date': '明天'})
🤖 助手: 帮您查到了:
上海明天:多云,25°C,湿度65%
明天的日程:
- 10:00 产品需求评审(2小时)
建议带件外套,温度适中。
六、踩坑记录
踩坑1:JSON Schema 定义错误
// ❌ 错误:description 写成了中文逗号
"description": "城市名称,如:北京、上海,广州"
// ❌ 错误:type 大小写不对
"type": "String"
// ✅ 正确
"description": "城市名称,如:北京、上海、广州",
"type": "string"
踩坑2:函数调用结果必须是字符串
DeepSeek 要求 tool role 的 content 必须是字符串。如果你返回的是 dict,先 json.dumps()。
踩坑3:temperature 不要设太高
Function Calling 建议设 temperature=0.1~0.3。太高会导致 AI 胡乱调用函数或参数格式错误。
踩坑4:死循环防护
AI 可能无限循环调用函数,必须设最大轮次限制(建议 5 轮)。
七、扩展方向
- 接入真实API:高德天气API、顺丰快递API、飞书日程API
- 动态注册函数:通过配置文件或数据库管理函数
- 接入MCP:用MCP Server替代本地函数,实现标准化
- 多模态:结合图片识别函数(如OCR)
🎉 Function Calling 是 AI 应用的"万能接口"——理解了它,你就掌握了让 AI 连接真实世界的能力。从这3个函数开始,你可以无限扩展。
如果觉得有帮助,点赞 + 收藏支持一下!有问题欢迎评论区讨论 💬
更多推荐


所有评论(0)