Function Calling 从零开始
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. 用户询问模型:巴黎的天气怎么样?
{
"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. 代码演示
-
文件结构
function_calling_demo/ ├── node_modules/ ├── .env # 环境变量配置(API Key) ├── index.js # 主程序入口 ├── tools.js # 工具定义 ├── package.json └── package-lock.json -
初始化项目
npm init -y npm install dotenv openai -
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; -
环境变量(.env)
apiKey="...你的api_key" -
主程序(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命令:
4. 和mcp的区别
- Function Calling 是模型内置的一项能力,用于在对话中输出结构化的工具调用指令;
- MCP是一个外部的、标准化的通信协议框架,用于连接模型与各种外部工具或数据源。
(1)Function Calling 流程
Function Calling 的核心是一个以模型为中心的、相对简单的请求-响应循环。其典型流程如下:
- 用户请求:应用将用户消息和可用的工具列表发送给模型。
- 模型决策:模型分析用户意图,若判断需要调用工具,则生成一个结构化的工具调用请求(包含函数名和JSON格式的参数)。
- 本地执行:应用端解析该请求,在本地执行对应的函数代码。
- 结果回传:应用将函数执行结果作为消息附加到对话历史中,再次发送给模型。
- 最终响应:模型整合工具返回的结果,生成最终的自然语言回复给用户。
整个流程的关键在于模型直接输出可执行的函数调用参数,由应用端负责执行并完成闭环。
(2)MCP 流程
MCP 则定义了一个更解耦、更标准化的架构,其流程涉及独立的组件:
- 工具发现与连接:一个 MCP 客户端连接到一个或多个 MCP 服务器。服务器会声明其提供的工具、资源等能力。
- 会话建立:客户端与服务器之间建立一个有状态的会话。
- 请求转发:当模型需要调用工具时,它不再直接生成函数参数,而是生成一个意图(例如,“需要查询天气”)。客户端将此意图按照 MCP 协议格式化为一个请求,并转发给对应的 MCP 服务器
- 服务器执行:MCP 服务器接收请求,在其环境中执行具体操作(如调用API、查询数据库),并将结果按照 MCP 协议格式化。
- 结果返回:服务器将结果返回给客户端,客户端再将其整合后提供给模型,以生成最终回复。
MCP 的关键在于模型不直接处理具体的函数调用格式,而是通过一个标准协议层与外部工具交互,这使得工具可以作为独立服务存在,并实现更复杂的上下文管理和能力发现。
5. 总结
Function Calling 让大模型能够主动输出结构化调用请求,由应用端执行函数并回传结果,最终生成落地回答。它连接了语言与行动,是 AI 从“理解”走向“执行”的关键一步。
大模型的本质界定了它的能力边界,却因此获得了无限的外延。真正的强大从不是全知全能,而是清醒地知道何时该低头问路。每一个结构化的函数调用请求,都是一次谦卑的求助,也是一次优雅的借力——在承认局限中,抵达更远的远方。
更多推荐


所有评论(0)