让流浪汉都能学会的大模型教程——分词器:大语言模型眼中的“世界”是怎样的?

41 阅读29分钟

在第 1 章我们提到过,在讲人工智能时,很多时候我们会用类比人类学习的方式来解释“机器是怎么学会东西的”。

比如你现在读一段话,理解它的过程其实很复杂:随着年龄增长,你的理解方式也在变,而且还涉及到很多同时发生的思维活动。这套机制相当高级。

但大型语言模型(LLM)就没那么复杂了,它的“理解”方式,反而简单得多

它用的是基于神经网络的算法,目的就是从大量文本数据中捕捉“词和词之间的关系”,然后基于这些关系去“理解”句子,甚至生成新的句子。

我们要讲 LLM 是怎么运作的,得先从它的“输入”开始说起——也就是:它是怎么处理句子的?

这一章我们就来讲讲这个过程:当你给 LLM 输入一句话,它是怎么一步步“转化”成模型能理解的东西的。

你可以把这理解为:就像语言是我们人类思考的核心,输入文本的方式,也会直接影响 LLM 能理解什么内容、能完成哪些任务

2.1 Token:让文字变成“数字语言”

你可能觉得,“LLM 处理一句话”这不就是它本来该干的事吗?但如果你真的想搞清楚 LLM 怎么运作,就得更具体一点看。

虽然人类用自然语言说话没啥问题,但对神经网络来说,文本是“不自然”的输入方式

因为神经网络本质上是靠数字在运作的。

所以,像图 2.1 展示的那样:在 LLM 真正“理解”一句话之前,第一步其实是把文字转换成数字形式。

这种转换的结果,就是所谓的 token ——分词器把一段文本拆成“可处理的小片段”,然后这些片段就可以被编码成数字,供 LLM 进一步处理。

1.jpg

你可以把 token(分词单元) 想象成 LLM 在处理文本时所看到的最小单位——就像语言的“原子”,万物都是由它构成的。

那么,语言的“原子”到底是什么?

想想你自己在读这本书时,你大脑用的最小“理解单位”是什么?两个最自然的答案是:字母单词

很容易就会觉得字母才是“最小单位”,因为单词是由字母组成的嘛。但你真的在阅读时,是一个字母一个字母读出来的吗?

对大多数人来说,答案是:“并不会”。

(当然啦,如果你像本书一位作者那样患有阅读障碍,那这个问题可能显得有点怪。但语言处理这事儿本身就很复杂,请大家允许我们用点类比来解释 🤓)

其实,我们在读的时候,往往是看词的整体结构,甚至只看词的一部分。

比如:

In fbct, yoy cn probbly unrestand ths sentnce ever through we diddt sue th ryght cpellng or l3ttrs.

是不是虽然拼写乱七八糟,但你居然还是看懂了?

这就说明:人类其实是靠“词的一部分”来理解句子的,而 LLM 的构造方式,也是基于这个原理。

所以这一章,我们会讲两个重点:

  1. Token 是什么,怎么理解?
  2. 一整句话到底是如何被切成 tokens 的?

2.2 语言模型只看得见 Tokens

一般来说,大多数以英语为母语的成年人,大概掌握了 3 万个左右的词汇。而 GPT-3(ChatGPT 最早背后的模型)用的“词库”是 50,257 个 token

注意:这里说的 token 并不是“完整的单词”,而是所谓的 “子词” (subword)——介于“单词”和“字母”之间的一种语义单位。

你可以把它理解为:token 是一句话中 最小的、还能带有一点语义的单位

比如:

  • schoolhouse 这个词,通常会被拆成两个 token:schoolhouse
  • thoughtful 也会被拆成 thoughtful

这样做有什么好处?

  • 第一,它可以更好地识别常见词;
  • 第二,它能在你遇到从没见过的新词时,也有机会靠“词根”来理解。

你是不是也经常会看到一个生词,通过拆解它的构成大致猜出它的意思?这在语言学里叫 语义分解(semantic decomposition) ,人类会做这件事,LLM 也是一样。

把数据转换成算法能理解的形式,这在机器学习里叫 特征工程(feature engineering)

举个例子:如果你要做一个算法,判断一句话是用哪种语言写的。你可以写一段代码,把句子拆开,数一下每个字符出现了几次。

比如,如果 é 这个字母出现得特别多,那这个文档很可能是法语或西班牙语,而不是俄语或中文。

特征工程的核心是:你得先明白你模型怎么工作、你想实现什么目标、然后再准备适合这个目标的数据。

而在 LLM 里,分词(tokenization)就是它的特征工程。

它非常非常重要,因为:

对 LLM 来说,它看到的唯一信息就是 tokens。
它不看文字、不看拼写、不看文法结构,它只看数字化之后的 token。

在图 2.1 里你可能已经注意到:

  • Disdis,虽然人类一眼就看出是同一个词(只是首字母大小写不同)

  • 但模型会给它们完全不同的数字编码,比如:

    • Dis 是 token 编号 4944
    • dis 是 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 可能会被拆成 unbelieveable
  • learning 可能会被拆成 learning

这一步叫做 分段(segmentation)

4️⃣ 把每个 Token 映射成唯一编号

最后一步是:把这些 Token 映射成唯一的数字编号(ID)

这些编号通常是整数,只有数字才能被 LLM 真正“看见”。

比如:

  • learn ➜ 2834
  • ing ➜ 517

模型处理的就是这些编号,而不是我们看到的字母和单词。

整个流程总结一下就是:

原始文本预处理(规范化)分词数字编码
让人类语言变成 LLM 能理解的“数字语言”。

1.jpg

我们刚才讲的四步里,第一步(拿到文本)和最后一步(给 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 体积的一个关键因素。

所以我们必须讨论:

  • 怎样通过调整分词策略,来控制词汇表的大小;
  • 怎么在词汇覆盖率、模型能力、准确性之间做取舍。

接下来这一小节,就会详细讲:分词器设计的变化,是怎么影响词汇表大小,进而影响模型表现的。

1.jpg

我们来看图 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']

是不是感觉挺自然的?这也是我们人类阅读句子的方式:按空格分词。

但注意哦,这种方法虽然直观,其实也带来一些隐形的复杂性

1.jpg

你有没有想过,如果输入文本里有标点符号,会发生什么?

比如我们用前面讲的“遇到空格就切词”的方法,来处理这句话:

"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 的分词流程大致如下:

  1. 一开始,把每个字母都当成一个 token
  2. 接下来,算法会扫描整个文本,找到出现频率最高的“相邻字母对”
  3. 把这两个字母合并成一个新的 token。
  4. 重复这个过程,一遍又一遍,直到词汇表够小为止。

举个例子:

英文里,“i”、“n”、“g”经常会挨在一起出现。

  • 在第一轮扫描中,BPE 发现 “n” 和 “g” 一起出现的频率比 “i” 和 “n” 更高,于是先把 ng 合并成一个 token:ng
  • 下一轮,它又发现 ing 出现得也很频繁,于是把它们合并成 ing

这样,在多个词中,比如 eatingdrinkingthinking,都能重用这个 ing 的 token。

最终,BPE 得到的词汇表会包含:

  • 一些完整单词(比如 eating);
  • 也包含一些子词片段(比如 eat、ing、drink 等);
  • 所以模型就能通过拼装这些 token,去表达更多的词。

这个整个流程在图 2.5 中有一个高级别的展示。

1.jpg

💡 注意:

别看 BPE 这个算法思路挺简单,但真正运行起来是挺“烧钱”的,因为它需要反复多次扫描大量文本,才能统计出哪些字母组合最常出现。

而且别忘了,大型语言模型的训练数据是几亿甚至几十亿网页起步的!但为了节省时间,BPE 的训练其实只会用一小部分文本来生成词表——通常只用几本小说那么大的量就够了。

把 BPE 当作“找高频短语”的算法来看就简单了。

比如,BPE 通常会学会把 “New York” 看成一个整体 token。
毕竟 “纽约” 在各种文本里都出现得非常频繁。

能把 “New York” 当作一个 token,有助于模型更好地识别它的整体语义——它不是“新 + 约”,而是一个地名。

大多数常见词,最终都会在词汇表里拥有一个独立的 token;而那些不常见的词呢,则会被拆成几段来表示。

比如:

单词 loquacious,在 GPT-4 中会被切成 loquacious 三个 token。

这其实是成功也是失败:

  • ✅ 成功点在于: “acious” 是一个常见的后缀,表示“倾向于…” ,模型识别了它,挺聪明;
  • ❌ 失败点在于: “loqu” 本身是拉丁语前缀,表示“说话”,结果它被拆成了 loqu,丢了意义

这说明: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 的分法不是照着字母数来算的,而是根据模型分词器预设的规则进行的。

1.jpg

你可能会疑惑:“为啥 ‘running’ 比 ‘runnin’ 多了一个字母,反而用的 token 更少?”
其实这是 BPE 的“贪心策略”在作怪。

它会尽可能找训练语料中最常见的子串作为 token
“running” 是高频词,自然有一个独立 token。
而“runnin” 呢?这种拼写只偶尔在非正式口语中出现,BPE 没认出来,就只能拆成两个 token,比如 runnin

这就是我们之前说的词表“覆盖能力”问题:分词方式不同,模型处理同一句话的方式就变了。

🐞 这也会引发软件 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” 被拆成 loquacious
  • 模型理解的是语义,不是精确拼写。

所以你让它判断哪个单词字母最多,它可能靠的是语感、词频、上下文,而不是数字母!

也就是说:

LLM 不是真的“按字母”处理文本的,分词把它们切割成“含义片段”了。

这也解释了为啥 ChatGPT 玩填字游戏、猜拼写、做英语选择题有时候“看着聪明,其实瞎蒙”。

1.jpg

🧠 玩文字游戏不重要,但暴露的问题很关键

你可能觉得:“我又不是做文字游戏 app,这事关我啥事?”

但问题不在于“游戏”,而在于——这类失败暴露了 LLM 的认知漏洞
虽然看起来是小问题,甚至像玩笑题,但它揭示了模型在某些任务中根本性的短板,这些短板可能在别的地方也会影响你。

举个“实用场景”的例子👇

💊 药品问答系统,拼错一个字,模型全答错

设想你要开发一个能回答用户处方药问题的应用。

问题来了:很多药的名字又长又绕口,用户记不住、拼不对,太正常了。
而 LLM 不是“按字母”处理文本的——它靠分词器来“理解”词语,如果你拼错了几个字母,那模型可能完全识别不了这个词。

比如👇

  • 正确拼写:Amoxicillin
  • 常见错拼:Amoxicillan

你可能会以为“只错了一个字母,模型应该能猜出来吧?”
但 GPT-3 里这两个词被分成完全不一样的 token 组合,模型根本看不出它俩有关!

这会导致什么?

  • 模型完全找不到正确的知识点;
  • 极端情况下,模型可能把 Amoxicillan 当成另一个药名,答非所问;
  • 而在这种高风险场景下,一次误答可能就是灾难

所以这类场景:

  • 反复测试
  • 可能要自己加自定义的 tokenizer 或补充词表;
  • 甚至要考虑是否适合用 LLM 来做,还是用更稳妥的规则引擎。

1.jpg

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 的知识点:

  1. 你觉得以下词语会被切成几个 token?

    • backstopped
    • large language models
    • Schoolhouse
    • 一句长句子:“How you process sentences to understand them...”
      👉 可以去这个网址试试:platform.openai.com/tokenizer
  2. 把上面的例子换成各种大写小写字母组合,再看看 tokenizer 怎么处理的?

  3. 用字母-数字加密模拟 LLM 的“思维”方式:

    • W = 8,A = 4,I = 7,T = 2
    • 那么 WAIT = 8472
    • 给出一个等式:GO + SLOW = STOP
    • 那你能猜出 STOP 是多少吗?
  4. 从技术角度讲,为什么 tokenizer 表达效率低的语言成本更高?

  5. 这是一个道德问题吗?
    用非英语服务却要花更多的钱,这算歧视吗?

2.5 Tokenizer 不只是前处理,它是 LLM 的“眼睛”

这一章讲了很多细节,有点绕,但其实核心很简单:

tokenizer 决定了 LLM 能“看到”什么,怎么理解,能理解多少。

它是模型的第一道入口,是把文字变成“模型能理解的数字”的那一层。
一个设计得好的 tokenizer,能让模型更轻松地理解复杂的语言结构、细微的拼写错误、甚至多语言混合输入。

而 tokenizer 一旦设计不合理,哪怕是最强大的大模型,也会“看不懂”。

所以 tokenizer 决定了:

  • 模型的训练效果;
  • 模型的输出质量;
  • 模型是否能跨语言使用;
  • 甚至决定了你用起来到底要花多少钱!

接下来我们会继续探讨其他 LLM 的核心构件。它们与 tokenizer 一起,构成了整个大模型理解世界的“知识引擎”。

✨ 本章总结:Tokenizer 是 LLM 看世界的眼睛

要让大模型(LLM)理解人类的语言,第一步就是 “切词” ,也就是把句子转换成一个个小单元——我们叫它们 Token(标记)

这些 Token 就是模型处理文字的基本单位。

✅ Token 是什么?

Token 可能是一个完整的单词(比如 cat),也可能是单词的一部分(比如 cat)。
它不一定跟我们说话时习惯的“词”一一对应,而是更接近机器习惯的处理单位

🛠 Tokenizer 是怎么干活的?

整个 Tokenization(切词)过程包含两个主要步骤:

  1. Normalization(标准化)
    👉 把所有字母变成小写、统一一些奇怪的 Unicode 字符(比如长得像的“a”其实不是一个编码)。
    这样可以避免模型看到“Hello”和“hello”就以为是两个不同的词。
  2. 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 的第一块“感官”,决定了它能看到多少、理解多少,也直接影响你最终的效果和成本。