罗德岛通讯与技术部

把「别重复」做成系统:一次关于平凡输入的诊断

Long conversations degraded into canned mannerisms. The root cause wasn't the model — it was that 34 of our 35 prompt sections were byte-identical every single turn.

罗德岛通讯与技术部

长对话聊到 30 轮以后,她开始"样板戏":固定的动作描写、固定的收尾、 同一件事换个说法再说一遍。

我们的诊断写下来只有一句话:35 段 system prompt 里,34 段每一轮完全一样。

问题

症状很好识别,但很难归因:

  • 动作描写退化成一套固定模式("(轻笑)" "(摇头)" "(顿了顿)");
  • 收尾句式连续复用;
  • 同一个话题反复提。

第一反应通常是"模型不够强" ✗ 或者"温度调坏了" ✗。但这两条都解释不了为什么只在长对话后出现

诊断:不是模型变笨,是输入太平凡

我们数了一遍当时的 system prompt —— 共 35 段,其中 34 段每一轮完全一样

而 LLM 是一个在重复输入分布里找最短路径的东西 ✗:当每一轮的输入几乎相同, 输出自然收敛到那个"最省力的答案" —— 也就是样板戏 ✓

所以问题不在"她说什么",而在"我们每轮喂给她的东西有没有变化"

这个诊断带来一条设计原则,后来贯穿始终:

每轮都应该有东西在变,而且要放在末尾**(prompt 最底部对下一句影响最大)。**

三个机制

优先级 机制 作用点 每轮变化 成本
P0 Author's Note prompt 最末尾 低(角色池 + 轮换)
P1 反样板戏指令 WRITING_RULES + Note 池 部分 极低(改一行字)
P2 示例对话轮换 人设里的示例段 中(需要一条转换管线)

P0 是主角:每轮从池子里挑一条作者注插在 prompt 最末尾 —— 内容可以是 "这一轮换个收法"、"别用同一个动作"、"把下一句留给博士"。位置是设计的一部分: 放在最前面,它会淹没在几千字的设定里;放在最末尾,它紧贴当前这一轮 ✓

P2 我们没做 ⬜(文档里明确标着"未实施"✓)—— 现在是示例段全量注入, 没有"每轮抽 2–3 条"的轮换。这条诚实地留在技术债里,而不是假装做过 ✓

被砍掉的 P3(以及为什么值得记下来)

我们还设计过 新鲜度种子:每轮注入一点环境变量("窗外下着雨")来打破重复 ✓

砍掉了 ✗ 理由:它会和用户自己建立的场景冲突 ✓ 用户说"今天外面很晴",而系统每轮塞一句"窗外有雨" ⇒ 直接矛盾 ✓ —— 打破重复的办法不能是引入与事实冲突的新信息

这条留在设计文档里,和"已实施"的部分并列 ✓ 因为半年后最值钱的是"当时为什么没做"

后来的修正(从提示词走到别的层)

那套机制上线后,重复问题并没有消失 ✗ 后来我们做了一次完整的排查(另一篇文章写了全过程), 得到几条与"提示词"无关的结论:

  1. 重复的成因之一在写入侧:某些自动生成的内容被当成"她说过的话"写进了记忆, 而且同一段写了 4 份 —— 上下文里同一件事出现多次,模型会当成"重要"而反复说它 ✓ ⇒ 修在读取侧:同一句话只让模型看一次
  2. 另一部分成因在解码侧:重复是自回归生成的吸引子(输出困惑度趋零)。 别人(比如 SillyTavern 那类前端)把这类问题当采样问题治: repetition penalty / no-repeat n-gram / DRY ✓ 而我们的采样参数从来没开过
  3. 判据要分层次:我们一开始只检测"收尾 12 个字是否相同" ✓ 但它抓不到 "话题在中段反复出现" ✓ 于是加了话题级判据:找出最近几轮反复出现的实词, 直接点名"这些事已经聊过了" ✓
  4. ⚠️ 一次实验推翻了我自己的假设:把她的同一句回复逐字复制 4 份塞进记忆, 她并没有开始复述(两臂都是 0/5 命中 ✓)—— 所以"上下文重复"不是唯一成因, 真正的杠杆在生成侧 ✓

结果

之前 之后
每轮变化的内容 1 段(人设里的示例,且不轮换) 末尾作者注池 + 话题级点名
检测的重复形状 收尾句式 + 话题共现
采样层重复惩罚 未开 已开
覆盖的对话路径 1 条 2 条(普通 + 深聊)

踩坑与教训

  • 先怀疑输入,再怀疑模型 ✓ "35 段里 34 段一样"这种事实,比任何调参直觉都有用 ✓;
  • 位置是设计的一部分:要影响"下一句",就放在最后 ✓;
  • 设计文档要标"未实施" ✓ 否则半年后连自己都以为做过了 ✗;
  • 砍掉的方案要留理由(新手会再想一遍"加个环境描写多好" ✗ 而文档里已经写着 "会和用户场景冲突" ✓);
  • 规则解决不了的事,去它的上游和下游找 ✓ —— 上游是写入(别重复写), 下游是解码(别被吸引子拖住)✓

这一篇的每个机制都能在仓库里找到实现或"未实施"的标记;每条结论都对应一次可复现的实验。