Function Calling 深度解析——大模型工具调用的工程化实践

本文为「AI Agent 技术系列」第 2 篇。Function Calling 是 Agent 调用工具的基础机制,理解本文是阅读 MCP 协议(第 3 篇)和 LangChain 工程化(第 4 篇)的前提。

一、主题定义与背景

Function Calling 的正式定义

OpenAI 官方文档的定义:

“Function Calling 让大语言模型能够调用外部工具,获取实时信息或执行特定操作,弥补模型自身能力的局限。它在应用程序与大模型之间建立多步骤交互,使模型可以参考外部工具信息进行准确回答。” [1]

解决的四大问题

问题 说明 Function Calling 如何解决
实时性 模型训练数据存在截止日期,无法回答实时天气、股价、新闻 调用实时 API 获取最新数据
计算与逻辑 模型在数学计算、精确推理上可能出错 调用计算器或代码执行器
系统集成 模型无法直接操作数据库、发送邮件、调用 API Function Calling 作为桥梁
结构化交互 自然语言输出不够精确,无法满足自动化系统需求 返回 JSON 格式的函数名与入参

从 Function Calling 到 MCP 的演进

Function Calling 解决了”模型如何决定调用工具”的问题,但每个工具的集成协议各自为政。MCP(Model Context Protocol)在此基础上标准化了”工具如何被接入”——从”N×M 集成”到”N+M 集成”(详见系列第 3 篇)。


二、核心技术原理与架构设计

2.1 五步工作流

Function Calling 的核心是一个五步循环:

sequenceDiagram
    participant U as 用户应用
    participant M as 大模型
    participant T as 工具函数

    U->>M: ① 用户问题 + 工具清单
    M-->>U: ② 返回 tool_calls (JSON)
    U->>T: ③ 执行工具函数
    T-->>U: 工具输出结果
    U->>M: ④ 结果回传 (追加到 messages)
    M-->>U: ⑤ 生成自然语言回复

关键特点:模型可选择是否调用工具——无工具调用时直接回复自然语言,跳过步骤 ②~⑤。

2.2 每步详解与代码

以下使用阿里云百炼 Qwen 模型(OpenAI 兼容协议),国内环境可直接运行。

步骤 ① 发起第一次模型调用:应用程序将用户问题与可调用的工具清单一同发送给大模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import OpenAI from "openai";

const client = new OpenAI({
apiKey: process.env.DASHSCOPE_API_KEY,
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
});

const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
{ role: "user", content: "北京天气咋样" },
];

const tools: OpenAI.Chat.ChatCompletionTool[] = [{
type: "function",
function: {
name: "get_current_weather",
description: "获取指定城市的当前天气",
parameters: {
type: "object",
properties: {
location: { type: "string", description: "城市名称,如北京" },
},
required: ["location"],
},
},
}];

const response = await client.chat.completions.create({
model: "qwen3.6-plus",
messages,
tools,
tool_choice: "auto", // 模型自主决策
});

步骤 ② 接收工具调用指令:模型判断需要调用外部工具,返回 JSON 格式的工具名称与入参。

1
2
3
4
// 模型返回的 tool_calls
const toolCall = response.choices[0].message.tool_calls?.[0];
// toolCall.function.name = "get_current_weather"
// toolCall.function.arguments = '{"location": "北京"}'

步骤 ③ 在应用端运行工具:应用程序接收到工具指令后,在本地执行对应的工具函数。

1
2
3
4
5
6
7
8
9
function getCurrentWeather(args: { location: string }): string {
// 实际调用天气 API
return `${args.location}今天是多云,气温22°C`;
}

// 执行工具
const args = JSON.parse(toolCall.function.arguments);
const result = getCurrentWeather(args);
// result = "北京今天是多云,气温22°C"

步骤 ④ 发起第二次模型调用:将工具输出结果添加到消息上下文,再次向模型发起请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 追加 assistant 的工具调用消息
messages.push(response.choices[0].message);
// 追加工具结果
messages.push({
role: "tool",
content: result,
tool_call_id: toolCall.id,
});

// 第二次调用模型
const finalResponse = await client.chat.completions.create({
model: "qwen3.6-plus",
messages,
});

步骤 ⑤ 接收最终回复:大模型将工具输出结果与用户问题整合,生成自然语言回复。

1
2
3
// 工具原始输出: "北京今天是多云,气温22°C"
console.log(finalResponse.choices[0].message.content);
// "北京今天的天气是多云,气温22°C。出门建议带件薄外套。"

2.3 核心特性机制

并行工具调用(Parallel Tool Calling)

2024 年 8 月,OpenAI 发布并行工具调用能力 [2]——单次请求可同时调用多个独立工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 用户问:"北京和上海天气分别如何?"
// 模型可一次性返回两个 tool_calls:
// 1. get_current_weather(location="北京")
// 2. get_current_weather(location="上海")

const toolCalls = response.choices[0].message.tool_calls ?? [];
// 并行执行多个工具
const results = await Promise.all(
toolCalls.map(async (tc) => {
const args = JSON.parse(tc.function.arguments);
const result = getCurrentWeather(args);
messages.push({
role: "tool",
content: result,
tool_call_id: tc.id,
});
return result;
})
);

强制工具调用(tool_choice 参数)

通过 tool_choice 参数控制模型行为 [3]:

行为 使用场景
"auto" 模型自主决策是否调用工具(默认) 通用场景
"none" 强制不使用工具,直接回复 测试模型纯文本能力
"required" 必须调用至少一个工具 强制工具优先
{ type: "function", function: { name: "xxx" } } 强制调用指定函数 工作流固定步骤
1
2
3
4
5
6
7
8
9
10
// 强制调用特定函数
const response = await client.chat.completions.create({
model: "qwen3.6-plus",
messages,
tools,
tool_choice: {
type: "function",
function: { name: "get_current_weather" },
},
});

⚠️ Qwen 注意tool_choice: "required" 或指定函数名时,部分 Qwen 模型需禁用 Thinking Mode(设置 enable_thinking: false),否则可能不返回 tool_calls

多轮对话上下文管理

维持 messages 数组上下文,支持连续对话中的工具调用:

1
2
3
4
5
6
// 第一轮:用户问"北京天气"
// 模型调用工具 → 返回"北京今天多云"

// 第二轮:用户问"上海的呢?"
// 模型从上下文理解"上海"是新的查询目标,再次调用工具
messages.push({ role: "user", content: "上海的呢?" });

三、实际应用场景与最佳实践

场景一:多城市天气查询(并行调用)

使用 createAgent 封装 Function Calling 循环,代码更简洁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { ChatOpenAI } from "@langchain/openai";
import { createAgent, tool } from "langchain";
import { z } from "zod";

const model = new ChatOpenAI({
model: "qwen3.6-plus",
configuration: {
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
apiKey: process.env.DASHSCOPE_API_KEY,
},
temperature: 0.3,
maxRetries: 3,
modelKwargs: { enable_thinking: false },
});

const getWeather = tool(
async ({ location }) => {
const db: Record<string, string> = {
"北京": "晴 25°C",
"上海": "多云 28°C",
"广州": "雨 30°C",
};
return db[location] ?? `${location}:数据未找到`;
},
{
name: "get_weather",
description: "获取指定城市天气",
schema: z.object({
location: z.string().describe("城市名"),
}),
}
);

const agent = createAgent({ model, tools: [getWeather] });

const result = await agent.invoke({
messages: [{ role: "user", content: "查询以下城市天气:北京、上海、广州" }],
});
console.log(result.messages[result.messages.length - 1].content);
// 输出:"北京:晴 25°C;上海:多云 28°C;广州:雨 30°C"

💡 createAgent 自动处理 tool_calls 循环、多轮对话与并行调用,无需手动管理五步工作流。

场景二:企业知识库问答(RAG + Function Calling)

将 RAG 检索封装为工具,让模型自主决定何时查询知识库:

1
2
3
4
5
6
7
8
9
10
11
12
13
const searchKnowledgeBase = tool(
async ({ query }) => {
// 调用向量数据库或全文检索
return await vectorSearch(query);
},
{
name: "search_knowledge_base",
description: "搜索企业内部知识库,用于回答公司制度、产品文档等问题",
schema: z.object({
query: z.string().describe("搜索关键词"),
}),
}
);

生产环境四条铁律

原则 说明 实践要点
动态工具路由 工具数量超过数十个时,用语义检索或轻量级 LLM 路由器预筛选 候选集不超过 20 个,降低 Token 消耗
最小权限 默认只读,危险工具隔离 不暴露代码执行、文件删除、数据库写入;高权限操作必须人工确认
用户体验优化 设置超时时间、提供即时反馈 正在查询... 提示;工具失败时重试上限 3 次 + 友好兜底话术
评估与调优 建立评估体系 工具选择准确率、参数提取率、端到端成功率

四、常见挑战与解决方案

挑战 表现 解决方案 代码要点
工具数量过多 模型在几十个工具中决策困难,准确率下降 语义检索预筛选相关工具 候选集 ≤ 20 个
参数提取错误 模型生成的 arguments JSON 格式错误或值不对 JSON Schema 严格约束 + 验证 required 字段必填 + 类型校验
工具调用超时 外部 API 响应慢导致用户等待 超时 + 重试 + 兜底话术 timeout=10, maxRetries=3
幻觉性工具调用 模型调用不存在的工具或编造参数 工具清单严格校验 执行前检查 function.name 是否在注册列表中
上下文膨胀 多轮工具调用导致 messages 过长 定期摘要 + 裁剪历史 超过 N 轮后 summarize

参数校验示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { z } from "zod";

// 工具的 Zod Schema
const weatherSchema = z.object({
location: z.string(),
});

function safeExecuteTool(
toolCall: { function: { name: string; arguments: string } },
tools: Map<string, { schema: z.ZodType; handler: (args: any) => Promise<string> }>
): Promise<string> {
// 1. 校验工具名
const tool = tools.get(toolCall.function.name);
if (!tool) return Promise.resolve(`工具 ${toolCall.function.name} 未注册`);

// 2. 校验参数
let args: unknown;
try {
args = JSON.parse(toolCall.function.arguments);
tool.schema.parse(args); // Zod 校验
} catch (e) {
return Promise.resolve(`参数校验失败: ${e}`);
}

// 3. 带超时执行
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 10_000);

return tool.handler(args).finally(() => clearTimeout(timer));
}

五、行业趋势与前沿进展

各大模型厂商 Function Calling 支持现状

2025-2026 年,主流大模型均已支持 Function Calling / Tool Use,但实现细节有差异 [4]:

厂商 模型 特性支持 差异点
OpenAI GPT-4o / o1 / o3 并行调用、tool_choice、structured output 最完善的工具调用生态
Anthropic Claude 3.5 / 4 Tool Use(并行支持) tool_use block 格式,与 OpenAI 不同
Google Gemini 2.0 / 2.5 Function Calling 原生多模态工具调用
阿里云 Qwen 系列 Function Calling 支持 DashScope API,兼容 OpenAI 格式
DeepSeek V3 / R1 Function Calling 兼容 OpenAI API 格式

关键差异:OpenAI 用 tool_calls 数组,Anthropic 用 tool_use content block,Google 用 function_call 对象。开发者需注意跨厂商适配 [4]。

Responses API vs Chat Completions API

2025 年 3 月,OpenAI 推出 Responses API(/v1/responses),作为构建 AI Agent 的推荐接口 [5]:

维度 Chat Completions API Responses API
定位 无状态对话补全 有状态 Agent 构建
状态管理 开发者自行维护 messages 内置状态管理
内置工具 Web Search、File Search、Code Interpreter 内置
工具调用 通过 tools 参数 统一工具接口
发布时间 2023 2025.03

Responses API 的核心改进是内置工具——Web Search、File Search、Code Interpreter 不再需要开发者自行实现,直接调用即可 [5]。

Function Calling 与 MCP 的关系演进

Function Calling 定义了”模型如何决定调用工具”,MCP 定义了”工具如何被标准化接入”。两者关系:

  • Function Calling 是模型层:模型输出 JSON 指令
  • MCP 是协议层:标准化工具的注册、发现、调用

未来趋势:Function Calling 仍是模型标配,MCP 成为工具接入的标准协议(详见系列第 3 篇)。


结论

Function Calling 的核心价值在于让大模型从”封闭的推理引擎”变成”能连接真实世界的智能体”。工程实践中需把握三个要点:

  1. 机制层面:理解五步工作流,每步都可能失败——做好校验、超时、重试
  2. 架构层面:工具数量超过 20 个时引入动态路由,生产环境必须最小权限
  3. 演进层面:关注 Responses API 和 MCP 协议——前者简化调用,后者标准化集成

参考资料

[1] OpenAI. Function Calling 官方文档. 2025

[2] OpenAI. Parallel Function Calling 发布说明. 2025-04-14

[3] OpenAI Function Calling 完全指南:tool_choice 参数详解. 2025-03-10

[4] 从 Function Calling 到 Tool Use:三大 LLM Agent 工具调用对比. 2026-05-26

[5] OpenAI Responses API 与 Chat Completions API 对比. 2026-06-19