1. 什么是 Function Calling?

Function Calling(函数调用)是大型语言模型(LLM)与外部工具、API 或代码进行交互的一种核心机制。它允许 LLM 根据用户的自然语言请求,理解其意图,并“调用”一个预定义的函数(或工具)来执行具体任务,然后将执行结果返回给用户。

简单来说,Function Calling 让 LLM 从一个“只会说”的聊天机器人,变成了一个“能动手做”的智能助手。

核心价值:

  • 突破上下文限制:LLM 本身无法直接操作数据库、发送邮件或查询实时天气。Function Calling 提供了桥梁。
  • 确保输出结构化:强制模型返回符合特定格式(如 JSON)的数据,便于程序化处理。
  • 增强可控性与安全性:开发者可以精确控制模型能“做”什么,避免其产生不受控的行为或信息。

2. 核心概念与工作原理

2.1 基本流程

一个典型的 Function Calling 流程包含以下步骤:

  1. 定义函数:开发者向 LLM 描述一个或多个可用的函数,包括函数名、描述、参数及其类型。
  2. 用户提问:用户提出一个自然语言请求,例如:“帮我查一下北京明天下午的天气。”
  3. 模型决策:LLM 分析用户意图,判断是否需要调用函数,以及调用哪一个函数。
  4. 生成调用请求:如果需要调用,LLM 会生成一个结构化的函数调用请求(通常是 JSON),包含函数名和根据用户输入填充的参数。
  5. 执行函数:开发者后端的代码接收到这个请求,解析 JSON,并真正执行对应的函数(如调用天气 API)。
  6. 返回结果:将函数执行的结果(如 {“temperature”: 25, “weather”: “sunny”})返回给 LLM。
  7. 生成最终回复:LLM 结合函数返回的结果,生成面向用户的自然语言回复。

2.2 关键组件

  • Function/Tool Definition:函数的元数据描述。
  • Tool Call:LLM 生成的调用指令。
  • Tool Call ID:用于关联调用和返回结果。
  • Tool Result:函数执行后返回的结果。

3. 主流平台实现对比

平台/框架 核心概念 特点 适用场景
OpenAI API tools / function_call 业界事实标准,定义清晰,支持并行调用。 直接使用 OpenAI 系列模型。
Anthropic Claude tools 与 OpenAI 设计高度相似,易于迁移。 使用 Claude 系列模型。
Google Gemini tools (Function Calling) 集成在 Vertex AI 和 Gemini API 中。 Google Cloud 生态。
LangChain Tools + Agents 高阶抽象,提供大量内置工具和多种代理执行策略。 快速构建复杂多步骤的AI应用。
LlamaIndex Tools + Query Engines 专注于数据检索和增强,工具常与数据源绑定。 构建RAG(检索增强生成)系统。
本地模型 (via Ollama, vLLM) 遵循 OpenAI 格式 通过兼容层支持,取决于模型本身能力。 私有化部署、成本敏感场景。

4. 实战示例:使用 OpenAI API 查询天气

以下是一个完整的 Python 示例,展示如何定义函数、处理模型调用并返回结果。

import openai
import json
from typing import List, Optional

# 1. 定义可用的函数(工具)
def get_current_weather(location: str, unit: str = "celsius") -> str:
    """获取指定城市的当前天气情况。"""
    # 这里是模拟数据,真实场景中应调用如 OpenWeatherMap 的 API
    weather_data = {
        "location": location,
        "temperature": 22,
        "unit": unit,
        "forecast": ["sunny", "windy"],
    }
    return json.dumps(weather_data)

# 可用工具列表
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "获取指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "城市名称,例如:北京,San Francisco",
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "温度单位",
                    }
                },
                "required": ["location"],
            },
        },
    }
]

# 2. 用户请求
user_query = "波士顿的天气怎么样?"

# 3. 调用模型,传入工具定义
client = openai.OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": user_query}],
    tools=tools,
    tool_choice="auto",  # 让模型自动决定是否调用工具
)

response_message = response.choices[0].message

# 4. 检查模型是否决定调用工具
if response_message.tool_calls:
    # 5. 解析工具调用
    tool_call = response_message.tool_calls[0]  # 可能有多条
    function_name = tool_call.function.name
    function_args = json.loads(tool_call.function.arguments)

    print(f"模型决定调用函数: {function_name}")
    print(f"函数参数: {function_args}")

    # 6. 执行对应的函数
    available_functions = {
        "get_current_weather": get_current_weather,
    }
    function_to_call = available_functions[function_name]
    function_response = function_to_call(**function_args)

    print(f"函数返回结果: {function_response}")

    # 7. 将结果返回给模型,让其生成最终回复
    second_response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "user", "content": user_query},
            response_message,  # 包含工具调用的消息
            {
                "role": "tool",
                "content": function_response,
                "tool_call_id": tool_call.id,  # 必须匹配调用ID
            },
        ],
    )

    # 8. 输出最终答案
    final_answer = second_response.choices[0].message.content
    print(f"\n助手最终回复: {final_answer}")
else:
    # 模型没有调用工具,直接回复
    print(f"助手回复: {response_message.content}")

5. 高级技巧与最佳实践

5.1 编写高质量的函数描述

  • 描述清晰description 字段要准确说明函数用途,这是模型判断是否调用的关键。
  • 参数明确:为每个参数提供清晰的 descriptiontype。使用 enum 限制可选值。
  • 必要参数:正确设置 required 字段。

5.2 处理并行工具调用

最新模型(如 GPT-4o)支持在单次响应中生成多个 tool_calls。后端需要遍历并执行所有调用,然后一次性将所有结果返回给模型。

5.3 错误处理与降级

  • 函数执行失败:在 tool 角色的消息中返回错误信息,让模型向用户解释。
  • 模型“幻觉”参数:在调用真实函数前,验证参数的有效性(如城市名是否存在)。
  • 设置超时与重试:对于依赖外部API的函数。

5.4 与 RAG 结合

Function Calling 常用于 RAG 流程中的最后一步。例如:

  1. 用户问:“公司去年Q4的财报摘要是什么?”
  2. RAG 系统先从向量数据库检索出相关财报文档。
  3. 将文档作为上下文,并定义 generate_summary 函数。
  4. LLM 调用该函数,生成基于检索内容的摘要。

6. 常见问题与陷阱

  • Q:模型总是不调用我定义的函数?

    • A:检查函数描述是否与用户问题匹配。尝试让用户提问更明确,或设置 tool_choice={"type": "function", "function": {"name": "your_function"}} 来强制调用。
  • Q:模型生成的参数格式错误?

    • A:确保参数 schema 定义正确(符合 JSON Schema)。对于复杂嵌套对象,提供示例(examples 字段,如果API支持)。
  • Q:如何控制成本?

    • A:Function Calling 会增加输入 tokens(因为要传递工具定义)。仅在必要时定义工具,并保持描述简洁。
  • Q:本地模型支持好吗?

    • A:取决于模型。许多微调过的开源模型(如 Qwen2.5、DeepSeek)支持 OpenAI 兼容的 Function Calling 格式。需查阅具体模型文档。

7. 总结与展望

Function Calling 是构建实用 AI 应用的基石。它将 LLM 的通用语言理解能力与确定性的程序逻辑相结合,实现了“思考”与“行动”的统一。

未来趋势

  1. 更复杂的规划能力:模型能自主规划多步骤的工具调用序列。
  2. 工具学习:模型能够根据少量示例自动学习使用新工具,而无需详细的模式定义。
  3. 端到端工具使用:可能出现更紧密的集成,让工具调用像语言生成一样自然。

掌握 Function Calling,意味着你能够将 LLM 无缝嵌入到现有的系统和业务流程中,解锁真正的智能化自动化潜力。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐