DeepSeek API 的账单不是简单的“调用次数乘单价”,而是由输入 Token、输出 Token 和缓存命中情况共同决定。很多团队按标价做预算,上线后却发现实际成本高出一截,原因通常不是单价变了,而是输入结构、缓存命中率和重试次数与估算时不一样。
本文把 DeepSeek API 的计费拆成可计算的部分:哪些 Token 在计费、缓存为什么有时生效有时不生效、如何用响应里的 usage 做估算,以及降本应该按什么顺序做。具体单价以站内模型价格和 DeepSeek 官方文档为准。
说明:DeepSeek 是其权利人的商标。本文以 2026 年 10 月的常见接口形态为例,价格、模型名与计费规则可能调整,采购前请再次核对官方页面。
一、先把账单拆成四个计费项
| 计费项 | 什么时候产生 | 主要影响因素 | 优化方向 |
|---|---|---|---|
| 输入(缓存未命中) | 新内容第一次进入上下文 | 文档长度、历史消息、工具定义 | 检索、摘要、裁剪 |
| 输入(缓存命中) | 请求复用了此前缓存的前缀 | 前缀稳定性、命中率 | 固定前缀、减少随机内容 |
| 输出 | 模型生成正文与结构化结果 | 输出长度、格式约束 | max_tokens、JSON 约束 |
| 推理内容 | 推理模型产生思考过程 | 问题难度、推理档位 | 简单任务不用推理模型 |
DeepSeek 的上下文缓存通常体现在输入侧:命中的前缀按更低的输入价格计费,未命中部分按标准输入价格计费。是否收取缓存存储费用、缓存保留多久,以官方文档当前说明为准,不要沿用旧文章里的规则。
单次请求可以写成一条成本公式:
单次成本 =
缓存命中输入 Tokens × 命中单价
+ 缓存未命中输入 Tokens × 输入单价
+ 输出 Tokens × 输出单价
把这条公式落到日志里,才能回答“这个功能一个月花多少”。只看控制台总账单,很难定位是哪个项目、哪类请求在放大成本。
二、缓存为什么能省钱,又为什么经常不生效
上下文缓存的基本逻辑是:如果两次请求的开头部分完全一致,服务端可以复用之前的计算结果,只对新增部分重新计算。因此,缓存对下面这些内容最有效:
- 固定的 system prompt 和角色设定。
- 稳定的工具定义、函数 schema。
- 反复使用的知识库片段、产品手册、合同模板。
- 多轮对话中不变化的前半段。
反过来说,以下写法会让缓存频繁失效:
- 在 system prompt 开头插入当前时间、随机 ID、用户昵称。
- 每次请求都重新排列工具或文档顺序。
- 把整份文档放在最前面,后面才是用户问题。
- 同一个业务在不同模型、不同入口之间来回切换。
- 前缀太短,还没达到可复用的粒度。
把变化的内容放到请求末尾,把稳定的内容放在开头,是最简单也最有效的做法。缓存通常是尽力而为,不承诺命中;所以预算要按“部分命中”估算,而不是假设全部命中。
三、用 usage 字段做一次真实估算
不要凭字数猜 Token。每次调用后把响应里的 usage 记下来,连续观察一周,就能得到自己业务的真实结构。
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url="https://api.deepseek.com",
)
resp = client.chat.completions.create(
model="deepseek-chat", # 模型名以站内价格页为准
messages=[
{"role": "system", "content": "你是客服助手,回答不超过三句话。"},
{"role": "user", "content": "订单发货后还能改地址吗?"},
],
max_tokens=256,
)
usage = resp.usage
hit = getattr(usage, "prompt_cache_hit_tokens", 0) or 0
miss = getattr(usage, "prompt_cache_miss_tokens", 0) or 0
print("输入", usage.prompt_tokens)
print("缓存命中", hit, "未命中", miss)
print("输出", usage.completion_tokens)
如果响应没有返回缓存细分字段,就记录总输入和总输出,再用账单或用量页面反推。关键是字段口径保持一致,不要把不同日期、不同入口的数据混在一起比较。
估算时至少记录:时间、项目、模型、输入 Token、输出 Token、缓存命中、重试次数、是否流式。金额等到月底再乘单价,过程指标每天都要看。
四、同样调用量,账单为什么差几倍
| 场景 | 典型 Token 结构 | 成本放大点 | 优化重点 |
|---|---|---|---|
| 客服机器人 | 输入多、输出短 | 历史消息反复传入 | 摘要、缓存、只带最近几轮 |
| 文档抽取 | 输入中等、输出结构化 | 同一份文档被反复读取 | 缓存前缀、批处理 |
| 代码助手 | 输入输出都大 | 工具结果和长文件 | 检索、分块、限制输出 |
| 长文生成 | 输入短、输出长 | 输出 Token 累积 | 分段生成、max_tokens |
| 推理任务 | 输入中等、输出含思考 | 思考过程计入输出 | 简单任务换非推理模型 |
差异通常来自五个地方:
- 输入输出比例不同:客服和长文写作的成本结构完全相反,不能用同一个平均值估算。
- 缓存命中率不同:固定前缀能复用,动态内容会让缓存失效。
- 上下文长度不同:每轮都把整份文档塞进去,输入成本会随轮数累积。
- 重试次数不同:429、超时后的重发会增加请求量,失败请求是否计费以账单为准。
- 模型档位不同:推理模型和非推理模型的单价、输出长度都不同,错配会放大预算。
五、降本的顺序不要反
- 先量化:用 usage 和日志算出每个功能的真实 Token 结构,不要凭感觉。
- 再提缓存命中:固定 system prompt、工具定义和知识前缀,减少开头的动态内容。
- 再减输入:RAG 只召回相关片段,历史消息做摘要,工具输出只保留必要字段。
- 限制输出:设置合理的
max_tokens,要求 JSON 或固定字段,减少重复解释。 - 做模型分流:分类、抽取、改写走轻量模型,复杂推理再升级。
- 异步与批处理:不要求实时返回的标注、摘要、离线分析放到队列里跑。
- 监控与告警:按项目、模型、场景三个维度看用量,设置预算上限。
顺序反了,通常的结局是:换了更便宜的模型,但输入没治理、缓存没命中,账单降不下来,质量还下降了。
六、预算和账单怎么管
- 一个项目一把 Key,测试和生产分开,避免互相挤占额度。
- 给 Key 设消费上限和告警,异常调用时能自动止损。
- 每周按“项目、模型、场景”对账,找出增长最快的调用。
- 缓存、模型分流带来的节省单独记录,否则无法证明优化有效。
- 需要人民币付款和发票的团队,可以用国内 AI 网关统一账单;具体价格、汇率和发票规则以模型价格为准。
常见问题
DeepSeek 的缓存需要手动开启吗?
通常不需要显式标记缓存段,服务端会按前缀自动判断是否复用;具体机制和保留时间以官方文档为准。你要做的是让前缀稳定,而不是增加更多配置。
缓存命中率为什么忽高忽低?
常见原因是前缀里混入了时间戳、随机 ID、用户信息,或者请求在不同模型、不同入口之间切换。先把变化内容移到末尾,再观察一周。
推理模型的思考内容会计费吗?
推理模型产生的思考 Token 通常计入输出,具体口径以官方文档和账单为准。简单分类、抽取任务不建议默认使用推理模型。
输入和输出哪个更贵?
多数模型的输出单价高于输入单价,但缓存命中后的输入价格通常更低。不要只比较两个单价,要按自己的输入输出比例算单次请求成本。
为什么估算和账单对不上?
常见漏算项包括历史消息、工具定义、重试请求、缓存未命中和长输出。用请求 ID 对照用量日志,才能定位差异。
下一步
先在中商起航 AI 网关创建测试 Key,用真实任务跑一周,记录输入、输出和缓存命中,再按模型价格折算预算。模型可用性与价格以价格页为准。
相关阅读:
