如何使用 DeepSeek V4 Pro API 的 Function Calling

本文详解如何使用 DeepSeek V4 Pro 的 Function Calling 构建 Agent。通过 Python SDK 实操,并结合前缀缓存实现百倍降本,教你打造高效的 AI 智能体。

用 Apifox,节省研发团队的每一分钟

如何使用 DeepSeek V4 Pro API 的 Function Calling

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录

DeepSeek 于 2026 年 8 月 12 日将 V4 Pro 移出了预览版,其发布报道主打 Agent 工作流:代码编写、工具使用以及能够链接数十个步骤且不丢失主线的长周期任务。这种定位使得一个 API 功能比其他任何功能都更重要,那就是 Function Calling(函数调用),而这恰恰是发布周各种指南未曾涉及的功能。目前为止,所有的教程都止步于 Chat Completions(对话补全)。

本文将更进一步:定义工具数据模型(schema),使用标准 Python openai SDK 发起你的第一次工具调用,构建完整的 Agent 循环,并在你的 Agent 发布前在 Apifox 中对整套流程进行测试。如果你还没有 DeepSeek API Key,请先根据我们关于如何使用 DeepSeek V4 API 的指南进行设置,然后再回来阅读本文。

AI Coding 交流群

如果你也在用 AI 写代码,或者正在研究 Cursor、Claude Code 这些工具,欢迎加入以下交流群。群里平时会聊一些 AI 编程的实际用法、开发工作流,还有各种新工具和新玩法。

TL;DR

  • deepseek-v4-pro(GA 版本 DeepSeek-V4-Pro-0813)支持 OpenAI 风格的 Function Calling:发送 tools 数组,接收 tool_calls,并以 tool 消息形式返回结果。标准的 openai SDK 可以直接配合 https://api.deepseek.com 使用。
  • 完整的 Agent 循环只需约 30 行 Python 代码:调用、执行、追加、重复,直到模型停止请求工具。支持并行调用和结构化输出;思考模式会添加 reasoning_content
  • 自动前缀缓存(Automatic prefix caching)将缓存命中的输入价格降低至每百万 Token 0.003625 美元,比未命中便宜 120 倍。这正是让深度 Agent 循环具有性价比的关键。
  • 工具调用的质量取决于你的测试框架和数据模型(schemas)。请在真实模型上测试你实际的工具,而不是只看基准测试。

为什么工具调用是 V4 Pro 的核心使用场景

DeepSeek 专为 Agent 构建了 V4 Pro,其规格表就像是一份 Agent 运行时的清单:

规格 DeepSeek V4 Pro
架构 稀疏 MoE:1.6T 总参数,每个 Token 激活 49B
上下文窗口 1M Token
最大输出 384K Token
输入价格 每百万 Token 0.435 美元(缓存未命中),每百万 Token 0.003625 美元(缓存命中)
输出价格 每百万 Token 0.87 美元
Function calling 兼容 OpenAI 的 tools 数组和 tool_calls 响应
其他接口形式 Anthropic Messages 格式,DeepSeek Responses API

每一项规格都对应着一个 Agent 的痛点问题:1M Token 的窗口可以承载长周期 Agent 的完整工具结果历史记录,384K 的输出上限为大型结构化有效负载(payload)留出了空间,而前缀缓存则让循环调用在经济上变得可行。该模型已在 OpenRouter 上以 deepseek-v4-pro-0813 的名称列出,方便与其他供应商进行对比。

在看代码之前,有一点需要注意。在 Hacker News 的发布讨论中,开发者反馈工具调用性能对测试框架高度敏感:同一个模型在不同的框架、Prompt 脚手架和数据模型(schema)风格下的表现得分大相径庭。基准测试无法告诉你它将如何处理你的工具数据模型(schemas)。请使用你真实的定义进行测试。

DeepSeek function calling 工作原理

Function calling 并不意味着模型会执行任何代码。它会返回一个结构化的请求,例如“使用 {"order_id": "ORD-10442"} 调用 get_order”,而不是一段自然语言。您的代码负责运行该函数并返回结果,随后模型将使用真实数据继续运行。该循环如下:

  1. 您发送 messages 以及一个使用 JSON Schema 描述每个函数的 tools 数组。
  2. 模型判定需要使用工具,并响应 tool_callsfinish_reason: "tool_calls"
  3. 您的代码解析参数并运行实际的函数。
  4. 您将结果作为与该调用 ID 关联的 role: "tool" 消息进行追加。
  5. 模型要么请求另一个工具,要么生成最终的回答。

如果您曾经使用过 OpenAI 的 function calling,两者的传输格式是完全相同的;大多数 Agent 代码只需更改前置 URL 和模型名称即可完成迁移。官方 DeepSeek 文档也介绍了一个兼容 Anthropic 的 Messages 接口和一个 Responses API,但本指南仅专注于兼容 OpenAI 的接口表层。

步骤 1:设置客户端

安装 SDK 并将其指向 DeepSeek:

pip install openai
export DEEPSEEK_API_KEY="sk-..."
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

这就是全部的设置。每个示例都使用 model="deepseek-v4-pro",它将解析为正式发布(GA)的版本 DeepSeek-V4-Pro-0813。

步骤 2:定义工具数据模型

我们将为一家在线商店构建一个支持 Agent。它的第一个工具用来查询订单。一个工具定义包含三个部分:名称(name)、描述(description)以及用于 parameter 的 JSON Schema。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order",
            "description": (
                "Look up a customer order by its ID. Returns the order status, "
                "carrier, tracking number, and estimated delivery date. Use this "
                "whenever the user asks where an order is or what state it's in."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "The order ID, formatted like 'ORD-10442'.",
                    }
                },
                "required": ["order_id"],
            },
        },
    }
]

这里的描述绝非装饰物:模型是通过阅读描述来决定何时调用该工具的。模糊的描述是导致模型忽略工具或选错工具的首要原因。

该数据模型所描述的本地函数(此处使用桩代码代替真实的订单服务):

def get_order(order_id: str) -> dict:
    """Stub for your real order service."""
    fake_db = {
        "ORD-10442": {
            "status": "shipped",
            "carrier": "DHL",
            "tracking_number": "4281337005",
            "estimated_delivery": "2026-08-15",
        },
        "ORD-10587": {
            "status": "processing",
            "estimated_ship_date": "2026-08-14",
        },
    }
    return fake_db.get(order_id, {"error": f"Unknown order ID: {order_id}"})
 

步骤 3:进行你的首次工具调用

发送一个模型在没有该工具的情况下无法回答的问题:

messages = [
    {"role": "system", "content": "You are a support agent for an online store."},
    {"role": "user", "content": "Where is my order ORD-10442?"},
]

response = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
)

message = response.choices[0].message
print(message.tool_calls[0].function.name) # get_order
print(message.tool_calls[0].function.arguments) # {"order_id": "ORD-10442"}

模型并没有直接回答,而是要求你运行 get_order。原始的响应 Payload 如下所示:

{
  "id": "chatcmpl-8f3a1c",
  "object": "chat.completion",
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "id": "call_0_f1c29a44",
            "type": "function",
            "function": {
              "name": "get_order",
              "arguments": "{\"order_id\": \"ORD-10442\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 312,
    "completion_tokens": 24,
    "total_tokens": 336,
    "prompt_cache_hit_tokens": 0,
    "prompt_cache_miss_tokens": 312
  }
}

这里有三个关键细节。首先,finish_reason"tool_calls",这会告知你的循环,模型需要执行工具。其次,每次调用都携带一个 id,你在返回结果时必须将其传回。最后,arguments 是一个需要你自行解析的 JSON 字符串,因此要做好它偶尔会出现格式错误的准备。

步骤 4:执行函数并返回结果

运行该函数,然后追加两条消息:包含 tool_calls 的 assistant 轮次消息,以及一条携带你的结果的 tool 消息。

import json

tool_call = message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = get_order(args)

messages.append(message) # the assistant turn containing tool_calls
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id, # must match the id from the response
    "content": json.dumps(result),
})

final = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)
# Your order ORD-10442 shipped with DHL and is estimated to arrive
# by August 15, 2026. Tracking number: 4281337005.

tool_call_id 的关联非常严格:在下一次模型轮次之前,每个 tool_calls 条目都必须有一个匹配的 tool 消息,否则请求将会失败。

步骤 5:完整的 agent 循环

真实的 agent 会进行链式调用:查询订单、检查退款政策、草拟电子邮件,每一个步骤都依赖于上一步。其模式为:持续调用模型并执行它所请求的任何操作,直到它返回一个正常的回答。

TOOLS_BY_NAME = {"get_order": get_order}

def run_agent(client, messages, tools, max_rounds=10):
    """Run the model until it produces a final answer or hits the cap."""
    for _ in range(max_rounds):
        response = client.chat.completions.create(
            model="deepseek-v4-pro",
            messages=messages,
            tools=tools,
        )
        message = response.choices[0].message
        messages.append(message)

        if not message.tool_calls: # no tool requests: we're done
            return message.content

        for tool_call in message.tool_calls:
            fn = TOOLS_BY_NAME.get(tool_call.function.name)
            try:
                if fn is None:
                    raise ValueError(f"Unknown tool: {tool_call.function.name}")
                args = json.loads(tool_call.function.arguments)
                result = fn(args)
            except Exception as exc:
                result = {"error": str(exc)} # feed failures back to the model
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result),
            })

    raise RuntimeError(f"Agent did not finish within {max_rounds} rounds")

各类框架和 agent SDK 都是在这个循环的基础上进行拓展的。max_rounds 上限可以将卡在重复调用失败 tool 的模型转化为一次明确的失败,而不是产生一笔无上限的账单。

并行 tool 调用

请求进行两次查询,例如“比较 ORD-10442 和 ORD-10587 的状态”,V4 Pro 通常会将这两者打包进同一个轮次中:

"tool_calls": [
  {
    "id": "call_0_a7d1",
    "type": "function",
    "function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10442\"}" }
  },
  {
    "id": "call_1_b3e9",
    "type": "function",
    "function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10587\"}" }
  }
]

run_agent 循环已经处理了这种情况:内部的 for 循环会为每个调用使用其专属的 tool_call_id 进行响应(在下一轮次之前,每个调用都需要一个匹配的结果),并且你可以自由地并发执行这一批处理。这与 GPT-5.6 的程序化 tool 调用理念不同,在 GPT-5.6 中,模型会在沙箱中编写编排代码;而 DeepSeek 则将执行和信任边界保留在你的运行环境中。

思考模式与 tools

V4 Pro 配备了三种思考模式,因此您可以在需要复杂规划的轮次中增加推理算力,在常规查询中则可选择跳过(有关模式名称和默认设置,请参阅官方文档)。启用思考模式后,API 将以 reasoning_content 的形式返回模型的推理逻辑,并与工具调用并列返回:

response = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
    extra_body={"thinking": {"type": "enabled"}},
)

message = response.choices[0].message
print(message.reasoning_content) # the planning trace
print(message.tool_calls) # the calls it settled on

该推理逻辑展示了模型选择某个工具的原因,而这通常也是糟糕的数据模型暴露问题的地方。在将 assistant 轮次追加到请求历史之前,请先剥离 reasoning_content,并将思考功能保留给需要大量规划的轮次,因为推理部分会按照输出计费,价格为 $0.87/M。

错误处理:当模型调用出错时

格式错误的工具调用很少见,但 Agent 循环会放大每一种失败模式。其核心模式是:永远不要因为错误的调用而崩溃,而是将问题作为工具执行结果返回,并让模型重试。这既适用于无法通过 json.loads 解析的参数,也适用于违反业务规则的值:

from jsonschema import ValidationError, validate

schema = tools[0]["function"]["parameters"]

try:
    args = json.loads(tool_call.function.arguments)
    validate(instance=args, schema=schema)
    result = get_order(**args)
except (json.JSONDecodeError, ValidationError) as exc:
    result = {
        "error": f"Invalid arguments: {exc}",
        "hint": "Call get_order again with an order_id string like 'ORD-10442'.",
    }

hint 字段非常重要:一行提示性的纠正通常就能让模型在下一轮尝试中修复调用。同时,也要将 Agent 错误视为安全事件。被诱导使用攻击者提供的参数调用 delete_order 的模型,其危险程度取决于其背后的密钥,这正是为 AI Agent 采用最小权限 API 密钥的原因。合理限制凭据的作用域,从而避免错误的调用演变成安全事故。

在发布前使用 Apifox 测试和调试工具调用

每个工具都是对 API 的一层薄封装,而模型现在是该 API 的使用者。如果底层的接口含糊不清或不稳定,模型也会继承这些缺陷。这也正是 Apifox 在此流程中体现其价值的地方:

  1. 先设计后端 API。在 Apifox 的可视化设计器中定义 GET /orders/{order_id} 作为接口规范;工具的 JSON Schema 会直接从规范中生成,因此两者不会出现未察觉的偏差。
  2. 在服务端实现前先进行 mock。Apifox 的智能 mock 会根据数据模型提供真实的响应,因此在真实服务构建期间,Agent 循环可以针对 get_order 接口进行运行。
  3. 检查原始 Payload。使用 Apifox 向 https://api.deepseek.com 发送相同的 messages + tools body,并直接读取原始的 tool_calls JSON。这样,嵌套错误的 properties 或重复编码的参数在一次检查中即可显现。
  4. 将对话转化为测试场景。对 finish_reason 和参数结构进行断言,并在每次数据模型变更时运行测试套件;鉴于 Hacker News 上提到的测试框架敏感性,针对真实数据模型构建的回归测试套件是预测生产环境表现的基准。有关更深层的模式,请参阅《将 AI Agent 接入 Apifox 测试框架》。

下载 Apifox 免费尝试,mock 服务和测试场景均包含在免费版中。

Agent 循环的成本(以及为什么缓存至关重要)

Agent 循环在每一轮都会重新读取整个对话:到第十轮时,系统提示词 (system prompt)、工具数据模型以及前九轮的结果会被计费第十次。V4 Pro 的自动前缀缓存 (prefix caching) 打破了这一成本曲线,每一轮的输入都是上一轮输入加上一点新增内容,因此几乎整个前缀都以 $0.003625/M 的价格计费,而非 $0.435/M。重新读取 100K token 的对话,未缓存时成本约为 $0.0435,而缓存后仅约 $0.0004;usage 模块中的 prompt_cache_hit_tokens 可以显示您的实际命中率。

为了保持高命中率,切勿修改早期的消息,并确保 tools 数组在各轮次间保持字节级稳定。我们关于“什么是提示词缓存”的入门指南涵盖了其运作机制。如果 $0.14/$0.28 的 deepseek-v4-flash 看起来很诱人:它适用于单次工具路由,但在进行 10 次以上调用的循环时表现会下降,导致重试消耗掉节省下来的费用,因此对于 Agent 而言,Pro 版本是更稳妥的默认选择。

常见问题

工具定义会消耗 token 吗?

是的,tools 数组在每次请求时都会作为输入。保持其稳定,它在第一轮之后就会加入缓存前缀,此后按缓存命中率计费。

我可以将函数调用与结构化输出结合使用吗?

可以。一种常见的模式是:工具负责获取中间数据,结构化输出的数据模型负责格式化最终答案,从而确保下游代码无需解析自然语言文本。

总结

在 DeepSeek V4 Pro 上实现 Function calling(函数调用)被刻意设计得平淡无奇:兼容 OpenAI 的数据模型、一个 tool_calls 数组,以及一个带有 ID 的 tool 消息。步骤 5 中的循环就是整个架构的全部,而缓存命中计费使得成本比大多数团队预期的还要低。基准测试无法告诉你的是该模型在面对 你的 数据模型时会如何表现,因此需要深思熟虑地设计后端 API、尽早进行 mock,并在 Apifox 中保留工具调用测试场景的回归测试集,从而避免数据模型的变更在无形中破坏你的 Agent。

开发必备:API 全流程管理神器 Apifox

介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、调试、设计、测试、Mock、自动化测试于一体的工具,Apifox 是目前提升研发效率的首选。

如果你正在开发项目,不妨试试其极其友好的界面设计,它完全兼容 Postman 和 Swagger 数据格式,导入数据非常方便,,即使是新手也能很快上手,点击这里即可注册使用

Apifox

值得一提的是,除了个人和常规团队使用,针对有高安全合规要求、或需要在内网环境协作的企业,Apifox 还提供了深度定制的私有化部署方案

获取专属报价与部署方案

icon 详细的私有化部署系统架构与安全白皮书
icon 针对您公司规模的专属报价单
icon 免费的 1v1 专属产品演示 (Demo) 机会
获取部署方案
* 提交后,我们的客户经理将在 1 个工作日内与您联系
林俊锋 企业微信
@Apifox 专属顾问
扫码备注: 私有化 + 公司名