FastAPI Agent 函数调用实战:我让 AI 学会了“自己动手查天气“

FastAPI Agent 函数调用实战:我让 AI 学会了"自己动手查天气"

引言:为什么需要让 AI 调用外部函数?在传统的 AI 聊天应用中,大语言模型(LLM)只能基于训练数据回答问题,无法获取实时信息。例如,当用户问"今天北京天气怎么样?"时,模型只能凭记忆给出模糊回答,甚至直接说"我无法获取实时数据"。这个问题在需要动态信息的场景(如天气、股票、数据库查询)中尤为突出。函数调用(Function Calling) 技术应运而生。它允许 LLM 识别用户意图,并返回一个结构化的函数调用请求,由应用后端执行实际逻辑。本文将演示如何使用 FastAPI 构建一个 Agent 系统,让 AI 学会调用"查天气"函数。## 技术栈概览- FastAPI :高性能 Python Web 框架,用于构建 API 端点- OpenAI Function Calling :GPT 模型原生支持的函数调用能力- Pydantic :数据验证与序列化- httpx :异步 HTTP 客户端(用于调用外部天气 API)## 核心原理:函数调用如何工作?函数调用的流程分为三步:1. 定义函数规范 :将每个外部能力描述为 JSON Schema(函数名、参数、返回说明)2. 模型决策 :LLM 根据用户输入,判断是否需要调用函数,并输出参数3. 执行与反馈 :应用调用实际函数,将结果返回给模型生成最终回答这种模式将"推理"与"行动"分离,模型负责理解意图,后端负责执行。## 实战:构建天气查询 Agent### 第一步:定义天气查询函数我们使用 OpenWeatherMap API 获取天气数据。首先定义函数规范:python# weather_agent.pyimport jsonimport httpxfrom pydantic import BaseModel, Fieldfrom typing import List, Dict, Any# 定义函数规范(OpenAI 格式)weather_function_spec = { "name": "get_current_weather", "description": "获取指定城市的当前天气信息", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,如北京、上海" }, "units": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位,默认摄氏度" } }, "required": ["city"] }}# 实际执行函数(使用异步HTTP客户端)async def get_current_weather(city: str, units: str = "celsius") -> Dict[str, Any]: """调用外部天气API获取实时数据""" api_key = "your_openweathermap_api_key" # 请替换为你的API密钥 if units == "celsius": unit_param = "metric" else: unit_param = "imperial" async with httpx.AsyncClient() as client: url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units={unit_param}" response = await client.get(url) data = response.json() # 提取关键信息 return { "city": city, "temperature": data["main"]["temp"], "description": data["weather"][0]["description"], "humidity": data["main"]["humidity"], "wind_speed": data["wind"]["speed"] }### 第二步:构建 FastAPI 端点我们创建一个 POST 端点,接收用户消息并调用 OpenAI API:python# main.pyfrom fastapi import FastAPI, HTTPExceptionfrom pydantic import BaseModelimport openaiimport jsonapp = FastAPI()# OpenAI 客户端配置client = openai.AsyncOpenAI(api_key="your_openai_api_key")# 定义请求模型class ChatRequest(BaseModel): message: str# 定义响应模型class ChatResponse(BaseModel): response: str function_calls: list = []@app.post("/chat", response_model=ChatResponse)async def chat_with_agent(request: ChatRequest): """ 接收用户消息,让AI决定是否调用天气函数 """ # 1. 构造消息列表 messages = [ {"role": "system", "content": "你是一个智能助手,可以根据用户需求调用外部函数获取实时信息。"}, {"role": "user", "content": request.message} ] # 2. 调用OpenAI模型,传入函数规范 response = await client.chat.completions.create( model="gpt-3.5-turbo-1106", # 支持函数调用的模型 messages=messages, functions=[weather_function_spec], function_call="auto" # 自动判断是否需要调用 ) # 3. 解析模型响应 response_message = response.choices[0].message # 4. 检查是否需要调用函数 if response_message.function_call: function_name = response_message.function_call.name function_args = json.loads(response_message.function_call.arguments) # 执行实际函数 if function_name == "get_current_weather": weather_data = await get_current_weather(**function_args) # 将函数结果发给模型生成最终回答 messages.append(response_message) messages.append({ "role": "function", "name": function_name, "content": json.dumps(weather_data, ensure_ascii=False) }) second_response = await client.chat.completions.create( model="gpt-3.5-turbo-1106", messages=messages ) final_answer = second_response.choices[0].message.content return ChatResponse( response=final_answer, function_calls=[{ "function": function_name, "arguments": function_args, "result": weather_data }] ) # 如果不需要调用函数,直接返回模型回答 return ChatResponse( response=response_message.content, function_calls=[] )### 第三步:测试与运行启动 FastAPI 服务并测试:bashuvicorn main:app --reload使用 curl 测试:bashcurl -X POST "http://localhost:8000/chat" \ -H "Content-Type: application/json" \ -d '{"message": "今天北京天气怎么样?"}'返回示例:json{ "response": "北京当前天气:温度 15°C,多云,湿度 60%,风速 4m/s。建议穿外套出行。", "function_calls": [ { "function": "get_current_weather", "arguments": {"city": "北京"}, "result": { "city": "北京", "temperature": 15, "description": "多云", "humidity": 60, "wind_speed": 4 } } ]}## 深度剖析:函数调用的关键设计### 1. 函数描述的精确性函数名称、参数描述必须清晰,否则模型可能错误解析。例如,city 参数描述为"城市名称,如北京、上海"有助于模型理解中文城市名。### 2. 错误处理策略- API调用失败 :应在函数执行前检查响应状态码,返回错误信息- 参数缺失 :模型可能不提供某些可选参数,需设置默认值- 超时保护 :使用 asyncio.timeout 避免函数执行阻塞### 3. 多函数调度当系统有多个函数时,模型可能一次请求调用多个函数。OpenAI 支持并行调用:python# 如果模型返回多个function_callif response_message.function_call: # 处理单个调用elif response_message.tool_calls: # 新版本使用tool_calls for tool_call in response_message.tool_calls: # 并行执行每个函数 results = await asyncio.gather( *[execute_function(tc) for tc in tool_calls] )## 进阶:添加更多能力扩展 Agent 的能力只需添加新函数规范:python# 添加查询股票价格函数stock_function_spec = { "name": "get_stock_price", "description": "获取指定股票的当前价格", "parameters": { "type": "object", "properties": { "symbol": { "type": "string", "description": "股票代码,如AAPL、GOOGL" } }, "required": ["symbol"] }}# 在端点中注册多个函数functions = [weather_function_spec, stock_function_spec]response = await client.chat.completions.create( model="gpt-3.5-turbo-1106", messages=messages, functions=functions, function_call="auto")## 总结本文完整演示了如何基于 FastAPI 和 OpenAI 函数调用构建一个能自主查询天气的 AI Agent。核心收获:1. 函数调用让 LLM 突破知识截止日期 ,获取实时数据2. FastAPI 的异步特性 完美适配 I/O 密集型的函数调用场景3. 结构化函数描述 是模型正确调用的关键4. 错误处理与超时机制 确保生产环境稳定性这套模式可以扩展到任何需要实时信息的场景------股票查询、数据库操作、API 聚合等。当你构建自己的 AI Agent 时,记住:好的函数设计,胜过千言万语的提示词。动手试试吧,让 AI 真正"动手"为你服务!

相关推荐
QN1幻化引擎2 小时前
两个 AI 互相“创造自己“:Dalin X × Dalin L 自创造闭环全记录
大数据·人工智能
smartpi_ai2 小时前
离线语音识别的“数字变量“限制:为什么不能识别“20.5度“?
人工智能·语音识别·xcode
IT小盘2 小时前
05-企业项目统一接入多个大模型-适配器模式实战
前端·人工智能·适配器模式
张彦峰ZYF2 小时前
从 Claude 到 Mythos:Anthropic 模型体系、对齐路线与企业级智能体实践分享
人工智能·claude·ai 安全·claude code·fable 5·mythos 5·企业级 ai
大鱼>2 小时前
Transformer时间序列预测:从Informer到TimesFM的完整演进
人工智能·深度学习·transformer
SEONIB_Explorer2 小时前
跨境电商新手零门槛教程:AI 一键生成 TikTok/Ins 投放短视频,5 步 60 秒出片
人工智能·音视频·跨境电商·视频制作·veonib
中微极客3 小时前
用LangChain 0.3构建生产级RAG与Agent:从API集成到Streamlit部署
数据库·人工智能·langchain
海上彼尚3 小时前
Nodejs也能写Agent - 22.LangGraph篇 - 上下文工程
前端·javascript·人工智能·langchain·node.js