深蓝黑背景封面。左侧是「复读循环」机制示意:上方一排词元方块依次写着「今天、天气、很好、,、今天、天气」,最后一个词元下方一条紫色回环箭头绕回开头,标注「相同片段概率被再次抬高」;下方三张成因卡片分别写「贪心 / Beam 解码:每步只取最高概率,没有跳出机制」「训练语料含重复片段:模型学会了接着重复自己」「上下文自我强化:重复越多,下一个词越像重复」,最底一行灰色小字写「复读不是偶发 bug,而是概率分布在特定条件下的稳态」。右侧大标题「大模型为什么会变成复读机」,副标题「解码策略、训练数据与概率自我强化的三重成因」,小注「重复惩罚、采样与对比解码各自能缓解多少」。左上标注「面试经典 · 文本生成」,右上圆角胶囊标注「Day 05 · 12-02」。 图 1:本文封面,复读循环的三重成因与对策方向。

先说明属性:这是一篇经典题解析,题目出自本地历史面试资料整理,与任何公司的当前招聘无关。「大模型为什么会出现复读机问题」是文本生成方向的常考题,很多人的答案停在「解码策略不够好」这一句,但真正要讲清的是三层成因——解码、数据、概率自我强化——以及每层对策能管到哪、管不到哪。

一句话结论:复读不是偶发 bug,而是概率分布在特定条件下的稳态。

先定义现象:生成重复可以发生在三个粒度——字符或词级别(同一个词反复刷屏)、语句级别(同一句话循环输出)、章节级别(换个提示词输出却千篇一律)。面试里通常聚焦前两种,即生成过程陷进了循环。

成因一:最大化式解码没有跳出机制。

贪心解码每一步都取概率最高的词,束搜索(beam search)保住的是总概率最高的几条路径,两者的共同点是「只看概率,不看历史里出现过什么」。2022 年发表的对比解码研究(arXiv:2202.06417)明确指出:这类最大化式解码经常产生「退化」输出——不自然、包含大量重复,并把深层原因之一归结为词元表示的各向异性,即不同词元的表示挤在向量空间的一小片区域里,模型对「该换个词」这件事缺乏区分度。换言之,解码器只是把模型给的分布原样执行,分布一旦偏向重复,贪心会一条道走到黑。

成因二:训练数据与训练目标埋下了种子。

训练语料里天然存在大量重复模式——模板化的商品标题、格式化的列表、反复的套话——模型在下一词预测的目标下会把「接着重复」也学成一个合法动作。2019 年发表的 unlikelihood training 研究(arXiv:1908.04319)给了一个更尖锐的观察:标准的似然目标本身就有问题,它让模型给「含重复的序列」和「高频词」分配了偏高的概率——复读倾向不是解码阶段才出现的,是训练目标亲手写进分布里的。

成因三:输出回填上下文,概率自我强化。

这是最容易被忽略、却最能解释「为什么会一直重复同一个词」的一层。自回归生成的每一步都把刚生成的词追加回上下文,再据此预测下一个词。2022 年关于归纳头(induction head)的机理解释研究(arXiv:2209.11895)表明,Transformer 里存在专门执行「前文出现过 [A][B],再见到 [A] 就倾向预测 [B]」的注意力头——这套机制本是上下文学习能力的来源,但在生成场景里它意味着:一旦某个片段在输出里出现了两次,模型就会越来越确信「下一个词还应该是它」。重复得越多,分布越尖,循环越死。

用一段玩具二元模型把三层机制串起来看(Node.js 22.15.0,node rep.js):转移表里逗号之后「今天」概率最高,纯贪心立刻陷入循环;给已出现过的词按出现次数施加重复惩罚后,第三次回到岔路口时惩罚把「今天」压到了备选词之下,输出拐向新句子:

纯贪心解码:    今天天气很好,今天天气很好,今天天气很好,今天天气很好,……
加重复惩罚1.5: 今天天气很好,今天天气很好,今天天气很好,我爱编程。

对策各管多少:解码层治标,数据层治本。

重复惩罚(repetition penalty)的思路出自 2019 年的 CTRL 论文(arXiv:1909.05858):把已出现词元的得分除以一个大于 1 的系数(Hugging Face 的生成参数文档里 repetition_penalty 默认 1.0 即不惩罚),出现过的词再次被选中就更难;更硬的办法是 no_repeat_ngram_size,直接禁止指定长度的 n-gram 第二次出现。代价是压过头会损伤流畅度——人名、术语本来就需要重复。采样类策略(temperature 拉平分布、top-p 截断长尾)靠引入随机性给非重复词留出口,但随机性同时牺牲可控性。对比解码则在选词时额外惩罚「与上文表示过于相似」的候选,直接针对成因一与三。训练层的 unlikelihood 目标和语料去重才是治本:把重复模式的来源从分布里削弱。工程上的真实答案是组合拳——线上通常是「数据去重 + 适度惩罚 + 采样参数调优」一起上。

深蓝黑背景概念图。顶部是自回归生成循环图:「上下文」方框经箭头进入「模型」方框,再进入「选词(贪心取最高概率)」方框,产出「输出词」方框,输出词下方一条紫色回环箭头绕回上下文方框,标注「输出追加回上下文,重复概率被进一步抬高」;选词方框上方另有灰色小注「重复片段的 logits 已偏高」。中部并排三张对策卡:第一张「解码层 · 重复惩罚」写已出现词元的 logits 除以 repetition penalty(常取 1.1~1.3),出现越久压得越狠,但过大会损伤流畅度;第二张「解码层 · 采样破贪心」写用 temperature 拉平分布、top-p 截断低概率尾巴,给非重复词留出出口;第三张「训练层 · 数据与解码治理」写语料去重减少重复模式来源,对比解码压低退化分布的权重。底部总结条写「解码层治标、数据层治本,线上通常是组合拳」,最下方小字补充「没有单一银弹:惩罚调太大损害连贯性,完全随机采样又牺牲质量」。 图 2:自回归循环的成因链条与三层对策的分工。

面试现场的答题结构。

先给结论「复读是概率分布在解码、数据、自我强化三层因素下的稳态」,再逐层展开:最大化式解码没有跳出机制且词元表示各向异性;训练语料与似然目标给重复序列分配了偏高概率;输出回填上下文后归纳头机制让重复自我强化。然后按「解码层治标、数据层治本」给对策,并点明每种对策的代价——惩罚过大伤流畅度,采样过强伤可控性,对比解码多一层计算。答到「对策之间不是替代关系而是组合拳」这一层,就把问题讲透了。你在生成业务里调过重复惩罚吗?惩罚调大之后遇到过哪些副作用?欢迎聊聊。