作为一名从传统开发转型AI领域的程序员,我深刻理解在接触大模型开发时的困惑点。Function Calling作为大模型与真实世界连接的桥梁,是每个AI开发者必须掌握的技能。本文将以天气查询为例,带你彻底吃透这一技术。
在传统编程中,我们习惯直接调用函数完成操作。但在AI领域,大模型本身并不执行任何函数——它更像一个聪明的"中间人",负责分析需求、生成调用指令,而真正的执行工作仍由开发者完成。这种分工模式初看可能反直觉,但理解后会发现其精妙之处。
Function Calling的实现涉及三个关键角色:
这种架构带来两个显著优势:
完整的工作链条包含六个关键步骤:
python复制functions = [{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}]
python复制def get_weather(city: str) -> dict:
api_url = f"https://api.weather.com/v1/current?city={city}"
response = requests.get(api_url)
return response.json()
python复制response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "杭州天气如何?"}],
tools=functions
)
python复制tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
python复制weather_data = get_weather(args["city"])
python复制messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(weather_data)
})
final_response = client.chat.completions.create(...)
推荐使用Python 3.8+环境,主要依赖包:
bash复制pip install openai requests python-dotenv
建议将API密钥等敏感信息存储在环境变量中:
python复制from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("DEEPSEEK_API_KEY")
将系统拆分为三个核心模块:
1. 工具模块(tools.py)
python复制import requests
class WeatherTool:
@staticmethod
def get_schema():
return {
"name": "get_weather",
"description": "获取城市天气信息",
"parameters": {...}
}
@staticmethod
def execute(city: str):
# 实现带错误处理和重试机制的API调用
pass
2. 模型交互模块(llm_client.py)
python复制from openai import OpenAI
class LLMClient:
def __init__(self):
self.client = OpenAI(
api_key=os.getenv("API_KEY"),
base_url="https://api.deepseek.com"
)
def chat_completion(self, messages, tools):
# 实现带超时控制的模型调用
pass
3. 主流程模块(main.py)
python复制from tools import WeatherTool
from llm_client import LLMClient
def process_query(query: str):
# 实现完整处理流程
pass
python复制def handle_multiple_functions(tool_calls):
results = []
for call in tool_calls:
if call.function.name == "get_weather":
results.append({
"call_id": call.id,
"result": WeatherTool.execute(
json.loads(call.function.arguments)["city"]
)
})
return results
python复制async def async_get_weather(city: str):
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.weather.com/v1/current?city={city}") as resp:
return await resp.json()
python复制from functools import lru_cache
@lru_cache(maxsize=100)
def get_cached_weather(city: str):
return WeatherTool.execute(city)
完善的错误处理应包含:
python复制def safe_get_weather(city: str, retries=3):
for attempt in range(retries):
try:
response = requests.get(
WEATHER_API_URL,
params={"city": city},
timeout=(3.0, 5.0)
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
if attempt == retries - 1:
raise WeatherAPIError(f"天气API请求失败: {str(e)}")
time.sleep(2 ** attempt)
建议监控以下关键指标:
python复制@contextmanager
def track_performance(metric_name):
start = time.perf_counter()
try:
yield
finally:
duration = time.perf_counter() - start
statsd.timing(f"function.{metric_name}", duration)
python复制def validate_city(city: str):
if not re.match(r"^[\w\s-]+$", city):
raise ValueError("无效的城市名称")
return city.strip()
python复制from ratelimit import limits, sleep_and_retry
@sleep_and_retry
@limits(calls=30, period=60)
def call_weather_api(city: str):
# API调用实现
问题1:模型未触发函数调用
问题2:参数解析失败
问题3:API响应超时
python复制import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.FileHandler("debug.log")]
)
python复制def debug_print(stage, data):
print(f"[DEBUG {stage}]", json.dumps(data, indent=2, ensure_ascii=False))
python复制class MockWeatherAPI:
@staticmethod
def get(city):
return {"temp": 25, "condition": "晴"}
实现旅行规划场景:
python复制tools = [
WeatherTool.get_schema(),
HotelTool.get_schema(),
FlightTool.get_schema()
]
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "下周去北京出差需要带什么?"}],
tools=tools
)
运行时添加新工具:
python复制def register_tool(tool_schema):
global tools
tools.append(tool_schema)
处理接口变更:
python复制def get_weather_v2(city: str):
# 新版本实现
pass
tools = [{
"name": "get_weather",
"description": "获取天气(v2)",
"parameters": {...}
}]
在实际项目开发中,Function Calling的这种"模型思考+开发者执行"模式,既保留了LLM强大的理解能力,又确保了关键操作的可靠性和安全性。经过多个项目的实践验证,这种架构特别适合需要连接外部系统或处理敏感操作的场景。