词元Token从概念到成本:大模型计费单位与BPE分词原理详解

发布时间:2026/10/26 21:19:52
词元Token从概念到成本:大模型计费单位与BPE分词原理详解

1. 从「Token」到「词元」:一个翻译背后藏着的行业共识

「Token」这个英文词,在大模型圈子里被叫了这么多年,终于有了一个官方味道比较浓的中文名——「词元」。这事看起来只是改个叫法,但如果你真在一线做模型应用、算过账单、调过接口,就会明白这个命名背后其实是一次行业层面的「对齐」:大家终于不用再各叫各的,有人叫「令牌」,有人叫「标记」,有人干脆不翻译直接念「token」,沟通成本高得离谱。

我自己最早接触这个词是在做文本分类的时候,那时候还没大模型什么事,Tokenizer 就是预处理流水线里的一个环节。后来 GPT 系列火了,Token 突然从「技术细节」变成了「计费单位」,变成了每个做 AI 产品的人绕不开的成本项。你去任何一个做 AI 应用的群里问一句「你们一个月 token 用量多少」,回复里一定夹杂着「token 失效」「token 用量」「token 怎么算」这些关键词,可见这个词已经彻底出圈了。

这篇东西我想干一件事:把「词元」这个概念从里到外讲透。它是什么、怎么切出来的、为什么能当计费单位、BPE 到底在干什么、不同模型的词元划分有什么差异、实际项目里怎么估算用量、怎么省钱。适合刚入行做 AI 应用开发的朋友,也适合产品、运营、甚至只是好奇「为什么我充的钱这么快就没了」的普通用户。我不打算写成教科书,就按我自己踩过的坑和实际算过的账来讲。

先给一个最直白的定义:词元(Token)是模型处理文本的最小单位。模型不认识「字」,也不认识「词」,它只认识一串被切好的、映射成数字 ID 的片段,这些片段就是词元。你发给模型的每一句话,都会先被切成词元,再喂进去;模型吐出来的内容,也是一个词元一个词元拼出来的。所以词元既是输入输出的计量单位,也是计费的计量单位——这就是为什么大家管它叫「AI 世界的水电费」。

2. 词元到底是什么:从「字」到「片段」的认知转换

2.1 为什么模型不直接按「字」处理

很多人第一反应是:中文按字切、英文按单词切,不就完了?理论上可以,但实际不行,原因有三个。

第一,词表爆炸。英文常用词几十万,加上各种变形、专有名词、拼写错误,词表能膨胀到几百万甚至上千万。词表越大,模型最后一层做 softmax 的计算量越大,显存占用越夸张。你不可能为了覆盖所有可能的词,去维护一个千万级的词表。

第二,未登录词问题。按词切的话,遇到一个模型没见过的词(比如新出的产品名、人名、网络梗),模型就完全没法处理,只能统一映射成一个<UNK>。这在真实场景里是灾难,因为新词每天都在产生。

第三,多语言和符号的兼容。中文、英文、日文、代码、数学公式、emoji,如果各用一套切法,工程上会非常复杂。你需要一个统一的、能覆盖所有字符的方案。

所以业界最终收敛到的思路是:不按字也不按词,按「子词」(subword)切。把常见的词整体保留,把不常见的词拆成更小的片段,这样既能控制词表大小,又能处理任意新词。这个思路的经典实现就是 BPE。

2.2 词元不等于字,也不等于词

这里必须澄清一个高频误解:一个词元不等于一个汉字,也不等于一个英文单词。

举几个实际的例子(基于常见的 GPT 系列分词器):

  • 英文apple通常是 1 个词元
  • 英文unbelievable可能被切成un+believ+able,3 个词元
  • 中文「你好」在有些分词器里是 1 个词元,有些是 2 个
  • 中文「人工智能」大概率是 2 到 3 个词元
  • 一个 emoji 可能是 1 到 3 个词元
  • 一段 Python 代码里的缩进空格,也会占词元

这就导致一个很反直觉的现象:同样一段意思,中文和英文的词元数可能差很多。早期 GPT 系列的分词器对中文不太友好,一个汉字经常要占 1 到 2 个词元,而对应的英文可能只占 0.3 个词元。后来随着中文语料占比提升,新一代分词器对中文的压缩率明显改善了,但差异依然存在。

提示:如果你在做成本估算,千万不要用「字数」直接换算词元。中文和英文的换算比例完全不同,甚至同一语言不同领域文本(代码 vs 小说)的比例也差很多。唯一靠谱的办法是用对应模型的分词器实测。

2.3 词元、字符、字节三者的关系

为了把这事说清楚,我用一个表格对比一下:

概念定义例子和词元的关系
字符一个书写符号「你」「a」「1」一个字符可能对应 0.5 到 2 个词元
字节8 位二进制UTF-8 下「你」占 3 字节词元通常基于字节或字符构建
词元模型处理的最小单位un、believ、able计费和上下文长度的单位

理解这三者的区别,是理解后面所有内容的基础。尤其是做多语言应用的朋友,一定要记住:你的成本是按词元算的,不是按字符算的,更不是按字节算的。

3. BPE 与 Tokenizer:词元是怎么被「切」出来的

3.1 BPE 的核心思想:从字符开始,不断合并

BPE 全称 Byte Pair Encoding,最早是数据压缩领域的算法,后来被引入到自然语言处理做子词切分。它的思路其实非常朴素,我用一个简化例子讲清楚。

假设你的训练语料里只有这几个词和它们的出现次数:

low: 5 lower: 2 newest: 6 widest: 3

第一步,把所有词拆成单个字符,并在末尾加一个结束符(比如</w>):

l o w </w> l o w e r </w> n e w e s t </w> w i d e s t </w>

第二步,统计所有相邻字符对的出现频率,找出最高频的那一对,把它合并成一个新的符号。比如e和s经常相邻,就合并成es。然后重复这个过程,每次合并一对,直到达到预设的合并次数或词表大小。

最终你会得到一套「合并规则」,这套规则就是分词器的核心。切分新文本时,就按这套规则从字符开始,能合并的就合并,合并不了的保持原样。

这个过程的精妙之处在于:高频组合会被合并成更少的词元,低频组合保持碎片化。所以常见词往往只占 1 个词元,生僻词会被拆成多个。这既控制了词表大小,又保证了任意文本都能被切分。

3.2 从 BPE 到 BBPE:字节级的分词

原始 BPE 是基于字符的,但字符集在不同语言间差异巨大。为了解决这个问题,后来出现了 BBPE(Byte-level BPE),也就是基于字节的 BPE。

BBPE 的做法是:先把文本转成 UTF-8 字节序列,然后在字节层面做 BPE。这样词表的基础单元就是 256 个字节值,天然覆盖所有语言和符号,不需要为每种语言单独设计字符集。GPT 系列、很多主流大模型用的都是这个思路。

BBPE 的好处是通用性极强,坏处是一个汉字在 UTF-8 下占 3 个字节,如果合并规则没覆盖到,就可能被切成 3 个词元。这就是为什么早期模型处理中文「贵」——不是模型歧视中文,而是字节层面的切分天然对多字节字符不友好。后来通过增加中文语料、优化合并规则,中文的压缩率才逐步提升。

3.3 Tokenizer 在工程里的位置

Tokenizer 不是一个抽象概念,它是一个实实在在的组件,通常包含两部分:

  1. 词表文件:记录每个词元对应的整数 ID,以及合并规则
  2. 编解码逻辑:把文本转成 ID 序列(encode),把 ID 序列转回文本(decode)

在实际项目里,Tokenizer 的位置非常靠前:你的原始文本 → Tokenizer → ID 序列 → 模型 → 输出 ID 序列 → Tokenizer → 文本。它就像翻译官,负责在「人类语言」和「模型语言」之间转换。

这里有个容易踩的坑:不同模型的 Tokenizer 是不通用的。你用 A 模型的 Tokenizer 去数 B 模型的词元,结果一定不准。因为词表和合并规则完全不同。我见过有人拿一个通用分词库去估算所有模型的用量,最后账单出来差了 30%,这就是原因。

注意:做成本预估时,必须用目标模型官方提供的 Tokenizer。很多平台都提供了在线分词工具或者 SDK,直接调用最准。

4. 词元为什么能当「水电费」:计费逻辑与成本结构

4.1 输入词元和输出词元,价格不一样

这是很多人第一次看账单会懵的地方:输入(prompt)和输出(completion)的单价通常不同,输出往往更贵。

为什么?因为输入是并行的,模型一次性读完所有输入词元,计算效率高;输出是串行的,模型每生成一个词元都要做一次完整的前向计算,还要维护 KV Cache,计算资源和时间成本都更高。所以输出定价通常是输入的 2 到 4 倍,具体看厂商。

这意味着一个反直觉的结论:如果你的应用是「长输入、短输出」,成本可能比「短输入、长输出」低很多。比如做文档摘要,输入几千词元、输出几百词元,成本其实可控;但做开放式对话,输出可能很长,成本就上去了。

4.2 上下文长度也是按词元算的

模型的「上下文窗口」指的是它能一次性处理的词元总数,包括输入和输出。比如标称 8K 上下文,意思是输入加输出总共不能超过 8192 个词元。

这里有个实际开发中的坑:你以为你只发了 3000 字,实际可能已经 6000 词元了。尤其是中文、代码、JSON 这类文本,词元密度很高。我做过一个测试,一段 2000 字的中文技术文档,用某模型的分词器数出来接近 3500 词元。如果你按字数估算上下文占用,很容易超限。

超限的后果通常是接口直接报错,或者模型悄悄截断前面的内容。后者更危险,因为你不报错,但模型「忘了」你前面说的话,回答质量莫名其妙下降,排查起来很费劲。

4.3 一个实际的成本估算例子

假设你在做一个客服机器人,日均 1 万次对话,每次对话平均输入 800 词元、输出 300 词元。用某模型的定价(假设输入 1 元/百万词元,输出 3 元/百万词元)来算:

  • 日输入词元:10000 × 800 = 8,000,000 = 8M
  • 日输出词元:10000 × 300 = 3,000,000 = 3M
  • 日输入成本:8 × 1 = 8 元
  • 日输出成本:3 × 3 = 9 元
  • 日总成本:17 元
  • 月成本:约 510 元

看起来不多,但如果你的输入里带了很长的系统提示词、历史对话、知识库检索结果,输入词元可能轻松翻 5 倍,月成本就上到两三千。这就是为什么很多团队会专门做「提示词压缩」和「上下文裁剪」。

成本项计算方式优化方向
输入词元系统提示 + 历史 + 检索 + 用户输入精简提示词、裁剪历史、检索结果去重
输出词元模型生成内容限制 max_tokens、优化提示词让回答更简洁
缓存部分平台对重复前缀有缓存优惠把固定内容放前面,利用前缀缓存

5. 不同模型的词元差异:为什么同一句话「价格」不同

5.1 词表大小与压缩率的权衡

不同模型的词表大小差异很大,常见的有 3 万、5 万、10 万、15 万甚至更大。词表越大,单个词元能覆盖的内容越多,压缩率越高,同样文本的词元数越少;但词表大也意味着模型最后一层的参数更多,训练和推理成本上升。

这是一个典型的工程权衡。厂商会根据目标语言分布、应用场景来选词表大小。比如主打中文的模型,词表里中文词元的占比会更高,中文压缩率更好;主打代码的模型,会专门优化代码片段的合并规则。

5.2 中英文词元比例的实际差异

我做过一组粗略测试,用几款常见模型的分词器,对同一段中英文对照文本数词元:

文本类型字符数词元数(模型 A)词元数(模型 B)比例
中文技术文档500约 620约 4801.24 : 0.96
英文技术文档500约 130约 1250.26 : 0.25
Python 代码500约 180约 1700.36 : 0.34
JSON 数据500约 220约 2000.44 : 0.40

可以看到,中文的词元/字符比明显高于英文,这就是中文应用成本偏高的直接原因。但不同模型之间也有差异,模型 B 对中文的压缩明显更好。所以选模型时,除了看效果和价格,也要看它对你这门语言的词元效率。

5.3 特殊内容对词元的影响

有些内容特别「吃」词元,做应用时要特别注意:

  • 代码缩进:大量空格和制表符会占词元
  • JSON/XML:括号、引号、键名都会占词元
  • Base64 编码:几乎每个字符都是独立词元,密度极高
  • emoji 和特殊符号:往往占多个词元
  • 数字:长数字串可能被逐位切分

我踩过的一个坑是:把图片转成 Base64 塞进 prompt,结果一张小图就吃掉几千词元,成本直接爆炸。后来改成用视觉接口或者先做 OCR 提取文字,成本降了一个数量级。

6. 实操:怎么准确统计和优化词元用量

6.1 用官方 Tokenizer 实测

最靠谱的办法永远是实测。以 Python 为例,很多模型都提供了分词器库,调用方式大同小异:

# 以某常见分词器库为例,具体包名以官方文档为准 from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("模型名称") text = "你好,这是一段测试文本。" tokens = tokenizer.encode(text) print("词元数:", len(tokens)) print("词元内容:", tokenizer.convert_ids_to_tokens(tokens))

跑一遍你就能看到每个词元被切成了什么,非常直观。我建议在项目初期就写一个小工具,把典型请求的输入输出都过一遍分词器,建立自己的「词元画像」。

6.2 建立成本监控

光会数还不够,要在生产环境里持续监控。我的做法是在调用模型接口的封装层里,记录每次请求的输入词元、输出词元、耗时、模型名,然后汇总到监控面板。这样你能清楚看到:

  • 哪些功能最耗词元
  • 哪些用户的请求特别长
  • 成本趋势是否异常

没有监控的话,成本问题往往是月底看账单才发现,那时候已经晚了。

6.3 几个实用的省钱技巧

第一,精简系统提示词。很多项目的系统提示词写了几百上千字,里面一半是废话。把重复的、可以合并的、模型本来就知道的内容删掉,能省不少。

第二,利用前缀缓存。部分平台对相同前缀的请求有缓存优惠,把固定不变的内容(系统提示、知识库公共部分)放在最前面,能命中缓存。

第三,裁剪历史对话。不要无脑把全部历史都带上,用滑动窗口或者摘要的方式保留关键信息。

第四,控制输出长度。设置合理的 max_tokens,并在提示词里明确要求简洁回答。

第五,选对模型。简单任务用便宜的小模型,复杂任务才上大模型,不要一刀切。

提示:省钱的前提是不牺牲效果。我见过为了省词元把提示词砍得面目全非,结果模型答非所问,用户投诉反而更多。优化要在效果和成本之间找平衡点。

7. 常见问题与排查实录

7.1 为什么我数出来的词元和账单对不上

这是最高频的问题。原因通常有几个:一是用了错误的分词器;二是没算上系统自动添加的特殊词元(比如对话模板里的角色标记);三是平台可能对某些内容做了额外处理。解决办法就是用官方工具实测,并且把请求完整内容(包括模板)都算进去。

7.2 中文为什么比英文贵这么多

本质是词元效率问题。中文在字节级分词下天然占更多词元,加上早期语料中中文占比低,合并规则对中文不友好。改善办法是选对中文优化好的模型,或者在提示词层面做精简。

7.3 上下文超限了怎么办

先确认是真的超限还是估算错误。如果确实超了,方案有:裁剪历史、压缩检索结果、分段处理、换更大上下文的模型。不要指望模型自动处理超长输入,大多数情况下它会截断或报错。

7.4 词元用量突然暴涨怎么排查

按这个顺序查:是不是有用户发了超长输入;是不是某个功能改了提示词;是不是检索模块返回了过多内容;是不是输出没限制长度。我遇到过一次是知识库检索的 top_k 被误改成 50,每次请求塞进去几万词元,查了半天才发现。

问题现象可能原因排查方法
账单远高于预估分词器用错、特殊词元未计用官方工具实测完整请求
中文成本偏高模型中文压缩率差对比不同模型词元数
上下文报错实际词元超限实测输入词元数
用量突增提示词或检索变更检查近期代码改动
输出被截断max_tokens 设置过小调整输出上限

7.5 一个容易被忽略的细节:对话模板

很多对话模型在底层会把你的消息包装成特定格式,比如加上<|user|>、<|assistant|>这类标记。这些标记也占词元,而且每次请求都会带上。如果你做多轮对话,这些标记会累积。做精确估算时一定要把它们算进去,否则会系统性低估。

8. 我对「词元」这个概念的一点个人体会

「词元」这个中文名定下来,我觉得最大的价值不是翻译本身,而是让更多非技术背景的人能参与到讨论里来。以前跟产品经理说「token 用量」,对方一脸茫然;现在说「词元消耗」,至少能理解这是「模型处理文本的计量单位」,沟通顺畅多了。

从工程角度看,词元这个概念提醒我们一件事:大模型不是魔法,它是有明确计量单位的计算过程。你输入的每一段文字、模型输出的每一个字,背后都是可量化、可优化的成本。做 AI 应用,不能只盯着效果,也要盯着词元效率。一个效果 90 分但词元消耗是别人 3 倍的方案,在规模化之后会非常痛苦。

我自己现在的习惯是,任何新功能上线前,先跑一遍典型请求的分词统计,估算日成本,再决定要不要做、怎么做。这个习惯帮我避免了好几次「上线即亏损」的尴尬。词元这东西,平时不起眼,但它确实是 AI 世界的「水电费」——用的时候没感觉,账单来了才知道疼。