大模型每写一个字,其实都先端出一整张概率表,而采样就是从这张表里真正挑出那个字的动作。这一步把模型算出的概率变成你看到的文字,是把"打分"落成"落笔"的最后一环。下面把完整的一步拆开。
模型每步端出什么:一整张概率表
前向计算走完,模型对词表里每个候选都打了一个分数。词表动辄十万条上下,等于每一步都有一张十几万行的打分表,分数经过一次归一化——直觉上就是把分数换成总和为一的占比——变成概率表。"猫坐在"后面,"垫子"可能占六成,"沙发"占两成,其余候选分掉小头。注意此时还没有任何字被选中,模型只交出概率,挑选是下一步的事。也正因为出表是独立一步,同一个问题换一次会话得到不同开头,别急着怀疑模型被换了,先想到这张表后面还接着一个掷骰子的环节。
先筛后抽:把候选池圈小
十万候选逐个考虑既慢,又容易抽到冷门错字,所以先筛。top_k 只保留分数最高的 k 个候选;top_p 从高往低累加概率,累加到刚超过设定值为止,圈出一个大小随情况变化的候选池。两个筛子一个按人数、一个按概率总量,目的相同:把长尾低质量候选挡在门外。像扣子这类智能体搭建平台会把这两个参数开放成表单选项,豆包等对话产品则在幕后替你调好默认值,普通使用者感知不到筛这一步。所以看到模型偶尔冒出奇怪冷僻词,多半是候选池筛得太松,把池子收小通常立竿见影。
| 筛法 | 圈池依据 | 池子大小 | 偏了会怎样 |
|---|---|---|---|
| top_k | 按分数排名,只留最高的 k 个 | 固定,由 k 决定 | k 偏小则可选面变窄 |
| top_p | 从高到低累加概率,加到刚超设定值 | 随分布变化,时大时小 | 阈值偏大则长尾混入 |
| 两个都不设 | 十万候选全进池 | 最大 | 既慢又容易抽到冷门错字 |
| 池子收得过小 | 只留少数高分候选 | 最小 | 回答偏保守 |
掷骰子:按权重抽出一个
筛完之后按概率大小分配中奖面:占六成的候选在骰子上就占六成的面,然后掷骰子,程序里叫按权重随机抽取。这一步引入了真正的随机:同样的问题问两次,答案可能不同,原因就在这里。类比要落回机制——骰子对应加权随机抽样,中奖面就是归一化后的概率占比,程序并没有真的刻一枚骰子。如果把随机性完全关掉,每次都取概率最高的候选,那就是贪心解码,输出稳定,但长文容易显得刻板。一条实用判断:代码、说明文这类容错低的输出,可以把随机收小;闲聊、创意写作则值得留些随机,答案才不会篇篇雷同。
抽完之后:接回开头,循环往复
抽中的 token 被接到已生成序列的末尾,整条流水线重新跑一遍:算下一张概率表、再筛、再抽,直到撞上停止条件。一篇回复就是几十上百次"出表—筛选—抽取"的接力。这条流水线上每个环节都有独立旋钮:温度是怎么改写概率的负责出表那一步,重复惩罚是怎么压制复读的给用过的词扣分,束搜索是怎么保留候选的则干脆多条路一起走。想看上游的缓存与长度问题,参考KV 缓存是怎么随对话变大的。
采样环节对照表
- 出表:全词表打分,归一化成概率
- 筛选:top_k 按人数圈,top_p 按概率总量圈
- 抽取:按概率加权随机选中一个
- 接续:选中的 token 接回序列,循环往复
一句话带走:模型只负责给概率,最终写出哪个字是采样掷出来的。
采样快问快答三则
- 同一个问题为什么两次回答不同?:抽取环节带随机性,概率表相同,掷骰子的结果也可以不同。
- 把随机调到零会怎样?:每次都选概率最高项,输出稳定,但长文容易显得呆板重复。
- 候选池圈得小些更稳吗?:圈太小回答保守,圈太大容易抽到不通顺的冷门词,按任务类型折中。


