Function Calling彻底讲透:AI Agent时代,大模型“动手“调用外部世界到底是怎么做到的?
前面几篇我们聊过Agent、MCP、Skill、Token、Embedding……这些概念拼在一起,构成了AI Agent的整个生态。但你有没有想过一个更底层的问题:
大模型本身只会"说话",它是怎么"动手"调用真实世界的工具、数据库、API的?
答案就藏在一个你可能听过、但不一定真正搞懂的概念里——Function Calling(函数调用)。
今天这篇文章,我们就来把Function Calling讲透。它到底是什么?为什么没有它就没有真正的AI Agent?它和MCP、Agent、Skill是什么关系?怎么从零写一个支持Function Calling的程序?以及——为什么说它是AI Coding时代每一个开发者都必须理解的分水岭?
一、一个真实的故事:为什么大模型必须会"打电话"
先把时间拉回2022年底,ChatGPT刚火的时候。那时候大家和大模型对话,最痛苦的事情是什么?
模型什么都懂,但它是个"缸中之脑"——它知道北京今天天气怎么样(用训练数据猜的,往往是错的),知道某个API的接口长什么样(可能版本已经过时了),但它没办法真的去查一下天气,没法真的调用那个API。
于是诞生了一个非常朴素的痛点:
如果用户问"今天上海天气怎么样",我们能不能让模型在回答之前,先真的去调用一下天气API,再把真实结果用自然语言告诉用户?
最早期,开发者们的解决方案是这样的"土办法":
- 在Prompt里写死:"如果你需要查天气,请输出[QUERY_WEATHER:上海]"
- 程序用正则匹配这个标记
- 匹配到了,就去调API
- 把结果拼回Prompt,让模型再生成一次
这种办法能跑,但很笨:
- 模型可能不按你的格式输出(产生幻觉)
- 多轮调用时上下文容易乱
- 需要为每个工具写一套"暗号"
- 完全没有结构化数据可言
2023年6月,OpenAI在GPT-4和GPT-3.5-turbo上正式推出Function Calling功能。紧接着Anthropic、Google、Meta、阿里、DeepSeek等纷纷跟进。从此,"让大模型调用工具"这件事,第一次有了工业级的标准答案。
那么,Function Calling到底是什么?
二、Function Calling到底是个啥?
2.1 一句话定义
Function Calling是一种让大模型在生成回答时,能够"决定"调用哪些预设函数、并以结构化方式输出调用参数的能力。
注意这个定义里的两个关键词:
- 决定:是模型自己判断的,不是写死的if-else
- 结构化:输出的不是字符串,而是严格的JSON对象
2.2 一个最直观的例子
假设你注册了两个工具:
[
{
"name": "get_weather",
"description": "查询指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,如:上海"}
},
"required": ["city"]
}
},
{
"name": "search_books",
"description": "根据关键词搜索图书",
"parameters": {
"type": "object",
"properties": {
"keyword": {"type": "string"},
"max_results": {"type": "integer", "default": 5}
},
"required": ["keyword"]
}
}
]
用户问:"上海今天热不热?另外帮我找3本关于Python编程的畅销书。"
传统大模型只能给一段文字回答。但支持Function Calling的模型会这样输出:
[
{
"name": "get_weather",
"arguments": "{\"city\": \"上海\"}"
},
{
"name": "search_books",
"arguments": "{\"keyword\": \"Python编程\", \"max_results\": 3}"
}
]
模型自己决定:这个问题需要调用两个工具。然后给出结构化的参数。整个过程模型没有真的去查天气、查书——它只是"提议"了调用方案。
真正的执行,是你的应用代码拿着这个JSON去调真实的API/函数,再把结果喂回给模型,让模型做最后一轮的自然语言回答。
2.3 Function Calling的本质:三步走
所有支持Function Calling的系统,底层都是同一个三步走流程:
| ① 声明 Declare 开发者告诉模型 "你可以调用这些工具, 每个工具的参数长这样" | ➜ | ② 决策 Decide 模型根据用户输入判断 要不要调用、调哪个、 参数是什么 | ➜ | ③ 执行 Execute 应用代码真正执行函数, 结果回传给模型, 生成最终回答 |
- 声明(Declare):开发者告诉模型"你可以调用这些工具,每个工具的参数长这样"
- 决策(Decide):模型根据用户输入,决定要不要调用、调哪个、参数是什么
- 执行(Execute):应用代码根据模型的决策去真正执行,再把结果回传给模型生成最终回答
模型本身从不真正执行任何外部调用。它只是个"参谋",决定方案。真正"动手"的是你的应用代码。
记住这一点,是理解后面所有概念的关键。
三、Function Calling的底层机制:模型到底是怎么"决定"的?
很多人以为Function Calling是某种"魔法"——模型真的会理解工具的含义、会推理参数。其实它的底层机制,比你想象的要朴素得多。
3.1 它本质是一种"结构化输出微调"
Function Calling并不是给模型装了一个"工具调用模块",而是在原有的"下一个token预测"基础上,加了一层结构化输出微调。
具体来说,训练数据里会大量包含这样的样本:
用户问:[某种需要工具的问题]
工具列表:[JSON格式的函数定义]
模型应该输出:[严格的JSON,包含要调用的函数和参数]
模型通过学习这些样本,就"学会"了:
- 看到工具描述,知道这个工具能干什么
- 看到用户问题,知道该不该用工具
- 知道输出必须符合JSON Schema的格式约束
这就是为什么Function Calling的可靠性远高于"Prompt里写暗号"——因为它是专门训练过的,不是临场发挥。
3.2 一个完整的运行流程
我们用一个具体的例子走一遍完整流程。假设用户问:"我钱包落在出租车上了,怎么办?"
Step 1: 应用构造请求
messages = [
{"role": "user", "content": "我钱包落在出租车上了,怎么办?"}
]
tools = [
{
"type": "function",
"function": {
"name": "search_taxi_lost_and_found",
"description": "查询出租车失物招领信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名"},
"time_range": {"type": "string", "description": "时间范围"}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4",
messages=messages,
tools=tools,
tool_choice="auto" # 让模型自己决定
)
Step 2: 模型决策
模型返回的不是文本,而是:
{
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "search_taxi_lost_and_found",
"arguments": "{\"city\": \"北京\", \"time_range\": \"今天\"}"
}
}
]
}
注意:模型根据上下文自动推断出city=北京,即使用户没说。这就是"推理"能力的体现。
Step 3: 应用执行真实函数
# 把模型返回的tool_calls拼回消息历史
messages.append(response.choices[0].message)
# 真正去调函数
result = search_taxi_lost_and_found(
city="北京",
time_range="今天"
)
# 把函数结果也回传给模型
messages.append({
"role": "tool",
"tool_call_id": "call_abc123",
"content": json.dumps(result, ensure_ascii=False)
})
# 让模型生成最终的自然语言回答
final_response = client.chat.completions.create(
model="gpt-4",
messages=messages
)
print(final_response.choices[0].message.content)
模型最终会输出:
"北京出租车失物招领电话是XXX,您可以在工作时间拨打,或者登录XXX平台在线报失。一般需要提供上下车时间、地点等信息……"
这就是一次完整的Function Calling。三步走,每一步都清晰可控。
3.3 关键技术点:tool_choice
你可能注意到上面有个参数 tool_choice="auto"。这个参数控制模型的行为模式:
- auto:模型自己决定要不要调用(最常用)
- none:强制模型不调用任何工具(普通聊天模式)
- {"type": "function", "function": {"name": "xxx"}}:强制模型必须调用某个特定工具
强制调用在生产环境很有用:比如做一个"天气查询机器人",不管用户说什么,模型都必须调用天气API(哪怕用户说"你好",也调一下当前城市天气作为开场白)。
3.4 关键技术点:并行调用
现代Function Calling支持并行多工具调用。也就是说,模型可以在一次响应里同时提议调用多个函数。
前面那个"上海天气+找Python书"的例子,模型实际上是在一次响应里同时给出了两个tool_calls。
这背后对应的是一次API请求里的多个独立子任务,对用户来说响应更快,对开发者来说更省token。
四、从零写一个完整可运行的Function Calling Demo
光说不练假把式。下面我们用Python + OpenAI SDK,从零写一个真正能跑的程序。
4.1 准备工作
pip install openai
如果你用的是国产模型(DeepSeek、通义千问、智谱等),只需要改一下base_url和api_key,代码完全一样——因为主流厂商都遵循了OpenAI的Function Calling协议。
4.2 完整代码
import json
import os
from openai import OpenAI
# ========== 1. 初始化客户端 ==========
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY", "sk-xxx"),
base_url="https://api.openai.com/v1" # 国产模型改这里
)
# ========== 2. 注册"工具"(伪实现) ==========
def get_weather(city: str) -> dict:
"""模拟天气API"""
fake_data = {
"北京": {"temp": 28, "weather": "晴", "humidity": 45},
"上海": {"temp": 32, "weather": "多云", "humidity": 70},
"广州": {"temp": 35, "weather": "雷阵雨", "humidity": 80}
}
return fake_data.get(city, {"temp": 25, "weather": "未知", "humidity": 50})
def calculate(expression: str) -> float:
"""安全计算器(生产环境请用ast.parse)"""
try:
# 简单白名单,只允许数字和基本运算符
allowed = set("0123456789+-*/.() ")
if not all(c in allowed for c in expression):
return {"error": "非法字符"}
return {"result": eval(expression)}
except Exception as e:
return {"error": str(e)}
# ========== 3. 用JSON Schema描述工具 ==========
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气,包括温度、天气状况、湿度",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海、广州"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "执行数学表达式计算,例如:(3+5)*2",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "合法的数学表达式字符串"
}
},
"required": ["expression"]
}
}
}
]
# ========== 4. 真正可用的对话函数 ==========
def chat(user_query: str) -> str:
messages = [{"role": "user", "content": user_query}]
# 第一轮:让模型决定要不要调工具
response = client.chat.completions.create(
model="gpt-4",
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
# 如果模型决定调工具
if msg.tool_calls:
print(f"🛠️ 模型决定调用 {len(msg.tool_calls)} 个工具")
messages.append(msg)
# 遍历每个工具调用
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f" - {func_name}({func_args})")
# 真正执行函数
if func_name == "get_weather":
result = get_weather(**func_args)
elif func_name == "calculate":
result = calculate(**func_args)
else:
result = {"error": "未知函数"}
print(f" 返回: {result}")
# 把结果回传给模型
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 第二轮:模型根据工具结果生成最终回答
final_response = client.chat.completions.create(
model="gpt-4",
messages=messages
)
return final_response.choices[0].message.content
# 模型决定不调工具
return msg.content
# ========== 5. 测试 ==========
if __name__ == "__main__":
print("=" * 60)
print("测试1: 单纯天气问题")
print("=" * 60)
print(chat("上海今天热不热?"))
print("\n" + "=" * 60)
print("测试2: 需要计算的问题")
print("=" * 60)
print(chat("帮我算一下 (125 + 75) * 3 等于多少?"))
print("\n" + "=" * 60)
print("测试3: 多工具并行调用")
print("=" * 60)
print(chat("北京今天多少度?另外计算一下 2的10次方。"))
print("\n" + "=" * 60)
print("测试4: 不需要工具的问题")
print("=" * 60)
print(chat("什么是光合作用?"))
运行后你会看到模型自己决定调不调工具、调哪个、怎么传参数。这就是Function Calling的完整实战。
4.3 一些生产环境的坑
上面的代码在Demo里没问题,但生产环境必须注意:
- JSON解析失败:模型可能输出不严格的JSON,必须用try-catch包住
- 幻觉参数:模型可能编造工具描述里没有的参数。要做严格的白名单校验
- 无限循环:模型可能一直调工具不回答。需要限制最大循环次数
- 敏感工具:涉及删库、付款、发邮件的工具,必须加二次确认
- Token消耗:工具描述会占用大量上下文。建议精简description
一个健壮的生产级Function Calling循环大概长这样:
MAX_ITERATIONS = 5
for i in range(MAX_ITERATIONS):
response = client.chat.completions.create(
model="gpt-4",
messages=messages,
tools=tools
)
msg = response.choices[0].message
if not msg.tool_calls:
return msg.content # 模型最终回答了,结束
messages.append(msg)
for tc in msg.tool_calls:
# 严格校验函数名
if tc.function.name not in SAFE_FUNCTIONS:
result = {"error": "forbidden function"}
else:
try:
args = json.loads(tc.function.arguments)
# 严格校验参数
validated = validate_args(tc.function.name, args)
result = SAFE_FUNCTIONS[tc.function.name](**validated)
except Exception as e:
result = {"error": str(e)}
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 超过最大轮次还没回答,强制结束
return "调用超时,请重新提问。"
五、Function Calling vs 几个"邻居"概念的边界
这是我被问过最多的问题之一。Function Calling、MCP、Agent、Skill、RAG,这几个词经常被混用。它们到底是什么关系?
| 用户层 用户提问 / 任务输入 |
| ▼ |
| Agent 层 任务规划,拆解多步骤(先查A → 再查B → 综合C) |
| ▼ |
| Function Calling 层 模型决定每一步调什么工具、参数是什么 |
| ▼ |
| Skill / MCP 层 工具的封装与发现(Skill = 能力单元,MCP = 通信协议) |
| ▼ |
| RAG / 数据层 实时知识检索 + 私有数据接入 |
| ▼ |
| 执行层 真实 API / 函数 / 命令执行 → 结果回传 → 最终回答 |
5.1 横向对比表
| 概念 | 层级 | 回答的问题 | 谁来做 |
|---|---|---|---|
| Function Calling | 模型能力 | 模型能不能决定调用工具 | 大模型 |
| MCP | 通信协议 | 工具怎么被发现、怎么被调用 | 协议规范 |
| Agent | 系统架构 | AI怎么自主规划多步任务 | 应用代码 |
| Skill | 能力封装 | 一个工具怎么被打包成可复用单元 | 开发者 |
| RAG | 数据接入 | 模型怎么获取实时/私有知识 | 应用代码 |
5.2 一个具体的类比
把这套系统想象成一个新入职的实习生:
- Function Calling = 实习生会看懂"工具说明书",知道该用哪个工具、参数怎么填(能力)
- MCP = 公司有统一的工具登记系统,新工具注册一次,全公司的实习生都能看到(协议)
- Agent = 实习生会自己拆解任务:"先查A,再查B,最后综合C"(规划能力)
- Skill = 资深员工把"查天气"这个动作打包成一个"技能包",新人直接调(封装)
- RAG = 给实习生配了一个资料库,遇到不知道的就去查(数据接入)
5.3 它们是怎么协作的?
一个完整的AI Agent系统,这五者缺一不可:
用户提问
↓
Agent(任务规划:把"订机票"拆成"查航班→比价→下单")
↓
Function Calling(决定每一步调什么工具)
↓
MCP(在工具库中发现可用的API)
↓
Skill(调用封装好的"订机票Skill")
↓
RAG(如果需要,检索用户的常旅信息)
↓
真实API执行 → 结果回传 → 最终回答
所以:
- 没有Function Calling,模型就是个哑巴聊天机器人
- 没有MCP,每个工具都要单独写适配代码
- 没有Agent,模型只能一次调用一个工具
- 没有Skill,工具调用代码会重复100遍
- 没有RAG,模型对实时/私有数据一无所知
六、Function Calling在AI Coding中的应用
前面都是从"通用Agent"角度讲的。现在切回我们这个号的主旋律——AI Coding。
Function Calling在AI Coding领域的地位,比很多人想象的重要得多。可以说,现代所有主流的AI Coding工具,底层都依赖Function Calling。
6.1 Cursor / Claude Code / Copilot:本质都是Function Calling
当你在Cursor里说"帮我重构这个文件",背后发生的事情是:
- Cursor把当前文件的代码、你的指令打包发给模型
- Cursor注册了一堆"工具"给模型:
read_file、edit_file、run_command、search_code…… - 模型通过Function Calling决定要调用哪些工具、参数是什么
- Cursor执行这些工具(读文件、跑命令、修改代码)
- 把结果回传,模型判断是否完成,循环直到任务结束
Cursor的"Agent模式",本质上就是一个多轮Function Calling的循环。
6.2 WorkBuddy / Marvis / Cline:都是Function Calling的工程化产品
前面几篇介绍过这些AI Coding工具,它们的核心机制:
- 把文件系统、终端、Git、网络请求都注册成"工具"
- 让模型通过Function Calling自主决定调用顺序
- 在循环里推进任务,直到模型认为完成
理解了Function Calling,你就能理解这些工具的能力边界:
- 模型能决定调哪个工具 → 所以工具覆盖范围决定了产品能力
- 模型不会执行工具 → 所以"模型说要删库" ≠ 真删库,中间有安全层
- 多轮循环 → 所以有最大轮次限制和Token消耗问题
6.3 自己做一个AI Coding小工具
理解了Function Calling,你完全可以自己撸一个迷你AI Coding工具。下面是极简版Demo:
import os
import subprocess
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# 注册"AI Coding"工具
tools = [
{
"type": "function",
"function": {
"name": "list_files",
"description": "列出当前目录下的所有文件",
"parameters": {"type": "object", "properties": {}}
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取指定文件的内容",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"}
},
"required": ["path"]
}
}
},
{
"type": "function",
"function": {
"name": "run_command",
"description": "执行shell命令,例如:ls, pwd, pytest",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string"}
},
"required": ["command"]
}
}
}
]
# 工具实现
def list_files() -> str:
return "\n".join(os.listdir("."))
def read_file(path: str) -> str:
with open(path, "r", encoding="utf-8") as f:
return f.read()[:3000] # 限制长度
def run_command(command: str) -> str:
# 生产环境必须做安全过滤
result = subprocess.run(
command, shell=True,
capture_output=True, text=True, timeout=30
)
return result.stdout + result.stderr
FUNCTIONS = {
"list_files": list_files,
"read_file": read_file,
"run_command": run_command
}
def ai_coding_agent(task: str):
messages = [{"role": "user", "content": task}]
for i in range(10): # 最多10轮
response = client.chat.completions.create(
model="gpt-4",
messages=messages,
tools=tools
)
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(f"\n✅ 任务完成:\n{msg.content}")
return
for tc in msg.tool_calls:
fname = tc.function.name
fargs = json.loads(tc.function.arguments)
print(f"🔧 调用 {fname}({fargs})")
try:
result = FUNCTIONS[fname](**fargs)
except Exception as e:
result = f"错误: {e}"
print(f" 结果: {str(result)[:200]}")
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": str(result)[:3000]
})
# 使用
ai_coding_agent("查看当前目录有哪些Python文件")
这几十行代码,就是Cursor、Claude Code、Cline的核心原理。所有的AI Coding工具,都是在这个骨架上长出来的。
七、Function Calling的局限与挑战
Function Calling虽然强大,但远非完美。当前主要有以下几个问题:
7.1 可靠性:模型还是会"幻觉"
虽然经过专门训练,模型仍然可能:
- 调用不存在的函数
- 给出不符合Schema的参数
- 在不该调用工具时调用
- 在需要调用时忘记调用
缓解方案:
- 严格的后端校验(白名单 + Schema验证)
- 使用
tool_choice="specific"强制调用 - 对工具描述做A/B测试,优化措辞
- Few-shot示例:在system prompt里给几个"标准调用案例"
7.2 上下文消耗:工具描述是Token大户
如果你注册了50个工具,每个工具的JSON Schema可能要占100-300 token。50个工具就是5K-15K token的纯消耗,模型可能还没看到用户问题,就已经"吃"掉了一大段上下文窗口。
缓解方案:
- 精简工具描述(用最少的词说清楚功能)
- 工具按需注册:把不相关的工具从这一轮请求中剔除
- 工具分层:先注册"工具集",模型选择工具集后再注册具体工具
7.3 安全:Function Calling是把双刃剑
Function Calling让模型能调用任何你注册的函数。如果你不小心注册了一个"删除数据库"的函数,而模型被Prompt Injection攻击了,可能就会真的执行。
缓解方案:
- 高危操作必须加二次确认("确定要删除xxx吗?[Y/N]")
- 权限分离:每个工具最小权限原则
- 操作审计:所有工具调用都要打日志
- 沙箱执行:危险操作在隔离环境里跑
7.4 多模态Function Calling
2024年开始,主流模型开始支持多模态Function Calling——也就是工具的参数可以是图片、音频、视频,而不仅仅是文本。
比如用户发一张菜单照片问"这个多少钱",模型可以调用OCR工具+计算器,输出准确的金额。
这是Function Calling的下一个重要演进方向。
八、实战选型建议:怎么用好Function Calling?
结合我自己的实战经验,给你6条具体建议:
建议1:从"小而精"开始,不要一次注册一堆工具
新手最常犯的错误就是一口气注册20个工具,结果模型调用混乱、参数错误百出。正确的做法是:一个任务只注册相关的3-5个工具。
建议2:工具描述要像"给新员工的SOP"
好的工具描述包含三要素:
- 功能:这个工具干什么的
- 何时用:什么样的场景应该调它
- 参数约束:每个参数的取值范围、格式、是否必填
反例:"description": "天气查询"
正例:"description": "查询中国主要城市的实时天气(温度、湿度、天气状况)。当用户问'今天xxx热不热'、'xxx下雨了吗'、'xxx适合穿什么'时使用。city参数必须是中国城市名,如'北京'、'上海'。"
建议3:必须做参数白名单和Schema验证
永远不要相信模型传来的参数。即使Schema声明了city是string,模型也可能传一个对象或数字。后端必须做一次校验。
建议4:设置最大循环次数
模型可能陷入"反复调同一个工具"的死循环。生产环境必须设置max_iterations(一般5-10次就够了),超时就强制结束。
建议5:把"工具执行结果"做摘要
一个工具可能返回10KB的数据,但你不需要全塞给模型——会让上下文爆炸。建议对结果做摘要:
- JSON只保留关键字段
- 列表只返回前N条
- 长文本只返回前500字 + 提示"更多内容已省略"
建议6:监控和日志是必须的
Function Calling一旦上线,可观测性比功能本身更重要。要监控:
- 每个工具的调用频次(识别哪些工具被低估/高估)
- 调用失败的常见原因(参数错误?权限问题?超时?)
- 平均循环次数(识别死循环)
- Token消耗分布(识别哪些工具描述太啰嗦)
九、Function Calling的下一个五年:未来趋势
站在2026年中这个时间点,Function Calling正在向几个方向快速演进:
9.1 标准化:OpenAI协议已成事实标准
虽然各家(Anthropic Tool Use、Google Function Calling、阿里DashScope)API细节有差异,但底层协议越来越趋同。OpenAI的tools/tool_choice/tool_calls格式已经成为事实标准,新出的模型基本都兼容。
这意味着:你学会一套API,可以无缝切换底层模型。
9.2 Agent化:从"单次调用"到"长任务"
现在的Function Calling还是"一问一回",未来会演化成长时运行的Agent任务:
- 支持持久化状态:Agent休息几天后再回来,还能继续之前的任务
- 支持异步调用:发起一个10分钟的任务,模型继续干别的,等结果回来再继续
- 支持多Agent协作:研究Agent、写作Agent、审校Agent协同完成任务
9.3 与MCP深度融合
前面说过,Function Calling是"模型决定调什么",MCP是"工具怎么被发现"。两者天然互补。
未来的趋势是:
- 模型只需要说"我要调用MCP server xxx的yyy工具"
- MCP协议自动发现工具、传递参数、执行、回传
- 应用层不再需要写适配代码
这就是"工具调用彻底标准化"的未来。
9.4 端侧Function Calling
随着端侧大模型(手机、浏览器、嵌入式设备)越来越强,Function Calling会下沉到端侧。
未来你的手机助手可能直接调用本地APP:打开相机、读取短信、控制智能家居……这一切都不需要云端中转。
这对Function Calling的延迟、隐私、离线能力提出了全新要求。
十、结语:Function Calling是AI Agent时代的"水电煤"
写到这里,我想说:
Function Calling不是一个酷炫的新技术,而是一个看不见的基础设施。
就像电力之于工业革命,你不会在每个产品宣传里都说"我用了电",但没有电就没有现代工业。Function Calling之于AI Agent,也是同样的存在。
它不性感、不前沿,但它是地基。
理解了Function Calling,你就能真正看懂:
- 为什么Cursor能帮你自动写代码(它注册了一堆Coding工具)
- 为什么Claude Code能在终端里帮你干活(它把shell命令都注册成了工具)
- 为什么MCP会出现(它要解决工具发现和复用的标准化问题)
- 为什么Agent能自主完成任务(它在循环里反复调Function Calling)
- 为什么Skill这么重要(它把高频工具调用打包成可复用的能力)
所有这些看似复杂的AI Agent概念,底层都建立在一个朴素的能力上——
让大模型决定调哪个函数,并把参数填对。
这就是Function Calling的力量。
如果这篇文章帮你理清了Function Calling的概念,欢迎点赞、收藏、关注。我们下一篇,会继续讲AI Coding领域的另一个关键基础概念。
我是hoaxxcj,专注分享AI Coding、LLM工程化、AI Agent等领域的实战经验。
更多推荐
所有评论(0)