
当你负责的项目从“能调用大模型”走向“每天有几十万次调用”后最先盯上的往往不再是模型的回答质量而是账单里的 Token 用量。最近 DeepSeek API 价格调整的消息出来后不少开发群都在讨论一个问题靠低价换市场的阶段是不是要过去了接下来该怎么控制成本这篇文章不打算做价格预测也不站队争论。我更想把“涨价”这个信号拆成技术问题来看Token 到底是怎么计费的一次请求为什么有时特别贵怎么在模型价格变化后继续控制成本以及遇到 Token 鉴权、流式返回、用量统计等问题时怎么排查。文章内容偏向工程落地会包含 DeepSeek API 的调用示例、Token 用量统计方法、成本优化手段和常见异常排查清单。适合正在接大模型 API 的后端开发、算法工程师以及准备做模型成本治理的团队参考。1. 涨价信号背后先重新认识 Token很多开发者第一次听到 Token是在注册大模型平台时看到的一句话“本次对话消耗 1280 Token。”当时可能没在意直到账单出现问题才意识到Token 才是大模型计费的最小单位。1.1 Token 是什么Token 可以理解为模型处理文本的基本单位。它不是一个字也不是一个词而是模型分词器对文本切分后得到的片段。以中文为例单个汉字在不少模型中可能对应一个 Token但在更细的分词策略下一个词、一个常用短语又可能被合并成一个 Token。英文中一个单词通常会被拆成一到多个 Token比如“developer”可能被拆成“de”和“veloper”两部分。通俗地说模型看到文本时会先把文本切成它认识的“积木块”这些积木块就是 Token。无论是输入给模型的提示词还是模型生成的结果最终都要折算成 Token 数量参与计费。1.2 为什么 Token 决定成本大模型 API 的计费方式通常是单次调用成本 输入 Token 数 × 输入单价 输出 Token 数 × 输出单价其中输入 Token 包含你发送的全部消息也就是多轮对话中所有历史消息之和。输出 Token 则是模型回复内容的总长度。这就带来了两个容易被忽略的问题多轮对话时历史消息越长输入 Token 越多成本越高。如果模型开启了思考模式思考过程也可能被计入 Token 消耗。了解 Token 的计费规则后再看“涨价”这个话题真正受影响的不只是单价还有我们平时写 Prompt 和管理上下文时的习惯。1.3 “价格战结束”意味着什么前两年大模型 API 价格一路走低很多团队的习惯是“先跑起来再说”反正调用成本低优化不优化差别不大。现在价格开始分化开发者的心态也需要跟着调整从“能用就行”转向“评估成本后再用它”。从“上下文越长越好”转向“控制上下文、按需截断”。从“单一模型打天下”转向“不同场景用不同模型”。这不是坏事。价格回归理性后反而会逼着团队把工程细节做扎实缓存、蒸馏、模型路由、用量监控这些以前优先级不高的能力现在都值得落地。2. 从成本结构看模型 API 为什么会有价格差异不理解成本结构就很难理解价格调整背后的逻辑。我们在大规模调用模型接口时真正消耗掉的资源主要有三部分。2.1 推理算力成本模型每次生成一个 Token都需要做一次完整的前向计算。生成 100 个 Token等于做了 100 次推理计算。对话场景要求低延迟不能像离线任务那样慢慢算所以服务端必须预置足够的 GPU 算力应对高峰。这部分成本与 Token 总量直接相关输入和输出都有开销但输出端的开销通常更高因为输出必须逐 Token 串行生成无法完全并行。2.2 上下文缓存成本长上下文请求会占用更多显存和带宽。如果服务端把每一轮请求都从头完整计算一遍成本会非常高。现在主流平台都在做“前缀缓存”或“上下文缓存”也就是相同的历史上下文可以复用不用重复计算。这就解释了为什么很多平台会对带有缓存命中的请求提供更低价格。对开发者来说保持 Prompt 前缀稳定就能在成本上获得实际收益。2.3 思考模型的额外开销现在的模型越来越强调推理能力。推理模型在生成最终回答前会先输出一段“思路过程”这个过程中产生的 Token 同样需要消耗算力。如果你的请求是“思考型模型”并且在返回结果中保留了 reasoning_content那么费用计算时很可能要包含这部分思考 Token。具体是否需要付费、是否影响计费总量取决于平台规则但在做成本估算时不能忽略它。3. DeepSeek API 接入与 Token 用量统计实战在讨论成本优化之前先确保你拿到了正确的用量数据。接下来我给出一个完整的调用示例包含环境准备、基础调用、流式输出和 Token 统计。3.1 环境准备与版本说明本文示例使用 Python 环境核心依赖是 openai 库。DeepSeek API 兼容 OpenAI 协议所以可以用 OpenAI SDK 直接访问。pip install openai建议使用较新的 openai SDK 版本。不同版本中 usage 字段的结构基本一致但如果你使用的是旧版本字段名可能有差异需要按实际版本调整。操作系统不限Windows、macOS、Linux 都可以。API Key 请在 DeepSeek 开放平台创建然后通过环境变量注入代码不要硬编码在源码里。3.2 创建项目与配置环境变量mkdir deepseek-cost-demo cd deepseek-cost-demo在项目根目录创建.env文件DEEPSEEK_API_KEYsk-你的密钥 DEEPSEEK_BASE_URLhttps://api.deepseek.com然后在代码中通过python-dotenv加载环境变量pip install python-dotenv创建主文件demo.py。3.3 基础调用与非流式 Token 统计import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlos.getenv(DEEPSEEK_BASE_URL), ) def chat_once(user_content: str, model: str deepseek-chat): response client.chat.completions.create( modelmodel, messages[ {role: system, content: 你是一个技术文档写作助手回答尽量简洁。}, {role: user, content: user_content}, ], streamFalse, ) message response.choices[0].message usage response.usage print(回答内容, message.content) print(提示 Token 数, usage.prompt_tokens) print(输出 Token 数, usage.completion_tokens) print(总 Token 数, usage.total_tokens) print(------------------------------------) if __name__ __main__: chat_once(请用三句话介绍 Token 计费的基本规则。)运行python demo.py预期会看到类似下面的输出回答内容 Token 是模型处理文本的基本单位计费时分别统计输入和输出部分输入 Token 指你发送的所有消息输出 Token 指模型生成的内容最终费用是两者分别乘以单价再求和。 提示 Token 数 34 输出 Token 数 78 总 Token 数 112这个usage对象是最基础的成本数据来源。任何成本统计系统的第一步都是把每次请求返回的usage落库。3.4 流式输出时的 Token 统计生产环境为了更快的首字延迟通常会使用流式输出。但流式响应默认不直接返回 usage需要额外处理。def chat_stream(user_content: str, model: str deepseek-chat): response client.chat.completions.create( modelmodel, messages[ {role: system, content: 你是一个技术文档写作助手回答尽量简洁。}, {role: user, content: user_content}, ], streamTrue, stream_options{include_usage: True}, ) full_content [] for chunk in response: delta chunk.choices[0].delta if chunk.choices else None if delta and delta.content: full_content.append(delta.content) if chunk.usage: print(流式请求最终用量, chunk.usage) print(提示 Token, chunk.usage.prompt_tokens) print(输出 Token, chunk.usage.completion_tokens) print(总 Token, chunk.usage.total_tokens) print(完整回答, .join(full_content)) if __name__ __main__: chat_stream(请给出一个 Java 读取文件的最小示例。)需要注意stream_options{include_usage: True}这个参数。如果不加则流式过程中可能拿不到 usage 字段成本统计会缺失。如果你的 SDK 版本不支持stream_options可以考虑两种替代方案使用非流式请求做成本记录同时用流式请求给用户展示。在前端或网关层自己记录输入输出字符数再按字符与 Token 的换算比例估算。3.5 为成本统计设计数据模型当调用量达到一定规模后我会建议把用量数据写入数据库。一个简单的表结构如下CREATE TABLE llm_call_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, request_id VARCHAR(64) NOT NULL, model VARCHAR(64) NOT NULL, prompt_tokens INT NOT NULL, completion_tokens INT NOT NULL, total_tokens INT NOT NULL, prompt_characters INT, completion_characters INT, estimated_cost DECIMAL(10, 6), scene VARCHAR(64), created_at DATETIME NOT NULL, INDEX idx_created_at (created_at), INDEX idx_model (model), INDEX idx_scene (scene) );每次请求结束后从响应中提取 usage换算成本后写入。这样后续做成本趋势分析、按场景审计、按模型对比时才有数据支撑。4. 价格调整背景下的 Token 成本优化方案价格变化后单纯祈祷“下次别涨”没有意义。真正可控的是我们自己的调用方式和上下文管理策略。下面几个方向是成本优化中投入产出比最高的。4.1 控制上下文长度与多轮会话策略很多人忽略了一个事实对话越长Token 消耗增长得越快。如果每轮都把完整历史消息发送给模型那么第 20 轮对话的输入 Token 可能是第 1 轮的几十倍。常用优化手段包括只保留最近若干轮消息。对历史消息做摘要用摘要代替完整对话。设定上下文窗口上限超出后自动裁剪。与业务无关的中间字段、调试信息、超长 SQL不要塞进对话。示例按最大轮次裁剪消息。def trim_messages(messages, max_rounds6): # messages: [{role: user, content: ...}, {role: assistant, content: ...}] if len(messages) max_rounds * 2: return messages keep_count max_rounds * 2 system messages[0] if messages and messages[0][role] system else None body messages[1:] if system else messages trimmed body[-keep_count:] if system: return [system] trimmed return trimmed这个函数先把 system 消息保留然后只截取最后的若干轮对话避免上下文无限增长。4.2 缓存重复请求结果如果你的业务中存在大量“相同或相近”的请求缓存能显著降低 Token 消耗。常见做法是使用 Redis 缓存模型回复import hashlib import json import redis cache redis.Redis(hostlocalhost, port6379, decode_responsesTrue) def get_cache_key(messages, model): payload json.dumps({model: model, messages: messages}, ensure_asciiFalse) return hashlib.md5(payload.encode(utf-8)).hexdigest() def chat_with_cache(user_content: str, model: str deepseek-chat): messages [ {role: system, content: 你是一个技术文档写作助手。}, {role: user, content: user_content}, ] key get_cache_key(messages, model) cached cache.get(key) if cached: print(命中缓存) return cached response client.chat.completions.create(modelmodel, messagesmessages) answer response.choices[0].message.content cache.set(key, answer, ex3600) return answer需要注意不是所有场景都适合缓存。实时性要求高的对话、依赖当前状态的问答不应盲目加缓存。适合缓存的通常是知识库问答、固定格式文档生成、代码解释等重复率高的场景。4.3 按业务场景做模型分级不同业务的复杂度不同没必要所有请求都用最强模型。可以建立一套简单的模型路由规则简单文案生成 - deepseek-chat 代码解释与复杂问答 - deepseek-reasoner 批量文本分类 - 小模型或本地模型实际项目中还可以根据 Prompt 长度和关键词做规则路由。比如用户问题较短、不涉及多步推理时直接走轻量模型问题较长或包含“分析”“对比”“优化”等关键词时才走更强的模型。这样可以在整体效果几乎不变的前提下降低高端模型的调用占比。4.4 设置预算告警与配额成本治理不能只靠事后看账单。建议在项目初期就接入额度告警机制。DeepSeek 开放平台通常提供额度信息也可以在每次调用后把 cost 累加到监控系统中当单日成本超过阈值时触发告警。一个朴素的实现思路import time DAILY_COST_KEY daily_llm_cost def record_cost(cost: float): today time.strftime(%Y-%m-%d) key f{DAILY_COST_KEY}:{today} new_total cache.incrbyfloat(key, cost) cache.expire(key, 86400 * 2) if new_total BUDGET_THRESHOLD: send_alert(f今日 LLM 成本已达 {new_total:.4f} 元)有了这种机制即使线上出现异常的循环调用或 Prompt 注入也能尽早发现而不是等到月底收到账单才追悔莫及。5. 常见 Token 异常与排查清单热搜词里出现了很多 Token 相关的报错比如 token exchange failed、403 forbidden、登录失败、reasoning_content 报错等。下面挑选几个有代表性的场景展开。5.1 token exchange failed: token endpoint returned status 403这类报错通常出现在通过第三方登录或某个平台认证服务获取访问令牌时。错误提示本身比较含糊但 403 状态码意味着服务端拒绝了请求。可能原因请求来源不在服务端允许的区域或网络范围内。客户端凭据client_id / client_secret配置错误。账号权限不足未开通对应接口权限。请求头缺少必要的 Authorization 信息。排查顺序建议检查请求头确认 Authorization 中的 Token 正确。检查 client_id 和 client_secret 是否与平台配置一致。检查账号是否开通对应接口权限。检查发起请求的服务器 IP 是否在平台白名单内。查看平台返回的响应体中的 error_description通常会有更详细的提示。在网络环境受限或安全策略较严格的企业网络中这类问题经常出现在终端用户侧而不是服务端。业务方需要根据实际报错环境区分处理。5.2 思考模型推理上下文必须回传有开发者反馈在通过第三方工具接入 DeepSeek 时出现类似下面的报错upstream_status: http 400 cause: the reasoning_content in the thinking mode must be passed back to the api这个报错的核心是当模型处于思考模式时多轮对话中需要把上一轮的reasoning_content一并回传给模型否则模型无法正确衔接推理状态。解决办法是在本地保存消息时不要只保存content还需要保存reasoning_content并在下一轮请求中把完整的历史消息原样发送给服务端。# 存储上一轮完整返回 history_message { role: assistant, content: final_answer, reasoning_content: reasoning_text, } # 下一次请求时确保历史消息中包含 reasoning_content messages.append(history_message)如果你是自己封装 API注意不要过滤掉reasoning_content字段。5.3 JWT Token 续签的工程实践虽然 JWT 和大模型计费关系不大但很多系统同时使用 JWT 做用户鉴权也有不少团队把 API Key 当作 Token 来管理。这里顺便补充一个 JWT 续签的常见做法。JWT 过期后客户端需要拿 Refresh Token 换取新的 Access Token。代码层面可以这样实现import time import jwt SECRET_KEY your-secret-key ALGORITHM HS256 ACCESS_TOKEN_EXPIRE 3600 REFRESH_TOKEN_EXPIRE 7 * 24 * 3600 def create_access_token(user_id: str): payload { user_id: user_id, type: access, exp: int(time.time()) ACCESS_TOKEN_EXPIRE, } return jwt.encode(payload, SECRET_KEY, algorithmALGORITHM) def create_refresh_token(user_id: str, session_id: str): payload { user_id: user_id, session_id: session_id, type: refresh, exp: int(time.time()) REFRESH_TOKEN_EXPIRE, } return jwt.encode(payload, SECRET_KEY, algorithmALGORITHM)刷新接口在验证 Refresh Token 有效后签发新的 Access Token同时更新 Refresh Token。需要特别注意Refresh Token 一旦泄露攻击者可以长期维持会话。因此 Refresh Token 要保存在安全存储中并且每次使用后做轮换。5.4 Cookie、Session、Token 的边界排查 Token 问题时经常有人混淆认证方案。简单区分Cookie浏览器自动携带的键值数据主要用于 Web 会话中保存状态。Session服务端保存的状态数据通过 Session ID 关联用户。Token客户端持有的凭证服务端验签后确认身份。大模型 API 场景中API Key 本质上也是一种长期 Token。它同样存在过期、泄露、轮换的问题。建议为不同业务模块使用不同的 API Key某个 Key 泄露时可以单独吊销而不影响其他业务。6. 价格变化后的工程选型建议涨价本身不是终点真正的挑战是如何在价格变化后选出最合适的调用方案。6.1 官方 API 与聚合平台的取舍官方 API 的优势是稳定、文档齐全、新模型更新快。聚合平台或 Gateway 层则可能提供统一鉴权、多模型路由、成本统计等功能。选择时需要考虑稳定性要求核心业务建议优先官方 API避免中间层故障。成本透明度聚合平台可能隐藏实际 Token 单价需要仔细核对。合规边界企业项目要注意数据是否允许发送给第三方平台。价格调整频繁的时候建议在代码层抽象出统一的模型调用接口避免业务代码和具体平台强耦合。6.2 本地部署是否值得本地部署大模型可以规避按 Token 计费但代价也很明显需要 GPU 资源硬件成本不低。需要自己处理并发、推理优化、模型更新。小型模型的回答质量可能与官方模型有差距。我的建议是如果不涉及严格的数据合规要求优先选择官方 API。本地部署更适合以下场景数据不能出内网。请求量非常稳定且巨大。有 GPU 运维能力和模型调优经验。即使是本地部署也要把 Token 统计能力建立起来便于后续和 API 方案做成本对比。6.3 成本治理的核心原则不管价格怎么变成本治理的核心原则不变每次调用都要记录用量。每个业务线都要有独立预算。每类模型都要有成本评估。每个异常消耗都要能回溯到具体请求。做到这四点即使价格再次调整也能快速评估影响面而不是被动等账单。7. 总结与下一步学习建议DeepSeek 价格调整给开发者提了个醒大模型 API 的成本不只是“单价 × 数量”那么简单它和上下文管理、缓存命中、模型选型、流式统计都有关。本文从 Token 的基本概念讲到了成本结构再用完整示例演示了 DeepSeek API 接入和 Token 用量统计方法最后给出了常见的 Token 异常排查思路。接下来建议你按照下面的路径继续深入先把自己项目的所有调用点梳理一遍确认每条链路是否记录了 usage。再针对调用量最大的场景做上下文裁剪和缓存优化。然后搭建成本监控设置预算告警。最后根据业务场景做模型分级让不同难度的问题走到不同规格的模型上。价格战结束时留在牌桌上的不仅是模型厂商还有那些能把每一笔 Token 都花在刀刃上的工程团队。希望你也能成为其中之一。如果这篇文章对你有帮助可以收藏备用。后续我还会分享更多关于 Token 计费、成本优化、模型网关建设的实践内容。