Files
2026-08-23 02:12:08 +08:00

26 KiB
Raw Permalink Blame History

DeepSeek API

来源:

文档采集于 2026-08-12。2026-08-13 用真实 API key 全量实测校验过一遍,实测与文档冲突处均以实测为准并标注 ⚠️。 实测环境 system_fingerprintflash = fp_a18b46594c_prod0820_fp8_kvcache_20260402pro = fp_v4pro_20260812_prod0820_fp8_kvcache_20260402

DeepSeek 的定位是 OpenAI 格式兼容,但有一批自有扩展和"看起来支持其实忽略"的参数。它同时提供三种入口格式(OpenAI / Anthropic / Responses),本身就是一个"中转站"的现成参考——而且是一个反面参考:实测发现它的三个入口在思考参数、图片处理、错误格式、tool_choice 上行为都不一致。

Base URL

  • https://api.deepseek.com — OpenAI Chat Completions 格式 + Responses API 格式
  • https://api.deepseek.com/beta — Beta 功能(prefix completion、FIM、strict tool calls
  • https://api.deepseek.com/anthropic — Anthropic Messages 格式

实测路径别名(文档未列):

  • Responses/responses/v1/responses 等价
  • Anthropic/anthropic/messages/anthropic/v1/messages 等价
  • Anthropic 入口鉴权:x-api-keyAuthorization: Bearer 都接受

额外端点(文档未列):GET /user/balance{"is_available":true,"balance_infos":[{"currency":"CNY","total_balance":"...","granted_balance":"...","topped_up_balance":"..."}]}。中转站可用它做上游健康检查与余额预警。


1. 模型与能力矩阵

GET /models 实测只返回两个模型:

模型 上下文 最大输出
deepseek-v4-flash 1,048,576 393,216
deepseek-v4-pro 1,048,576 393,216

实测精确值,来自越界报错:This model's maximum context length is 1048576 tokensthe valid range of max_tokens is [1, 393216]

⚠️ 模型名别名deepseek-chatdeepseek-reasoner(旧模型名)会被静默映射到 deepseek-v4-flash,响应的 model 字段返回 deepseek-v4-flash。其他未知名字(gpt-4deepseek-v3、空串等)会明确报错:The supported API model names are deepseek-v4-pro or deepseek-v4-flash, but you passed X.

中转站注意:用户传 deepseek-chat 拿到的是 v4-flash 且无任何提示,账单模型名与请求模型名对不上。

能力 v4-flash v4-pro
Tool Calls
JSON Output(仅 json_object
FIM Completion
Chat Prefix Completion
Thinking Mode ✓(默认开) ✓(默认开)
Responses API ⚠️
内置 web_search(仅 Responses 入口)
Anthropic API

⚠️ 文档称 Responses API "不支持 v4-pro,计划 2026-08 初支持"——实测已支持deepseek-v4-pro/v1/responses 正常返回。 ⚠️ 文档称 FIM "仅非思考模式"且"模型用 v4-pro"——实测 flash 和 pro 都支持 FIM,见 §7。

价格(每 1M token):

模型 缓存命中 缓存未命中 输出
v4-flash $0.0028 $0.14 $0.28
v4-pro $0.003625 $0.435 $0.87

官方页面明确预告将大幅涨价,价格不要硬编码。


2. Chat CompletionsPOST /chat/completions

必填:messagesmodel

参数 类型 默认 实测行为
thinking object {type:"enabled"} DeepSeek 自有扩展type: enabled/disabled/adaptive ⚠️reasoning_effort: low/high/max
reasoning_effort string ⚠️ 顶层 OpenAI 写法也生效(文档未列),"none" 可关闭思考
max_tokens int 范围 [1, 393216],越界 400
temperature number 1 范围 [0, 2],越界 400(非静默忽略)
top_p number 1 范围 (0, 1.0],越界 400
response_format object {type:"text"} text / json_objectjson_schema 报 400
stream bool false
stream_options object include_usage
stop string|array 最多 16 个,17 个报 Stop string array too long: 17
tools array type 只接受 functionweb_search 等报 400
tool_choice auto ⚠️ 思考模式下只支持 none/auto,见 §4
logprobs bool false ⚠️ 思考模式下返回结构不同,见下
top_logprobs int 0 ~ 20,需 logprobs=true
user_id string ≤512 字符,文档称字符集 [a-zA-Z0-9\-_]实测不校验(传 用户@1 也 200
n int 1 只支持 1n=2Invalid n value (currently only n = 1 is supported)

已废弃frequency_penaltypresence_penalty — 实测传了不报错,静默忽略。 静默忽略(传了不报错也不生效):seed、OpenAI 标准的 user(注意与 DeepSeek 自有的 user_id 不是同一个参数)。

硬报错的兼容性坑

  • role: "developer"OpenAI 新标准)→ 400 unknown variant 'developer'。中转站必须把 developer 降级成 system
  • content 数组中的 image_url → 400 unknown variant 'image_url', expected ...注意这与 Anthropic / Responses 入口的静默降级行为不一致,见 §8。
  • 纯文本的 content: [{"type":"text","text":"..."}] 数组形式 → 正常支持。

消息序列约束极宽松(实测均返回 200):连续两条 user、以 assistant 结尾(无 prefix)、system 出现在中间、只有 system 一条——全部接受。唯一报错的是空数组 messages: []Empty input messages

响应字段基本对齐 OpenAI,额外有:

  • message.reasoning_content — 思考内容(字符串)
  • usage.prompt_cache_hit_tokens / usage.prompt_cache_miss_tokens
  • usage.prompt_tokens_details.cached_tokens(与 prompt_cache_hit_tokens 同值,两套字段并存)
  • usage.completion_tokens_details.reasoning_tokens⚠️ 仅思考模式存在;非思考模式下整个 completion_tokens_details 对象都不出现
  • finish_reason 多一个取值:insufficient_system_resource
  • ⚠️ 非流式响应的 tool_calls[]也带 index 字段OpenAI 非流式不带)

⚠️ logprobs 在思考模式下结构不同

非思考模式:logprobs.content[](同 OpenAI)。 思考模式:返回的是 logprobs.reasoning_content[] ——这个 key 在 OpenAI 规范里不存在(OpenAI 只有 contentrefusal)。严格按 OpenAI schema 反序列化的客户端会拿到空的 logprobs 或直接解析失败。


3. Thinking Mode 的怪癖

⚠️ 三个入口的参数写法互不相同——且与官方文档记载相反

文档给出的映射表(Anthropic 用 reasoning.effort、Responses 用 output_config.effort实测是错的。以"关闭思考"为探针跑的完整交叉矩阵(观察 reasoning_content/thinking block 是否出现、prompt_tokens 是 5 还是 84):

入口 写法 实测结果
OpenAI {"thinking":{"type":"disabled"}} 生效(prompt=5
OpenAI {"reasoning_effort":"none"} 生效(prompt=5)——文档未记载
OpenAI {"reasoning":{"effort":"none"}} 静默忽略(prompt=84,仍思考)
Anthropic {"thinking":{"type":"disabled"}} 生效(input=5
Anthropic {"reasoning":{"effort":"none"}} 静默忽略(input=84)——文档说这个才对,实测无效
Anthropic {"reasoning_effort":"none"} 静默忽略(input=84
Responses {"reasoning":{"effort":"none"}} 生效(reasoning_tokens=0
Responses {"output_config":{"effort":"none"}} 静默忽略——文档说这个才对,实测无效
Responses {"thinking":{"type":"disabled"}} 静默忽略

结论Chat 与 Anthropic 入口统一用 thinking.typeResponses 入口用 OpenAI 标准的 reasoning.effort。所有"不生效"的写法都是静默忽略、不报错——中转站若照文档实现关思考,会得到一个照常思考并照常计费的响应。

⚠️ thinking.type 有第三个取值 adaptive(文档完全未记载)

从 400 报错里泄露的枚举:unknown variant 'banana', expected one of 'adaptive', 'enabled', 'disabled'

实测 adaptive 会按问题难度调节思考量("hi" → 24 reasoning tokens"严格证明 √2 无理" → 262),但不会完全关闭思考,简单问题仍产出 reasoning_content

⚠️ 思考模式会注入约 79 token 的隐藏 system prompt,并计入你的账单

同一条 "hi" 请求:

prompt_tokens
thinking.type = disabled 5
thinking.type = enabled(默认) 84

这 79 token 的差额是 DeepSeek 服务端注入的思考指令,按输入价计费,且三个入口都一样Anthropic 入口 input_tokens 同为 84)。默认开启意味着中转站转发的每一条短请求都在为它买单。

reasoning_effort 的实际效果存疑

reasoning_effort非法值不报错"banana" 照常返回 200),只有 thinking.type 是强类型枚举。none/minimal/xhigh/medium 等文档外取值也一律静默接受。

在 flash 上对同一道题各档采样 5 次的 reasoning_tokens

effort 样本 均值
low 116, 80, 118, 68, 118 100.0
high 48, 71, 120, 73, 90 80.4
max 101, 56, 111, 89, 79 87.2

方差远大于档位间差异,flash 上看不出 effort 有可观测效果。 v4-pro 上采样(low ≈ 513、high ≈ 799)倾向于正相关,但样本量不足以定论。文档所称"flash 直通、pro 上 high 与 xhigh 都映射为 high"未能证实也未能证伪——不要基于这个假设做路由决策。

例外:Responses 入口的 reasoning.effort: "none" 是唯一能观测到确定效果的取值(reasoning_tokens 精确为 0)。

⚠️ reasoning_content 多轮回传是硬性要求(不回传直接 400)

文档表述为"必须回传",实测是服务端强校验

{"error":{"message":"The `reasoning_content` in the thinking mode must be passed back to the API.",
 "type":"invalid_request_error","code":"invalid_request_error"}}

精确的触发条件(实测逐一验证):

场景 不回传 reasoning_content
思考模式 + 历史含 tool_calls 400 报错
思考模式 + 无 tool_calls 的普通多轮 正常,不报错
非思考模式 + 历史含 tool_calls 正常,不报错

传空串 "reasoning_content": "" 可以过校验——这是中转站从 Anthropic/OpenAI 格式转过来、丢失了原始思考内容时的可用降级手段(模型质量可能下降,但不会 400)。

这和 Anthropic 的规则(thinking block 必须原样、带 signature 回传)以及 OpenAI 的规则(encrypted_content / reasoning item)都不同,中转站需要按上游分别处理。

流式响应的两处非 OpenAI 行为

  1. usage 挂在最后一个正常 chunk 上,而不是像 OpenAI 那样单独发一个 choices: [] 的 usage-only chunk。DeepSeek 把 usage 塞进了带 finish_reason 的那个 chunk 里,之后直接 data: [DONE]。按 OpenAI 语义等待独立 usage chunk 的实现会永远拿不到 usage。
  2. delta 中未使用的字段是显式 null 而非省略{"delta":{"content":null,"reasoning_content":"We"}} / {"delta":{"content":"4","reasoning_content":null}}。对 null 与"字段缺失"处理不同的客户端需注意。

思考内容通过 delta.reasoning_content 增量下发,先出完 reasoning_content 再出 content


4. Tool Calls 的怪癖

  • 结构与 OpenAI 一致:tools[].{type:"function", function:{name, description, parameters}},回传用 role: "tool" + tool_call_idtools[].type 只接受 function
  • 思考模式下 tool_choice 只支持 autonone⚠️ 文档未记载):
tool_choice thinking enabled thinking disabled
"auto"
"none"
"required" 400
{"type":"function","function":{"name":...}} 400

报错信息:Thinking mode does not support this tool_choice。由于思考模式是默认开启的,中转站转发一个带 tool_choice: "required" 的普通 OpenAI 请求会直接 400——必须同时下发 thinking.type: "disabled",或把 required 降级为 auto

  • strict 是 Beta 功能,文档称必须切到 https://api.deepseek.com/beta。实测在主 base_url 上传 strict: true 不报错(静默接受并正常返回),无法从响应上区分是否生效——属于典型的静默失效。
  • strict 模式支持的 schema 类型:object、string、number、integer、boolean、array、enum、anyOf、$ref$def。实测传入 patternminLength 等不支持的关键字也不报错(静默接受,约束不保证生效)。
  • 思考模式下的工具调用从 DeepSeek-V3.2 起支持,实测思考 + 工具调用可同时返回 reasoning_contenttool_callsfinish_reason: "tool_calls"

5. JSON Output 的怪癖

  • 只有 response_format: {"type": "json_object"}json_schema 明确报错:This response_format type is unavailable now(措辞暗示未来会支持,但目前中转站必须拦截或降级)。
  • 必须在 system 或 user prompt 中出现 "json" 字样,否则硬报错: Prompt must contain the word 'json' in some form to use 'response_format' of type 'json_object'. 中转站从其他上游格式转发时,如果用户 prompt 里没有 "json" 字样,会拿到一个用户完全无法理解的 400。
  • 官方承认 API 偶尔会返回空 content,建议通过调整 prompt 措辞规避。中转站需要有重试策略。
  • max_tokens 给小了会截断成非法 JSON。
  • 与思考模式可共存,reasoning_content 与 JSON content 同时返回。

6. Context Caching 的怪癖

  • 全自动,无 cache_control 之类的手动参数。 与 Anthropic 的显式断点模型完全不同——不能双向映射。

  • ⚠️ 实测缓存粒度为 64 token(文档称"未说明最小可缓存粒度")。两组独立实测的 prompt_cache_hit_tokens 均为 64 的整数倍:3328 = 52×64、1920 = 30×64。命中量向下对齐到 64 的倍数,尾部不足 64 的部分计为 miss。

  • ⚠️ 缓存即时生效(文档称"缓存构建需要数秒")。实测第 1 次请求 miss 全量,紧接着的第 2 次请求立即命中,无需等待:

    请求 prompt_tokens hit miss
    第 1 次 3379 0 3379
    第 2 次 3379 3328 51
    第 3 次 3379 3328 51
  • 公共前缀缓存已验证:两个只有尾部一个词不同的请求(2006 / 2007 token)交替发送,双方都稳定命中共同前缀的 1920 token。

  • 缓存不再使用后自动清除,通常在数小时到数天内。

  • 统计字段:prompt_cache_hit_tokens / prompt_cache_miss_tokens,以及 prompt_tokens_details.cached_tokens(同值)。Anthropic 入口映射为 cache_read_input_tokenscache_creation_input_tokens 实测恒为 0DeepSeek 没有"写入缓存"这个计费概念,官方 Anthropic 的缓存写入溢价在此不存在)。


7. Beta 功能(需 base_url=https://api.deepseek.com/beta

Chat Prefix Completion

messages 最后一条设 {"role": "assistant", "content": "...", "prefix": true},模型从该前缀继续生成。

  • ⚠️ 在主 base_url 上传 prefix明确报错(不是静默忽略): prefix is only available when using beta api (set base_url="https://api.deepseek.com/beta")
  • 最后一条 message 的 role 必须是 assistant
  • 常与 stop 配合,例如前缀 ```python\n + stop=["```"] 强制只出代码。
  • 中转站注意:这个能力无法映射到 Claude 4.6+(明确禁止 prefill),也不是 OpenAI 标准能力。

FIM Completion

端点是 /beta/completions(不是 chat),参数 prompt + suffix。在主 base_url 上调用明确报错:completions api is only available when using beta api (...)

⚠️ 文档的三条限制实测全部不成立

文档说法 实测
max_tokens 上限 4K 上限 3932164096/8192/65536/393216 全部 200393217 才报错)
模型用 deepseek-v4-pro flash 和 pro 都可用
仅非思考模式支持 thinking 参数不报错、正常返回(该参数在此端点无意义)

其他实测:支持 legacy completions 的 echologprobsint 型),但两者互斥——同时传报 echo should not be used with logprobs。响应是 object: "text_completion"choices[].text没有 completion_tokens_details


8. 官方兼容层(DeepSeek 自己做的中转)

Anthropic 格式(https://api.deepseek.com/anthropic

模型名自动映射(实测确认):

  • claude-opus*deepseek-v4-pro
  • claude-haiku* / claude-sonnet*deepseek-v4-flash
  • 直接传 deepseek-v4-pro / deepseek-v4-flash 也接受
  • ⚠️ 其他未知名字(如 gpt-4实测是报错,不是静默兜底The supported API model names are deepseek-v4-pro or deepseek-v4-flash, but you passed gpt-4.(此处修正了文档"静默兜底到 flash"的说法)

支持:modelmax_tokenssystemtemperature[0, 2],比官方 Anthropic 的 0~1 宽,2.5 报 400)、streamstop_sequencestoolsthinkingbudget_tokens 被忽略)。

流式格式规范,事件序列为 message_startcontent_block_startpingcontent_block_delta(×N) → content_block_stop → …… → message_deltamessage_stop,含 thinking_delta / signature_delta / text_delta 三种 delta 类型。

⚠️ 实测发现的四个兼容性缺陷

  1. 错误响应用的是 OpenAI/DeepSeek 格式,不是 Anthropic 格式。 实际返回 {"error":{"message":"...","type":"authentication_error","param":null,"code":"invalid_request_error"}} 而 Anthropic SDK 期望 {"type":"error","error":{"type":"authentication_error","message":"..."}}。 顶层缺 "type":"error"、多出 param/code 字段——官方 Anthropic SDK 的错误反序列化会失败或降级成通用异常。

  2. max_tokens 不是必填。 官方 Anthropic API 中 max_tokens 必填,此处省略不报错,静默用默认值。依赖该校验的客户端会行为不一致。

  3. thinking block 的 signature 是伪造的——它就是本次响应的 id

    {"id":      "a7f8579c-ef83-49fb-b93c-bda7d513c07b",
     "content": [{"type": "thinking", "thinking": "...",
                  "signature": "a7f8579c-ef83-49fb-b93c-bda7d513c07b"}]}
    

    不是真正的加密签名,不具备任何校验意义,也不能与真实 Anthropic 上游互换。

  4. tool_choice 行为与 OpenAI 入口不一致。

    tool_choice Anthropic 入口 对应的 OpenAI 入口写法
    {"type":"auto"} "auto"
    {"type":"any"} ⚠️ 静默降级为 auto(实测明确要求"不要用工具"时模型确实不调工具,stop_reason: "end_turn" "required" 思考模式下 400
    {"type":"tool","name":"..."} 400 Thinking mode does not support this tool_choice 同样 400

    同一个语义(强制调用工具),一个入口静默失效、另一个入口硬报错。

忽略 / 不支持:anthropic-betaanthropic-version header、top_k、大部分 metadata 字段(例外:metadata.user_id 支持,用于限流隔离)。

⚠️ image content 不是"不支持",而是静默替换成占位文本(文档表述为不支持,实测是降级)。传入 {"type":"image","source":{...}} 不报错,模型的思考内容里暴露了它实际收到的是 [Unsupported Image] 占位符,然后回答"我看不到图片"。用户拿到的是一个 HTTP 200 的错误答案。

Responses 格式(https://api.deepseek.com/v1/responses

  • ⚠️ v4-flash 和 v4-pro 都已支持(文档称仅 flash)。
  • 未支持的参数一律静默忽略,不报错,且响应里会把它们回显成默认值而非你传入的值——这是判断是否生效的可靠手段: store: true → 回显 falseprevious_response_id: "resp_123" → 回显 nullconversation 不支持。
  • 思考参数用 reasoning.effort(见 §3),effort: "none" 可确定关闭思考。响应中 reasoning 字段会回显你传入的 effort。
  • 上下文缓存自动进行,无手动参数(prompt_cache_keynull)。
  • ⚠️ image 和 file 输入被替换成字面占位文本 [Unsupported Image](而不是报错)——这个行为对中转站尤其危险,用户会得到一个"成功但内容错误"的响应。与 Anthropic 入口行为一致,但与 OpenAI 入口(硬报错)不一致。
  • usage 结构是 Responses 风格:input_tokens / input_tokens_details.cached_tokens / output_tokens / output_tokens_details.reasoning_tokens / total_tokens
  • 输出为 output[] 数组,思考是 {"type":"reasoning","content":[{"type":"reasoning_text","text":"..."}],"summary":[]},正文是 {"type":"message","phase":"final_answer",...}⚠️ phase 是非 OpenAI 标准字段)。
  • 流式事件完整:response.created / response.in_progress / response.output_item.added / response.content_part.added / response.reasoning_text.delta / response.reasoning_text.done / response.output_text.delta / response.output_text.done / response.content_part.done / response.output_item.done / response.completed

⚠️ 内置 web_search 工具(文档完全未记载,且只有这一个入口有)

"tools":[{"type":"web_search"}] 实测真的会执行联网搜索,输出数组中出现:

{"type":"web_search_call","id":"call_00_...","status":"completed",
 "action":{"type":"search","queries":["capital of France","ws_call_id=call_00_..."]}}

回显的工具定义为 {"type":"web_search","search_context_size":null,"user_location":null}。搜索结果注入会显著抬高 input_tokens(实测同一问题从 84 涨到 2403)。

跨入口对比:

入口 web_search
Responses 真实执行
OpenAI Chat 400 unknown variant 'web_search', expected 'function'
Anthropicweb_search_20250305 ⚠️ 静默接受但不执行,模型直接凭知识作答

9. 错误码

Code 含义 处理
400 请求体格式非法 按错误信息调整
401 API key 错误 实测消息体:Authentication Fails, Your api key: ****-bad is invalidtype: "authentication_error"
402 余额不足 OpenAI/Anthropic 无此码,兼容层需决定映射到 429 还是 403
422 参数非法
429 限流
500 服务端故障 重试
503 服务器过载 稍后重试

错误响应体统一为 OpenAI 风格 {"error":{"message","type","param","code"}}——包括 Anthropic 入口(见 §8 缺陷 1)。

type 实测取值:invalid_request_error400/422)、authentication_error401)。注意 401 的 code 字段仍是 invalid_request_error,与 type 不一致,不要用 code 判断错误类别。

限流:实测 30 并发短请求全部 200,未触发 429,具体阈值未知。文档未说明限流时是否有 keep-alive 空行等连接层行为。

反序列化错误(Rust serde 风格)会泄露内部枚举,可用于探测未文档化的取值——adaptive 思考模式就是这么发现的:

Failed to deserialize the JSON body into the target type: thinking.type: unknown variant `banana`,
expected one of `adaptive`, `enabled`, `disabled` at line 1 column 100

10. 中转站实现要点速查

按危险程度排序的实测结论:

# 陷阱 后果
1 思考默认开启且注入 ~79 token 隐藏 prompt 每条请求静默多计 79 输入 token
2 关思考的参数名三个入口各不相同,文档还写错了两个 照文档实现 = 关不掉、照常计费
3 tool_choice: required + 默认思考模式 = 400 标准 OpenAI 请求直接失败
4 思考模式下 reasoning_content 不回传 = 400(仅工具场景) 跨格式转发丢思考内容即中断;空串可降级过关
5 image 在 Anthropic/Responses 入口被换成 [Unsupported Image] HTTP 200 + 错误答案,最难排查
6 Anthropic 入口错误体不是 Anthropic 格式 官方 SDK 错误解析失败
7 Anthropic 入口 tool_choice: any 静默降级为 auto 强制工具调用失效且无提示
8 deepseek-chat/deepseek-reasoner 静默映射到 v4-flash 账单模型名与请求不符
9 流式 usage 在最后一个正常 chunk,非独立 chunk 按 OpenAI 语义等待 = 永远拿不到 usage
10 思考模式 logprobs 返回 logprobs.reasoning_content 非 OpenAI schema,解析失败
11 json_object 要求 prompt 含 "json" 字面量 跨格式转发时用户看不懂的 400
12 role: "developer" 硬报错 必须降级为 system
13 strict / seed / user / 非法 reasoning_effort 静默接受 用户以为生效了