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