在第 1 章我们提到过,在讲人工智能时,很多时候我们会用类比人类学习的方式来解释“机器是怎么学会东西的”。
比如你现在读一段话,理解它的过程其实很复杂:随着年龄增长,你的理解方式也在变,而且还涉及到很多同时发生的思维活动。这套机制相当高级。
但大型语言模型(LLM)就没那么复杂了,它的“理解”方式,反而简单得多。
它用的是基于神经网络的算法,目的就是从大量文本数据中捕捉“词和词之间的关系”,然后基于这些关系去“理解”句子,甚至生成新的句子。
我们要讲 LLM 是怎么运作的,得先从它的“输入”开始说起——也就是:它是怎么处理句子的?
这一章我们就来讲讲这个过程:当你给 LLM 输入一句话,它是怎么一步步“转化”成模型能理解的东西的。
你可以把这理解为:就像语言是我们人类思考的核心,输入文本的方式,也会直接影响 LLM 能理解什么内容、能完成哪些任务。
2.1 Token:让文字变成“数字语言”
你可能觉得,“LLM 处理一句话”这不就是它本来该干的事吗?但如果你真的想搞清楚 LLM 怎么运作,就得更具体一点看。
虽然人类用自然语言说话没啥问题,但对神经网络来说,文本是“不自然”的输入方式。
因为神经网络本质上是靠数字在运作的。
所以,像图 2.1 展示的那样:在 LLM 真正“理解”一句话之前,第一步其实是把文字转换成数字形式。
这种转换的结果,就是所谓的 token ——分词器把一段文本拆成“可处理的小片段”,然后这些片段就可以被编码成数字,供 LLM 进一步处理。
你可以把 token(分词单元) 想象成 LLM 在处理文本时所看到的最小单位——就像语言的“原子”,万物都是由它构成的。
那么,语言的“原子”到底是什么?
想想你自己在读这本书时,你大脑用的最小“理解单位”是什么?两个最自然的答案是:字母和单词。
很容易就会觉得字母才是“最小单位”,因为单词是由字母组成的嘛。但你真的在阅读时,是一个字母一个字母读出来的吗?
对大多数人来说,答案是:“并不会”。
(当然啦,如果你像本书一位作者那样患有阅读障碍,那这个问题可能显得有点怪。但语言处理这事儿本身就很复杂,请大家允许我们用点类比来解释 🤓)
其实,我们在读的时候,往往是看词的整体结构,甚至只看词的一部分。
比如:
“In fbct, yoy cn probbly unrestand ths sentnce ever through we diddt sue th ryght cpellng or l3ttrs. ”
是不是虽然拼写乱七八糟,但你居然还是看懂了?
这就说明:人类其实是靠“词的一部分”来理解句子的,而 LLM 的构造方式,也是基于这个原理。
所以这一章,我们会讲两个重点:
- Token 是什么,怎么理解?
- 一整句话到底是如何被切成 tokens 的?
2.2 语言模型只看得见 Tokens
一般来说,大多数以英语为母语的成年人,大概掌握了 3 万个左右的词汇。而 GPT-3(ChatGPT 最早背后的模型)用的“词库”是 50,257 个 token。
注意:这里说的 token 并不是“完整的单词”,而是所谓的 “子词” (subword)——介于“单词”和“字母”之间的一种语义单位。
你可以把它理解为:token 是一句话中 最小的、还能带有一点语义的单位。
比如:
schoolhouse
这个词,通常会被拆成两个 token:school
和house
thoughtful
也会被拆成thought
和ful
这样做有什么好处?
- 第一,它可以更好地识别常见词;
- 第二,它能在你遇到从没见过的新词时,也有机会靠“词根”来理解。
你是不是也经常会看到一个生词,通过拆解它的构成大致猜出它的意思?这在语言学里叫 语义分解(semantic decomposition) ,人类会做这件事,LLM 也是一样。
把数据转换成算法能理解的形式,这在机器学习里叫 特征工程(feature engineering) 。
举个例子:如果你要做一个算法,判断一句话是用哪种语言写的。你可以写一段代码,把句子拆开,数一下每个字符出现了几次。
比如,如果 é
这个字母出现得特别多,那这个文档很可能是法语或西班牙语,而不是俄语或中文。
特征工程的核心是:你得先明白你模型怎么工作、你想实现什么目标、然后再准备适合这个目标的数据。
而在 LLM 里,分词(tokenization)就是它的特征工程。
它非常非常重要,因为:
对 LLM 来说,它看到的唯一信息就是 tokens。
它不看文字、不看拼写、不看文法结构,它只看数字化之后的 token。
在图 2.1 里你可能已经注意到:
-
Dis
和dis
,虽然人类一眼就看出是同一个词(只是首字母大小写不同) -
但模型会给它们完全不同的数字编码,比如:
Dis
是 token 编号 4944dis
是 token 编号 834
换句话说:
模型根本看不出它们俩是相关的。它看到的只是两个数字而已。
所以,我们可以这样理解:
- 一个 token 就是:子词 ➜ 数字 的一个映射
- Tokenization 就是:一句完整的话 ➜ 一串 tokens 的转换过程
如果你之前用过机器学习的 NLP 工具,可能接触过一些“简单版”的分词方法,比如:按空格切词。
但这种做法有局限:
- 它无法识别子词
- 它不适用于那些没有空格分词的语言(比如中文)
这就是为什么现代 LLM 使用的分词器都更复杂、更智能,它能根据语义和词频,把一段话切成更有意义的 token。
2.2.1 分词的全过程是怎样的?
我们可以参考图 2.2 来看一下通用的 Tokenization(分词) 流程,它主要分成 四个关键步骤:
1️⃣ 获取要处理的文本
这一步说起来简单:就是你得先拿到一段文本。来源可能是:
- 用户输入的内容
- 网络上抓取的数据
- 文件、网页、数据库等等
总之,我们拿到的就是一段字符串(string)——由字母、数字、符号组成。
2️⃣ 规范化处理字符串(Normalization)
有了字符串之后,我们通常会先对它进行一些“预处理”,比如:
- 把所有大写字母转换成小写字母
- 移除多余的空格或标点
- 清洗掉一些潜在的恶意字符(比如用户可能输入脚本代码)
这一操作叫做 规范化(normalization) ,目的是让模型更容易学到有用的东西,避免被无关差异干扰。
3️⃣ 把字符串拆成一个个 Token(Segmentation)
接下来,就是正式的“分词”环节了。
这一步会把一整段文本按一定规则切割成一个个小的子串(也就是 token) 。这些 token 可能是词、词的一部分,或者是非常高频的前缀、后缀。
比如:
unbelievable
可能会被拆成un
、believe
、able
learning
可能会被拆成learn
和ing
这一步叫做 分段(segmentation) 。
4️⃣ 把每个 Token 映射成唯一编号
最后一步是:把这些 Token 映射成唯一的数字编号(ID) 。
这些编号通常是整数,只有数字才能被 LLM 真正“看见”。
比如:
learn
➜ 2834ing
➜ 517
模型处理的就是这些编号,而不是我们看到的字母和单词。
整个流程总结一下就是:
原始文本 ➜ 预处理(规范化) ➜ 分词 ➜ 数字编码
让人类语言变成 LLM 能理解的“数字语言”。
我们刚才讲的四步里,第一步(拿到文本)和最后一步(给 Token 编号) ,基本上是没什么选择空间的:
- 你得有输入,不然模型啥都干不了;
- 你得把每个 Token 编上号,不然模型没法把它当数字用。
但中间两步——规范化(normalization) 和 分词(segmentation) ——就有很多“操作空间”了,可以根据实际需求来调整策略。
在最后这一步,模型的“词汇表”(vocabulary)就诞生了。
词汇表可以理解为:模型训练过程中所见过的所有“唯一 token”的总集合。换句话说,模型在学东西的时候,每发现一个新 token,就把它加进词汇表里。
要构建一个丰富的词汇表,就得喂给模型大量的数据,这样才能涵盖更多样的词和子词。
但这也不是越大越好——构建词汇表时要在多个因素间做权衡:
想象一下,一个只有几十个词汇量的一岁小孩,沟通能力肯定不太行(但这很正常,他们还有时间慢慢学)。
同样道理,词汇量越大,模型能表达和理解的东西就越多。
可问题是:
如果词汇表太大,会怎样?
- 模型处理起来会更慢;
- 占的内存或磁盘空间也更大;
- 移植起来更麻烦,比如你要部署到手机、嵌入式设备、游戏主机时,空间就成了大问题。
所以我们在训练时要做取舍:既要词汇够多,覆盖广,又不能太大,不然难以部署。
构建词汇表的过程其实很简单:
- 每碰到一个新 token,就分配一个新的编号;
- 通常只需要一个计数器从 0 开始递增就够了。
最终你会得到一个“分词器”(tokenizer),它就像一个编码器:
它可以接收一段文本,返回一串数字(token ID),供 LLM 使用。
2.2.2 如何控制分词时的词汇量?
以开源模型 GPT-NeoX 为例:
它的词汇表光存储在磁盘上就需要将近 10GB 的空间。
这体积已经大得惊人了:
- 你要是放在 micro-SD 卡 里读取,基本会慢得让人怀疑人生;
- 想部署在手机或游戏机上,基本没戏;
- 想在线流式传输?更不现实,必须一次性下载并加载进内存才能运行。
但话说回来:
模型的词汇表也不能太小。为什么?
因为如果模型在训练或使用中遇到某个词:
- 它既不在词汇表里;
- 又不能被拆分成“模型认识的子词”;
那就 GG 了——这个词的相关信息,模型压根没法理解或处理。
这种情况在自然语言处理(NLP)里有个专门的名字:
叫做 “词表外问题”(out-of-vocabulary, OOV) 。
它的本质就是:
模型的词汇表不够用,没法覆盖所有输入。
词汇表大小,实际上也是影响 LLM 体积的一个关键因素。
所以我们必须讨论:
- 怎样通过调整分词策略,来控制词汇表的大小;
- 怎么在词汇覆盖率、模型能力、准确性之间做取舍。
接下来这一小节,就会详细讲:分词器设计的变化,是怎么影响词汇表大小,进而影响模型表现的。
我们来看图 2.3,它重点展示了分词过程中的第二步:规范化(normalization) 。
举个例子,它会把 “H” 和 “W” 这样的大写字母转换成小写,同时也会移除标点符号。
这些做法其实早在“传统 NLP 时代”就已经被广泛使用了,在一些现代深度学习模型中也还在继续使用。它们的最大优点是:
能有效减少词汇表的体积。
比如,不需要把 “Hello” 和 “hello” 当成两个不同的 token,而是可以统一成一个。这看起来只是个小优化,但实际影响非常大!
因为很多句子开头的单词首字母是大写的,如果不做小写处理,你的词汇表里就得再放一遍这些词的“首字母大写版”——直接把词表翻倍,你懂的 🤯。
这个转换操作对于各种拼写错误、大小写混用也很有用。
我们在写这本书的时候,就多次打错了 “LLMs”:什么 “LLms”、 “llms”,甚至奇奇怪怪大小写混搭。
如果把所有字符统一转换成小写,就可以把这些错别字都归一成一种形式,这不就又减少了词汇混乱,还顺便优化了处理效率。
但话说回来,小写化并不总是好事。
比如你看到 “Bill” 和 “bill”:
- 前者多半是人名(比如比尔·盖茨);
- 后者很可能是账单、钞票,或者别的含义。
这个时候,大小写就是决定意思的关键因素了。
不仅如此,如果模型能够区分大小写,它还能识别出错误——比如我们前面拼错的那些 “LLms”。一个高质量的 AI 模型应该能看出:“嗯,这是写错了,我来帮你改。”
像 ChatGPT 这样的大模型,确实能做到这些事,所以它的模型在训练时保留了大小写信息,没有一味地全转成小写。
这就引出一个很重要的权衡点:
要不要为了缩小词汇表,牺牲一部分模型的理解能力?
在传统 NLP 和早期的深度学习模型(比如 BERT,ChatGPT 的“前辈”之一)里,大多数模型几乎不能自动识别和纠正拼写错误,除非你专门为这件事设计算法。
所以过去 NLP 很看重“规范化预处理”,但在 LLM 时代,这部分工作被大幅简化了。因为:
- 现代模型词汇表更大
- 模型更强大,可以直接学会理解拼写错误
2.2.3 深入理解分词(Tokenization)细节
前面我们提到,规范化 和 分词 这两个步骤,几乎决定了词汇表的大小。
在图 2.4 中,我们展示了一种非常基础的分词策略。它的规则很简单:
“看到空格就切开”。
比如你输入的是 "hello world"
,那么它就直接变成:
"hello world".split(" ")
# ➜ ['hello', 'world']
是不是感觉挺自然的?这也是我们人类阅读句子的方式:按空格分词。
但注意哦,这种方法虽然直观,其实也带来一些隐形的复杂性。
你有没有想过,如果输入文本里有标点符号,会发生什么?
比如我们用前面讲的“遇到空格就切词”的方法,来处理这句话:
"hello, world"
结果就会变成这样:
["hello,", "world"]
看上去没毛病吧?但仔细想想,这里我们其实得到了两个不同的 token:
"hello"
和"hello,"
(多了一个逗号)
这和我们前面说的大小写问题类似:两个本质相同的词,因为形式稍有不同,就被当成了两个 token。这不仅增加了词汇表的大小,还可能导致模型理解出偏差。
以前的做法是——移除标点,然后写一堆规则来分词。虽然这也算是一种“优化”,但仍然存在很多问题。
最明显的问题就是:
规则式分词法(rule-based tokenization)对中文这类不空格分词的语言很不友好。
中文里没有空格啊!
如果你还在靠“空格分词”或“标点符号切词”,那在处理中文时就直接崩溃了。模型甚至不知道“今天下雨”是三个词,还是一个“超级词”。
使用 BPE(Byte Pair Encoding)来识别子词
现代的大语言模型(LLMs)有个基本原则:
别手工造轮子,把这些“分词工作”交给算法来自动完成。
因此,大多数 LLM 都采用了一种叫 BPE(字节对编码) 的算法来自动分词。
这个算法的核心目标是:
把单词拆成一些常见的“子词片段” (subword units)
BPE 分词时,通常不怎么做规范化(比如不会统一大小写、也不特意清除标点)。它直接对字符串本身进行分析。
💡 小贴士:
一些 ChatGPT 类产品会悄悄移除某些奇怪的 Unicode 字符(那些不可见但会干扰编码的字符),但整体上都是尽可能保留原文。
而“到底该不该规范化、怎么规范化”——目前在 NLP 领域仍然是一个开放问题,没标准答案。
那么 BPE 是怎么分词的呢?
其实,它没有去暴力枚举“最优子词组合”——那样计算量太大了。
它用的是一种启发式策略(也就是“靠经验猜出来的好方案”):
BPE 的分词流程大致如下:
- 一开始,把每个字母都当成一个 token。
- 接下来,算法会扫描整个文本,找到出现频率最高的“相邻字母对” 。
- 把这两个字母合并成一个新的 token。
- 重复这个过程,一遍又一遍,直到词汇表够小为止。
举个例子:
英文里,“i”、“n”、“g”经常会挨在一起出现。
- 在第一轮扫描中,BPE 发现 “n” 和 “g” 一起出现的频率比 “i” 和 “n” 更高,于是先把
n
和g
合并成一个 token:ng
。 - 下一轮,它又发现
i
和ng
出现得也很频繁,于是把它们合并成ing
。
这样,在多个词中,比如 eating
、drinking
、thinking
,都能重用这个 ing
的 token。
最终,BPE 得到的词汇表会包含:
- 一些完整单词(比如 eating);
- 也包含一些子词片段(比如 eat、ing、drink 等);
- 所以模型就能通过拼装这些 token,去表达更多的词。
这个整个流程在图 2.5 中有一个高级别的展示。
💡 注意:
别看 BPE 这个算法思路挺简单,但真正运行起来是挺“烧钱”的,因为它需要反复多次扫描大量文本,才能统计出哪些字母组合最常出现。
而且别忘了,大型语言模型的训练数据是几亿甚至几十亿网页起步的!但为了节省时间,BPE 的训练其实只会用一小部分文本来生成词表——通常只用几本小说那么大的量就够了。
把 BPE 当作“找高频短语”的算法来看就简单了。
比如,BPE 通常会学会把 “New York” 看成一个整体 token。
毕竟 “纽约” 在各种文本里都出现得非常频繁。
能把 “New York” 当作一个 token,有助于模型更好地识别它的整体语义——它不是“新 + 约”,而是一个地名。
大多数常见词,最终都会在词汇表里拥有一个独立的 token;而那些不常见的词呢,则会被拆成几段来表示。
比如:
单词 loquacious,在 GPT-4 中会被切成
lo
、qu
和acious
三个 token。
这其实是成功也是失败:
- ✅ 成功点在于: “acious” 是一个常见的后缀,表示“倾向于…” ,模型识别了它,挺聪明;
- ❌ 失败点在于: “loqu” 本身是拉丁语前缀,表示“说话”,结果它被拆成了
lo
和qu
,丢了意义。
这说明:BPE 并不完美,它是基于频率来猜“该不该合并”的,而不是语言学家式的精准语义拆解。
BPE 完成词表构建后,模型作者还会“手动添加”一些额外的 token。
为什么?因为某些词对特定行业或领域非常重要,比如:
- 医疗专业术语
- 法律专用词汇
- 编程语言关键词
这些词不一定是高频,但你总得能处理吧?所以需要提前塞进词汇表里。
模型开发者还会添加一些 “特殊 token” ,比如:
token | 用途说明 |
---|---|
[UNK] | unknown,用来表示“无法识别”的字符或词 |
[SYSTM] | 表示系统提示,用来区分系统内容和用户输入 |
[IMG] | 在多模态模型中,用来表示“从这里开始是图片输入” |
OpenAI 在开发 ChatGPT 的时候,选用了 BPE 作为默认的分词算法,并把它做成了开源工具包 tiktoken。
当然,市面上还有别的分词算法,比如:
- WordPiece(Google 发明,用于 BERT)
- SentencePiece(也是 Google 的,用于多语言支持)
这些算法跟 BPE 很像,但各自有不同的“权衡点”:
- WordPiece 用了不同的词频计算方法;
- SentencePiece 会保留空格信息,对处理多语言任务(比如中英混合)更友好;
- 不过,目前行业里使用最广的还是 BPE,连 Google 自家最新的 LLM 都用它。
不管选哪个算法,一个关键参数永远绕不开:
👉 词汇表的大小。
这是训练 LLM、设计 tokenizer 时,数据科学家必须决定的核心参数之一。
接下来的几节,我们会详细讲:
- 如何控制词表大小?
- 词表的大小会影响什么?
- 分词策略可能带来哪些“坑”?
2.2.4 分词(Tokenization)可能带来的风险
在第 1 章我们说过,这本书不会涉及太多编程。我们真正想做的,是:
✅ 帮你理解 LLM 是怎么工作的;
✅ 拆掉那些“看起来很神奇”的神秘感;
✅ 让你专注在: “它能帮我干啥?”
而分词,就是这个过程的第一步。它虽然看起来简单,但却是一个非常关键的步骤。
到目前为止,你已经了解了:
- ✅ 分词决定了模型能看懂什么内容;
- ✅ 词汇表的大小影响模型能不能部署到小设备、跑得快不快;
- ✅ 想表达得细致,就得词表大;词表太大又拖慢性能;
- ✅ 自动分词靠像 BPE 这样的算法来完成,不靠人工规则了。
但这些选择,不只是影响现在的模型,也会影响未来模型的发展。
接下来我们会说两个非常有意思、但又容易被忽视的分词“陷阱”:
陷阱一:句子变长 ≠ token 变多
这点听起来有点反直觉:句子变长了,token 数不一定就多。
举个例子(来自图 2.6):
- “I’m runnin”
- “I’m running”
第一句比第二句少一个字母,但你知道吗?
👉 它反而用了更多的 token!
是不是有点懵?你可以自己试试看:
👉 OpenAI Tokenizer 在线测试工具
这说明:token 的分法不是照着字母数来算的,而是根据模型分词器预设的规则进行的。
你可能会疑惑:“为啥 ‘running’ 比 ‘runnin’ 多了一个字母,反而用的 token 更少?”
其实这是 BPE 的“贪心策略”在作怪。
它会尽可能找训练语料中最常见的子串作为 token。
“running” 是高频词,自然有一个独立 token。
而“runnin” 呢?这种拼写只偶尔在非正式口语中出现,BPE 没认出来,就只能拆成两个 token,比如 run
和 nin
。
这就是我们之前说的词表“覆盖能力”问题:分词方式不同,模型处理同一句话的方式就变了。
🐞 这也会引发软件 bug
不同的 tokenizer(比如你从 GPT-2 换成 GPT-4 的)可能对同一段文本给出完全不同的分词方式。
所以:
- 做测试的时候,千万别忽略 tokenizer 的版本;
- 如果你在更新模型或更换 tokenizer 后发现结果变化很大,不一定是模型烂了,有可能只是分词方式变了;
- 对一些对空格特别敏感的模型来说,tokenizer 的差异可能严重影响结果评价!
⚠️ 警惕“同形异码”字符(Homoglyph)攻击
这是在多语言处理、用户输入安全里一个常见的坑。
什么叫“同形异码”?
指两个字符长得一模一样,但底层编码不同。
比如:
- 西欧语言里的拉丁字母 “H”
- 东欧或中亚语言里用的西里尔字母 “Н”
它们在屏幕上看起来都是“H”,但编码不同,所以 tokenizer 会当成两个完全不一样的 token!
这会带来一堆麻烦:
- token 数激增,导致计算量暴涨;
- 模型理解出现偏差;
- 黑客甚至可以故意注入这类字符,让模型行为异常(比如绕过过滤系统)!
还有一种更“离谱”的字符:U+200B 零宽空格
你看不到它,它不占位,但 tokenizer 会认它是个字符!
你一不注意,可能加了几十个 token,模型算得累你还不知道为啥慢。
所以很多 tokenizer(比如 OpenAI 的 tiktoken)都做了默认清洗:
- 去掉“看不见”的字符;
- 统一“同形”字符为标准形式。
如果你要把模型部署在用户设备上,或者有用户输入参与的流程,必须小心 homoglyphs!
2.3 分词方式决定了 LLM 能力的“上限”
说到底,如果你只关心“生成的内容像不像人写的”,那么 tokenizer 怎么分词,其实影响不大——只要你用的是个大模型,算力堆上去了,结果大概率不会太差。
但!有些任务下,分词方式就变得超级重要。
本节会举一些例子,虽然不一定和你的实际业务直接相关,但有助于你理解:
“LLM 能力的边界,取决于它用什么样的 token 看世界。”
而这个“世界观”,一旦选定,就很难改。
所以如果你在做一个 LLM 应用,遇到某些奇怪 bug,或者模型总是答错某类问题——
👉 先考虑是不是分词方式的问题!
如果真的是 tokenizer 的锅,那很抱歉,你基本没法自己修……
要么:
- 自己手动改词表(高级玩法);
- 要么重新选一个 tokenizer;
- 实在不行就考虑换思路,比如用规则系统来弥补。
🤹 2.3.1 LLM 玩不好文字游戏
很多人喜欢拿 ChatGPT 玩文字类的小游戏,比如猜字母、找回文、数单词个数等等。
比如图 2.7 里的例子(暂略)展示了这样一个问题:
答案完全依赖于字母顺序和单词长度——而这正是 LLM 的弱点。
为啥?因为 tokenizer 把字符串切成了“语义单位”——也就是 subword,而不是按“每个字母”去理解。
举个例子:
- “loquacious” 被拆成
lo
、qu
和acious
; - 模型理解的是语义,不是精确拼写。
所以你让它判断哪个单词字母最多,它可能靠的是语感、词频、上下文,而不是数字母!
也就是说:
LLM 不是真的“按字母”处理文本的,分词把它们切割成“含义片段”了。
这也解释了为啥 ChatGPT 玩填字游戏、猜拼写、做英语选择题有时候“看着聪明,其实瞎蒙”。
🧠 玩文字游戏不重要,但暴露的问题很关键
你可能觉得:“我又不是做文字游戏 app,这事关我啥事?”
但问题不在于“游戏”,而在于——这类失败暴露了 LLM 的认知漏洞。
虽然看起来是小问题,甚至像玩笑题,但它揭示了模型在某些任务中根本性的短板,这些短板可能在别的地方也会影响你。
举个“实用场景”的例子👇
💊 药品问答系统,拼错一个字,模型全答错
设想你要开发一个能回答用户处方药问题的应用。
问题来了:很多药的名字又长又绕口,用户记不住、拼不对,太正常了。
而 LLM 不是“按字母”处理文本的——它靠分词器来“理解”词语,如果你拼错了几个字母,那模型可能完全识别不了这个词。
比如👇
- 正确拼写:
Amoxicillin
- 常见错拼:
Amoxicillan
你可能会以为“只错了一个字母,模型应该能猜出来吧?”
但 GPT-3 里这两个词被分成完全不一样的 token 组合,模型根本看不出它俩有关!
这会导致什么?
- 模型完全找不到正确的知识点;
- 极端情况下,模型可能把
Amoxicillan
当成另一个药名,答非所问; - 而在这种高风险场景下,一次误答可能就是灾难。
所以这类场景:
- 要 反复测试;
- 可能要自己加自定义的 tokenizer 或补充词表;
- 甚至要考虑是否适合用 LLM 来做,还是用更稳妥的规则引擎。
2.3.3 LLM 与语言公平性:有的语言天生“更贵”
从技术上讲,大多数 LLM 的 tokenizer 都支持 Unicode,所以它们“理论上”能处理世界上绝大多数语言的字符。
但问题是:处理得“好不好”差别巨大。
💡 tokenizer 对某些语言更友好
每种语言在训练语料中占的比例不同,tokenizer 在设计时往往参考了英文、法文、德文这类“高频语言”的数据。
而对于使用频率较低的语言,比如藏语、奥里亚语、桑塔利语,tokenizer 就没那么“贴心”了。
结果是什么?
- 这些“低频语言”的词,会被切成很多碎片化的 subword token;
- 这样一来,一个简单的词,在英语里可能是 1 个 token,在少数语言里可能是 5 个;
- 每个 token 都是要钱的,所以……这些语言的用户要多付几倍的钱。
💰 用不同语言,花的钱差别有多大?
大模型厂商,比如 OpenAI、Anthropic,普遍采用“按 token 收费”的方式。
每输入一句话、每生成一个词,都会消耗 token。
于是语言差异,直接变成了价格差异👇
- 德语、意大利语比英语贵 50%;
- 保加利亚语、图布卡语贵 2 倍;
- 藏语、奥里亚语、桑塔利语、掸语:贵 12 倍!
想象一下,如果你是个印度农村的开发者,使用桑塔利语构建应用——你的 API 成本是美国英语开发者的 12 倍。
这不光是技术问题,已经涉及到语言公平、数字不平等的伦理问题。
2.4 检查一下你是否掌握了这些概念
书中设置了几个小测试,让你自己玩一下 tokenizer 和 token 的知识点:
-
你觉得以下词语会被切成几个 token?
backstopped
large language models
Schoolhouse
- 一句长句子:“How you process sentences to understand them...”
👉 可以去这个网址试试:platform.openai.com/tokenizer
-
把上面的例子换成各种大写小写字母组合,再看看 tokenizer 怎么处理的?
-
用字母-数字加密模拟 LLM 的“思维”方式:
- W = 8,A = 4,I = 7,T = 2
- 那么 WAIT = 8472
- 给出一个等式:GO + SLOW = STOP
- 那你能猜出 STOP 是多少吗?
-
从技术角度讲,为什么 tokenizer 表达效率低的语言成本更高?
-
这是一个道德问题吗?
用非英语服务却要花更多的钱,这算歧视吗?
2.5 Tokenizer 不只是前处理,它是 LLM 的“眼睛”
这一章讲了很多细节,有点绕,但其实核心很简单:
tokenizer 决定了 LLM 能“看到”什么,怎么理解,能理解多少。
它是模型的第一道入口,是把文字变成“模型能理解的数字”的那一层。
一个设计得好的 tokenizer,能让模型更轻松地理解复杂的语言结构、细微的拼写错误、甚至多语言混合输入。
而 tokenizer 一旦设计不合理,哪怕是最强大的大模型,也会“看不懂”。
所以 tokenizer 决定了:
- 模型的训练效果;
- 模型的输出质量;
- 模型是否能跨语言使用;
- 甚至决定了你用起来到底要花多少钱!
接下来我们会继续探讨其他 LLM 的核心构件。它们与 tokenizer 一起,构成了整个大模型理解世界的“知识引擎”。
✨ 本章总结:Tokenizer 是 LLM 看世界的眼睛
要让大模型(LLM)理解人类的语言,第一步就是 “切词” ,也就是把句子转换成一个个小单元——我们叫它们 Token(标记) 。
这些 Token 就是模型处理文字的基本单位。
✅ Token 是什么?
Token 可能是一个完整的单词(比如 cat
),也可能是单词的一部分(比如 ca
和 t
)。
它不一定跟我们说话时习惯的“词”一一对应,而是更接近机器习惯的处理单位。
🛠 Tokenizer 是怎么干活的?
整个 Tokenization(切词)过程包含两个主要步骤:
- Normalization(标准化)
👉 把所有字母变成小写、统一一些奇怪的 Unicode 字符(比如长得像的“a”其实不是一个编码)。
这样可以避免模型看到“Hello”和“hello”就以为是两个不同的词。 - Segmentation(切分)
👉 把一长串文字切成更小的块。用的常见算法是 BPE(Byte Pair Encoding) ,它会自动学习哪些字母组合最常出现,从而把它们合并成 Token。
比如:
“drinking” 可能被切成 “drink”和“ing”,
“loquacious” 可能是 “lo”、“qu”、“acious”
🧠 Tokenizer 的产物:Vocabulary(词表)
训练 tokenizer 的过程,其实就是在建立一份词表(vocabulary):
- 把出现过的 token 都收集起来;
- 每个 token 分配一个唯一编号;
- LLM 训练、预测时都只看这些编号。
这份词表的大小就成了模型能力和性能的权衡点:
- 词表越大,模型能表达的内容越丰富;
- 但也会占用更多存储、内存,运行更慢。
💥 Tokenizer 的局限会影响模型能力
- Token 只是编号,模型并不知道哪些 token 有类似拼写、属于同一个词根;
- 如果词表没把“重要词”收录进去,比如特定行业术语或药品名,模型就很容易搞错;
- 没法理解单个字母或数字的 tokenizer,在做 数学计算、拼字游戏 时就会“拉垮”。
🔧 可以人为补充词表
为了让模型更好地支持某个行业(比如医学、法律),我们也可以手动补充一些 token,让它更懂专业术语。
甚至还能加入一些特殊 token,比如:
- [UNK] 代表“我不认识这个东西”;
- [SYSTM] 代表系统提示;
- [IMG] 代表图片输入开始……
总之,Tokenizer 是 LLM 的第一块“感官”,决定了它能看到多少、理解多少,也直接影响你最终的效果和成本。