📌 前言
随着大语言模型(LLM)的快速发展,我们发现纯文本对话模式下的 AI 存在明显的能力边界:它不知道今天的天气、查不到实时股价、算不出复杂的数学公式、更操作不了你电脑上的文件。
Function Calling(函数调用) 正是为了解决这个问题而生的核心能力。它让大模型从"只会聊天的知识库"进化为"能调用工具的智能中枢",是构建 Agent、智能助手、自动化工作流的基石技术。
本文将从 原理概念 → 工作流程 → 核心技术 → 实战代码 → 最佳实践 五个维度,带你彻底掌握 Function Calling。
一、Function Calling 是什么?
1.1 核心定义
Function Calling 是大模型的一项原生能力:当用户的问题需要外部工具辅助时,模型不再直接输出自然语言回答,而是输出一段结构化的 JSON 指令,告诉开发者"我需要调用这个函数,参数是这些"。
开发者的程序接收到这段 JSON 后,执行对应的函数/API,再把执行结果传回给大模型,由模型基于真实数据生成最终回答。
简单来说:
- 没有 Function Calling:AI 是"闭卷考试",只能用脑子里的知识回答
- 有了 Function Calling:AI 是"开卷考试 + 可以用计算器 + 可以上网查资料"
1.2 为什么需要 Function Calling?
大模型本身存在三大天然局限:
| 局限类型 | 具体表现 | Function Calling 的解决方案 |
|---|---|---|
| 时效性限制 | 训练数据有截止日期,不知道最新事件 | 调用搜索 API、新闻 API 获取实时信息 |
| 专业性不足 | 复杂计算、精确查询容易出错 | 调用计算器、数据库、专业工具保证准确性 |
| 无法交互外部 | 不能操作软件、不能发消息、不能控制设备 | 调用系统接口、IoT API、企业内部系统 |
1.3 发展背景
Function Calling 并非一开始就有。早期开发者想用大模型调用工具,只能靠 Prompt Engineering(提示词工程),在 System Prompt 里写一大堆规则:"如果用户问天气,就输出 WEATHER:城市名 这种格式..."
这种方式的问题很明显:
- ❌ 格式不稳定,模型经常"不听话"
- ❌ 解析成功率低,需要大量容错代码
- ❌ 只能支持简单的单参数场景
- ❌ 多函数场景下模型容易混乱
直到 OpenAI 在 2023 年 6 月正式推出原生 Function Calling 能力,通过对模型进行专项微调,让模型学会了稳定输出结构化的函数调用 JSON,这才真正让工具调用进入工业级可用阶段。如今,几乎所有主流大模型(GPT、Claude、文心一言、通义千问、DeepSeek 等)都支持了 Function Calling。
二、Function Calling 的工作原理
2.1 完整工作流程(四步走)

Function Calling 的标准执行流程分为四个核心步骤:
第一步:用户提问 + 函数定义
开发者在调用大模型 API 时,除了传入用户的问题,还要传入一份 函数清单(functions 数组),告诉模型"你可以调用这些工具,每个工具的功能和参数格式如下"。
第二步:模型判断并输出函数调用
模型接收到问题和函数清单后,进行判断:
- 如果问题能用自身知识回答 → 直接输出自然语言回答
- 如果问题需要调用工具 → 输出
function_call格式的 JSON,包含函数名和提取出的参数
第三步:开发者执行函数
你的后端程序解析模型返回的 JSON,根据函数名执行对应的真实函数/API,拿到执行结果。
第四步:结果回传 + 生成最终回答
把函数执行结果作为一条新的 message(role=function)传回给大模型,模型基于真实数据整理成自然语言回答,返回给用户。
2.2 与普通对话模式的对比

| 对比维度 | 普通对话模式 | Function Calling 模式 |
|---|---|---|
| 输出内容 | 纯自然语言文本 | 自然语言 或 结构化JSON |
| 信息来源 | 模型训练数据 | 训练数据 + 外部工具实时数据 |
| 准确性 | 依赖模型知识,可能幻觉 | 调用真实接口,数据准确 |
| 交互轮次 | 一问一答,单轮完成 | 可能多轮交互(提问→调工具→回答) |
| 适用场景 | 知识问答、创意写作 | 实时查询、计算、操作外部系统 |
2.3 关键技术点:模型到底做了什么?
很多人误以为 Function Calling 是模型"真的执行了代码",其实不是。模型本身只做了三件事:
- 意图识别:判断用户的问题是否需要调用工具,以及该调用哪个工具
- 参数提取:从用户的自然语言描述中,抽取出函数需要的各个参数值
- 格式生成:按照约定的 JSON Schema 格式,稳定输出结构化结果
💡 核心本质 :Function Calling 本质上是一个"结构化输出 + 意图分类 + 信息抽取"的组合任务,模型并没有真的执行函数,执行动作是由开发者的代码完成的。
三、Function Calling 的核心概念
3.1 函数定义(Function Definition)
要让模型调用函数,首先要告诉模型有哪些函数可用。每个函数的定义通常包含三部分:
json
{
"name": "get_weather",
"description": "查询指定城市的实时天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海、深圳"
},
"date": {
"type": "string",
"description": "查询日期,格式为YYYY-MM-DD,默认为今天"
}
},
"required": ["city"]
}
}
三个关键字段:
- name:函数名,模型输出时会原样返回,用来匹配你代码里的真实函数
- description:函数功能描述,这是模型判断"要不要调用这个函数"的关键依据,写得越清晰越准确
- parameters:参数的 JSON Schema 定义,包括参数名、类型、描述、是否必填
3.2 模型返回的函数调用格式
当模型决定调用函数时,会在回复中包含 function_call 字段:
json
{
"role": "assistant",
"content": null,
"function_call": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\", \"date\": \"2026-07-09\"}"
}
}
注意 arguments 是一个 JSON 字符串,需要你自己 parse 成对象再使用。
3.3 多轮调用链(Multi-step Function Calling)
复杂任务往往不是调用一个工具就能解决的,需要连续调用多个工具串联完成。

例如用户说:"帮我规划一下下周从上海去北京的出差行程",模型可能会按这个链路执行:
- 调用查询火车票 API → 获取上海到北京的高铁班次和时间
- 调用查询天气 API → 获取北京下周的天气情况
- 调用查询酒店 API → 根据行程推荐附近的酒店
- 综合所有信息 → 生成一份完整的行程规划
这就是 Agent 应用 的核心原理:大模型作为"大脑",不断思考→调用工具→观察结果→再思考→再调用工具,直到任务完成。
四、典型应用场景
Function Calling 的应用场景非常广泛,这里列举最常见的几大类:
4.1 实时信息查询类
- 🌤️ 天气查询、空气质量
- 📈 实时股价、基金净值、汇率
- 📰 最新新闻、热点事件
- 🚄 火车票、机票、酒店查询
- 📦 快递物流追踪
4.2 计算与数据处理类
- 🧮 复杂数学计算、公式求解
- 📊 数据库查询、数据分析
- 📈 统计报表生成、图表绘制
- 🔢 单位换算、日期计算
4.3 系统操作与自动化类
- 📧 发送邮件、短信、企业消息
- 📅 创建日程、预约会议
- 📁 文件读写、文档生成
- 🔧 服务器运维、命令执行
- 🏠 智能家居控制、IoT 设备操作
4.4 企业业务集成类
- 🏢 CRM 客户信息查询
- 💰 订单系统、财务系统对接
- 📋 工单创建、审批流程触发
- 👥 企业通讯录、人事信息查询
4.5 垂直领域专业工具
- 🏥 医疗问诊辅助(调用医学知识库)
- ⚖️ 法律条文查询
- 🧬 生物信息分析
- 🌐 代码解释器(Code Interpreter)
五、实战案例:从零实现天气查询 Function Calling
理论说了这么多,我们来动手写一个完整的可运行示例。本文以 OpenAI API 风格为例,其他大模型的调用方式基本一致。
5.1 环境准备
首先安装依赖:
bash
pip install openai requests
5.2 第一步:定义函数
我们先写一个真实的天气查询函数(这里用模拟数据代替真实 API):
python
import json
import requests
def get_weather(city: str, date: str = None) -> str:
"""
查询指定城市的天气信息
:param city: 城市名称
:param date: 查询日期,格式YYYY-MM-DD
:return: 天气信息JSON字符串
"""
# 实际项目中这里调用真实天气API,如和风天气、心知天气等
# 这里用模拟数据演示
weather_data = {
"city": city,
"date": date or "2026-07-09",
"weather": "晴转多云",
"temperature": "22°C ~ 32°C",
"humidity": "45%",
"wind": "东南风 3级",
"air_quality": "优"
}
return json.dumps(weather_data, ensure_ascii=False)
5.3 第二步:定义函数清单(给模型看的描述)
python
functions = [
{
"name": "get_weather",
"description": "查询指定城市的实时天气信息,包括温度、天气状况、空气质量等",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "要查询的城市名称,例如:北京、上海、广州、深圳"
},
"date": {
"type": "string",
"description": "查询的日期,格式为YYYY-MM-DD,默认为当天"
}
},
"required": ["city"]
}
}
]
5.4 第三步:完整的 Function Calling 交互流程
python
from openai import OpenAI
client = OpenAI(api_key="你的API_KEY", base_url="你的BASE_URL")
def chat_with_function(user_message: str) -> str:
# 第一轮:发送用户问题 + 函数定义
messages = [
{"role": "user", "content": user_message}
]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
functions=functions,
function_call="auto" # auto让模型自己决定是否调用函数
)
reply = response.choices[0].message
# 判断模型是否要调用函数
if reply.function_call:
# 解析函数名和参数
func_name = reply.function_call.name
func_args = json.loads(reply.function_call.arguments)
print(f"🤖 模型决定调用函数: {func_name}")
print(f"📋 参数: {func_args}")
# 执行真实函数
if func_name == "get_weather":
func_result = get_weather(**func_args)
else:
func_result = json.dumps({"error": "未知函数"})
print(f"✅ 函数执行结果: {func_result}")
# 把助手回复和函数结果都加入消息历史
messages.append(reply)
messages.append({
"role": "function",
"name": func_name,
"content": func_result
})
# 第二轮:让模型基于函数结果生成最终回答
second_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
return second_response.choices[0].message.content
else:
# 模型不需要调用函数,直接回答
return reply.content
# 测试一下
if __name__ == "__main__":
# 测试1:需要调用函数的问题
print("=== 测试1:天气查询 ===")
result = chat_with_function("北京今天天气怎么样?")
print(f"最终回答:{result}\n")
# 测试2:不需要调用函数的问题
print("=== 测试2:普通问答 ===")
result2 = chat_with_function("你好,介绍一下你自己")
print(f"最终回答:{result2}")
5.5 运行效果预览
=== 测试1:天气查询 ===
🤖 模型决定调用函数: get_weather
📋 参数: {'city': '北京', 'date': '2026-07-09'}
✅ 函数执行结果: {"city": "北京", "date": "2026-07-09", ...}
最终回答:根据查询,北京今天(2026年7月9日)的天气为晴转多云,
气温在22°C到32°C之间,湿度45%,东南风3级,空气质量优。
天气不错,适合户外活动~
=== 测试2:普通问答 ===
最终回答:你好!我是一个AI助手,可以回答问题、帮你查询天气、
计算数据等等。有什么可以帮你的吗?
5.6 多函数扩展
支持多个函数也很简单,只需在 functions 数组里继续添加即可。比如再加一个计算器函数:
python
def calculate(expression: str) -> str:
"""执行数学计算"""
try:
result = eval(expression)
return json.dumps({"expression": expression, "result": result})
except Exception as e:
return json.dumps({"error": str(e)})
# functions数组里增加定义
functions.append({
"name": "calculate",
"description": "执行数学计算,支持加减乘除和复杂表达式",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "要计算的数学表达式,例如:(3+5)*2"
}
},
"required": ["expression"]
}
})
然后在执行函数的分支里加上对应判断就可以了。
六、进阶技巧与最佳实践
6.1 函数描述怎么写才准确?
函数的 description 是影响调用准确率的关键,遵循以下原则:
✅ 好的描述:
python
"description": "查询指定城市未来7天的天气预报,包括每日最高最低温度、降水概率和天气状况"
❌ 不好的描述:
python
"description": "查天气" # 太简略,模型不知道适用场景
写作技巧:
- 一句话说清楚功能 + 适用场景
- 说明输入输出的范围(比如"未来7天"、"支持国内城市")
- 有歧义的地方要明确(比如温度单位是摄氏度还是华氏度)
6.2 参数描述的注意事项
- 枚举值尽量写全 :如果参数是有限的枚举值,用
enum字段列出来,模型就不会瞎编 - 默认值说明白:非必填参数要说明默认行为
- 格式要求写清楚:比如日期格式 YYYY-MM-DD、手机号 11 位数字等
示例:
json
{
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,默认celsius摄氏度"
}
}
6.3 函数粒度怎么把控?
| 策略 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 粗粒度大函数 | 调用次数少,省 token | 单个函数太复杂,模型参数容易填错 | 简单固定的业务流程 |
| 细粒度小函数 | 灵活组合,参数准确 | 多轮调用多,耗时久 | 复杂 Agent、通用工具集 |
建议:优先按"单一职责"拆分成小函数,每个函数只做一件事。
6.4 错误处理与降级策略
真实生产环境中,函数调用可能失败,一定要做好容错:
python
try:
func_result = get_weather(**func_args)
except Exception as e:
# 把错误信息传回模型,让它向用户解释或换一种方式
func_result = json.dumps({
"error": f"天气查询失败: {str(e)}",
"suggestion": "请稍后重试或检查城市名是否正确"
})
模型看到错误信息后,通常会自动向用户道歉并说明原因,甚至会尝试换参数重试。
6.5 安全防护
Function Calling 相当于给 AI 开了"执行权限",安全问题不容忽视:
- 权限最小化:AI 能调用的函数只给必要的权限,比如查询可以、删除要谨慎
- 关键操作二次确认:涉及删除、付款、发送消息等操作,一定要人工确认
- 参数校验:模型提取的参数不要直接用,代码里再做一次合法性校验
- 调用频率限制:防止异常情况下循环调用打爆你的 API
七、常见问题与坑点
Q1:模型总是不调用函数怎么办?
排查方向:
- 函数描述写得太模糊,模型没理解这个函数能干什么
- 问题本身模型觉得自己能回答(比如问"北京在哪",模型自己就知道)
- 可以把
function_call设为具体函数名,强制模型调用
Q2:模型调用函数时参数填错了?
常见原因:
- 参数描述不清楚,模型理解有偏差
- 参数有特殊格式要求但没说明
- 模型幻觉,编造不存在的参数值
解决:参数 description 写详细 + 代码侧做参数校验 + 校验失败后把错误回传给模型重试
Q3:函数返回结果太长,超 token 限制了?
解决策略:
- 函数返回前先做摘要,只返回关键信息
- 用更长上下文的模型(如 gpt-4-128k)
- 对返回结果做分页或截断处理
Q4:怎么让模型连续调用多个函数?
原生 Function Calling 支持并行调用(Parallel Function Calling),一次回复里可以返回多个函数调用指令。或者用循环方式:检查回复里有没有 function_call,有就执行,执行完继续传回去,直到模型输出纯文本回答为止。
八、总结
Function Calling 是大模型从"聊天机器人"走向"智能助手"的关键一步。它的核心价值在于:
- 突破知识边界:连接实时数据、专业工具、企业系统
- 提升回答准确性:用真实计算/查询替代模型幻觉
- 实现主动操作:从"只能说"变成"还能做"
- 构建 Agent 基础:是 AutoGPT、智能体应用的底层核心技术
掌握了 Function Calling,你就打开了大模型应用开发的新世界大门。从简单的查询工具,到复杂的多 Agent 协作系统,本质上都是在 Function Calling 的基础上搭建起来的。
🔗 延伸阅读:
- 想深入了解 Agent 开发?可以学习 LangChain、AutoGen 等框架
- 想做代码解释器?可以结合 Code Interpreter 沙箱
- 想做多工具协作?研究一下 ReAct、Toolformer 等论文
如果这篇文章对你有帮助,欢迎点赞 👍 收藏 ⭐ 关注 👀,我们下篇文章见!