这篇解决什么问题

把 DeepSeek API 的 key 交给程序之后,成本问题就收敛成三个具体的问题:这个月用了多少 token、折算成多少钱、和平台后台的账单能不能对上。

DeepSeek 开放平台(platform.deepseek.com)后台自带用量与账单页,能看到按天汇总的 token 消耗与金额,充值、开票也在后台完成【待补:后台当前入口名称与界面截图】。这套页面解决的是”官方口径”问题。但只要你有超过一个项目在调 API,或者把 key 配进了第三方客户端,光看后台就不够了——你不知道每一笔消耗对应哪条业务,月底的成本分摊无从谈起。

这篇按三个层次走:后台人工核对建立基准、接口自动查余额做低额告警、程序里逐条落盘 usage 月底对账。所有脚本可以直接抄走改改就用。

环境与版本

要求
账号DeepSeek 开放平台账号,已充值或持有可用余额【待补:最低充值金额、支付方式与发票入口】
API Key后台「API Keys」页创建,sk- 开头,只在创建时完整显示一次
Python3.9 及以上;SDK 用 openai 官方包(1.0 版本之后的客户端写法),当前版本【待补:openai SDK 最新版本号】
curlWindows 10/11 系统自带 curl.exe,macOS/Linux 原生自带
网络本机或服务器能直连 api.deepseek.com

先记住两个固定约定:DeepSeek API 兼容 OpenAI 接口协议,base_url 填 https://api.deepseek.com,带不带 /v1 后缀都能用;常用模型名就两个,deepseek-chat(对话)与 deepseek-reasoner(推理)。这些是官方文档里的稳定约定,下文脚本照抄即可。

分步操作

第一步:在后台建立”对账基准”

登录后台,先花两分钟把三个页面看一遍:用量页(按天的 token 与金额汇总)、账单页(充值记录与余额)、API Keys 页。之后你自己的所有记账,最终都要和用量页的按天数字对平——先有官方基准,再谈自账。

对账涉及的四类数据与来源,一张表说清:

记账项来源用途
余额GET /user/balance 接口低额自动告警
单次消耗每条响应里的 usage 对象逐条记账、按业务分摊
按天汇总后台用量页对账基准
月度结算后台账单页与充值/开票核对

DeepSeek 开放平台用量页位置示意

第二步:接口查余额,做成低额告警

余额查询是文档里公开的接口,一条 curl 就能调:

curl -s https://api.deepseek.com/user/balance \
  -H "Authorization: Bearer $DEEPSEEK_API_KEY"

返回是 JSON,核心信息是总余额、赠送余额与是否可用【待补:真实返回示例与字段名】。把它包成定时任务,低于阈值就通知自己:

# check_balance.py —— 每天查一次余额,低于阈值告警
import os
import requests

resp = requests.get(
    "https://api.deepseek.com/user/balance",
    headers={"Authorization": "Bearer " + os.environ["DEEPSEEK_API_KEY"]},
    timeout=30,
)
resp.raise_for_status()
print(resp.json())
# 从返回里解析出总余额,与阈值比较,低于阈值就走邮件/钉钉/飞书通知
# 阈值按消耗速度定:假设日均消耗 10 元,那低于 100 元就该提醒充值了

key 只从环境变量读,别把 sk- 开头的串写死进代码仓库——泄露的 key 就是别人的免费钱包。

第三步:让每条响应的 usage 落盘

非流式响应自带 usage 对象,token 数以它为准——自己按字符估 token 永远有偏差,响应里的 usage 才是计费口径。DeepSeek 还额外返回两个缓存字段 prompt_cache_hit_tokensprompt_cache_miss_tokens:上下文缓存命中与未命中的单价不同【待补:缓存命中、未命中、输出三档当前单价】,对账时必须分开记。

# chat_with_usage.py —— 每次调用把 usage 追加写入 jsonl
import json
import time
import os
from openai import OpenAI

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

def ask(prompt: str, model: str = "deepseek-chat", tag: str = "demo"):
    t0 = time.time()
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
    )
    u = resp.usage
    record = {
        "ts": time.strftime("%Y-%m-%d %H:%M:%S"),
        "tag": tag,            # 业务标签,成本分摊全靠它
        "model": model,
        "prompt_tokens": u.prompt_tokens,
        "completion_tokens": u.completion_tokens,
        "total_tokens": u.total_tokens,
        "cache_hit": u.prompt_cache_hit_tokens,
        "cache_miss": u.prompt_cache_miss_tokens,
        "latency_s": round(time.time() - t0, 2),
    }
    with open("usage.jsonl", "a", encoding="utf-8") as f:
        f.write(json.dumps(record, ensure_ascii=False) + "\n")
    return resp.choices[0].message.content

if __name__ == "__main__":
    print(ask("用一句话解释什么是 token"))

流式调用要注意:OpenAI 兼容接口的流式响应默认不带 usage,需要显式传 stream_options={"include_usage": True},usage 会挂在最后一个 chunk 上。如果你的框架封装把这个参数吞掉了,日志里的 token 就会永远是 0。

第四步:月底对账

# reconcile.py —— 把 usage.jsonl 按天聚合,与后台用量页对
import json
from collections import defaultdict

day = defaultdict(lambda: {"calls": 0, "total": 0, "hit": 0, "miss": 0})
for line in open("usage.jsonl", encoding="utf-8"):
    r = json.loads(line)
    d = day[r["ts"][:10]]
    d["calls"] += 1
    d["total"] += r["total_tokens"]
    d["hit"] += r["cache_hit"]
    d["miss"] += r["cache_miss"]

for k in sorted(day):
    d = day[k]
    print(k, f"{d['calls']} 次调用", f"token {d['total']}", f"缓存命中 {d['hit']}")

对账口径:金额 = 缓存命中 token × 命中单价 + 未命中 token × 未命中单价 + 输出 token × 输出单价【待补:当前三档单价】。和后台同一天的数字比,差异应当在小几十 token 的量级——超出这个量级,优先排查是不是有调用没走你的封装函数(第三方客户端、同事另起的脚本都算漏网之鱼)。

常见坑

坑一:流式调用记账恒为 0。 原因就是上面说的 include_usage 没开。凡是发现”后台账单比自己日志大一大截”,先查流式路径有没有记上 usage,这是最高频的对账缺口。

坑二:只拿一个单价乘总数。 DeepSeek 的上下文缓存是自动生效的,命中部分的单价明显更低【待补:缓存命中与未命中的当前单价】。拿 total_tokens 统一乘一个价,月底和后台必然对不上——而且通常是”自己算的偏贵”,这不是后台多扣了,是你没把缓存价算进去。

坑三:多人共用一个 key,无法分摊。 平台侧对单个 key 没有独立账单视图(以后台实际功能为准),分摊只能在调用侧解决:每条记录打 tag,月底按 tag 聚合。上面脚本里的 tag 字段就是干这个的,按项目名、按业务线命名都行。

坑四:429 之后无脑重试。 触发限流(HTTP 429)就立刻重试,只会继续撞限流。通用做法是指数退避:等 2 秒、4 秒、8 秒,连试 3 次失败就告警人工介入。一般只有成功返回的响应才产生 token 计费(以官方计费说明为准),但重试风暴会实打实拖垮业务时延。

最终效果

跑通之后你手里有三样东西:一条随时能查余额的 curl;一个逐条记录 usage 的 jsonl 文件;一个按天聚合的对账脚本。对账表长这样(数字为示意,真实数字【待补:某天实际调用量与金额】):

日期调用次数总 token缓存命中 token记账金额(元)后台金额(元)
2026-08-291204182 万96 万【待补:按三档单价计算】【待补:后台数字】

差异列长期接近零,才说明记账是完整的。成本管理从”月底惊吓”变成”每天一瞥”——余额告警管账户安全,tag 聚合管业务分摊,按天对账管数据完整性,三件事各管一段,谁也糊弄不了谁。

相关阅读