函数调用(Function Calling)
先说结论
Function Calling 是让 LLM 根据用户输入和可用工具定义,生成结构化的工具调用请求(通常是 JSON 格式),从而与外部 API、数据库、代码执行器等交互,是 Agent 能力的基础。
QUESTION 面试高频:Function Calling 的完整工作流程是什么? 四步流程:①工具定义注入——在请求中向模型提供工具的 JSON Schema(函数名、描述、参数类型);②模型决策——模型判断是否需要调用工具,如需要则生成结构化的函数调用 JSON;③执行与注入——后端解析 JSON,执行对应函数,将结果注入对话;④最终生成——模型基于工具返回结果生成最终回答。
工作流程
用户输入 → [LLM + Tool Schema] → 判断是否需要工具
↓ 是
生成 function_call JSON
↓
执行函数,获取结果
↓
结果注入对话上下文
↓
[LLM] → 生成最终回答
主流 Function Calling 实现
| 方案 | 特点 | 工具定义方式 |
|---|---|---|
| OpenAI Function Calling | GPT-4o/4o-mini 原生支持 | JSON Schema |
| Anthropic Tool Use | Claude 原生 tool_use block | JSON Schema |
| Google Gemini | 支持并行函数调用 | FunctionDeclaration |
| Hermes 系列 | Nous Research 开源微调 | 特殊格式 |
| LLaMA 3.1/3.2 | Meta 改进的结构化输出 | 自定义格式 |
OpenAI Function Calling 示例
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}
}]
# 模型返回
{"name": "get_weather", "arguments": {"city": "北京", "unit": "celsius"}}
QUESTION 面试高频:Function Calling 是怎么训练出来的? 三种主要方法:①SFT(监督微调)——在 (查询, 工具定义, 正确调用) 三元组上训练,建立基础工具调用能力;②拒绝采样——生成多条调用轨迹,筛选成功的用于微调;③RL(强化学习)——以任务成功为奖励信号优化,提升复杂多步工具使用。实践中通常先用 SFT 建立基础能力,再用 RL 提升成功率。
训练数据构造
数据格式
输入:用户查询 + 可用工具定义(JSON Schema)
输出:结构化的工具调用(函数名 + 参数 JSON)
数据来源
| 来源 | 说明 | 质量 |
|---|---|---|
| 人工标注 | 人工编写查询-工具调用对 | 高,但成本大 |
| 合成数据 | 用 GPT-4/Claude 生成 | 中高,需验证 |
| 真实 API 日志 | 从实际使用中收集成功轨迹 | 高,但数据稀疏 |
| 开源数据集 | ToolLLM, API-Bank, BFCL | 中,覆盖面广 |
数据构造最佳实践
- 多样性:覆盖搜索、计算、数据库查询、代码执行等不同类型
- 复杂度梯度:从单工具单参数 → 多工具多步调用逐步递进
- 负样本:包含不应调用工具的查询,教模型判断"何时不调用"
- 错误处理:包含工具返回错误后的重试/恢复轨迹
- 多轮交互:包含工具结果返回后的后续推理
并行工具调用
QUESTION 面试高频:如何实现并行工具调用?
现代 API(OpenAI、Anthropic)支持在单轮中并行调用多个无依赖关系的工具:
# 模型一次返回多个 function_call
[
{"name": "get_weather", "arguments": {"city": "北京"}},
{"name": "get_weather", "arguments": {"city": "上海"}},
{"name": "get_stock_price", "arguments": {"symbol": "AAPL"}}
]
后端并行执行所有调用,将所有结果一起注入上下文,减少多轮交互延迟。
关键评估指标
| 指标 | 说明 | 重要性 |
|---|---|---|
| 函数选择准确率 | 是否选择了正确的函数 | 极高 |
| 参数填充准确率 | 参数值是否正确 | 高 |
| 多函数调用准确率 | 并行调用的正确性 | 高 |
| 触发率/误触发率 | 何时该调/何时不该调 | 高 |
| 端到端任务成功率 | 最终任务是否完成 | 最高 |
容易踩的坑和对应解法
| 失败模式 | 原因 | 解决方案 |
|---|---|---|
| 参数格式错误 | JSON 类型不匹配 | 严格校验 + fallback |
| 幻觉工具名 | 编造不存在的函数 | 校验函数名在定义列表中 |
| 不必要的调用 | 简单问题强行调用 | 负样本训练 + 判断逻辑 |
| 循环调用 | 工具间形成循环依赖 | 最大调用次数限制 |
| 错误路由 | 选错工具或传错参数 | 优化工具描述 + 缩小候选集 |
工程落地时我会怎么做
- 工具描述是第一优先级:描述质量直接决定调用准确率
- 防御性解析:对模型输出的 JSON 做严格校验和 fallback
- 工具数量控制:10-20 个是舒适区,超过需要先路由筛选
- 超时和重试:每个工具调用设置超时,设计优雅降级
- 可观测性:记录完整的调用轨迹(输入、输出、耗时、成功与否)
- 安全红线:涉及写入/删除/支付的操作必须人工确认
如果要对外讲,可以怎么概括
"Function Calling 是 Agent 的基础能力,核心流程是'工具定义注入 → 模型决策 → 执行函数 → 结果注入 → 最终生成'。在训练层面,通常用 SFT 建立基础能力、再用拒绝采样或 RL 提升复杂场景成功率。工程落地中最大的挑战是工具描述质量和错误处理——描述不清的工具有如盲人摸象,缺乏防御性解析的系统在生产环境会频繁崩溃。我的经验是:工具设计比模型选择更重要,10-20 个工具是舒适区,超过要先做路由筛选,并行调用是性能关键。"
最后记几条
- 工具描述质量决定调用准确率——模型对工具的理解完全依赖描述文本
- 训练路径:SFT 建基础能力 → 拒绝采样提纯 → RL 提升复杂场景
- 10-20 个工具是舒适区——超过此数量模型选择准确率显著下降
- 并行调用减少延迟——无依赖的工具应并行执行
- 防御性解析是必需品——模型输出不可信,必须做校验和 fallback
参考资料
- OpenAI Function Calling 文档: https://platform.openai.com/docs/guides/function-calling
- Anthropic Tool Use 文档: https://docs.anthropic.com/en/docs/build-with-claude/tool-use
- Patil, S. et al. "Gorilla: Large Language Model Connected with Massive APIs" (2023)
- Qin, Y. et al. "ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs" (ICLR 2024)
- BFCL (Berkeley Function Calling Leaderboard): https://gorilla.cs.berkeley.edu/leaderboard.html