1. 什么是 Function Calling?

【官方原文】:OpenAI Function Calling 官方文档

" Function calling provides a powerful and flexible way for OpenAI models to interface with external systems and access data outside their training data."

一句话说透:Function Calling 是大语言模型的一项能力:让模型在生成回复时,根据用户意图,主动输出一个结构化的函数调用请求(函数名 + JSON 参数)

{
  "name": "get_weather",
  "arguments": { "city": "北京" }
}

2. 核心流程

【官方原文】:

Function Calling 是通过 OpenAI API 实现应用与模型之间的多步对话。流程包含五个高层步骤

  1. 用模型可以调用的工具向模型提出请求
  2. 从模型接收工具调用
  3. 在应用端执行代码,输入工具调用
  4. 向模型发送第二个请求,带着工具输出
  5. 收到模型的最终响应(或更多工具调用)

1. 用户询问模型:巴黎的天气怎么样?

{
    "tools" : [获取天气、数字计算],
    "message""巴黎的天气怎么样呀?"
}

2. 模型返回结构化工具调用请求

{
  "name": "get_weather",
  "arguments": { "city": "巴黎" }
}

3. 应用端执行函数代码

function get_weather(city) {
  return weatherData[city];
}
// 返回结果:"巴黎:多云,28°C"

4. 应用端向模型回传工具执行结果

{
    "message" : "...之前的消息",
     "output": "巴黎:多云,28°C",
}

5. 模型返回最终自然语言回答

{
  "message":  "巴黎当前的温度是28°C,多云⛅"
}

整个流程:用户提问→模型判断需要调用 get_weather,参数是"巴黎"→应用端执行函数拿到天气结果→应用端把结果整合用户的问题一起发给大模型→模型整合结果给出自然语言回答。


3. 代码演示

  1. 文件结构

    function_calling_demo/
    ├── node_modules/          
    ├── .env                   # 环境变量配置(API Key)
    ├── index.js               # 主程序入口
    ├── tools.js               # 工具定义
    ├── package.json           
    └── package-lock.json  
    
  2. 初始化项目

     npm init -y
     npm install dotenv openai
    
  3. tools工具函数(tools.js)

    const tools = [
      {
        type: "function",
        function: {
          name: "get_weather",
          description: "获取指定城市的天气",
          parameters: {
            type: "object",
            properties: {
              city: {
                type: "string",
                description: "城市名,如 北京、巴黎",
              },
            },
            required: ["city"],
          },
        },
      },
    ];
    
    export default tools;
    
  4. 环境变量(.env)

    apiKey="...你的api_key"
    
  5. 主程序(index.js)

    import "dotenv/config";
    import OpenAI from "openai";
    
    // 1. 初始化 AI 客户端
    const openai = new OpenAI({
      apiKey: process.env.apiKey,
      baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
    });
    
    // 2. 定义工具
    import tools from "./tools.js";
    
    // 3. 工具函数
    function get_weather(city) {
      const data = {
        北京: "晴,26°C",
        巴黎: "多云,28°C",
        上海: "小雨,22°C",
      };
      return data[city] || "暂无天气";
    }
    
    // ---------- 控制台样式工具 ----------
    const C = {
      reset: "\x1b[0m",
      bold: "\x1b[1m",
      dim: "\x1b[2m",
      title: "\x1b[36;1m",   // 青色粗体
      step: "\x1b[33;1m",    // 黄色粗体
      user: "\x1b[32m",      // 绿色
      ai: "\x1b[35m",        // 紫色
      tool: "\x1b[34m",      // 蓝色
      result: "\x1b[33m",    // 黄色
      success: "\x1b[32;1m", // 绿色粗体
      arrow: "\x1b[90m",     // 灰色
    };
    
    function line(char = "─") {
      console.log(`${C.arrow}${char.repeat(50)}${C.reset}`);
    }
    
    function step(n, text) {
      console.log(`\n${C.step}  Step ${n}${text}${C.reset}`);
      line();
    }
    
    function label(tag, color, value) {
      console.log(`  ${color}${tag}${C.reset}  ${value}`);
    }
    
    // ============================================
    //  主流程(完整的 Function Calling 循环)
    // ============================================
    async function run() {
      const messages = [
        { role: "user", content: "巴黎的天气怎么样?" },
      ];
    
      console.log(`\n${C.title}╔══════════════════════════════════════╗${C.reset}`);
      console.log(`${C.title}  ║     Function Calling  流程演示       ║${C.reset}`);
      console.log(`${C.title}  ╚══════════════════════════════════════╝${C.reset}`);
    
      step(1, "用户发起请求");
      label("USER", C.user, `"${messages[0].content}"`);
    
      step(2, "发送至 LLM,等待模型决策...");
      let response = await openai.chat.completions.create({
        model: "qwen-plus-2025-07-28",
        tools: tools,
        messages: messages,
      });
    
      const choice = response.choices[0];
      messages.push(choice.message);
    
      if (choice.finish_reason !== "tool_calls") {
        label("RESPONSE", C.ai, choice.message.content || "(空)");
        console.log(`\n${C.dim}  模型未调用工具,流程结束。${C.reset}\n`);
        return;
      }
    
      label("DECISION", C.ai, `finish_reason = "tool_calls" → 模型决定调用工具`);
      for (const tc of choice.message.tool_calls) {
        console.log(`\n${C.tool}  ┌─ 函数调用 ─────────────────────────┐${C.reset}`);
        console.log(`${C.tool}    │  function : ${tc.function.name}${C.reset}`);
        console.log(`${C.tool}    │  arguments: ${tc.function.arguments}${C.reset}`);
        console.log(`${C.tool}    │  call_id  : ${tc.id}${C.reset}`);
        console.log(`${C.tool}    └─────────────────────────────────────┘${C.reset}`);
      }
    
      step(3, "本地执行工具函数");
      for (const tc of choice.message.tool_calls) {
        if (tc.function.name === "get_weather") {
          const { city } = JSON.parse(tc.function.arguments);
          label("EXECUTE", C.tool, `get_weather("${city}")`);
          const result = get_weather(city);
          label("RESULT", C.result, result);
          messages.push({ role: "tool", tool_call_id: tc.id, content: result });
        }
      }
    
      step(4, "将工具结果回传 LLM,生成最终回答...");
      response = await openai.chat.completions.create({
        model: "qwen-plus-2025-07-28",
        tools: tools,
        messages: messages,
      });
    
      line("═");
      console.log(`${C.success}  ✦ 最终回答:${response.choices[0].message.content}${C.reset}`);
      line("═");
      console.log();
    }
    
    run();
    

    运行:node index.js命令:

    img

4. 和mcp的区别

  • Function Calling 是模型内置的一项能力,用于在对话中输出结构化的工具调用指令;
  • MCP是一个外部的、标准化的通信协议框架,用于连接模型与各种外部工具或数据源。

(1)Function Calling 流程

Function Calling 的核心是一个以模型为中心的、相对简单的请求-响应循环。其典型流程如下:

  1. 用户请求:应用将用户消息和可用的工具列表发送给模型。
  2. 模型决策:模型分析用户意图,若判断需要调用工具,则生成一个结构化的工具调用请求(包含函数名和JSON格式的参数)。
  3. 本地执行:应用端解析该请求,在本地执行对应的函数代码。
  4. 结果回传:应用将函数执行结果作为消息附加到对话历史中,再次发送给模型。
  5. 最终响应:模型整合工具返回的结果,生成最终的自然语言回复给用户。

整个流程的关键在于模型直接输出可执行的函数调用参数,由应用端负责执行并完成闭环。


(2)MCP 流程

MCP 则定义了一个更解耦、更标准化的架构,其流程涉及独立的组件:

  1. 工具发现与连接:一个 MCP 客户端连接到一个或多个 MCP 服务器。服务器会声明其提供的工具、资源等能力。
  2. 会话建立:客户端与服务器之间建立一个有状态的会话。
  3. 请求转发:当模型需要调用工具时,它不再直接生成函数参数,而是生成一个意图(例如,“需要查询天气”)。客户端将此意图按照 MCP 协议格式化为一个请求,并转发给对应的 MCP 服务器
  4. 服务器执行:MCP 服务器接收请求,在其环境中执行具体操作(如调用API、查询数据库),并将结果按照 MCP 协议格式化。
  5. 结果返回:服务器将结果返回给客户端,客户端再将其整合后提供给模型,以生成最终回复。

MCP 的关键在于模型不直接处理具体的函数调用格式,而是通过一个标准协议层与外部工具交互,这使得工具可以作为独立服务存在,并实现更复杂的上下文管理和能力发现。


5. 总结

Function Calling 让大模型能够主动输出结构化调用请求,由应用端执行函数并回传结果,最终生成落地回答。它连接了语言与行动,是 AI 从“理解”走向“执行”的关键一步。

大模型的本质界定了它的能力边界,却因此获得了无限的外延。真正的强大从不是全知全能,而是清醒地知道何时该低头问路。每一个结构化的函数调用请求,都是一次谦卑的求助,也是一次优雅的借力——在承认局限中,抵达更远的远方。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐