☰
跨多次运行累积缺口证据:backpass 的 Gap Ledger 跨运行佐证机制完整指南
2026/10/12 22:21:35 网站建设 项目流程

【免费下载链接】backpass

You don't write AGENTS.md. You train it with gradient descent.

项目地址:https://gitcode.com/gh_mirrors/ba/backpass
点击查看免费下载

backpass 是一个用"梯度下降"思路训练 AGENTS.md、CLAUDE.md 与项目 skills 的开源工具。它的Gap Ledger(缺口台账)机制负责跨多次运行累积"缺口证据":同一个缺口这次只被 1 个会话提到、下次又被另一个会话提到,两次运行加起来才算数,从而让真实复发的教训有机会通过"至少两个不同会话佐证"的证据门槛。

🤔 问题:为什么一次运行内佐证不够?

backpass 的核心规则是:一个缺口(gap)必须被至少 2 个不同会话独立报告,才会进入提案(minGapEvidence默认 2)。单看一次运行,有两个坑会让佐证永远凑不齐:

坑原因后果
证据文件会被重写每次apply都会改变记忆文件,触发重分析,旧证据被新证据覆盖上次"看到"的缺口记录消失了
模型会换措辞分析模型每次用不同的话描述同一个缺口两次观察在单次聚合里对不上号

换句话说,"这个会话见过这个缺口"这个事实,不能只存在于当次运行的内存里。它必须被持久化,才能在若干次运行之后与新的观测汇合。这就是 Gap Ledger 存在的理由。

📒 Gap Ledger 是什么:跨运行的观察档案

台账是一个普通 JSON 文件,位于仓库状态目录:

  • 文件位置:.backpass/gap-ledger.json
  • 读写入口:src/state.js 中的readGapLedger/writeGapLedger
  • 核心逻辑:src/gap-ledger.js

它的组织方式是"按缺口(gap)分组、再按会话(session)索引"。每次运行结束时,backpass 把本轮证据中报告的所有缺口作为**观察(observation)**记入台账,每条观察携带:原始引语(quote)、错误描述、领域投票(project/orchestration)、首次发现时间等。

设计目标写得很直白:"let observations collected on different runs reach the bar when their sessions are together in a later run's selected sample"(让不同运行收集到的观察,在它们的会话同时进入某次运行样本时仍然能凑够门槛)——见 src/gap-ledger.js 的文件头注释。

🧬 三层身份判定:如何认出"同一个缺口"

不同会话、不同措辞,怎么知道说的是同一件事?backpass 设计了三层机制,可靠性从高到低:

1️⃣ 引用机制:让模型直接"点名"

每轮分析前,backpass 会把台账中所有未解决的缺口(含稳定 id)渲染进分析 prompt(renderOpenGapIndex,提示词模板见 src/prompts/analysis.md)。模型如果发现本次的缺口与已知缺口是同一件事,就在返回 JSON 里用matchesGap字段引用那个 id。

有效的引用直接获胜——因为"是否同一件事"是语义判断,模型面前摆着两句话,比任何词重叠分数都可靠。

2️⃣ 词法相似度兜底:bigram 分数 0.45

没有引用时,回退到 Sorensen-Dice 词二元组相似度(实现见 src/memory.js 的similarity),与台账条目的"规范措辞"(保留最短的那句)比较,阈值定在0.45(src/gap-ledger.js)。

3️⃣ Consolidation 判定调用:合并"平行新造"的条目

还有种情况前两层都覆盖不了:同一次运行里,两个并行分析同时发现一个全新缺口——谁也不知道对方,于是各自"造"了一个条目。

于是 backpass 在聚合前插入一次有界的模型调用(src/consolidate.js、prompt 见 src/prompts/consolidate.md):把全部未解决缺口交给模型,只问一个问题——"哪些 id 是同一个缺口?"。合并本身是纯机械操作(mergeGapEntries),模型说错不会污染计数,会话永远不会被重复计数。

源码注释里有一段很有说服力的实测数据:生产台账中 89 个多会话缺口条目,跨会话词法相似度最高只有0.34,全部低于 0.45 门槛——纯词法匹配根本认不出真实的重述,所以必须引入判定(src/consolidate.js)。同时它设计为 fail-soft:调用失败就降级回词法身份,绝不让整轮运行挂掉。

🛡️ 记账规则:不双计、不过期、不"诈尸"

台账最怕三类脏数据,对应三条铁律(均在 src/gap-ledger.js 实现):

  • 同一会话永不双计:观察以会话的规范身份为 key,同一会话重复分析只会覆盖自己旧的观察并保留首次发现时间,recordGapObservations(L171-L250)保证重新观察绝不增加计数。
  • 观察只被替换、不因缺席被删除:某次重分析没再提到某缺口,是模型噪音而非"会话变了",所以旧观察不会被删掉。
  • 两条退出路径(pruneGapLedger,L259-L285):
    1. 被覆盖即退休——记忆文件里出现了相似度 ≥ 0.6 的指令,或某个 skill 的 description/正文能回答该缺口(比如缺口恰好通过"提取为 skill"解决了),条目整体退休,不再" haunting "分析 prompt;
    2. 等待超期——从首次发现算起超过gapLedgerMaxAge(默认90d)仍未凑齐伙伴的观察过期删除。重分析不会刷新这个时钟,避免"永不老化"。

另外还有一层采样护栏:台账里的历史观察只有当对应会话属于本次运行选中的样本时才参与计数(src/commands/propose.js)。这样超出maxTranscripts上限或时间窗口的旧观察既不能扭曲样本构成、又能在会话重新入选时继续提供佐证。

🔄 一次运行中,台账参与的完整流程

foldForRun(src/commands/propose.js)把整个顺序编排得非常讲究,顺序本身就是一种设计:

  1. 过滤:只取属于本次选中样本、匹配当前记忆文件哈希的新鲜证据;
  2. record:把本轮观察写入台账;
  3. consolidate:判定合并——刻意放在 record 之后,让"同一次运行平行发现的新缺口"也有机会对齐;
  4. prune:放在合并之后,因为被合并进来的旧观察证据文件还躺在磁盘上,先剪枝会被它们"加回来";
  5. fold:把台账摊平成观察列表(ledgerGapObservations),交给 src/fold.js 的foldEvidence聚类;会话数 ≥minGapEvidence的聚类才有资格进入 synthesis 生成 ADD/REWRITE 提案。

一句话总结:在凑够佐证之前,缺口完全不出现在提案里——它是静默积累的。

⚙️ 相关配置参数

在 src/config.js 中可看到两个直接相关的默认值,也写在.backpassrc.json里:

  • minGapEvidence: 2—— 佐证门槛:需要几个不同会话
  • gapLedgerMaxAge: "90d"—— 观察等待伙伴的最长寿命,"all"可设为永不过期

✅ 设计要点小结

设计决策解决的问题
台账按 (缺口, 会话) 持久化证据文件重写导致跨运行信息丢失
引用 > 词法 > 判定合并 的三级身份判定模型重述让同一缺口"对不上号"
会话去重 + 90 天过期 + 覆盖即退休防止双计、陈旧证据与僵尸条目
仅计入选中样本的会话旧观察扭曲采样构成
全程 fail-soft(台账损坏重建、合并失败降级)任何一环出错都不阻断主流程

Gap Ledger 体现的是 backpass 整体的"证据门控"哲学:小步、有界、可追溯——单次运行的教训可以很微弱,但跨运行累积的、来自多个独立会话的复发现象,才是记忆文件值得为之更新的理由。所有上述行为的回归测试集中在 test/gap-ledger.test.js,值得想深入了解行为边界时一读。

【免费下载链接】backpass

You don't write AGENTS.md. You train it with gradient descent.

项目地址:https://gitcode.com/gh_mirrors/ba/backpass
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询