2024年3月31日

函数调用

Function Calling 是让 LLM 根据用户输入和可用工具定义,生成结构化的工具调用请求(通常是 JSON 格式),从而与外部 API、数据库、代码执行器等交互,是 Agent 能力的基础。

知识库大模型智能体与工具调用agentfunction-calling

函数调用(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 中,覆盖面广

数据构造最佳实践

  1. 多样性:覆盖搜索、计算、数据库查询、代码执行等不同类型
  2. 复杂度梯度:从单工具单参数 → 多工具多步调用逐步递进
  3. 负样本:包含不应调用工具的查询,教模型判断"何时不调用"
  4. 错误处理:包含工具返回错误后的重试/恢复轨迹
  5. 多轮交互:包含工具结果返回后的后续推理

并行工具调用

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
幻觉工具名 编造不存在的函数 校验函数名在定义列表中
不必要的调用 简单问题强行调用 负样本训练 + 判断逻辑
循环调用 工具间形成循环依赖 最大调用次数限制
错误路由 选错工具或传错参数 优化工具描述 + 缩小候选集

工程落地时我会怎么做

  1. 工具描述是第一优先级:描述质量直接决定调用准确率
  2. 防御性解析:对模型输出的 JSON 做严格校验和 fallback
  3. 工具数量控制:10-20 个是舒适区,超过需要先路由筛选
  4. 超时和重试:每个工具调用设置超时,设计优雅降级
  5. 可观测性:记录完整的调用轨迹(输入、输出、耗时、成功与否)
  6. 安全红线:涉及写入/删除/支付的操作必须人工确认

如果要对外讲,可以怎么概括

"Function Calling 是 Agent 的基础能力,核心流程是'工具定义注入 → 模型决策 → 执行函数 → 结果注入 → 最终生成'。在训练层面,通常用 SFT 建立基础能力、再用拒绝采样或 RL 提升复杂场景成功率。工程落地中最大的挑战是工具描述质量和错误处理——描述不清的工具有如盲人摸象,缺乏防御性解析的系统在生产环境会频繁崩溃。我的经验是:工具设计比模型选择更重要,10-20 个工具是舒适区,超过要先做路由筛选,并行调用是性能关键。"

最后记几条

  1. 工具描述质量决定调用准确率——模型对工具的理解完全依赖描述文本
  2. 训练路径:SFT 建基础能力 → 拒绝采样提纯 → RL 提升复杂场景
  3. 10-20 个工具是舒适区——超过此数量模型选择准确率显著下降
  4. 并行调用减少延迟——无依赖的工具应并行执行
  5. 防御性解析是必需品——模型输出不可信,必须做校验和 fallback

参考资料

延伸阅读