AI 智能体

DeepSeek Agent 函数调用:Schema、循环与安全边界

DeepSeek 函数调用(Function Calling)手把手实战:tool 模式定义、strict 严格模式、并行工具调用、思考模式与 MCP,以及生产环境的校验与修复模式——全部附可运行的 Python 示例。

Judy3 分钟阅读
DeepSeek Agent 函数调用:Schema、循环与安全边界

信息核对截至 2026 年 10 月 13 日。 示例说明官方工具调用模式;模型别名、beta 端点和功能限制应以 DeepSeek 实时 API 文档为准。

TL;DR

  • DeepSeek 函数调用让 Agent 能通过 OpenAI 兼容的 tools 数组请求结构化动作——查数据库、读文件或调 API。真正校验并执行请求的是你的应用,不是模型。

  • 线上格式是标准的:用 JSON Schema 定义工具、随消息一起发送、查看 message.tool_calls、在本地执行、把结果以 role: "tool" 消息追加回去,再调一次 API。参数可靠性至关重要时,严格模式(经 /beta 端点开启 "strict": true)会强制输出贴合 schema。

  • 思考模式与工具调用可以配合使用。MCP 不是模型原生能力:客户端或框架发现 MCP 工具,再把可调用 schema 提供给模型。

  • 生产级 Agent 需要一层修复机制:校验 JSON 参数、返回模型能自我纠正的结构化错误、限制并行执行。如果你还没搭过 Agent 循环,先读 如何构建 DeepSeek Agent;本文专门深入工具调用这一层。

1. 在 DeepSeek Agent 里,「函数调用」是什么

函数调用——也叫工具调用——是把 Agent 和聊天机器人区分开来的机制。聊天机器人收到提示词,返回文本。Agent 收到提示词外加一份可用工具清单,自己判断有没有工具能帮忙,返回一个结构化请求去调用其中一款或多款工具,等你的代码执行完这些调用,再带着结果继续推理。

在 DeepSeek V4 上,函数调用是 deepseek-v4-pro 与 deepseek-flash 的原生能力。API 采用 OpenAI 兼容格式:在 chat completion 请求里放一个 tools 数组,工具调用经由 message.tool_calls 返回,结果以 role: "tool" 消息配合对应的 tool_call_id 回传,详见 DeepSeek 的工具调用文档。

本文假设你已理解基本 Agent 循环——发消息、查工具调用、执行、回传、重复。如果这套模式对你陌生,先读 如何构建 DeepSeek Agent。我们这里聚焦工具调用层内部发生的事:schema 设计、并行执行、严格模式、与思考模式的交互,以及那些防止 Agent 循环在畸形参数上崩溃的生产级模式。

「函数调用」和「Agent」的区别对搜索意图和架构都重要。函数调用是 API 的一个能力;Agent 是一个系统,把这一能力包进带错误处理、状态管理与工具权限的循环里。大多数 DeepSeek Agent 在生产中的故障都追溯到工具调用层——无效 JSON、参数类型错误、并行调用和共享状态竞态——而不是模型的推理质量。

2. 设计模型真正会遵循的工具 Schema

工具定义的质量,决定模型调用它的可靠性。V4 模型在结构化输出上比 V3 强一大截,但含糊的 schema 依然会产出含糊的工具调用。

每个工具都是一个 JSON 对象:type: "function",外加一个包含 name、description 与 parameters(JSON Schema)的 function 块。description 不是给人类看的文档——它是给模型的指令。写它时,想象你在告诉一个初级开发者:什么时候用、怎么用这个函数。

tools = [
    {
        "type": "function",
        "function": {
            "name": "search_codebase",
            "description": (
                "Search the project codebase for files matching a query. "
                "Use this when the user asks about code location, function definitions, "
                "or file structure. Do NOT use for running tests or modifying files."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search term — function name, file path fragment, or keyword",
                    },
                    "file_type": {
                        "type": "string",
                        "enum": ["py", "js", "ts", "all"],
                        "description": "Limit search to specific file extensions",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "run_tests",
            "description": (
                "Execute the project's test suite or a specific test file. "
                "Use after code changes to verify correctness. "
                "Returns pass/fail counts and failure messages."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "test_path": {
                        "type": "string",
                        "description": "Optional path to a specific test file or directory",
                    },
                },
                "required": [],
            },
        },
    },
]

在 V4 上提升调用可靠性的三条设计原则:

**把边界写清楚。**上面 search_codebase 的 description 明确告诉模型什么时候别用这个工具("Do NOT use for running tests")。否定式约束能减少多工具 Agent 里的选错工具问题。

**受限选择用枚举。**当一个参数只有一组固定合法值时,把它们声明成 "enum",而不是自由文本。模型会从列表里挑,而不是在你期望 "py" 时自己发明一个 "python"。

**required 字段保持最少。**只有当工具真的缺了某参数就跑不了时,才把它标成 "required"。过度约束必填字段,会在模型省略可选上下文时增加 JSON 解析失败的概率。

对参数正确性至关重要的 Agent——计费系统、数据库写入、部署触发——请在函数定义里设 "strict": true、并调用 https://api.deepseek.com/beta 这个 /beta 端点来开启严格模式,详见 DeepSeek 的函数调用文档。严格模式约束模型产出的参数必须完全符合你的 JSON Schema,减少下游校验的需要,代价是首次工具调用延迟略高。

3. 工具调用循环:超越基础

如何构建 DeepSeek Agent 里的最小循环,每轮只处理一个工具调用。生产级 Agent 还需要三个额外控制:tool_choice、并行调用处理、会话状态保全。

tool_choice **控制模型是否必须调用工具。**默认的 "auto" 让模型自己决定。当每一轮都必须产出工具调用时设 "required"(少见——通常用于被强制的管线步骤)。在所有工具执行完毕后的最终综合轮设 "none",这样你想要纯文本答案时,模型不会再去调更多工具。

# Force a final text answer after tools complete
final_response = client.chat.completions.create(
    model="deepseek-flash",
    messages=messages,
    tools=tools,
    tool_choice="none",
)

并行工具调用指模型在一轮的 message.tool_calls 中返回多个条目。不要围绕未经实时确认的最大值设计系统:执行器应主动限制并发,并同时考虑 API 限流与下游服务容量。模型可以提出多个独立调用,但是否适合并行执行由应用决定。

处理并行调用:遍历 tool_calls 里所有条目、各自独立执行、把每个结果作为一条独立的 role: "tool" 消息追加。只要每条结果带着正确的 tool_call_id,顺序对模型无关紧要。

for tc in assistant_msg.tool_calls:
    args = json.loads(tc.function.arguments)
    result = TOOL_REGISTRY[tc.function.name](**args)
    messages.append({
        "role": "tool",
        "tool_call_id": tc.id,
        "content": json.dumps(result),
    })

状态保全是最常见的生产 bug。追加那条含工具调用的 assistant 消息时,必须把完整的 tool_calls 数组连同 id、type、function.name / function.arguments 按原样带回来。省略或改动任何一个字段,都会破坏工具结果与产生它们的调用之间的关联,模型会搞不清哪个结果属于哪个动作。

如果你在 LangChain 或 LangGraph 之上开发,这些细节都被抽象掉了——直到某天抽象失效。到那时,理解原始消息形状,才是你调试卡死 Agent 循环的本钱。

4. 并行工具调用:什么时候用、怎么用

子任务相互独立时,并行工具调用最出彩。一个编码 Agent 要重构三个互不相干的模块,可以一轮读完三个文件。一个要从多个来源收集数据的研究 Agent,可以同时去查。省下的成本来自延迟——一次 API 往返,而不是三次串行——不是来自 token 单价,因为每个工具结果照样计入上下文。

当工具对共享状态有副作用时,这套模式就崩了。如果 write_file 和 read_file 操作同一条路径,并行执行会制造一个你的 Agent 循环控制不了的竞态条件。对有状态工具,要么把执行串行化(一次处理一个工具调用),要么把工具设计成带显式锁语义。

多 Agent 扇出是框架设计,不是“原生 DeepSeek Agent”类别的证据。第三方客户端被集成仓库收录,也不代表它属于 DeepSeek 模型运行时。若采用扇出,应独立评估权限、结果合并、失败处理与总成本。

对多数自定义 Agent:先用串行执行把循环跑稳,再对独立性有保证的只读工具(search、fetch、query)开并行。只有在有了幂等性保证或显式冲突解决之后,才升级到并行写入。

5. 思考模式与工具调用一起用

V4 模型支持思考模式(思维链推理)与工具调用并存——这个组合在早几代模型上不可靠。两个一起开:

response = client.chat.completions.create(
    model="deepseek-flash",
    messages=messages,
    tools=tools,
    tool_choice="auto",
    extra_body={
        "thinking": {"type": "enabled"},
        "reasoning_effort": "high",
    },
)

协议返回 reasoning_content 时,应按 DeepSeek 当前文档处理。它可以帮助调试消息格式与回放,但不是模型决策原因的可靠解释,也不能作为审计证据。审计应记录可观察的工具请求、校验、批准、结果与动作。

成本含义:思考 token 按输出 token 计费。一次简单工具调用前的高强度推理,可能多花 300–800 token 的推理开销。对几十轮的 Agent 循环,思考模式要挑着用——用在任务开头的规划轮、以及模型整合多个工具结果的综合轮,而不是每个工具执行轮都开。

编码 Agent 里一套很管用的分工:第一轮用 deepseek-v4-pro 配 reasoning_effort: "high"(规划改哪些文件);中间的工具执行轮用关掉思考的 deepseek-flash;最后一轮复核用 deepseek-v4-pro 配 reasoning_effort: "max"。一次 Agent 运行里三种模型配置,各按那一步的经济性来选。

6. MCP:把工具面扩到内联定义之外

Model Context Protocol(MCP)让客户端或框架连接外部工具服务器。DeepSeek 模型提供函数/工具调用,但不会自己运行 MCP 客户端。框架负责发现 MCP 工具、转换成模型可见定义、执行获准调用并回传结果。

内联函数定义(本文 tools 数组那套)适合工具集固定、已知的 Agent——代码库里定义五到十五个函数那种。当工具面是动态的(插件、用户配置的集成),或工具由不同团队各自维护时(数据库团队跑 MCP 服务端,Agent 团队消费它),MCP 就变得必要。

集成模式:你的 Agent 循环不变。模型返回工具调用后,不再调用本地 Python 函数,而是把调用转发给 MCP 服务器,由它执行动作、返回结果。消息历史的格式不变——变的只是 TOOL_REGISTRY 背后的执行层。

工具少而稳定时,内联定义是更简单的起点。工具需要独立迭代、标准化发现或隔离凭据时,再考虑 MCP。它是架构选择,不应由一个固定工具数量决定;DeepSeek Agent 品类总览解释了不同框架如何影响选择。无论哪种设计,都应核对客户端公开说明的工具与权限,不能从 DeepSeek 模型支持反推出客户端能力。

7. 生产模式:校验、修复与失败形态

演示 Agent 与生产 Agent 的差别,几乎全在工具调用的错误处理上。V4 模型在拿到结构化反馈时自我纠正能力很好,但面对被静默吞掉的错误,它们无法恢复。

**先校验,再执行。**把 tool_call.function.arguments 解析成 JSON。检查函数名是否在你的注册表里。确认必填参数都在、类型都对。把错误以模型能读的 JSON 字符串返回:

def execute_with_repair(tool_call, registry):
    try:
        args = json.loads(tool_call.function.arguments)
    except json.JSONDecodeError as e:
        return json.dumps({"error": "invalid_json", "detail": str(e)})

    fn = registry.get(tool_call.function.name)
    if fn is None:
        return json.dumps({
            "error": "unknown_tool",
            "requested": tool_call.function.name,
            "available": list(registry.keys()),
        })

    try:
        return json.dumps({"result": fn(**args)})
    except TypeError as e:
        return json.dumps({
            "error": "invalid_arguments",
            "detail": str(e),
            "schema": get_schema(tool_call.function.name),
        })

**给循环设界。**设 max_turns,并跟踪连续失败的工具调用次数。如果模型用相同参数连续三次调同一个工具,直接报错退出,别无限烧 token。

**记工具调用日志。**生产环境里,把每次工具调用的参数、结果和延迟都记下来。当 Agent 产出错误结果,日志轨迹——而不是最终答案——能告诉你:模型是选错了工具、传错了参数,还是你的执行层喂给了它误导性的数据。

**处理上下文膨胀。**每个工具结果都会加 token。对会读大文件、或返回分页查询结果的 Agent,在把工具输出追加进上下文前先截断或摘要。第 3 轮读一个 5 万 token 的文件,到第 10 轮就会霸占整个上下文预算。

结论

函数调用是每个 DeepSeek Agent 的连接组织。模型的推理质量重要,但决定这段推理能否变成正确动作的,是工具调用层。schema 设计、并行执行、思考模式取舍、以及本文讲的修复模式——这些才是区分「演示里能跑」与「生产流量下活得下来」的 Agent 的东西。

从两三个定义良好的工具加一个串行循环起步。当参数错误成为你最头的失败模式时,加严格模式。当瓶颈是延迟、而不是正确性时,加并行调用。当工具面撑破内联定义时,加 MCP。

完整的 Agent 架构——API 配置、模型选择、以及本文所扩展的那个循环骨架——如何构建 DeepSeek Agent 每一步都带可运行代码走了一遍。

https://floatboat.ai/zh/blog/deepseek-agent-function-calling

常见问题

什么是 DeepSeek 函数调用?
它是模型请求应用执行结构化工具的机制。
模型会自己执行工具吗?
不会,应用代码负责校验、授权、执行与回传。
新示例用什么模型名?
使用 deepseek-flash 等当前官方名称,并核对实时目录。
strict 模式做什么?
它可在受支持处提高 schema 符合度,但仍需业务校验。
能并行调用吗?
模型可返回多个调用,但执行器必须限制安全并发。
工具错误怎么回传?
用有边界的结构化结果,让循环停止、重试或请求审核。
什么时候用 MCP?
工具需要标准发现或隔离凭据时使用。MCP 由客户端或框架实现,模型仍然只是发出工具调用。
reasoning_content 能作为审计记录吗?
不能。它只是协议或调试字段,不是可靠的决策解释,也不能替代审批证据。