场景:AI 编码 Agent 反复修同一个 Bug?RegressionLedger 用跨会话指纹终结修复死循环
用 Claude Code 或 Cursor 写代码时,你一定遇到过这样的场景:Agent 修了一个 Bug,测试挂了;它换了个姿势修,测试又挂了;再换,再挂……直到上下文窗口填满被重置,它忘了刚才所有失败尝试,重新从第一步开始,重复同样错误的修复路径。
这就是 AI 编码 Agent 最令人头疼的「修一个、坏两个」死循环(doom loop)。RegressionLedger 是一个零依赖的 Claude Code 钩子 + CLI,用跨会话的语义指纹追踪每一次编辑结果,在 Agent 试图重试已经失败的修复时,直接硬阻断而非仅仅建议。
死循环的根源
这个问题的症结在于三个环节的断裂:
- Agent 的失败记忆无法跨越上下文窗口填充——Claude Code 的上下文满后自动压缩(compaction),压缩后 Agent 忘了自己之前的失败尝试
- 现有的循环检测器只在一个会话内检测完全相同的工具调用——它们不跨会话记录”哪个修复试过了以及它为什么失败”
- 通用 Agent 记忆层(如 lessons learned)只是建议——模型可以自由忽略它不想听的建议
结果是:Agent 在一个会话内修同一个 Bug 修了 5 次,每次都用同样的错误方法;上下文重置后,第 6 次依然是同样的错误路径。
RegressionLedger 的解决方案
RegressionLedger 是四个环节的闭环:
指纹化(Fingerprint):每次 Agent 执行 Edit、Write 或 MultiEdit 时,对修改的代码生成语义指纹。指纹分为两个通道——原始通道保留字面量(只去除空白和注释),折叠通道将字符串/数字抽象为 STR/NUM 占位符。
结果关联(Outcome Linkage):Agent 运行 npm test、pytest、tsc 等命令后,钩子解析输出,将之前的编辑标记为 pass 或 fail,并捕获首个错误行作为签名。
持久化(Persistence):所有记录存入 .regressionledger/ledger.json——纯 JSON 文件,无数据库、无网络调用、无 API Key。
硬阻断(Hard Block):Agent 再次提交相同指纹的修改时,PreToolUse 钩子直接拒绝,并给出具体原因——”你在 2 小时前对 src/auth.js 试过同样的修复,失败原因是 AssertionError: expected 200, got 401,请更换策略。”
关键特性
双通道指纹
普通修复(改缩进、改注释)被原始通道匹配,触发硬阻断。修改常量值(timeout 5000→30000)只命中折叠通道,触发建议而非阻断——因为它可能是合理的参数调整。基准测试验证了这一点:60/60 次相同修复被 100% 阻断,40 次参数调整零误阻断。
跨会话简报
SessionStart 钩子在每次会话开始时注入一份紧凑的”过去失败总结”——包括在上下文压缩之后。这意味着 Agent 在构思失败修复之前就被阻止,而不是在已经写完后才被拦截。
震荡升级(Thrash Escalation)
当 3 种以上不同的修复尝试都撞在同一堵墙上时(同一个错不同修法),钩子会升级干预:”诊断有问题,不是补丁有问题——停下来,提出根本原因假设,验证一个,再修复。”
群体免疫
rl export / rl import 在不同机器和团队成员之间共享已确证的失败记录——你的 Agent 继承别人 Agent 已经走过的死胡同。
快速上手
作为 Claude Code 插件安装(推荐)
/plugin marketplace add anlor1002-alt/regressionledger /plugin install regressionledger@anlor1002-plugins
钩子自动激活,无需编辑 settings.json。
作为 npm 包安装
npx regressionledger init
init 会自动在 ./.claude/settings.json 中注册 PreToolUse / PostToolUse 钩子,并创建 .regressionledger/ 目录。重启 Claude Code(或运行 /hooks)即可生效。
验证安装
npx regressionledger doctor
包含实时钩子往返测试——首次编辑必须通过,预设的重复失败必须被拒绝。
常用命令
| 命令 | 作用 |
|---|---|
rl demo | 在沙箱模拟中演示死循环被阻断 |
rl doctor | 验证安装,包含实时钩子测试 |
rl why | 查看某个文件的历史失败记录和原因 |
rl show [file] | 显示完整尝试历史 |
rl stats | 统计摘要,包含被阻断的重复修复次数 |
rl unblock | 在上下文确实变化时解除对文件的阻断 |
rl export / rl import | 跨机器共享已确证的失败记录 |
rl uninstall | 完全移除,不留痕迹 |
配置项
配置文件 .regressionledger/config.json 包含以下核心参数:
- mode(默认
block):block为硬阻断,warn为仅警告 - threshold(默认
0.9):指纹相似度阈值,越高越严格 - minFailures(默认
1):失败多少次后才触发阻断,设为2更谨慎 - crossSymbol(默认
true):是否跨符号匹配同一文件内的失败
第一天担心误判?以 rl init --warn 启动观察模式,rl stats 查看本应阻断的次数,确认准确后再切换到 block 模式。
对比其他方案
| 工具 | 跨会话 | 关联结果 | 阻断/建议 |
|---|---|---|---|
| 会话内循环检测器 | ✗ | ✗ | 警告 |
| 通用 Agent 记忆层 | ✓ | ✗ | 建议 |
| RegressionLedger | ✓ | ✓ | 硬阻断 |
与通用记忆层的本质区别:记忆层存储建议,模型可以忽略;RegressionLedger 发出 PreToolUse 拒绝命令,模型无法绕过。
适用场景
- 复杂的多步骤修复:Agent 修复 A 功能,测试 B 功能,B 失败后 Agent 反复尝试相同路径
- 跨会话的回归问题:同一类 Bug 在多个会话中被反复用错误方法修复
- 团队共享学习成本:一个 Agent 发现的死胡同通过
rl import让整个团队受益
局限
- 当前仅支持 Claude Code 的钩子系统(Cursor/Windsurf 在路线图中)
- 批量归因的噪音:一次测试运行同时判定多个编辑时,归因是近似的
- 需要 Node ≥ 18
相关链接: