当前大语言模型(LLM)的API生态正在经历从单纯对话到功能调用的转变。去年OpenAI推出的Function Calling功能彻底改变了开发者与大模型交互的方式——它不再局限于文本生成,而是允许模型智能地识别用户意图并触发外部工具或API。这种模式让大模型真正成为了能"做事"的智能体。
我在实际开发中发现,一个设计良好的Skill(技能)需要同时考虑三个维度:自然语言理解准确性、函数调用的可靠性、以及错误处理的鲁棒性。这比单纯开发对话机器人复杂得多,因为涉及到意图识别、参数提取、执行反馈的完整闭环。典型的开发痛点包括:如何定义清晰的函数规范?如何处理模糊的用户请求?怎样设计fallback机制?
大模型的函数调用本质上是一个三步流程:
以天气查询为例,当用户说"上海明天会下雨吗",模型需要:
经过多个项目实践,我总结出可复用技能的四层架构:
| 层级 | 组件 | 说明 | 技术实现 |
|---|---|---|---|
| 交互层 | 自然语言接口 | 处理用户原始输入 | 大模型NLU |
| 逻辑层 | 意图路由器 | 路由到对应技能 | 函数描述+few-shot |
| 执行层 | 技能实现 | 具体功能逻辑 | 外部API/本地代码 |
| 反馈层 | 结果格式化 | 生成用户友好的响应 | 模板+模型后处理 |
函数定义的质量直接影响模型调用的准确性。以下是经过验证的最佳实践:
python复制weather_function = {
"name": "get_current_weather",
"description": "获取指定位置的当前天气情况", # 中文描述更适配中文场景
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或区县名称,如'北京市海淀区'" # 添加示例提升准确性
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["location"] # 明确必选参数
}
}
关键技巧:
python复制import requests
def get_current_weather(location, unit="celsius"):
"""实际调用天气API的实现"""
base_url = "https://api.weatherapi.com/v1/current.json"
params = {
"key": os.getenv("WEATHER_API_KEY"),
"q": location,
"lang": "zh" # 指定中文返回
}
try:
response = requests.get(base_url, params=params, timeout=3)
data = response.json()
# 统一错误处理
if "error" in data:
raise ValueError(data["error"]["message"])
# 单位转换逻辑
temp_c = data["current"]["temp_c"]
temp_f = data["current"]["temp_f"]
return {
"location": location,
"temperature": temp_f if unit == "fahrenheit" else temp_c,
"unit": unit,
"conditions": data["current"]["condition"]["text"]
}
except Exception as e:
return {"error": str(e)}
完整的调用流程示例:
python复制import openai
def run_conversation():
messages = [{"role": "user", "content": "北京现在多少度?"}]
# 首次调用:让模型决定是否调用函数
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages,
functions=[weather_function],
function_call="auto"
)
# 处理函数调用
if response["choices"][0]["message"].get("function_call"):
function_name = response["choices"][0]["message"]["function_call"]["name"]
if function_name == "get_current_weather":
# 提取参数并执行
args = json.loads(response["choices"][0]["message"]["function_call"]["arguments"])
weather_data = get_current_weather(**args)
# 将结果返回给模型进行自然语言生成
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(weather_data)
})
# 获取最终回复
second_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages
)
return second_response["choices"][0]["message"]["content"]
return response["choices"][0]["message"]["content"]
通过few-shot示例显著提升准确率:
python复制weather_function["examples"] = [
{"role": "user", "content": "上海天气怎么样"},
{"role": "assistant", "content": None, "function_call": {
"name": "get_current_weather",
"arguments": '{"location":"上海"}'
}}
]
实现参数自动修正的装饰器:
python复制def validate_params(func):
def wrapper(**kwargs):
if "location" in kwargs:
# 简单的地理位置标准化
kwargs["location"] = kwargs["location"].replace(" ", "")
if kwargs["location"].endswith("市"):
kwargs["location"] = kwargs["location"][:-1]
return func(**kwargs)
return wrapper
python复制from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10))
def call_weather_api(url, params):
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
return response.json()
核心监控指标应包括:
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 模型不调用函数 | 函数描述不清晰 | 添加更多示例 |
| 参数提取错误 | 参数描述模糊 | 在description中添加示例值 |
| API返回超时 | 网络延迟 | 实现重试机制 |
| 结果解析失败 | 返回格式不符 | 添加严格的schema校验 |
通过工作流引擎实现技能组合:
python复制def travel_assistant(query):
# 并行调用天气和地图技能
weather = get_weather(query)
route = get_route(query)
# 让模型综合两个结果
return synthesize_results(weather, route)
将用户偏好保存到数据库,在下文对话中调用:
python复制user_prefs = {
"default_unit": "celsius",
"home_location": "北京"
}
def get_weather_with_prefs(location=None):
loc = location or user_prefs["home_location"]
unit = user_prefs["default_unit"]
return get_current_weather(loc, unit)
在实际项目中,我发现函数调用最容易被低估的是错误处理环节。一个健壮的技能实现中,错误处理代码通常会占到总行数的40%以上。建议为每个技能建立标准的错误分类体系,包括输入错误、API错误、处理错误等类型,并为每类错误设计对应的恢复策略。