第一个麻烦:机器不认字
上一章我们说了,机器只认识数字。那好,你想让机器读一句话,第一个拦路虎马上出现:「我今天很开心」这七个字,在机器眼里什么都不是。得先想办法把它们变成数。
怎么变?最容易想到的办法是:给每个字编个号。建一本大字典,「我」是 1024 号,「今」是 3857 号……机器拿到的就不再是文字,而是一串编号,像发电报一样。
这个思路方向没错,但按「字」还是按「词」来编号,差别就大了。而这正是第一个值得停下来想的地方。
按词切,还是按字切?都有坑
先看「按词切」。英语好像天然按词切——空格都替你分好了。但真干起来麻烦不断:eat、eats、eating、eaten 是四个词还是同一个词?如果算四个,字典就得把它们全收进去;碰上没见过的新词(网络上每天造出来的梗、某家公司的名字),字典里查不到,机器当场抓瞎——这叫未登录词,大白话就是「户口本上没这人」。更要命的是中文,连空格都没有,「研究生命的起源」该切成「研究/生命/的/起源」还是「研究生/命/的/起源」?切词本身就得先理解语义,成了鸡生蛋蛋生鸡。
再看「按字切」。每个字一个编号,字典小(中文常用字几千个,足够了),永远不会有查不到的字。但代价是:单个字往往没啥意思。「蝴」字单独拎出来是什么意思?它只有跟「蝶」凑在一起才有意义。把意义全推给后面的模型去重新拼,等于白白增加了学习的难度。
按词切,字典爆炸还漏词;按字切,字字都是碎片。两头都不舒服。
实际答案:切成「零件」
工程上真正用的办法,是取一个中间态:把文字切成常见的「零件」,而不是完整的词,也不是单个的字。这种零件叫 token(中文常译「词元」),大白话说,就是机器眼里的最小语言单位。
怎么切?思路朴素得可爱:哪些字符组合出现得特别频繁,就把它整个收进字典。统计海量文本后发现「ing」老是出现,那「ing」就当一个 token;「un」老是出现在开头,也收;「吃」「饭」「今天」「人民」这些高频组合也整个收。而「eating」这种词,就拆成「eat」+「ing」两个 token。
大白话:这套切法像玩乐高。字典里存的不是所有可能的城堡,而是一批最常用的积木块。常见的东西整块整块地有,没见过的新词也能用小块现场拼出来——字典不大,还永远不抓瞎。
这么一切,效果立竿见影:
- 字典大小可控:主流模型大概收 5 万到 15 万个 token,中英文、标点、代码符号全在里面。
- 新词、网络梗、生僻名字都不再是问题——大不了多拆几块。
- 常见的词整块进出,不用让机器从偏旁部首重新悟意思。
一个直观的量级:对中文来说,一个 token 大约是「大半个字到一个词」之间;日常聊天一句话,通常十几二十个 token。你每次用 AI 按 token 计费,计的就是这个「零件」的个数。
编号只是门牌号,不携带任何意思
切完之后,每个 token 拿到一个编号。到这里,「我今天很开心」在机器眼里就变成了类似 [1024, 3857, 66, 29013] 的一串数。
但请注意一个极其重要、后面会反复用到的事实:这些编号只是门牌号,本身不携带任何意思。
门牌 1024 和 1025 是邻居,但「我」(1024 号)和碰巧排在 1025 号的那个 token 之间,意思上可能八竿子打不着。编号是人随手发的,跟语义毫无关系。这就好比通讯录里,排在你妈后面的那个人,跟你妈没有任何关系。
所以到现在为止,机器手里只有一串「门牌号」。它能做的全部事情,就是拿着号码去查表、数数、算概率。你说这离「理解语言」还差着十万八千里——没错。编号解决了「机器能存下这句话」,但完全没解决「机器知道这句话什么意思」。
下一步,就是给这些干巴巴的门牌号注入「意思」。怎么注入?答案藏在一个出人意料的地方:让意思变成空间里的距离。这就是下一章的内容。