前面几篇我们聊过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,再把真实结果用自然语言告诉用户?

最早期,开发者们的解决方案是这样的"土办法":

  1. 在Prompt里写死:"如果你需要查天气,请输出[QUERY_WEATHER:上海]"
  2. 程序用正则匹配这个标记
  3. 匹配到了,就去调API
  4. 把结果拼回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
应用代码真正执行函数,
结果回传给模型,
生成最终回答
  1. 声明(Declare):开发者告诉模型"你可以调用这些工具,每个工具的参数长这样"
  2. 决策(Decide):模型根据用户输入,决定要不要调用、调哪个、参数是什么
  3. 执行(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里没问题,但生产环境必须注意:

  1. JSON解析失败:模型可能输出不严格的JSON,必须用try-catch包住
  2. 幻觉参数:模型可能编造工具描述里没有的参数。要做严格的白名单校验
  3. 无限循环:模型可能一直调工具不回答。需要限制最大循环次数
  4. 敏感工具:涉及删库、付款、发邮件的工具,必须加二次确认
  5. 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里说"帮我重构这个文件",背后发生的事情是:

  1. Cursor把当前文件的代码、你的指令打包发给模型
  2. Cursor注册了一堆"工具"给模型:read_fileedit_filerun_commandsearch_code……
  3. 模型通过Function Calling决定要调用哪些工具、参数是什么
  4. Cursor执行这些工具(读文件、跑命令、修改代码)
  5. 把结果回传,模型判断是否完成,循环直到任务结束

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"

好的工具描述包含三要素:

  1. 功能:这个工具干什么的
  2. 何时用:什么样的场景应该调它
  3. 参数约束:每个参数的取值范围、格式、是否必填

反例:"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等领域的实战经验。

更多推荐