30秒快速回答: Function Calling 是大模型的一项核心能力——它能在对话中识别「什么时候该调用外部工具」,然后生成符合工具要求的参数。模型本身不执行函数,它只是「发号施令」——告诉系统「请调用这个函数,参数是这些」。你(开发者)负责执行函数并把结果返回给模型,模型再基于结果生成最终回答。


Function Calling 的工作流程

用户: 「北京今天天气怎么样?」
         ↓
    ┌─────────────┐
    │  大模型判断  │  「我需要调用 get_weather 函数」
    │  (决策层)   │  「参数: city='Beijing'」
    └──────┬──────┘
           ↓  返回 function_call 请求
    ┌─────────────┐
    │  你的代码    │  执行 get_weather("Beijing")
    │  (执行层)   │  → 结果: {"temp": 25, "condition": "晴"}
    └──────┬──────┘
           ↓  将结果返回给模型
    ┌─────────────┐
    │  大模型回答  │  「北京今天晴,气温 25°C。」
    └─────────────┘

关键理解: 模型不执行任何代码。它只是”请求”你执行,你执行完后把结果告诉它,它再生成人类可读的回答。


代码实战:OpenAI Function Calling

from openai import OpenAI
import json

client = OpenAI()

# 1. 定义工具(函数声明)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的实时天气信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,如 Beijing, Shanghai"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "温度单位"
                    }
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "发送邮件",
            "parameters": {
                "type": "object",
                "properties": {
                    "to": {"type": "string", "description": "收件人邮箱"},
                    "subject": {"type": "string", "description": "邮件主题"},
                    "body": {"type": "string", "description": "邮件正文"}
                },
                "required": ["to", "subject", "body"]
            }
        }
    }
]

# 2. 模拟天气查询函数
def get_weather(city: str, unit: str = "celsius") -> dict:
    # 实际项目中调天气 API
    weather_data = {
        "beijing": {"temp": 25, "condition": "", "humidity": 45},
        "shanghai": {"temp": 28, "condition": "多云", "humidity": 70}
    }
    return weather_data.get(city.lower(), {"temp": 20, "condition": "未知"})

# 3. 对话循环
messages = [{"role": "user", "content": "北京今天热吗?帮我查一下天气"}]

while True:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto"  # 模型自动判断是否调用工具
    )

    msg = response.choices[0].message

    # 如果模型不需要调工具,直接输出答案
    if not msg.tool_calls:
        print("AI:", msg.content)
        break

    # 如果模型要调工具,执行工具调用
    messages.append(msg)
    for tool_call in msg.tool_calls:
        func_name = tool_call.function.name
        func_args = json.loads(tool_call.function.arguments)

        print(f"[调用工具] {func_name}({func_args})")

        # 执行函数
        if func_name == "get_weather":
            result = get_weather(**func_args)
        elif func_name == "send_email":
            result = {"status": "sent", "message": f"邮件已发送至 {func_args['to']}"}
        else:
            result = {"error": f"未知工具: {func_name}"}

        # 将工具结果返回给模型
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result, ensure_ascii=False)
        })

输出:

[调用工具] get_weather({'city': 'Beijing'})
AI: 北京今天晴,气温 25°C,湿度 45%。不热,天气很舒适。

DeepSeek Function Calling(兼容 OpenAI 格式)

from openai import OpenAI

client = OpenAI(
    api_key="你的key",
    base_url="https://api.deepseek.com"
)

# 完全兼容 OpenAI 的 tools 参数格式
response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "user", "content": "搜索2026年AI最新趋势"}
    ],
    tools=[{
        "type": "function",
        "function": {
            "name": "web_search",
            "description": "搜索互联网信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "搜索关键词"}
                },
                "required": ["query"]
            }
        }
    }]
)

Function Calling 的进阶技巧

1. 并行调用

模型可以在一次响应中请求调用多个独立函数:

# 用户: "比较北京和上海的天气"
# 模型一次返回两个 tool_calls:
#   tool_call 1: get_weather(city="Beijing")
#   tool_call 2: get_weather(city="Shanghai")

2. 强制调用

设置 tool_choice 确保模型一定调用某个函数:

# 强制调用特定函数
tool_choice = {"type": "function", "function": {"name": "get_weather"}}

# 或强制必须调用(任意一个已注册的函数)
tool_choice = "required"

3. 结构化输出

利用 Function Calling 强制模型输出结构化 JSON:

tools = [{
    "type": "function",
    "function": {
        "name": "extract_person_info",
        "description": "从文本中提取人物信息",
        "parameters": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "age": {"type": "integer"},
                "occupation": {"type": "string"},
                "skills": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["name", "age", "occupation"]
        }
    }
}]

# 模型会强制按这个 JSON Schema 输出

Function Calling vs MCP vs Agent

维度 Function Calling MCP Agent
定位 模型内部的工具调用机制 外部工具的发现和连接协议 自主规划+执行的任务系统
谁负责调度 你的代码 MCP 客户端 Agent 自身
复杂度 低(手写调用逻辑) 中(统一接口) 高(自主决策)
适用场景 1-3 个工具的简单调用 多工具标准化接入 复杂多步骤任务

关系: Agent 通常使用 Function Calling 作为底层机制来调用工具,而 MCP 协议可以为这些工具提供统一的发现和接入标准。三者是不同层次的互补关系。


常见问题

Q: Function Calling 需要额外付费吗?

不需要。Function Calling 是模型的内置能力,按正常的 Token 计费。但工具定义(tools 参数)和调用结果都会消耗 Token。

Q: 模型不调用我注册的函数怎么办?

确保函数命名清晰、description 描述准确。模型基于函数名和描述决定是否调用。如果描述是”获取天气”但用户问”外卖”,模型就不会触发。

Q: 函数调用失败了怎么处理?

在你的代码中捕获异常,将错误信息作为 tool result 返回给模型,模型会尝试用其他方式回答或告知用户无法完成。

Q: 支持多少个工具同时注册?

GPT-4o 支持最多 128 个工具。但工具越多,模型选择越容易出错。建议按需注册——当前对话可能用到的工具不超过 5-10 个。


下一步建议: 把本文的代码复制到 Colab 或本地运行,放一个真实的 REST API(如和风天气 API)替代 mock 数据,体验让 AI 真正调用外部世界的感觉。