Token计算深度分解:搞懂大模型的“计价单位”

📅 2026/7/8 3:32:01
Token计算深度分解:搞懂大模型的“计价单位”
你有没有遇到过这种情况在OpenAI的API里输入一段中文Token数比你预想的多出一大截换成英文同样意思的内容Token却少了很多。或者用DeepSeek和Claude处理同一段文本算出来的Token数居然不一样。这不是错觉而是Token计算本身的复杂性造成的。Token可以理解为大模型处理文本时的最小“积木块”。它既不是字也不是词而是介于两者之间的“子词subword”或“字节序列”。大模型看不懂原始文字只能看懂数字。所以每一段文字输入模型之前都要先被切分成Token再映射成数字ID。一、Token是怎么“切”出来的——Tokenization的核心流程把文本变成Token的过程叫Tokenization分词整个过程可以分为三步1.1 为什么不用“字”或“词”做最小单位如果用词做单位比如英文单词会遇到生僻词问题——模型不可能认识所有单词遇到不认识的词就不知道怎么办了。如果用字/字符做单位又会导致序列太长——一个英文句子平均5个字符才等于1个词序列长度直接膨胀5倍计算量暴涨。所以主流方案取了个折中用子词Subword做单位。高频词保留为完整Token低频词拆分成共享子词单元。这样既控制了词表大小又能覆盖几乎所有文本。举个直观的例子英文单词unhappiness可能被拆成un happiness两个Token而不是一个完整的词也不是一个一个字母。二、三大主流分词算法BPE、WordPiece、SentencePiece不同模型用不同的分词算法这是导致同样文本在不同模型里Token数不一样的根本原因。2.1 BPEByte-Pair Encoding——最主流代表模型GPT系列、Llama、Qwen2等核心思想从字母开始不断合并出现频率最高的相邻字符对。训练过程简化初始词表a, b, c, d, e, ...第1步发现 ab 出现次数最多 → 合并成 ab第2步发现 ab c 出现最多 → 合并成 abc第3步继续合并直到词表达到预定大小特点纯数据驱动只看统计频率可逆且无损Token可以完美还原回原文OpenAI的tiktoken就是基于BPE的快速实现2.2 WordPiece——BERT的选择代表模型BERT与BPE的区别BPE选频率最高的合并WordPiece选能最大提升似然概率的合并——简单说BPE看“谁出现最多”WordPiece看“谁合并后效果最好”。2.3 SentencePiece——语言无关的解决方案代表模型LLaMA、T5、ALBERT等最大特点把空格也当成普通字符处理不需要预先按空格分词。这让它天然支持中文、日文等没有空格的语言。三种算法对比总结算法代表模型核心逻辑中文支持BPEGPT、Llama、Qwen2合并频率最高的相邻对一般WordPieceBERT合并后似然提升最大的对一般SentencePieceLLaMA、T5把空格当字符不依赖预分词优秀三、Token计算框架模型是怎么算Token的3.1 OpenAItiktokenOpenAI官方提供了一个叫tiktoken的Python库专门用来计算OpenAI模型的Token数。import tiktoken # 根据模型名称获取对应的编码器 encoding tiktoken.encoding_for_model(gpt-4o) # 计算Token数 text Hello, how are you? tokens encoding.encode(text) print(fToken数量: {len(tokens)}) print(fToken列表: {tokens})tiktoken的编码规则不同模型用不同的编码encoding。比如cl100k_base是GPT-4系列用的编码词汇表有10万个Token。英文的估算规则1个Token ≈ 4个字符1个Token ≈ 0.75个单词100个Token ≈ 75个单词3.2 DeepSeek基于BPE的自研分词器DeepSeek同样采用BPE算法但词汇表和具体切分规则与OpenAI不同。这就是为什么同样一段中文在DeepSeek和OpenAI里算出来的Token数不一样。一个有意思的发现在DeepSeek-V3和Qwen 3.6上中文比英文更省Token——同样的内容中文版的Token数只有英文版的0.65倍。这与OpenAI的情况正好相反OpenAI里中文通常比英文更费Token。3.3 Hugging Face Tokenizers统一框架Hugging Face提供了tokenizers库统一实现了BPE、WordPiece、Unigram等多种算法。from transformers import AutoTokenizer # 加载任何Hugging Face模型的tokenizer tokenizer AutoTokenizer.from_pretrained(bert-base-uncased) # 分词并计算Token数 tokens tokenizer.tokenize(Hello, how are you?) print(fToken列表: {tokens}) print(fToken数量: {len(tokens)})Tokenizer的完整流水线Normalizer标准化转小写、去重音等Pre-tokenizer预切分按空格等规则初步拆分Model核心分词算法BPE/WordPiece/UnigramPost-processor后处理添加特殊标记如[CLS]、[SEP]等四、模型之间Token计算的差异为什么同样文本在不同模型里不一样4.1 差异来源一词表大小不同每个模型训练时都会构建自己的词表。词表越大一个Token能覆盖的文本就越多。模型词表大小约GPT-250,257GPT-4 (cl100k_base)100,000Llama 232,000DeepSeek-V3129,000词表越大生僻词越可能被保留为完整Token而不是拆成多个Token数就越少。4.2 差异来源二分词粒度不同同样是中文人工智能模型可能的切分方式Token数模型A[人工智能]1模型B[人工, 智能]2模型C[人, 工, 智, 能]4没有一个“标准答案”全看模型训练时的分词策略。4.3 差异来源三特殊Token的添加很多模型会在输入前后自动添加特殊Token[CLS]分类标记—— BERT系列[SEP]分隔标记—— BERT系列|im_start|、|im_end|消息起止—— 部分开源模型|endoftext|文本结束—— GPT系列这些特殊Token也会计入总数而且不同模型加的数量不一样。五、多模态Token计算图像、音频是怎么变成Token的多模态模型的Token计算比纯文本复杂得多——不同模态的Token是分开计算的而且计算方式完全不同。5.1 图像转Token视觉编码器多模态模型处理图像时不是直接把图片“当作”Token而是通过视觉编码器把图片转换成Token序列。典型的转换流程以ViT-L/14为例处理224×224分辨率图像时默认生成196个Patch Token。分辨率越高Token越多。不同平台的图像Token计算规则平台/模型图像Token计算方式StepFun默认每张图169 Token开启detail模式后根据图片大小计算通义千问VL最小28×28像素1 Token每张图最少4 Token最多1280 TokenQwen3-Omni图片/视频输入单独计价与文本输入价格不同5.2 音频转Token声学特征提取音频的处理方式又不一样——通过声学特征提取把声音信号转成Token序列。不同模态的Token价格完全不同。以阿里云Qwen3-Omni-Flash为例模态输入价格元/百万Token文本3.156图片/视频5.725音频27.962音频Token的价格是文本的将近9倍。5.3 多模态Token是“相互”还是“分开”计算的答案是分开计算但合并计费。计算上分开文本走文本分词器图像走视觉编码器音频走声学编码器——各自独立转换成Token计费上合并最终把所有模态的Token数加在一起按各自的价格分别计费计费公式总费用 (图像Token数 × 图像单价) (音频Token数 × 音频单价) (文本Token数 × 文本单价) (输出Token数 × 输出单价)5.4 多模态模型的“隐藏成本”多模态调用有一个容易被忽略的成本即使你只问了一个简单问题模型也要先把整张图片转成几百个Token才能处理。比如你发一张高清图问“这是什么”模型可能先消耗了500个图像Token“读图”再用10个文本Token生成回答。读图的成本远高于回答本身。六、VSCode实战Token计算的完整代码示例6.1 使用tiktoken计算OpenAI模型的Tokenimport tiktoken def count_tokens_openai(text, modelgpt-4o): 使用tiktoken计算OpenAI模型的Token数 try: encoding tiktoken.encoding_for_model(model) except KeyError: # 如果模型名不存在使用默认编码 encoding tiktoken.get_encoding(cl100k_base) tokens encoding.encode(text) return len(tokens), tokens # 测试不同文本 test_texts [ Hello, how are you?, # 英文 你好最近怎么样, # 中文 Artificial Intelligence, # 英文单词 人工智能, # 中文词汇 ] for text in test_texts: count, tokens count_tokens_openai(text) print(f文本: {text}) print(f Token数: {count}) print(f Token IDs: {tokens[:5]}...) # 只显示前5个 print()运行结果示例实际数字可能因模型版本而异文本: Hello, how are you? Token数: 6 Token IDs: [9906, 11, 703, 527, 499, 30]... 文本: 你好最近怎么样 Token数: 7 Token IDs: [44300, 106395, 16, 38412, 102, 450, 116]... 文本: Artificial Intelligence Token数: 3 Token IDs: [21646, 12518]... 文本: 人工智能 Token数: 2 Token IDs: [44300, 106395]...6.2 使用Hugging Face Tokenizer计算任意模型from transformers import AutoTokenizer def count_tokens_hf(text, model_nameQwen/Qwen2.5-7B): 使用Hugging Face加载指定模型的tokenizer并计算Token tokenizer AutoTokenizer.from_pretrained(model_name) tokens tokenizer.tokenize(text) token_ids tokenizer.encode(text) return len(tokens), tokens, token_ids # 测试 text 人工智能正在改变世界 count, tokens, ids count_tokens_hf(text) print(f文本: {text}) print(fToken数: {count}) print(fToken列表: {tokens}) print(fToken IDs: {ids})6.3 对比不同模型的Token计算差异import tiktoken from transformers import AutoTokenizer def compare_tokenizers(text, models): 对比不同模型对同一段文本的Token切分 results {} # OpenAI模型 for model in models.get(openai, []): try: enc tiktoken.encoding_for_model(model) tokens enc.encode(text) results[fOpenAI-{model}] { count: len(tokens), tokens: tokens[:10] # 只显示前10个 } except: pass # Hugging Face模型 for model in models.get(hf, []): try: tokenizer AutoTokenizer.from_pretrained(model) tokens tokenizer.tokenize(text) ids tokenizer.encode(text) results[fHF-{model}] { count: len(tokens), tokens: tokens[:10] } except: pass return results # 测试文本 text 大语言模型的Token计算方式因模型而异 # 要对比的模型 models { openai: [gpt-4o, gpt-3.5-turbo], hf: [Qwen/Qwen2.5-7B, meta-llama/Llama-2-7b] } results compare_tokenizers(text, models) for model_name, data in results.items(): print(f{model_name}: {data[count]} 个Token) print(f 前10个Token: {data[tokens]}) print()6.4 多模态Token估算模拟def estimate_multimodal_tokens(image_resolution(224, 224), text, audio_seconds0): 估算多模态请求的Token消耗模拟 total 0 details {} # 图像Token估算基于ViT风格 if image_resolution: patch_size 16 h, w image_resolution image_tokens (h // patch_size) * (w // patch_size) details[图像Token] image_tokens total image_tokens # 文本Token估算粗略 if text: # 粗略估算中文约1.5 Token/字英文约0.25 Token/字符 chinese_chars sum(1 for c in text if \u4e00 c \u9fff) other_chars len(text) - chinese_chars text_tokens int(chinese_chars * 1.5 other_chars * 0.25) details[文本Token] text_tokens total text_tokens # 音频Token估算粗略1秒≈50 Token if audio_seconds 0: audio_tokens int(audio_seconds * 50) details[音频Token] audio_tokens total audio_tokens details[总计] total return details # 示例一张图 一段文字 10秒音频 result estimate_multimodal_tokens( image_resolution(224, 224), text请分析这张图片的内容, audio_seconds10 ) print(多模态Token估算:) for key, value in result.items(): print(f {key}: {value})输出示例多模态Token估算: 图像Token: 196 文本Token: 7 音频Token: 500 总计: 703维度核心要点Token是什么大模型处理文本的最小单元介于字和词之间的“子词”怎么计算预处理 → 分词BPE/WordPiece/SentencePiece→ 映射为ID三大算法BPE最主流、WordPieceBERT用、SentencePiece支持中文好为什么不同模型不一样词表大小不同、分词粒度不同、特殊Token不同多模态怎么算图像→视觉编码器转Token音频→声学编码器转Token分开计算、合并计费主要框架OpenAI tiktoken、Hugging Face Tokenizers、Google SentencePiece小编建议不要用字符数估算Token数中文1个字≈1.5-2 Token英文1个词≈1-1.5 Token不同模型用不同的计算工具OpenAI用tiktokenHugging Face用AutoTokenizer多模态调用前先估算图像Token一张高清图可能消耗几百个Token成本远超你的想象中文场景优先选中文优化好的模型DeepSeek和Qwen的中文Token效率优于OpenAI生产环境务必在代码里精确计算Token不要靠猜用官方工具算小编团自动研发 大型文件翻译、文本润色链接[免费]翻译全文网页你是否为翻译烦恼-CSDN博客