大模型Function Calling与GPTs实战:从原理到构建智能天气助手
1. 背景与核心概念
在AI技术浪潮席卷全球的今天,大模型(Large Language Model, LLM)已经从实验室走向了千行百业。然而,许多开发者和技术爱好者发现,直接使用大模型API进行对话,往往难以满足复杂的业务需求,比如查询实时天气、操作数据库、调用内部API等。这时,如何让大模型“学会”调用外部工具,就成了应用落地的关键瓶颈。
本文将聚焦于解决这一核心问题,深入浅出地讲解如何通过 Function Calling(函数调用) 和 GPTs(自定义GPT) 两大关键技术,将大模型从一个“聊天机器人”升级为能够执行具体任务的“智能体”。无论你是零基础的初学者,还是希望将AI能力集成到现有系统的开发者,都能从本文中找到一套清晰、完整、可复现的实战路径。
什么是Function Calling?
简单来说,Function Calling 是一种让大模型理解和调用开发者预先定义好的函数(或工具)的能力。你告诉大模型:“我这里有一些工具,比如get_weather(city)可以查天气,search_database(query)可以查数据。当用户的问题需要用到这些工具时,请你告诉我应该调用哪个工具,以及传入什么参数。” 大模型会分析用户的意图,然后返回一个结构化的调用请求,你的程序再根据这个请求去真正执行函数,并将结果返回给大模型,由它组织成最终的回答。这就像给大模型配了一个“万能工具箱”。
什么是GPTs? GPTs是OpenAI推出的一个功能,允许用户通过自然语言对话的方式,定制一个专属的、具备特定知识和能力的AI助手。你可以为它配置指令(Instructions)、上传知识文件(Knowledge)、并最关键的一步——启用Actions。Actions 的本质就是基于OpenAI的Function Calling能力,让你定义的GPT能够连接外部API,执行真实世界的操作。因此,GPTs是Function Calling能力面向终端用户的一个产品化、低代码的封装。
为什么需要掌握它们?
- 突破大模型的知识与能力边界:大模型的知识存在截止日期,且无法访问私有数据或执行动态操作。Function Calling/GPTs Actions 是连接大模型与外部世界(数据库、API、工具)的桥梁。
- 实现复杂业务流程自动化:从简单的信息查询,到涉及多步骤决策和外部系统交互的复杂流程(如智能客服、自动化报告生成、智能审批),都可以通过编排多个函数调用来实现。
- 降低AI应用开发门槛:GPTs提供了图形化界面,让非开发者也能快速构建具备特定功能的AI应用。而理解其背后的Function Calling原理,则是开发者进行深度定制和集成的基础。
接下来,我们将从零开始,手把手带你搭建环境、编写代码、配置GPTs,最终打造一个能真正“干活”的AI应用。
2. 环境准备与版本说明
在开始实战之前,我们需要准备好开发环境。本文将以Python作为主要开发语言,因为它在大模型生态中拥有最丰富的库和社区支持。我们将使用OpenAI的官方API作为大模型服务,同时也会介绍如何适配其他兼容OpenAI API的模型(如国内的一些大模型)。
核心环境与工具:
- 操作系统:Windows 10/11, macOS, 或 Linux (如 Ubuntu 20.04+)。本文示例在macOS/Linux环境下编写,Windows用户请注意命令行的差异(如使用
dir代替ls)。 - Python版本:Python 3.8 或更高版本。这是大多数现代AI库的最低要求。
- 包管理工具:
pip(Python自带) 或conda(推荐用于管理复杂的Python环境)。 - 代码编辑器/IDE:VS Code, PyCharm, Jupyter Notebook 等任选。
- OpenAI账户与API Key:你需要一个OpenAI账户,并在API Keys页面创建一个API Key。请妥善保管此Key,不要泄露。
- (可选) 国内大模型API:如果你希望使用国内的大模型服务(如百度文心一言、阿里通义千问、智谱GLM等),需要准备对应平台的API Key。这些平台大多提供了兼容OpenAI API格式的接口,迁移成本较低。
项目初始化与依赖安装:
-
创建项目目录并初始化虚拟环境(强烈推荐): 虚拟环境可以隔离项目依赖,避免版本冲突。
BASH# 创建项目文件夹mkdir ai_function_calling_democd ai_function_calling_demo# 创建虚拟环境 (以 venv 为例)python -m venv venv# 激活虚拟环境# macOS/Linux:source venv/bin/activate# Windows:# venv\Scripts\activate激活后,命令行提示符前通常会显示
(venv)。 -
安装核心依赖库: 我们将主要使用
openai这个官方库。同时安装python-dotenv来管理环境变量(如API Key)。BASHpip install openai python-dotenv requestsopenai: OpenAI官方Python SDK,用于调用GPT模型和Function Calling。python-dotenv: 从.env文件加载环境变量,安全地管理敏感信息。requests: 用于在自定义函数中调用外部HTTP API。
-
配置环境变量: 在项目根目录创建一个名为
.env的文件,将你的OpenAI API Key写入其中。BASH# .env 文件内容OPENAI_API_KEY=你的OpenAI_API_Key_在这里重要:确保
.env文件被添加到.gitignore中,避免将密钥提交到代码仓库。
至此,基础开发环境已搭建完成。接下来,我们将深入Function Calling的核心机制。
3. Function Calling 核心机制与流程拆解
理解Function Calling的工作流程是成功应用它的关键。整个过程可以分解为以下几个清晰的步骤:
1. 定义工具(函数)列表 你首先需要告诉大模型你有哪些工具可用。这通过一个JSON Schema格式的列表来完成。你需要描述每个函数的名称、描述和参数。描述至关重要,大模型依靠它来判断是否以及如何调用该函数。
2. 用户发起对话 用户向你的应用程序提出一个问题或请求。
3. 应用程序调用大模型(首次)
你的程序将用户的问题和你定义的工具列表一起,发送给大模型(例如gpt-3.5-turbo或gpt-4)。你需要在API调用中设置tools参数。
4. 大模型分析并返回“工具调用请求”
大模型分析用户意图后,如果认为需要调用某个工具,它不会直接执行,而是返回一个结构化的消息。这个消息类型是tool_calls,其中包含了它想调用的function的名称和计算好的参数。
5. 应用程序执行函数
你的程序接收到这个tool_calls请求后,根据function.name找到本地对应的真实函数,并用function.arguments(一个JSON字符串)作为参数来执行它。
6. 应用程序将函数结果返回给大模型
函数执行完毕后,会得到一个结果(例如,{“temperature”: 22, “city”: “北京”})。你的程序需要将这个结果作为一条新的消息(类型为tool,包含结果和对应的tool_call_id)追加到对话历史中,然后再次调用大模型。
7. 大模型整合信息并生成最终回答 大模型收到了函数执行的结果,结合之前的对话历史,生成面向用户的、自然流畅的最终回答。
8. 应用程序将最终回答呈现给用户。
这个流程的核心在于大模型只负责“思考”和“规划”(决定调用什么、参数是什么),而具体的“执行”由你的代码完成。这种“思考-执行”的分离,既安全又灵活。
下面,我们通过一个最简单的代码示例来直观感受这个过程。
4. 完整实战案例:打造一个智能天气查询助手
我们将构建一个命令行下的智能天气查询助手。它不仅能回答关于天气的简单问题,还能理解“北京和上海哪里更暖和?”这类需要比较的复杂查询。
4.1 项目结构与核心文件
项目目录结构如下:
4.2 编写工具函数模块
首先,我们创建tools/weather_tools.py,这里定义了我们的“工具箱”。为了演示,我们用一个模拟函数代替真实的天气API调用。
关键点解析:
- 函数定义 (
get_current_weather):这是一个普通的Python函数,它接收参数并返回一个JSON字符串。在实际项目中,这里应该调用如OpenWeatherMap、和风天气等真实的API。 - 工具列表 (
weather_tools):这是一个符合OpenAI Function Calling格式的列表。description字段必须清晰描述函数的作用,这是大模型做决策的主要依据。parameters的JSON Schema定义了函数需要的参数及其类型、描述。 - 函数映射 (
available_functions):一个字典,将工具列表中定义的函数名name映射到我们实际编写的Python函数对象。这样,当大模型返回调用请求时,我们可以快速找到并执行对应的函数。
4.3 编写主程序逻辑
接下来,创建主程序文件weather_assistant.py。
4.4 运行与验证
- 确保你的
.env文件已正确配置OPENAI_API_KEY。 - 在终端中,确保位于项目根目录且虚拟环境已激活。
- 运行程序:BASHpython weather_assistant.py
- 与助手进行对话,观察其行为:
- 简单查询:输入“北京天气怎么样?”。程序会调用
get_current_weather函数,获取模拟数据,然后生成回答。 - 带参数查询:输入“旧金山现在的气温是多少华氏度?”。模型会识别出
location为“旧金山”,unit为“fahrenheit”。 - 复杂比较:输入“北京和上海哪里更暖和?”。这是Function Calling威力的体现。模型会分析出需要比较两个城市,因此可能会连续发起两次工具调用(一次查询北京,一次查询上海),获取数据后再进行对比分析,最后给出一个综合回答。
- 无需工具的对话:输入“你好!”。模型识别出不需要天气信息,会直接根据系统指令进行友好问候,不会调用工具。
- 简单查询:输入“北京天气怎么样?”。程序会调用
4.5 结果说明
运行程序后,你会在终端看到类似以下的输出,清晰地展示了“思考-执行-回答”的完整链路:
通过这个案例,你已经成功实现了一个具备外部工具调用能力的AI助手。接下来,我们看看如何将这套能力产品化,通过GPTs创建一个无需代码的图形化应用。
5. 进阶实战:使用GPTs Actions打造无代码AI应用
GPTs的Actions功能,本质上是一个为你自动生成Function Calling配置界面的工具。我们将把上面编写的天气查询函数,部署成一个可供公网访问的API,然后配置到GPTs中。
5.1 将函数部署为Web API
我们需要一个简单的Web服务器来暴露我们的天气查询函数。这里使用轻量级的Flask框架。
-
安装Flask:
BASHpip install flask -
创建API服务器文件
weather_api.py:PYTHON# weather_api.pyfrom flask import Flask, request, jsonifyimport jsonimport randomfrom datetime import datetimeapp = Flask(__name__)def get_current_weather(location: str, unit: str = "celsius") -> dict:"""与之前工具函数逻辑一致,但返回字典"""weather_conditions = ["晴朗", "多云", "小雨", "阴天", "大雪"]condition = random.choice(weather_conditions)random.seed(hash(location) % 10000)if unit == "fahrenheit":temperature = random.randint(50, 90)else:temperature = random.randint(10, 35)random.seed()return {"location": location,"temperature": temperature,"unit": unit,"condition": condition,"timestamp": datetime.now().isoformat(),}def weather_endpoint():"""处理GPTs Actions发来的请求"""try:data = request.get_json()# GPTs Actions 发送的参数在 `parameters` 字段中arguments = data.get('parameters', {})location = arguments.get('location')unit = arguments.get('unit', 'celsius')if not location:return jsonify({"error": "Missing required parameter: location"}), 400weather_data = get_current_weather(location, unit)# 返回格式需包含 `result` 字段,GPTs期望读取其中的内容return jsonify({"result": weather_data})except Exception as e:return jsonify({"error": str(e)}), 500if __name__ == '__main__':# 本地运行,端口5000app.run(debug=True, port=5000) -
运行API服务器:
BASHpython weather_api.py服务器将在
http://127.0.0.1:5000本地运行。
5.2 配置GPTs Actions
由于GPTs需要访问公网API,本地服务器需要借助内网穿透工具(如ngrok、localtunnel)暴露到公网。这里以ngrok为例(需注册并获取authtoken)。
-
下载并配置ngrok,然后运行:
BASHngrok http 5000ngrok会提供一个临时的公网URL,如
https://abc123.ngrok-free.app。 -
创建GPTs:
- 登录OpenAI ChatGPT,点击左侧边栏的
Explore GPTs,然后点击Create a GPT。 - 在
Configure标签页下:- Name:
智能天气专家 - Description: 一个可以查询全球城市实时天气的助手。
- Instructions: 你是一个专业的天气助手。当用户询问天气时,使用“获取天气”工具来查询。如果用户没有指定城市,请主动询问。如果用户询问比较,请分别查询后再对比。用中文回答。
- Name:
- 在
Knowledge部分,可以不上传文件。 - 关键步骤:配置Actions:
- 点击
Create new action。 - Schema选择
OpenAPI 3.1,但我们手动输入更简单。在API Schema框中粘贴以下内容:
YAMLopenapi: 3.1.0info:title: Weather APIdescription: Get current weather for a city.version: 1.0.0servers:- url: https://abc123.ngrok-free.app # 替换为你的ngrok URLpaths:/weather:post:operationId: getCurrentWeathersummary: Get current weatherrequestBody:required: truecontent:application/json:schema:type: objectproperties:location:type: stringdescription: The city name.unit:type: stringenum: [celsius, fahrenheit]description: Temperature unit.required:- locationresponses:'200':description: OKcontent:application/json:schema:type: objectproperties:result:type: object- 点击
Import,GPTs会自动解析这个Schema,并在下方生成一个名为getCurrentWeather的Action。 - 确保
Authentication选择None(因为我们的演示API是公开的,生产环境务必使用API Key等认证方式)。
- 点击
- 登录OpenAI ChatGPT,点击左侧边栏的
-
保存并测试:
- 点击右上角
Save,选择发布范围(例如Only me)。 - 在预览界面,直接与你的GPT对话:“上海今天天气如何?”。GPT会识别意图,调用你配置的Action,从你的API获取数据,并生成回答。
- 点击右上角
至此,你已成功创建了一个无需编写前端界面、通过自然语言即可调用自定义API的AI应用。GPTs帮你处理了所有的对话逻辑和Function Calling的封装。
6. 常见问题与排查思路
在实际开发中,你可能会遇到以下典型问题:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型不调用函数 | 1. 函数描述(description)不清晰或与用户问题不匹配。2. 用户问题太简单,模型认为无需调用工具也能回答。 3. API调用时未正确传入 tools参数。 |
1. 优化函数描述,确保准确概括函数功能和应用场景。 2. 在系统指令中明确要求模型使用工具,或设置 tool_choice: “required”强制使用。3. 检查API调用代码,确认 tools列表格式正确。 |
| 模型调用参数错误 | 1. 参数Schema定义不严谨(如类型、枚举值)。 2. 用户表述模糊,模型推断有误。 |
1. 在parameters的description中详细描述每个参数,使用enum限制可选值。2. 可以在函数内部增加参数验证和错误处理逻辑,对错误参数返回清晰提示。 |
| 函数执行失败 | 1. 本地函数代码存在Bug或依赖服务不可用。 2. available_functions映射错误,找不到对应函数。 |
1. 在调用真实函数前进行充分的本地测试和异常捕获。 2. 检查函数名是否与工具定义中的 name完全一致。 |
| GPTs Action 返回“无法调用” | 1. API服务器未运行或网络不通。 2. ngrok等隧道服务中断。 3. OpenAPI Schema格式错误或URL不对。 4. API返回的JSON格式不符合GPTs预期(缺少 result字段)。 |
1. 使用curl或Postman手动测试你的API端点,确保能收到正确响应。2. 检查ngrok状态,重新启动。 3. 仔细核对Schema,特别是 paths、requestBody和responses部分。4. 确保API返回 {“result”: ...}格式。 |
| Token消耗过多/成本高 | 1. 函数描述或参数Schema过于冗长。 2. 对话历史未合理管理,上下文过长。 |
1. 精简description和parameters的描述,在清晰的前提下保持简洁。2. 对于长对话,可以适时总结或清除早期历史。对于固定工具集,可以考虑在每次请求中只携带必要的工具定义。 |
7. 最佳实践与工程建议
将Function Calling投入生产环境,需要考虑更多工程化细节:
-
安全第一
- 输入验证与清理:永远不要信任模型直接返回的参数。在本地函数中,对
arguments进行严格的类型、范围、长度验证,防止注入攻击。 - 权限控制:不同的函数可能对应不同的权限级别。在执行函数前,应结合用户会话信息进行权限校验。
- 敏感信息:API Key、数据库密码等绝不能硬编码在代码或GPTs的Schema中。使用环境变量或安全的密钥管理服务。
- 输入验证与清理:永远不要信任模型直接返回的参数。在本地函数中,对
-
提升可靠性
- 结构化错误处理:函数执行失败时,应返回结构化的错误信息(如
{“error”: “具体原因”}),方便大模型理解并向用户解释。 - 设置超时与重试:调用外部API或执行耗时操作时,务必设置超时。对于暂时性失败,可以实现简单的重试机制。
- 使用更强大的模型:对于复杂逻辑和工具选择,
gpt-4系列模型通常比gpt-3.5-turbo表现更稳定、更准确。
- 结构化错误处理:函数执行失败时,应返回结构化的错误信息(如
-
优化性能与成本
- 工具选择策略:在
tool_choice参数中,可以使用“none”、“auto”或指定具体的{“type”: “function”, “function”: {“name”: “xxx”}}来精细控制模型的行为。 - 上下文管理:及时修剪过长的对话历史。对于多轮对话中不变的工具定义,可以考虑在后续请求中省略,但需注意模型可能需要工具定义来理解上下文。
- 并行处理:当模型一次性返回多个
tool_calls时(如比较多个城市),可以并行执行这些函数调用以减少总耗时。
- 工具选择策略:在
-
设计模式
- “规划-执行”模式:对于复杂任务,可以先让模型制定一个调用多个函数的“计划”,然后由你的程序按顺序或条件执行。这比让模型在单次对话中决定所有调用更可控。
- “Human-in-the-loop”:对于高风险操作(如发送邮件、数据库删除),可以在函数中设计审批环节,将执行权交还给真人确认。
-
面向GPTs的开发
- 提供清晰的隐私说明:在GPTs的配置中,明确告知用户你的Action会访问哪些数据以及用途。
- 设计友好的用户提示:在Instructions中引导用户如何更好地使用你的Action,例如“你可以问我‘纽约的天气’,或者‘比较伦敦和巴黎的气候’”。
- 处理模糊查询:在API后端,可以集成地理编码服务,将“帝都”、“魔都”这样的别名转换为标准城市名。
掌握Function Calling和GPTs,你就掌握了将大模型从“智库”变为“执行者”的钥匙。从简单的数据查询到复杂的业务流程自动化,其应用场景只受限于你的想象力。建议从本文的天气助手案例出发,尝试将其改造成查询股票、搜索文档、管理待办事项的实用工具,在实践中不断深化理解。