返回首页

文章详情

2026.04.18

2 分钟阅读

llm / transformer / token / foundation

模型读到的不是文字:Token 如何把语言变成可计算的输入

从固定词表、子词切分到特殊标记,解释 Token 为什么是语言进入大模型的第一层接口,而不只是另一种“字数”。

铺在深色工作台上的 Transformer 架构草图和代码稿纸

从 Token 到 Transformer · 01 / 10

把“周末去上海”发给大模型时,我们很容易想象:模型先看见这五个汉字,再开始理解句子。真实过程更机械,也更有意思。模型首先接到的不是文字,而是一串整数;在整数出现之前,文本还要经过 tokenizer,被切成一组来自固定词表的 token。

这一步经常被一句“把文字转成数字”带过。但 tokenization 决定了模型能看见什么、一次能装下多少内容,也决定了后续计算从哪里开始。它不是清洗数据的边角工作,而是语言与神经网络之间的接口。

模型为什么不能直接读字符串

神经网络的输入必须是形状明确的数值张量。Unicode 字符串没有可以直接参与矩阵乘法的形式,所以系统要先建立一套有限的词表,再把输入映射到词表中的编号。

一条简化后的链路是:

text
原始文本
  -> token 列表
  -> token ID
  -> embedding 向量
  -> Transformer 层

这里最容易混淆的是 token 与 token ID。token 是切分后的符号,ID 只是它在词表中的索引。编号 1532 并不比编号 97 “更有意义”,它只负责找到 embedding 表中的对应行。

为什么不按字或单词切

字符级方案很稳:只要字符集覆盖足够广,几乎不会遇到未知词。但它会把序列拉得很长。“tokenization” 若按字符拆开,需要模型重新学习这些字符如何组合成一个概念。

整词方案正好相反。常见词可以保留完整语义单位,但现实语言是开放的:新产品名、拼写变体、代码标识符和长尾术语每天都在出现。把所有完整单词收入固定词表既不现实,也会让词表膨胀。

现代语言模型因此多采用子词切分。高频片段可以作为一个 token,罕见词则拆成更小的已知片段。它是在三个目标之间做折中:

  • 词表不能无限大;
  • 序列不能被切得过长;
  • 没见过的词仍要能够表示。

同一个词在不同 tokenizer 中可能有完全不同的切法。Token 不是语言里天然存在的原子,而是模型训练方案的一部分。

中文也不是“一个字一个 Token”

英文有空格,中文没有天然的词边界,但这不意味着中文一定逐字切分。具体结果取决于词表、训练数据和算法。常见短语可能整体进入词表,生僻字可能退化为更小的字节表示,中英文混排、数字和标点也会改变切分。

这解释了一个常见现象:肉眼看起来同样长的两段文本,在不同模型里可能消耗不同数量的 token。比较模型的上下文或调用成本时,不能用“一个汉字约等于一个 token”当作稳定规则,应该使用目标模型自己的 tokenizer 统计。

Tokenizer 还负责输入协议

Tokenizer 不只切正文。它通常还会加入一些特殊标记,用来表达会话边界、角色、填充或任务结构,例如序列开始、序列结束和 padding。随后,运行时还会生成 attention_mask 等辅助字段,告诉模型哪些位置是真实输入,哪些只是为了对齐批次而补出来的空位。

因此,一条聊天消息真正进入模型时,往往包含用户看不到的模板和控制 token。上下文窗口计算的是这整套序列,而不只是输入框里的正文。

Tokenization 会留下什么影响

切分方式会沿着整条系统链路向后传递:

  • 切得更碎,序列通常更长,占用更多上下文;
  • 专业词被反复拆散,模型需要更多层计算才能组合出稳定表示;
  • 代码、表格和多语言文本的 token 密度差异,会影响吞吐与费用;
  • 特殊 token 和聊天模板设计,会影响模型学到的交互边界。

这并不意味着“token 越少越好”。一个极小词表会让序列过长,一个极大词表则会增加 embedding 参数并稀释长尾 token 的训练机会。好的 tokenizer 是面向数据、模型规模和使用场景做出的系统选择。

小结

模型并不是先理解文字,再把理解结果交给计算。顺序恰好相反:文字先被 tokenizer 重写为有限词表中的符号,再变成 ID 和向量,理解才从后续层里逐步形成。

下一篇会沿着这条链路继续回答一个更实际的问题:为什么 token 数量会同时影响成本、延迟和回答质量。

延伸阅读

    模型读到的不是文字:Token 如何把语言变成可计算的输入