相信大家都听说过 Context Window 这个概念。它代表了模型一次能够处理的最大信息量,比如 GPT-5.2 的 context window 为 40 万。这就代表它一次最多能够处理 40 万个 Token,注意了,我说的不是 40 万个字,也不是 40 万个词,而是 40 万个 Token。相信 Token 这个词大家都有听过,但究竟什么是 Token、是怎么生成的?它和字或者词到底是有什么关系?这些问题吧,其实很少有人仔细研究。今天我就来为大家彻底讲明白 Token 这个概念,我们首先要从大模型的基本运行原理开始讲起。
其实大模型本质上是一个巨大的数学函数,内部全是矩阵运算。它输入的是数字,输出的也是数字,根本就不理解人类的文字。所以在人类和大模型之间必须站着一个翻译官,这个翻译官的名字就叫做 Tokenizer。它一共是负责“编码”和“解码”两个环节,其中编码的意思就是把文字转换为数字,而解码就反过来把数字转回文字。下面我们来用一个具体的流程了解下编码和解码这两个环节。
首先用户提问:“马克喜欢人工智能吗?”这个问题会先发给 Tokenizer,它会把这些文字转换为数字。此时发挥作用的就是编码环节,我们来把编码这个流程放大了仔细研究下,看看它到底是怎么做到文字转数字的。它内部一共是包含两个具体的步骤:第一步,切分;第二步,映射。
它把用户的问题拿过来,将它切成一个个最小的单位,这些切出来的碎片就叫做 Token。我们这里就有四个 Token:马、克、喜、欢(注:此处原文逻辑暗示单字切分,但后文有合并过程,暂按原文“四个Token”描述)。第二步是映射。因为模型只认数字,所以 Tokenizer 会把每一个 Token 映射为一个对应的数字,这个数字就叫做 Token ID。Token ID 与 Token 是一对一的关系:Token 是文字,而 Token ID 是数字。它们就是一个硬币的正反面,所表达的内容是一样的,只不过表现形式不同而已。
经过这两步后,我们原本的一句话就变成了一串 Token ID 列表。然后 Tokenizer 就会把这个列表传给模型,模型在内部一通运算,最后吐出来了一个 Token ID。这时 Tokenizer 再次登场,它要把这个 Token ID 再翻译回 Token。这次发挥作用的就是解码环节了。
解码过程只有一步,那就是映射。只不过它的映射方向与编码环节是反的,它是把数字转换为文字。注意,解码环节不需要切分,因为模型每次就只会给出一个 Token,没什么好切分的。
解码阶段完成后,我们就拿到了大模型输出的第一个 Token:“喜欢”。当然,如果模型没有说完的话,还可以继续输出第二个 Token、第三个 Token 等等。后面的流程都类似,所以我在这里也就不赘述了。大模型的工作原理我们基本就讲完了。现在你明白了 Tokenizer 的两个重要功能:编码和解码。
问题来了,编码和解码涉及到切分和映射这几个环节,切分和映射分别是如何实现的呢?要搞清楚这一点,我们就需要先搞清楚 Tokenizer 这个东西到底是怎么被制造出来的。
Tokenizer 其实是被训练出来的。说到训练,大家脑子里面想到的可能都是大模型的训练过程,其中涉及到非常复杂的数学运算、各种求导各种指数。但是 Tokenizer 的训练过程其实并没有这么复杂,业界有很多实现 Tokenizer 的算法,比如现在屏幕上展示的 Unigram 和 BPE。Google 用 Unigram 比较多,而 OpenAI 和 Anthropic 则多使用 BPE。我们今天就以 BPE 为例,给大家演示一下 Tokenizer 的训练流程。
它的原理也很简单:大致说来就是从一堆文章里面找出哪些字经常在一起使用,然后把这些经常在一起使用的字合起来作为一个 Token。让我们来看一个具体的例子:首先我们要准备个文章作为训练材料,然后用这个训练材料做出两个产物:一个是词表,另外一个是合并规则。
训练过程所做的第一件事,就是把所有的单字拿过来放到词表里面。比如“马”、“克”、“喜”、“欢”等等,限于屏幕大小我们这里只展示四个字。但实际上训练材料里面所有出现过的字都要放到这个词表里,它们都是 Token。然后我们会给这里面的每一个字分配一个数字,也就是 Token ID。
你可能已经发现了,这个 Token ID 并没有什么实际含义,它就是个编号而已。我们这里就是从 1 开始往下数,只要保证 Token 和 Token ID 是一对一的关系就行。有些人可能会以为 Token ID 和 Embedding 向量类似,含义相近的词所对应的 Token ID 应该也相近。但其实并没有这么一回事:Token ID 只是个编号,并没有什么特殊的语义在里面。可以看出,词表就是记录 Token 和 Token ID 的一个表格。
有了这个表格之后,我们就可以把用户的问题切分为 Token 了。比如说是这个问题:“马克喜欢人工智能吗?”我们可以这么切:每一个字都可以作为一个 Token 使用。而每一个 Token 也都可以根据词表映射为一个 Token ID,当然 Token ID 也可以映射为 Token(一对一的嘛)。这样编码和解码的问题就都解决了。
实际上,一个只有单字的词表完全就可以当成一个简易的 Tokenizer 来使用。但是只用单字的话效率太低了,我们希望每一个词都是一个 Token(比如说是“马克”、“喜欢”、“人工智能”等等)。就像是这样,让这些常见的词作为 Token 才是最佳方案。
这样模型的输入就会从原来的 9 个减少到现在的 4 个,模型的推理速度也就更快。所以我们最好能够把这些词也加入到词表里面。那怎么才能够让 Tokenizer 找到这些词呢?答案就是“找规律”。
我们可以让算法扫描整段训练材料,统计哪些“字”或者是哪些“词”喜欢待在一起。让我们来模拟一下这个过程:首先,算法整个扫描了一遍训练材料,然后发现了一件事情:“智”和“能”这两个字简直是形影不离。在这对话里面,它们一共是在一起出现了 5 次,频率是最高的。
既然这么亲密,干脆在一起算了!于是算法执行了第一次合并:从此以后,在 Tokenizer 的眼里,“智能”就不再是两个字,而是一个不可分割的整体。这时候我们需要做两件事:第一,把“智能”这个新词加入到右边的词表里(当然我们也要给它一个对应的 Token ID);第二,我们要把“智 + 能 = 智能”这个公式记录在合并规则里。以后只要见到这两个字挨在一起,直接把它们变成一个 Token“智能”。
这个词算是处理完了。接下来算法继续扫描:这次他发现“人”和“工”这两个字也经常在一起,一共是出现了 4 次,是现在的频率冠军。同样的流程:我们将它们合并、更新一下词表,然后记录下“人 + 工 = 人工”这条合并规则。好,现在“人工”这个词也处理完毕了。
第三轮:这次要合并的词是哪个呢?有人可能说是“马克”,有人可能说是“喜欢”。不过这都不太对,这次要合并的是“人工”和“智能”,它们在一起一共是出现了 3 次,比“马克”和“喜欢”出现的频率都要高。所以我们要把它们合并为“人工智能”。
没错,合并之后的词还可以拿过来继续合并。跟之前一样:我们要把“人工智能”加入到词表和合并规则中,这样 Tokenizer 就认识“人工智能”这个长长的词了。按照这个规则,我们可以继续把“马克”和“喜欢”这两个词也加入到词表和合并规则中。具体过程我就不演示了,跟之前一样:全部处理完后,我们的 Tokenizer 就训练完毕了。它的核心组件就是词表和合并规则。
下面我们回到模型的运行流程里,看看这个 Tokenizer 是怎么用的。我们还是以之前讲过的经典的流程为例:首先讲讲这个过程中的编码环节,它包括切分和映射两个步骤。
我们先看切分:在切分阶段,我们把用户的问题拿过来,先分成一个一个的单字。再把之前训练好的合并规则拿过来,看看有没有能够应用上的合并规则: 1. 先看第一条:“智 + 能 = 智能”。这条可以用上吗?当然可以,用户问题里面“智”和“能”就连着呢。所以我们就把它们合并为“智能”。 2. 再看第二条:“人 + 工”合并为“人工”。正好问题里面“人”和“工”也连着呢。所以我们也把它们合并起来。
就这样,我们按照合并规则里面的顺序把剩下的词也都合并起来:“人工”和“智能”合并为“人工智能”,“喜”和“欢”合并为“喜欢”,“马”和“克”合并为“马克”。这样切分阶段就结束了。在这一阶段里面,我们把一句完整的用户问题切分为 4 个 Token(马克、喜欢、人工智能、吗)。
切分完成之后,我们就来到了编码的第二步:也就是最后一步——映射。这一步我们需要把切分后所得到的 Token 转换为 Token ID,所以我们需要的就不是合并规则了,而是词表(毕竟词表上面记有每个 Token 和 Token ID 的映射关系)。
这一步相当简单:就是到词表里面去寻找每个 Token 的 Token ID。比如“马克”是 35,“喜欢”是 36,等等(具体呢我就不细说了)。到这里编码这一步也就结束了。
下面我们来看看解码:解码就更简单了,就是做映射。你看模型吐出来的 Token ID 是 36,我们查一下词表发现:36 对应的是“喜欢”这两个字。所以我们的 Tokenizer 就输出了“喜欢”。解码就到此结束了,然后整个流程也就随之结束了。
现在我们再回头看一下视频开头的问题:为什么 40 万个 Token 和 40 万个字不是一回事呢?相信现在你应该明白了:因为 Tokenizer 不光是一个翻译机,它还是一个压缩机。
它把经常在一起出现的字合并成了一个 Token(就像我们在视频里面演示的这样:原本 9 个字的“马克喜欢人工智能吗”被合并为了 4 个 Token)。所以 Tokenizer 可以使模型的输入更少,因此模型的训练和推理效率也就更高。
从总体上来看:一个 Token 大概能够代表 1.5 到 2 个汉字,或者是 4 个英文字母(也可以说成是 0.75 个英文单词)。如此看来,40 万的 Context Window 就大致代表了 60 到 80 万个汉字,或者是 30 万个英文单词。
掌握了这个换算概念以后,你在看大模型参数时相信心里就会有一杆秤了。好,今天的视频就到此结束了。我是马克,用最通俗的语言讲最硬核的技术。如果今天的视频对你有帮助,别忘了点赞关注!我们下次再见,拜拜。