7 月读到 Alex Tong 在 dev.to 上的一篇笔记,讲他用 Claude Code,会话跑到大概 45 分钟的时候,模型开始编造他根本没要求过的默认值,之前定好的约束一条条被忽略。这篇我记两件事:会话脏了之后怎么判断该不该救,以及真要重开时,怎么重新播种。
读的时候心里咯噔一下,因为上个月我干过一模一样的事。区别只在于我纠正的次数更多,硬撑到会话最后本该给我的东西全没了才肯放手。
先说为什么「再纠正一次」这个动作本身没用。
Alex 那篇里有一句我印象很深:每一次纠正,都是往同一个已经出问题的上下文窗口里追加内容,所以纠正这个动作本身在加重污染。这个因果链写出来像废话,但在会话里对着模型讲道理的时候,人是意识不到的——你会默认下一句说得更清楚一点它就懂了,跟和同事沟通一样。不是的。窗口里已经堆着它自己编出来的那堆默认值,你再说十句也压不掉。
他用的比喻是海绵:干的时候吸水很快,浸透了脏水以后再挤,不会变干净,只会把脏水推来推去。我一开始觉得这比喻有点文艺,后来发现它精准的地方在「挤」这个动作——你继续纠正,就是那个挤。
两个比「感觉不对」靠谱的信号
Alex 的原则是感觉不对就直接重开,不调查不争论,他自己每天要重开好几次。这条我认同,我现在的节奏也差不多。问题在于「感觉不对」这个阈值,人和人的迟钝程度差很多。我是感觉来得特别晚的那一类,很多次都是浪费了大概 30 分钟,跟一个已经不听指令的模型争论完,才发现问题。
Edu Peralta 在评论区给了一个比感觉靠谱得多的信号。他并行跑好几个编码代理的时候发现,最早的异常是代码 diff 和聊天回复里声称的东西对不上——回复里说加了空值检查,diff 里改的却是别的文件。我拿过来自己用了,因为它是可核验的:
git diff --stat
对一眼改动范围,跟你脑子里预期的对不上,就是信号。这不是在质疑模型有没有说谎,是它的自我报告和它实际做的事已经脱钩了,说明它对自己状态的判断也不可信。
Mudassir Khan 留的另一个信号更狠:他们团队把「模型的解释长度超过实际代码 diff 三倍」当成终止会话的早期信号。我回头翻过几个已经坏掉的会话,模型开始话多、开始解释自己为什么这么做、还列一堆注意事项,基本都出现在它开始乱改东西前后。解释变长不是变认真,是它在一个塞满的窗口里找不到重点了。
别在坏会话里 /compact
看到这里大概会有人想到折中方案:不重开,跑一下 /compact 把历史压一压,腾出空间继续用。我一开始也觉得这中间态合理,还专门试过。
Kartik N V J K 把为什么不行说清楚了:/compact 是把窗口里的内容摘要一遍,而它分不清哪些是正确的推理、哪些是已经跑偏的那部分——摘要出来是两者的混合物。空间释放了,坏的东西一点没少,还被压成了更浓的一小团,模型带着那个错误的转向继续往下走。
所以有个更早的评论我不认同。Mykola Kondratiuk 说作者把症状当成了解决方案,主张在上下文退化之前每 30 分钟压缩一次,保住已有决策,而不是从头重启。
我说清楚我不认同哪一点:定时压缩确实比「等到崩了再压」强,这个我承认。但它管的是空间分配,管不了内容对错。窗口里已经有一个错误的默认假设,压缩之后它还在,而且因为被压成更短的形态,你后面更难发现它是哪一步溜进来的。定时压缩能延长一个会话的寿命,但延长出来的那段寿命里,模型的可信度是持续打折的,你得一直提着神盯。与其把精力花在盯上,不如花在重开上。
重开不难,难的是从哪儿重新播种
这是我读那篇笔记时觉得最重要、也最容易被略过的一点:重开不是关掉再开一个就完事。新会话得有东西喂进去,而喂进去的东西,决定了新会话是不是真的干净。
最容易犯的错,是让那个已经混乱的会话自己总结一遍,再把总结搬过去。Wren Calloway 和 Mudassir Khan 都专门说了这个不能做,理由和 /compact 救不了场是同一个:坏会话的总结里,错误推理和正确推理是按同样的权重写下来的,你没有能力从一段摘要里分辨出哪句是当初的误判。等于换个窗口继续污染。
我现在的做法分两层。真需要旧会话里的东西,先让它总结,但总结出来我自己逐句看一遍,只挑那些能对着代码或需求文件核验的部分,手动复制过去,其余一律不带。更常规的情况我干脆跳过总结,直接从真实文件和需求重新播种——把当前目录结构、相关需求描述、这次要改的范围重新讲一遍。这一步其实比想象的快。Alex 那句话我完全同意:新会话三分钟里写出来的代码,会比在旧会话里争论 30 分钟的结果更好。
播种这一步,Mudassir 团队的做法值得抄:按功能区域拆多份 CLAUDE.md,重开的时候只把跟这次改动相关的那一份喂进去,不把整个项目的全量规则塞进新窗口。他们把重置时间从大概 10 分钟压到了 2 分钟。
我照着改了一下自己的目录,大概长这样:
my-project/
├── CLAUDE.md # 全局:技术栈、命名约定
├── src/
│ ├── api/
│ │ └── CLAUDE.md # 只讲这一层的约定
│ └── web/
│ └── CLAUDE.md
💡 小技巧:分区的粒度按「你会不会独立重开这个区域的工作」来定,别按功能模块平均切。我之前记过另一篇讲 CLAUDE.md 该放哪一层的笔记,那篇是位置问题,这篇是内容怎么拆的问题,两个坑不冲突。
划重点
第一,要不要重开别靠感觉,靠可核验的东西:diff 和回复对不上、解释长度明显超过改动量,这两个信号一出现就直接停,不要再往里加内容,清历史或者开个新终端窗口。
第二,/compact 和「让坏会话自己总结」是一条路上的两个岔口,都只解决空间,解决不了内容层面的污染。真要保留旧上下文,人工审一遍再搬,能核验的才搬。
第三,重开本身的技术成本很低,真正花时间的是重新播种,值得把它当固定动作练熟——分区拆好的 CLAUDE.md 能让这一步从十分钟缩到两分钟。
这篇就记到这里。你下次开会话之前可以先看一眼自己有没有分区规则文件,没有的话,从最常改的那一层开始拆一份,用一次就知道省不省事。
