← cd ~/notes

AI / 大模型

大模型是怎么"说话"的:从 token 到下一个词

拆开一次对话的全过程:分词、向量、Transformer、采样,以及这套机制为什么会导致幻觉和数不清字母。

/6 分钟阅读

用了很久 ChatGPT 之类的产品,一直把它当黑盒。这篇把一次“提问 → 回答”拆开,看看里面到底发生了什么。结论先放这:大模型做的事只有一件 —— 根据前文,预测下一个 token。 其他一切都是这件事反复执行的结果。

第一步:把文字切成 token

模型不直接读字符,而是读 token。token 是分词器(tokenizer)从海量语料里统计出来的“常见片段”,主流做法是 BPE(Byte Pair Encoding):从单个字节开始,反复把最常一起出现的两个片段合并成新片段,直到词表够大(通常几万到二十几万)。

结果大概是这样:

  • 英文常见词往往是一个 token,比如 hello;长词会被拆开,比如 unbelievable 可能是 un + believ + able
  • 一个汉字通常是 1 到 2 个 token,取决于分词器对中文的训练程度
  • 代码里的缩进、常见关键字也会被合并成 token

每个 token 对应一个整数 id。所以模型真正看到的输入,是一串数字:[9906, 11, 1917, 0]。

这也是 API 按 token 计费、上下文长度按 token 算的原因 —— token 才是模型的基本单位。

第二步:id 变向量

整数本身没有意义,模型先查一张 embedding 表,把每个 token id 换成一个高维向量(比如 4096 维)。再加上位置信息(现在主流是 RoPE 旋转位置编码),模型就知道“这是第几个 token”。

到这里,一句话变成了一个 token 数 × 维度 的矩阵。

第三步:过几十层 Transformer

矩阵会依次穿过几十层结构相同的 Transformer block,每层做两件事:

  1. 自注意力(Self-Attention):每个 token 去“看”它前面所有 token,决定从谁那里汲取多少信息。“它”指代谁、这个“苹果”是水果还是公司,都在这一步被上下文消歧。
  2. 前馈网络(FFN):对每个 token 的向量单独做一次非线性变换。一般认为大量“知识”就存在这部分参数里。

每层的输出都会加回输入(残差连接),所以信息是一层层叠加精炼的,而不是被替换掉。注意力的细节和它带来的成本问题,我单独写在 KV Cache 那篇 里。

第四步:算出下一个词的概率

最后一层输出里,只取最后一个位置的向量,乘上一个“词表大小”的矩阵,得到每个候选 token 的分数(logits),再过 softmax 变成概率分布:

"今天天气真" → 好 0.62 | 不 0.11 | 热 0.09 | 冷 0.05 | ...

然后从这个分布里采样一个 token。常见的采样参数:

参数 作用
temperature logits 先除以 T 再 softmax。T 小分布更尖,输出稳定;T 大更平,输出更“有创意”
top-p 只在累计概率达到 p 的那批候选里抽,砍掉长尾的离谱选项
top-k 只在概率最高的 k 个里抽

temperature 设成 0 基本等于每次取概率最大的那个(贪心解码),适合写代码、做抽取;写文案可以调高一点。

第五步:循环

选出的 token 拼回输入末尾,再跑一遍,得到下一个 token……直到生成结束符或达到长度上限。伪代码就这么几行:

tokens = tokenizer.encode(prompt)
while True:
    logits = model(tokens)[-1]          # 只要最后一个位置
    next_id = sample(logits, temperature=0.7, top_p=0.9)
    if next_id == EOS:
        break
    tokens.append(next_id)
    yield tokenizer.decode([next_id])   # 这就是"流式输出"

所以回答是一个字一个字蹦出来的 —— 不是为了效果好看,而是它本来就是这么一个一个生成的。

它是怎么学会的

训练分几个阶段:

  1. 预训练:拿万亿级 token 的文本,任务只有一个 —— 遮住下一个 token 让模型猜,猜错就调参数。这一步让模型学会语言、常识和大量知识。
  2. 指令微调(SFT):用“问题 → 好回答”的数据继续训练,让它从“续写文本”变成“回答问题”。
  3. 偏好对齐(RLHF / DPO 等):让人或模型给多个回答排序,训练它更倾向于有帮助、无害的回答。

预训练出来的模型只会续写:你问“法国的首都是哪里?”,它可能续写成一串类似的考试题。后两步才让它成了“助手”。

理解了这个,很多现象就说得通了

幻觉。 模型优化的目标是“说出最像真的下一个词”,而不是“说真话”。当它不知道答案时,一个流畅且看起来合理的编造,在概率上往往比“我不知道”更顺。

数不清字母。 问“strawberry 里有几个 r”,模型看到的可能是 str + aw + berry 这样的几个 token,而不是 10 个字母。它得靠记忆而不是“看”来回答,所以容易错。

先想再答更准。 让模型“一步步思考”,等于让它先生成一些中间 token,后面的预测就能基于这些中间结果。计算量是跟着生成的 token 走的,多写几步就是多算几步。现在的推理模型,本质上就是把这个过程训练成了默认行为。

上下文就是全部记忆。 模型参数在对话中不会变,它“记得”你前面说的话,只是因为前面的话每次都被重新塞进了输入里。对话太长,前面的内容就会被截断或稀释。

一句话:大模型是一个极其强大的“下一个 token 预测器”,所有能力都是这件事在规模上的涌现。

↑↓ 选择↵ 打开