Function Calling 解决什么问题

大模型本身只能输出文字,但 Agent 需要它能「做事」——查天气、读数据库、发邮件。Function Calling 就是让大模型在合适的时候,输出一个结构化的函数调用请求,由你的程序去执行,再把结果喂回给模型继续回答。整个过程模型不直接碰外部系统,它只负责「决定调什么、传什么参数」。

和早期让模型自由生成代码再解析执行的做法相比,Function Calling 的优势是结构化:模型输出严格符合你定义的 JSON Schema,不需要正则去猜。这让工具调用变得可靠,也让调试变得容易——模型说要调哪个函数、传什么参数,一目了然。

Function Calling 的本质是给大模型装了一个「结构化输出开关」:不是让它自由发挥,而是让它按你定义的格式填写调用单。
本文核心知识点
  • Function Calling让模型按 JSON Schema 输出工具调用请求,由外部代码执行。
  • 工具描述工具的名称、参数说明和描述文字直接影响模型选对工具的概率。
  • MCP 协议把工具接入标准化,一次接入多处可用,不用每个客户端重复对接。
  • 参数校验模型生成的参数不一定对,必须在执行前做校验和纠错。
MCP 配图:中央发光核心通过双向连线连接扳手、放大镜与数据库三个工具节点,蓝色渐变扁平风格
MCP 的示意:一个统一的核心连接多种工具,模型通过标准协议调用任意工具而不需要单独对接。

工具描述怎么写才有效

Function Calling 的效果很大程度上取决于你给工具写的描述。模型看不到你的代码,它只根据工具名称和描述来判断「这个工具能不能解决当前问题」。描述写得模糊,模型就会选错工具或者乱传参数。

# 一个工具的 JSON Schema 定义示例
tools = [{
    "type": "function",
    "function": {
        "name": "search_flights",
        "description": "查询指定城市间的航班信息,返回航班号、时间和价格。用于用户询问机票或出行方案时调用。",
        "parameters": {
            "type": "object",
            "properties": {
                "from": {"type": "string", "description": "出发城市,如北京"},
                "to": {"type": "string", "description": "到达城市,如上海"},
                "date": {"type": "string", "description": "出发日期,格式 YYYY-MM-DD"}
            },
            "required": ["from", "to", "date"]
        }
    }
}]

写描述的几个要点:说清楚工具做什么、什么时候该用、参数什么格式。特别是「什么时候该用」这一句,直接决定了模型在面对模糊问题时会不会乱调工具。

MCP 协议:工具接入的标准化

有了 Function Calling 之后,每个 AI 客户端都要自己对接一套工具。你做一个聊天应用要对接天气、日历、数据库;换一个客户端又要重新对接一遍。MCP(模型上下文协议)就是来解决这个重复劳动的:它定义了一套标准协议,工具方实现一次 MCP Server,任何支持 MCP 的客户端都能直接用。

从开发者角度看,MCP 的价值是「写一次工具,到处接入」。你不用为每个 AI 应用单独写对接代码,只要把工具封装成 MCP Server,Claude、IDE 插件、自定义 Agent 框架都能自动发现和调用它。这和 USB-C 的思路一样:统一接口,免去各做各的线。

MCP 的核心概念
  • Server工具提供方,暴露一组可调用的工具和资源。
  • Client大模型应用,通过协议发现和调用 Server 提供的工具。
  • Resources除了工具,还可以暴露文件、数据库记录等可读资源。
# MCP Server 的最简结构(伪代码)
from mcp import Server

server = Server("my-tools")

@server.tool()
def search_flights(from_city: str, to_city: str, date: str):
    """查询航班信息"""
    return flight_api.search(from_city, to_city, date)

server.run()

参数校验与错误处理

模型生成的工具调用参数不一定对。日期格式可能写错、城市名可能拼成拼音、必填参数可能漏了。在真正执行工具之前,必须加一层校验:按 JSON Schema 检查参数类型和必填项,发现错误就把错误信息返回给模型,让它修正后再试一次。

# 参数校验与纠错循环
while True:
    call = model.next_tool_call()
    errors = validate(call.parameters, tool_schema)
    if not errors:
        result = execute_tool(call)
        break
    # 把错误反馈给模型,让它修正
    messages.append({"role": "tool", "content": f"参数错误: {errors}, 请修正后重试"})

这种「试错-反馈-修正」的循环是 Agent 可靠性的关键。不要假设模型一次就能调对,要把它当成一个会犯错但能看提示改正的实习生,给它纠错的机会。

多工具编排与选择策略

当你给 Agent 挂了十几个工具时,问题就变成了:模型怎么知道该用哪个?工具太多会让模型困惑,也会占用大量上下文。常见的做法有三种:让模型自己选(工具不多时)、先用一个小模型做工具分类再路由(工具多时)、或者按工作流预先固定每一步用哪个工具(流程明确时)。

策略做法适用场景
模型自选所有工具描述塞进 prompt,让模型选工具少于 10 个
路由分类先用小模型判断意图,再路由到对应工具组工具几十个
工作流固定按流程定义好每一步用什么工具业务流程明确