用DeepSeek-V2.5和WeatherAPI打造智能天气助手:5步搞定Function Calling实战
·
用DeepSeek-V2.5和WeatherAPI打造智能天气助手:5步搞定Function Calling实战
当你在清晨醒来,想知道今天是否需要带伞时,一个能理解自然语言并实时查询天气的AI助手无疑是最贴心的伙伴。本文将带你从零开始,用DeepSeek-V2.5和WeatherAPI构建这样一个智能天气助手,重点解决实际开发中的关键问题。
1. 环境准备与API配置
在开始编码前,我们需要准备好开发环境和必要的API密钥。这里假设你已经安装了Python 3.8+版本,并熟悉基本的Python开发。
首先安装必要的依赖库:
pip install requests python-dotenv
接下来,我们需要获取两个关键的API密钥:
- DeepSeek API密钥:从DeepSeek开发者平台获取
- WeatherAPI密钥:注册WeatherAPI免费账户获取
建议将API密钥存储在环境变量中,避免硬编码在代码里。创建.env文件:
DEEPSEEK_API_KEY=your_deepseek_api_key
WEATHER_API_KEY=your_weather_api_key
2. 定义天气查询函数
核心功能是能够查询指定城市的天气。我们使用WeatherAPI的免费套餐,它提供基本的天气数据查询功能。
import requests
import os
from dotenv import load_dotenv
load_dotenv() # 加载环境变量
def get_weather(city: str) -> str:
"""
查询指定城市的当前天气情况
参数:
city (str): 城市名称,支持中文或英文
返回:
str: 格式化后的天气信息或错误消息
"""
base_url = "http://api.weatherapi.com/v1/current.json"
params = {
'key': os.getenv('WEATHER_API_KEY'),
'q': city,
'aqi': 'no' # 不查询空气质量数据
}
try:
response = requests.get(base_url, params=params, timeout=5)
response.raise_for_status() # 检查HTTP错误
data = response.json()
weather = data['current']['condition']['text']
temp_c = data['current']['temp_c']
feelslike_c = data['current']['feelslike_c']
humidity = data['current']['humidity']
return (f"{city}当前天气:{weather},"
f"温度:{temp_c}°C(体感{feelslike_c}°C),"
f"湿度:{humidity}%")
except requests.exceptions.RequestException as e:
return f"无法获取{city}的天气信息:{str(e)}"
这个函数做了几项重要改进:
- 增加了完整的类型提示和文档字符串
- 使用环境变量管理敏感信息
- 添加了超时处理和异常捕获
- 返回更丰富的天气信息(体感温度、湿度)
3. 配置Function Calling工具
为了让DeepSeek知道它可以调用我们的天气查询函数,需要按照特定格式定义工具描述:
from typing import List, Dict, Any
def get_tools() -> List[Dict[str, Any]]:
"""返回DeepSeek可用的工具列表"""
return [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气情况,包括温度、体感温度和湿度",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如'北京'或'New York'",
}
},
"required": ["city"],
},
}
}
]
关键点说明:
name必须与实际的函数名完全一致description要清晰准确,这直接影响模型是否及如何调用该函数parameters定义了函数需要的参数及其类型
4. 实现Function Calling主逻辑
现在我们可以实现核心的对话处理逻辑,处理用户输入并决定是否需要调用函数。
from openai import OpenAI
import json
class WeatherAssistant:
def __init__(self):
self.client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1"
)
self.tools = get_tools()
def process_message(self, user_input: str) -> str:
"""处理用户输入并返回响应"""
messages = [{"role": "user", "content": user_input}]
response = self.client.chat.completions.create(
model="deepseek-v2.5",
messages=messages,
tools=self.tools,
tool_choice="auto",
temperature=0.3 # 适当降低随机性
)
response_message = response.choices[0].message
# 检查是否需要调用函数
if tool_calls := response_message.tool_calls:
for tool_call in tool_calls:
if tool_call.function.name == "get_weather":
# 解析参数
args = json.loads(tool_call.function.arguments)
weather_info = get_weather(args["city"])
# 将函数结果添加到对话上下文中
messages.append({
"role": "tool",
"content": weather_info,
"tool_call_id": tool_call.id
})
# 获取模型对函数结果的总结回复
second_response = self.client.chat.completions.create(
model="deepseek-v2.5",
messages=messages,
)
return second_response.choices[0].message.content
return response_message.content
这个实现有几个关键优化:
- 封装为类,便于维护和扩展
- 使用
tool_choice="auto"让模型自主决定是否调用函数 - 正确处理多个可能的函数调用
- 适度的temperature设置平衡创造性和稳定性
5. 异常处理与工程化改进
在实际应用中,我们需要考虑更多边界情况和工程化细节:
5.1 增强的错误处理
def safe_process_message(assistant: WeatherAssistant, user_input: str) -> str:
"""带错误处理的对话处理"""
try:
return assistant.process_message(user_input)
except json.JSONDecodeError:
return "抱歉,处理天气数据时出现问题,请稍后再试。"
except Exception as e:
print(f"Error processing message: {str(e)}")
return "系统暂时无法处理您的请求,请稍后再试。"
5.2 多城市查询优化
许多用户会同时询问多个城市的天气,我们可以改进函数支持批量查询:
def get_multiple_weather(cities: List[str]) -> str:
"""批量查询多个城市天气"""
results = []
for city in cities:
weather = get_weather(city)
results.append(f"- {weather}")
return "\n".join(results)
# 更新工具定义
def get_tools():
return [
{
"type": "function",
"function": {
"name": "get_multiple_weather",
"description": "批量查询多个城市的天气情况",
"parameters": {
"type": "object",
"properties": {
"cities": {
"type": "array",
"items": {"type": "string"},
"description": "城市名称列表",
}
},
"required": ["cities"],
},
}
}
]
5.3 缓存与限流
为避免频繁调用API,可以添加简单的缓存机制:
from functools import lru_cache
import time
@lru_cache(maxsize=100)
def get_weather_cached(city: str) -> str:
"""带缓存的天气查询,10分钟内相同城市查询返回缓存结果"""
return get_weather(city)
6. 完整示例与测试
让我们看一个完整的交互示例:
assistant = WeatherAssistant()
queries = [
"今天北京天气怎么样?",
"比较一下上海和广州的天气",
"下周纽约的天气会如何?" # 测试无法回答的情况
]
for query in queries:
print(f"用户: {query}")
response = safe_process_message(assistant, query)
print(f"助手: {response}\n")
预期输出可能类似于:
用户: 今天北京天气怎么样?
助手: 北京当前天气:晴朗,温度:23°C(体感25°C),湿度:45%
用户: 比较一下上海和广州的天气
助手: 以下是上海和广州的天气情况:
- 上海当前天气:多云,温度:28°C(体感30°C),湿度:75%
- 广州当前天气:雷阵雨,温度:31°C(体感35°C),湿度:85%
用户: 下周纽约的天气会如何?
助手: 我目前只能查询当前天气情况,无法提供未来天气预报。
7. 部署与扩展建议
完成开发后,你可以考虑:
- 部署为Web服务:使用FastAPI或Flask包装为REST API
- 添加更多功能:
- 天气预警通知
- 历史天气数据查询
- 多语言支持
- 性能优化:
- 异步处理请求
- 更智能的缓存策略
- 用户界面:
- 开发聊天机器人界面
- 集成到现有通讯工具如微信、Slack
通过这5个关键步骤,我们构建了一个实用的智能天气助手。Function Calling的强大之处在于,你可以用同样的模式集成各种API,为AI助手添加无限可能。
更多推荐


所有评论(0)