1. 使用场景

Function Calling(函数调用)允许模型根据用户需求调用外部工具或 API,核心价值包括:
  • 扩展数值计算能力:解决模型原生计算不精准的问题。
  • 获取实时外部信息:通过调用搜索、天气、数据库等接口获取即时数据。
  • 环境交互与控制:自动化操控智能设备、发送邮件或执行代码。

2. 使用方式

2.1 通过 REST API 添加 tools 参数

在发送请求时,通过 tools 字段定义可用的函数列表:
{
  "model": "DeepSeek-V3.2",
  "messages": [
    { "role": "user", "content": "帮我计算 123.45 乘以 67.89" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "calculate_mul",
        "description": "计算两个数字的乘积",
        "parameters": {
          "type": "object",
          "properties": {
            "a": { "type": "number", "description": "乘数 a" },
            "b": { "type": "number", "description": "乘数 b" }
          },
          "required": ["a", "b"]
        }
      }
    }
  ]
}

2.2 通过 OpenAI 库请求

推荐使用 OpenAI SDK 进行集成,调用方式如下:
response = client.chat.completions.create(
    model="DeepSeek-V3.2",
    messages=messages,
    tools=[
        {
            "type": "function",
            "function": {
                "name": "get_stock_price",
                "description": "获取指定股票代码的实时价格",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "symbol": { "type": "string" }
                    },
                    "required": ["symbol"]
                }
            }
        }
    ]
)

3. 支持模型列表

您可以访问 模型广场,查看模型是否支持工具调用。

4. 使用示例 (Python)

以下展示一个完整的闭环调用示例:
from openai import OpenAI
import json

client = OpenAI(
    api_key="Your-api_key", 
    base_url="https://api.nonelinear.com/v1"
)

# 1. 定义工具函数
def calculate_add(a, b):
    return a + b

tools = [
    {
        "type": "function",
        "function": {
            "name": "calculate_add",
            "description": "计算两个数字之和",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"}
                },
                "required": ["a", "b"]
            }
        }
    }
]

# 2. 发起首次请求
messages = [{"role": "user", "content": "123.45 加上 67.89 等于多少?"}]
response = client.chat.completions.create(
    model="DeepSeek-V3.2-Think",
    messages=messages,
    tools=tools
)

# 3. 处理工具调用
tool_call = response.choices[0].message.tool_calls[0]
if tool_call:
    function_name = tool_call.function.name
    function_args = json.loads(tool_call.function.arguments)
    
    # 执行本地函数
    function_response = calculate_add(**function_args)
    
    # 将结果反馈给模型
    messages.append(response.choices[0].message)
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": str(function_response)
    })
    
    # 再次请求获取自然语言回答
    final_response = client.chat.completions.create(
        model="DeepSeek-V3.2-Think",
        messages=messages
    )
    print(final_response.choices[0].message.content)

5. 特殊模型注意事项

不同模型厂商在工具调用上存在一些差异化要求。本节说明需要额外处理的情况,建议在接入对应模型前仔细阅读。

5.1 Gemini 3 系列:多轮工具调用必须回传 thought_signature

5.1.1 背景

Gemini 3 系列模型(如 gemini-3.1-pro-previewgemini-3-flash-preview 等)引入了 Thought Signature 机制:模型在返回 tool_call 时,会附带一段加密的思考轨迹,用于在后续轮次中保持推理上下文的连续性。 在多轮工具调用中,客户端必须将这段 signature 原样回传给模型,否则会收到类似如下的 400 错误:
Error code: 400 - Function call is missing a thought_signature in functionCall parts. 
This is required for tools to work correctly...

5.1.2 关键规则

场景规则
单个工具调用tool_call 会带有 thought_signature,下一轮必须原样回传
串行多步调用(多轮 tool_call)每一步tool_call 都带 signature,历史中的每一个都必须保留回传
并行工具调用(一次返回多个 tool_call)只有第一个 tool_call 带 signature,其他不带;回传 message 顺序必须为 assistant(FC1+sig, FC2) → tool(FR1) → tool(FR2)不能交错

5.1.3 signature 在 OpenAI 兼容格式中的位置

通过 OpenAI SDK 调用时,thought_signature 位于每个 tool_callextra_content.google.thought_signature 字段:
{
  "id": "function-call-xxx",
  "type": "function",
  "function": {
    "name": "get_weather",
    "arguments": "{\"city\":\"北京\"}"
  },
  "extra_content": {
    "google": {
      "thought_signature": "EvQBCvEBAQw51seEezqzHHepPSYOlXMl..."
    }
  }
}
注意:OpenAI SDK 的 pydantic 模型对 extra_content 这类非标准字段的序列化行为在不同版本间可能不一致。推荐从 response.model_dump() 的原始 dict 里提取该字段,而不是依赖 message.tool_calls 的结构化对象属性访问。

5.1.4 完整示例代码

以下是一个跑通 Gemini 3 多轮工具调用的完整示例,重点关注 build_assistant_message_from_raw 辅助函数——它是保证 signature 不丢失的关键。
from openai import OpenAI
import json
import copy
 
client = OpenAI(
    api_key="Your-api_key",
    base_url="https://api.nonelinear.com/v1"
)
 
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"}
                },
                "required": ["city"]
            }
        }
    }
]
 
 
def execute_tool(name, args):
    """模拟工具执行"""
    args = json.loads(args) if isinstance(args, str) else args
    if name == "get_weather":
        return json.dumps(
            {"city": args["city"], "temp": "28°C", "condition": "晴"},
            ensure_ascii=False
        )
    return json.dumps({"error": "unknown tool"})
 
 
def build_assistant_message_from_raw(raw_response):
    """
    从原始响应 dict 构造 assistant message,保留 extra_content 中的 thought_signature。
    这是 Gemini 3 多轮工具调用的关键步骤。
    """
    raw_msg = raw_response["choices"][0]["message"]
 
    assistant_msg = {
        "role": raw_msg.get("role", "assistant"),
        "content": raw_msg.get("content"),
    }
 
    if raw_msg.get("tool_calls"):
        assistant_msg["tool_calls"] = []
        for tc in raw_msg["tool_calls"]:
            new_tc = {
                "id": tc["id"],
                "type": tc["type"],
                "function": {
                    "name": tc["function"]["name"],
                    "arguments": tc["function"]["arguments"],
                },
            }
            # 关键:保留 extra_content(包含 google.thought_signature)
            if "extra_content" in tc:
                new_tc["extra_content"] = copy.deepcopy(tc["extra_content"])
            assistant_msg["tool_calls"].append(new_tc)
 
    return assistant_msg
 
 
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
 
MAX_ROUNDS = 5
for round_num in range(1, MAX_ROUNDS + 1):
    response = client.chat.completions.create(
        model="gemini-3.1-pro-preview",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
 
    raw = response.model_dump()
 
    # 使用辅助函数构造回传的 assistant message
    assistant_msg = build_assistant_message_from_raw(raw)
    messages.append(assistant_msg)
 
    raw_tool_calls = raw["choices"][0]["message"].get("tool_calls")
    if raw_tool_calls:
        for tc in raw_tool_calls:
            result = execute_tool(tc["function"]["name"], tc["function"]["arguments"])
            messages.append({
                "role": "tool",
                "tool_call_id": tc["id"],
                "content": result
            })
    else:
        print(f"最终回复: {response.choices[0].message.content}")
        break

相关链接