☰
Claude API Token成本计算与用量分析实战:Python脚本实现成本优化
2026/10/5 5:22:10 网站建设 项目流程

1. 从一次账单异常说起:为什么我要自己算 Token 成本

上个月帮一个做知识库问答的朋友排查问题,他跟我说:“这个月 API 账单比上个月翻了一倍多,但我感觉用户量没怎么涨啊。”我让他把最近两周的调用日志导出来,跑了一遍统计,发现一个很典型的情况:他的系统里有一段“对话历史拼接”逻辑,每次请求都会把之前所有轮次的对话原封不动带上,而且没有做长度截断。结果就是,一个用户聊到第 15 轮的时候,单次请求的输入 Token 已经涨到了 8000 多,而输出只有短短一两百 Token。账单里绝大部分成本,其实都花在了那些被反复重发的历史对话上。

这件事让我意识到,很多开发者对 API 成本的理解还停留在“用多少付多少”的模糊阶段,真正落到 Token 这个计量单位上,心里是没有数的。Claude API 的计费方式是按输入 Token 和输出 Token 分别计价,输入和输出的单价还不一样,缓存命中和未命中的价格也有差异。如果你不去主动计算和分析,很容易出现“感觉没怎么用,账单却很高”的情况。

这篇内容就是把我自己这套 Token 成本计算与 API 用量分析的实战方法完整拆出来。核心目标有三个:第一,搞清楚 Claude API 的计费逻辑和 Token 计算方式;第二,写一个能直接跑的 Python 脚本,把调用日志里的 Token 用量算清楚;第三,基于统计结果做成本优化,把该省的钱省下来。适合正在用 Claude API 做产品、做副业项目,或者单纯想搞清楚自己钱花在哪儿的开发者。哪怕你刚接触 API 调用,跟着步骤走也能跑通。

2. Claude API 计费逻辑拆解:钱到底花在哪几个地方

2.1 输入 Token 与输出 Token 的定价差异

Claude API 的计费模型并不复杂,但有几个关键点容易被忽略。最基础的一条:输入 Token 和输出 Token 是分开计价的,而且输出 Token 通常比输入 Token 贵。以目前主流的模型档位为例,输出单价往往是输入单价的数倍。这意味着什么呢?意味着如果你的应用是“长输入、短输出”型,比如文档摘要、分类打标,成本相对可控;但如果是“短输入、长输出”型,比如内容生成、代码补全,那输出 Token 就是成本大头。

我拿一个实际场景算过:假设某次请求输入 2000 Token,输出 500 Token。如果输入单价是每百万 Token 3 美元,输出单价是每百万 Token 15 美元,那么这次请求的成本是:

  • 输入成本:2000 / 1,000,000 × 3 = 0.006 美元
  • 输出成本:500 / 1,000,000 × 15 = 0.0075 美元
  • 合计:0.0135 美元

看起来不多,但如果你的应用每天有 10 万次这样的请求,一天就是 1350 美元。所以单价的小数点后面几位,放大到规模上就是真金白银。

2.2 缓存机制对成本的影响

Claude API 有一个对成本影响很大的机制:提示缓存(Prompt Caching)。简单说,如果你有一段很长的系统提示词或者固定的上下文,在多次请求中反复使用,可以把它标记为可缓存内容。缓存写入的时候会有一个略高于普通输入的单价,但后续命中缓存的部分,输入单价会大幅降低。

这个机制的设计意图很明确:鼓励开发者把那些“不变的长内容”缓存起来,而不是每次请求都重新传一遍。我见过不少项目,系统提示词写了三四千字,每次请求都完整带上,从来不缓存,等于每次都在为同一段文字重复付费。把这段内容改成缓存模式之后,输入成本能降下来一大截。

注意:缓存有有效期,一般是几分钟到几十分钟不等。如果你的请求间隔很长,缓存可能已经失效,这时候命中不了反而要重新写入。所以缓存适合“短时间内高频重复使用同一段上下文”的场景。

2.3 不同模型档位的价格梯度

Claude 系列有多个模型档位,从轻量快速型到高能力型,价格差距可以到十几倍。很多开发者习惯性地所有任务都用最强模型,结果就是简单任务也在付高价。我的做法是按任务复杂度分层:分类、抽取、格式转换这类任务用轻量模型;复杂推理、长文生成、代码理解用高能力模型。光这一条,就能把整体成本压下来不少。

下面这张表是我自己整理的一个对照参考,帮助你在选型时快速判断:

任务类型推荐档位理由
文本分类、意图识别轻量快速型任务简单,不需要深度推理
信息抽取、结构化输出轻量或中档对指令遵循要求高,但推理深度要求低
长文摘要、内容生成中档或高能力型需要语言质量和连贯性
复杂代码理解、多步推理高能力型需要强推理能力,轻量模型容易出错
高频简单问答轻量快速型成本敏感,响应速度优先

这张表不是绝对的,但作为一个起步参考,能帮你避免“杀鸡用牛刀”的浪费。

3. Token 到底怎么数:计算原理与常见误区

3.1 Token 不是字数,也不是单词数

很多人第一次接触 Token 这个概念,会下意识地把它等同于“字数”或者“单词数”。实际上,Token 是模型处理文本的最小单位,它的切分规则和语言、标点、空格都有关系。英文里一个常见单词可能是 1 个 Token,也可能被拆成 2 到 3 个;中文里一个字通常是 1 到 2 个 Token,具体取决于分词方式。

举个直观的例子:英文句子 “I am learning Claude API” 大概会被切成 5 到 6 个 Token;而同样意思的中文“我正在学习 Claude API”,Token 数量可能接近甚至更多。这就导致一个现象:同样长度的内容,中文的 Token 消耗往往比英文高。如果你的应用面向中文用户,做成本预估时不能直接套用英文的经验值。

3.2 用官方 Tokenizer 做精确计算

靠肉眼估算 Token 数量是不靠谱的,尤其是涉及代码、特殊符号、多语言混排的时候。正确做法是用官方提供的 Tokenizer 工具做精确计算。Anthropic 提供了对应的计数接口和库,你可以在发送请求之前先算一遍,做到心里有数。

在 Python 里,最直接的方式是调用官方的计数接口。下面这段代码演示了如何计算一段文本的 Token 数量:

import anthropic client = anthropic.Anthropic(api_key="你的API密钥") def count_tokens(text, model="claude-3-5-sonnet-20241022"): response = client.messages.count_tokens( model=model, messages=[{"role": "user", "content": text}] ) return response.input_tokens sample_text = "请帮我总结这段内容的核心观点,并用三点列出。" print(f"Token 数量: {count_tokens(sample_text)}")

这个接口的好处是准确,缺点是每次计数都要发一次请求,有网络开销。如果你要批量统计大量历史日志,更高效的做法是用本地的 Tokenizer 库做离线计算。虽然本地计算和官方接口可能有极小的偏差,但对于成本分析来说完全够用。

3.3 容易被忽略的 Token 消耗点

在实际项目里,有几个地方的 Token 消耗特别容易被低估:

  • 系统提示词:很多人写系统提示词的时候很随意,一写就是上千字,而且每次请求都带上。这部分是纯输入成本,积少成多。
  • 对话历史:多轮对话场景下,如果不做截断或摘要,历史会越来越长,输入 Token 线性增长。
  • 工具定义和函数描述:如果你用了工具调用(Tool Use),每个工具的名称、描述、参数 schema 都会计入输入 Token。工具多了,这部分开销不小。
  • 格式化的输出要求:如果你在提示词里要求模型输出 JSON、Markdown 表格等结构化内容,模型为了满足格式要求,输出 Token 往往会比自由文本更多。

我自己的经验是,做一次完整的 Token 审计,把每个请求的输入构成拆开看,经常能发现一两个“隐形大户”,优化掉之后成本立竿见影地下降。

4. 动手写一个可运行的用量分析脚本

4.1 脚本整体设计思路

这个脚本的目标很明确:读取 API 调用日志,统计每天的请求数、输入 Token、输出 Token、缓存命中情况,并计算出对应的成本。设计上我遵循几个原则:

第一,日志格式要兼容常见情况。不同项目的日志格式不一样,有的记 JSON,有的记纯文本。我在脚本里做了一个简单的解析层,你可以根据自己的日志格式调整。

第二,成本计算参数可配置。模型单价会变,缓存价格和普通价格不同,这些我都做成配置项,改起来方便。

第三,输出要直观。除了打印汇总,还会按天聚合,方便你看趋势。

4.2 日志解析与数据清洗

假设你的日志是每行一个 JSON 对象,包含时间戳、模型名、输入 Token 数、输出 Token 数、缓存读取 Token 数、缓存写入 Token 数这几个字段。解析代码如下:

import json from datetime import datetime from collections import defaultdict def parse_log(file_path): records = [] with open(file_path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue try: obj = json.loads(line) records.append({ "timestamp": obj.get("timestamp"), "model": obj.get("model", "unknown"), "input_tokens": obj.get("input_tokens", 0), "output_tokens": obj.get("output_tokens", 0), "cache_read_tokens": obj.get("cache_read_tokens", 0), "cache_write_tokens": obj.get("cache_write_tokens", 0), }) except json.JSONDecodeError: continue return records

这里有个细节:日志里缺失的字段要补默认值,否则后面统计的时候会报错。另外,如果日志里有异常记录(比如请求失败但记了 Token),最好单独标记出来,不要混进正常统计。

4.3 成本计算核心逻辑

成本计算的关键是把不同类别的 Token 乘以对应的单价。我定义了一个价格配置字典,按模型区分:

PRICING = { "claude-3-5-sonnet-20241022": { "input": 3.0, "output": 15.0, "cache_write": 3.75, "cache_read": 0.30, }, "claude-3-5-haiku-20241022": { "input": 0.80, "output": 4.0, "cache_write": 1.0, "cache_read": 0.08, }, } def calc_cost(record): model = record["model"] price = PRICING.get(model) if not price: return 0.0 cost = ( record["input_tokens"] / 1_000_000 * price["input"] + record["output_tokens"] / 1_000_000 * price["output"] + record["cache_write_tokens"] / 1_000_000 * price["cache_write"] + record["cache_read_tokens"] / 1_000_000 * price["cache_read"] ) return cost

提示:上面的单价是示例值,实际使用时请以官方最新价格为准。价格会调整,脚本里的配置要跟着更新。

4.4 按天聚合与结果输出

统计部分我按天做聚合,同时保留按模型维度的拆分,这样你能看到“哪个模型花钱最多”:

def aggregate(records): daily = defaultdict(lambda: { "requests": 0, "input_tokens": 0, "output_tokens": 0, "cost": 0.0, }) for r in records: day = r["timestamp"][:10] if r["timestamp"] else "unknown" daily[day]["requests"] += 1 daily[day]["input_tokens"] += r["input_tokens"] daily[day]["output_tokens"] += r["output_tokens"] daily[day]["cost"] += calc_cost(r) return daily def print_report(daily): print(f"{'日期':<12}{'请求数':<10}{'输入Token':<14}{'输出Token':<14}{'成本(美元)':<12}") for day in sorted(daily.keys()): d = daily[day] print(f"{day:<12}{d['requests']:<10}{d['input_tokens']:<14}{d['output_tokens']:<14}{d['cost']:<12.4f}")

跑出来的效果大概是这样:

日期请求数输入Token输出Token成本(美元)
2025-01-1015202,340,000380,00012.84
2025-01-1116802,890,000420,00015.63
2025-01-1214202,100,000350,00011.37

有了这张表,哪天用量异常、哪个模型成本高,一眼就能看出来。

5. 从数据到决策:用量分析与成本优化实战

5.1 识别成本大头:输入还是输出

拿到统计结果之后,第一件事是看输入和输出的比例。如果输入 Token 远大于输出 Token,说明你的成本主要花在“喂给模型的内容”上,优化方向是精简提示词、做对话截断、启用缓存。如果输出 Token 占比很高,那就要考虑是不是输出要求太啰嗦,或者模型档位选高了。

我帮朋友分析的那次,输入输出比大概是 8:1,明显是输入侧的问题。后来把对话历史做了滑动窗口截断,只保留最近 5 轮,输入 Token 直接降了六成。

5.2 缓存命中率分析

如果你启用了提示缓存,一定要单独统计缓存命中率。命中率高,说明缓存策略有效;命中率低,可能是缓存内容太短、有效期设置不合理,或者请求间隔太长导致缓存失效。我一般会算一个指标:缓存读取 Token 占总输入 Token 的比例。这个比例越高,说明省下的钱越多。

5.3 模型分层使用的效果验证

把简单任务切到轻量模型之后,要回头验证效果有没有下降。我的做法是抽一批样本,用两个模型分别跑,人工对比输出质量。如果轻量模型在简单任务上表现够用,那就放心切。实测下来,分类和抽取类任务,轻量模型和高端模型的差距很小,但成本能差好几倍。

5.4 一个完整的优化前后对比

还是拿朋友那个项目举例。优化前:每天约 1500 次请求,平均每次输入 1800 Token,输出 200 Token,全部用高端模型,日成本约 13 美元。优化措施包括:对话历史截断到 5 轮、系统提示词启用缓存、分类任务切到轻量模型。优化后:平均输入降到 700 Token,缓存命中率约 40%,日成本降到约 4.5 美元。功能上没有明显退化,用户反馈也正常。

6. 常见问题与排查技巧实录

6.1 Token 统计对不上官方账单怎么办

这是最常见的问题。可能的原因有几个:一是本地 Tokenizer 和官方计数有偏差,尤其是特殊字符和代码;二是日志记录不完整,有些请求没记上;三是缓存 Token 的计费方式和你理解的不一样。排查顺序建议是:先用官方计数接口抽样验证几条记录,确认偏差范围;再检查日志是否有遗漏;最后核对缓存部分的计费规则。

6.2 请求报错但 Token 已经消耗了

有些错误是在模型已经开始生成之后才发生的,比如连接中断、超时。这种情况下,已经生成的 Token 可能会计费。我的做法是在日志里区分“成功请求”和“异常请求”,异常请求单独统计,看看占比高不高。如果异常请求的 Token 消耗占比超过 5%,就要排查网络稳定性或者超时设置。

6.3 缓存不生效的几种情况

缓存不生效通常有这几个原因:缓存内容太短,没达到最小缓存长度要求;请求间隔超过了缓存有效期;缓存内容每次都有细微变化,导致无法命中。解决办法是尽量让缓存内容保持稳定,把变化的部分放到缓存之外。

6.4 常见问题速查表

问题现象可能原因排查方向
账单比预估高很多对话历史未截断、未启用缓存检查输入 Token 构成
缓存命中率低缓存内容不稳定、有效期短检查缓存内容和请求间隔
轻量模型输出质量差任务复杂度超出模型能力换回高端模型或优化提示词
Token 统计与账单偏差大本地计数偏差、日志遗漏用官方接口抽样验证
异常请求 Token 消耗高网络不稳定、超时设置短检查网络和超时配置

6.5 几个我踩过的坑

第一个坑是用字符数估算 Token。早期我图省事,按“一个汉字约等于 1.5 Token”来估,结果实际偏差能到 30% 以上,成本预估完全不准。后来老老实实用 Tokenizer 算,才把误差控制住。

第二个坑是缓存内容里带了时间戳。我一开始把“当前时间”写进了缓存内容,结果每次请求缓存都无法命中,白白付了缓存写入的钱。后来把时间戳挪到缓存之外,命中率立刻上来了。

第三个坑是忽略了工具定义的 Token 开销。有一次接入了十几个工具,每个工具的描述都写得很详细,结果光工具定义就占了一千多 Token。后来精简了工具描述,只保留必要信息,输入成本降了不少。

7. 把脚本用起来:日常监控与持续优化

脚本写完之后,我建议把它挂到日常流程里。最简单的做法是每天定时跑一次,把结果输出到一个文件或者发到自己的通知渠道。这样一旦某天成本异常,你能第一时间发现,而不是等到月底看账单才反应过来。

如果你用的是云服务,也可以把统计结果推到监控面板上,做一个成本趋势图。我自己的习惯是每周看一次趋势,每月做一次完整的成本审计,把优化措施的效果量化出来。成本优化不是一锤子买卖,模型价格会变,业务量会变,使用模式也会变,定期回顾才能持续把钱花在刀刃上。

另外,脚本里的价格配置记得定期更新。API 价格调整的时候,如果不更新配置,算出来的成本就是错的,基于错误数据做的决策也会跑偏。我一般会在官方价格页做个书签,每隔一段时间核对一次。

最后分享一个我常用的技巧:在脚本里加一个“单次请求平均成本”的指标。这个数字的变化比总成本更敏感,能更早地反映出使用模式的变化。比如总成本没涨,但单次平均成本涨了,说明请求结构在变化,可能某个功能模块的调用方式出了问题。这个指标帮我提前发现过好几次潜在的成本异常。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询