工程上下文已经留在 GitHub,Agent 还需要独立记忆吗?Beacon 与 Checkpoint 对照实测
前两篇先把两个基础问题拆开了:《把工程上下文留在 GitHub:AI 编程跨工具接力与多分支协作》 讨论工程状态如何持久化、如何让不同 AI 工具接力;《代码不上云,网页端 AI 能参与到哪一步?Local-first 与 GitHub-first 的接入边界》 划定数据访问与执行权限的边界。
在这两条边界之上,第三篇要回答的不是记忆能不能被保存,而是:Agent Memory 到底能补充什么?它能否保存当前仓库无法推导的历史知识,并在新会话里带来可测量的额外价值?
先给不想看实验细节的朋友交个底:现阶段,真别指望靠加一层独立 Agent Memory 来帮写代码提效。 只要是 Agent 翻翻当前仓库就能自己看懂的规矩,还是老老实实写进 README、AGENTS.md、Makefile 和测试里比什么都强;只有那些翻遍代码也查不到的“历史恩怨”和妥协决策,才值得考虑塞进独立记忆。这次我轮番折腾了三轮实测,结果现实很骨感:跨工具(Harness)读记忆确实跑通了,但它并没能让新任务多过哪怕一个隐藏测试。
三篇串起来,是一个工程判断:工程状态由谁保存 → 数据和执行权限在哪里 → 额外的 Agent 记忆究竟有没有必要。
我用三轮合成实验把问题拆成两半:前两轮测“仓库自己就能推导的规则”,第三轮测“只有历史纠正才知道的跨格式隐性约定”。
真正需要分开验收的是三件事:记忆有没有保存下来、另一个 Harness 有没有读到、读到之后是否真的改善了任务结果。三者不能互相替代。本文所说的 Harness,是运行 Agent 的工具/宿主环境,例如 Codex Desktop 与 Antigravity。
仓库能教会 Agent 的事,不该被算成记忆的功劳
第一轮实验使用 Beacon 1.3.46(build f8177a68)和 Codex CLI 0.162.1,运行在 macOS arm64,目的地明确设为 Local。合成项目通过 api.yaml 描述接口,README 说明生成客户端已检入,Makefile 提供生成目标,测试则检查生成客户端与 API 定义的一致性。
第一轮刚跑完,其实挺容易让人产生幻觉的。当时无记忆的对照组 A0 挂了,而走了 Beacon 记忆路径的会话 3/3 测试全过。我复盘时越看越不对劲:第一轮的 A0 居然跑在只读沙箱里,连文件都改不了——好比把对照组的手绑住,然后宣布实验组跑得更快,属于典型的无病呻吟。再加上第一轮的报错信息里直接把 make gen 给漏出来了,就算做对了,也根本分不清是记忆的功劳还是报错提示喂到了嘴边。
等到第二轮把沙箱改成可写、把报错泄漏堵上之后,打脸来得非常直接:没有任何记忆的 A0 自己翻了翻 README、Makefile 和测试,顺理成章地推导出生成规则,1/1 测试一把过。
下表中的“独立隐藏检查”是实验控制器在公开测试之外执行的任务验收,不是 Beacon 内置组件。各轮使用不同的合成夹具和测试套件,1/1、2/2、3/3、4/4 的分母不能横向比较;尤其第三轮 TRAIN 测的是 TSV,两个消费者组测的是 CSV。
| 实验 | 实际结果 | 允许得出的结论 |
|---|---|---|
| 第一轮:A0 / Beacon 路径 | A0 的只读沙箱无效;Beacon 路径人工候选获批、Skill 物化,新会话读取后 3/3 通过 | A0 不提供 Agent 失败证据;第一轮也不能证明记忆带来任务收益 |
| 第二轮 A0:无记忆、可写 | 从 README、Makefile、测试推导规则,get_metrics 的 1/1 测试通过 | 该任务能靠仓库内信息完成,不能把成功归因于记忆 |
| 手工 Checkpoint | Agent 读取 CHECKPOINT.md,最终 2/2 通过 | 手工交接也能完成任务;没有同条件耗时基准 |
| 第三轮 TRAIN:Codex | TSV 公开测试 3/3 通过,实验控制器的隐藏检查 PASS | 训练任务通过;不代表自动蒸馏或跨 Harness 复用通过 |
| 第三轮消费者:Antigravity A0 / MCP | 两组 CSV 公开测试均 3/3 通过;隐藏检查均 FAIL | MCP 读取真实发生,但本次消费者任务的增量收益未得到证明 |
看到这个结果,我默默把原本准备写的“记忆复用成功”给划掉了。给我提了个醒:如果一件事情仓库自己已经写得明明白白,Agent 做对了那是它本来就会看代码,真别硬往 Memory 脸上贴金。
Checkpoint 与 Agent Memory,保存的不是同一种东西
这里我得先按住想看跑分对比的冲动:这轮手工 CHECKPOINT.md 和 Beacon 组并不是严格控制变量的竞速赛,中间的纠错过程和统计口径都不一样,我当时也没拿秒表和统一口径去掐两边的耗时和 Token。
现在事后硬凑两个数字出来比谁更省钱省时间,那就纯属是忽悠了。
抛开跑分,这两种做法在手感上的工程差异其实非常直观:Checkpoint 是摆在明面上的交接单,跟着 Git 走,谁都能审;而 Agent Memory 却像是自动攒经验的错题本……
| 知识类型 | 优先放在哪里 | 需要额外记忆吗? |
|---|---|---|
| 当前代码约束、生成步骤、接口不变量 | README、AGENTS.md、Makefile、测试 | 通常不需要重复存一份;仓库应是当前事实的权威来源 |
| 当前任务进度、已验证 SHA、下一步和阻塞 | Issue、PR、Checkpoint、CI 记录 | 只有在跨会话恢复确有缺口时再补充 |
| 仓库中没有的历史决策、为什么曾经否决某个方案 | 可审查的决策记录或经批准的 Agent Memory | 可能有价值,但要写清来源、适用范围和证据限制 |
| 已经变化的规则、临时例外 | 更新当前仓库事实,并明确废止旧规则 | 不能只追加新记忆;旧记忆必须能被发现、限制或退役 |
| 不能跨数据边界的敏感上下文 | 留在获准的本地边界内 | 不应为了“记住”而默认复制到云端 |
这也是三部曲之间的关系:工程状态由谁保存,数据和执行权限在哪里,最后才是独立记忆层有没有必要。GitHub-first 不是说所有信息都要塞进仓库;它要求项目当前事实可读回、可审查。Agent Memory 也不应成为第二个彼此矛盾的 README。
第三轮:Antigravity 读到了记忆,任务却没通过
前两轮回答了仓库可推导约定的问题,却没有检验历史知识能否跨 Harness 被读取并用于新任务。第三轮换成合成 Python 导出任务:先检验经人工审核批准的历史兼容记忆能否被 Google Antigravity 通过 Beacon Local MCP 真实读取,再观察读取是否改善任务验收。目的地仍是 Local,没有启用 Beacon Cloud;没有安装 Skill,也没有运行 Beacon 评估器。
与前两轮的 make gen 不同,这条兼容规则来自训练会话中的历史纠正,而不是 README、AGENTS.md 或当前测试能直接推导出来的仓库约定。规则是:CSV 和 TSV 导出都应把 Python None 序列化为字面文本 \N(一个反斜杠加大写 N);空字符串仍为空字段,字符串 NULL 保持原样。第三轮的训练 Harness 是 Codex Desktop 0.164.0-alpha.11.1(版本来自本地 Trace 元数据);消费者是 Google Antigravity 桌面版,但精确版本没有记录。现有实验记录也没有保存两侧底层模型名称、推理档位/温度或完整提示词,因此这不是只改变“是否有记忆”一个变量的严格同条件基准。训练组中,Codex 完成 TSV 任务,公开测试 3/3 通过;实验控制器返回的独立隐藏检查回执也报告 PASS。训练结束后,实验执行了 scrub-train。现有回执只记录它把合成仓库恢复到初始源码,没有说明该步骤是否触及 Beacon memory store;批准记忆是在这之后创建并批准的,因此本轮不能用这一步证明记忆库被清空或完全未被触及。
到了最关键的第三轮 MCP 消费者组,我盯着本地回执看:Antigravity 确实老老实实调了 get_memory 和两次 search_memory,把那条“遇到 None 要转成 \N”的历史记忆完完整整读进来了。公开测试 3/3 绿灯。结果一跑独立隐藏检查——又是一个FAIL。
| 消费者组 | 是否读取 Beacon 记忆 | 公开 CSV 测试 | 独立隐藏检查 |
|---|---|---|---|
| A0:Antigravity 无记忆 | 否 | 3/3 PASS | FAIL |
| MCP:Antigravity 有记忆 | 是,实际调用 get_memory / search_memory | 3/3 PASS | FAIL |
最戏剧性的地方就在这:它明明读到了标准答案,为什么还是交了白卷?
翻看 Antigravity 的执行摘要,它的逻辑让人没法反驳:虽然记忆的正文里写了 CSV 和 TSV 都要遵守 None → \N,但这条记忆的 applicability(适用范围)元数据里,只标了 render_tsv 或 TSV 兼容性。再加上 README 里说两个导出函数是独立实现的,Antigravity 就非常正经地认为:既然标签写的是 TSV,那我写 CSV 的时候就不瞎套用了。
这当然还算不上板上钉钉的唯一根因(毕竟隐藏检查器只吐了 FAIL,没给具体挂在哪个断言),但它把做 Agent Memory 一个痛点扒了个底朝天:记忆的适用范围到底该怎么划?
划太宽,上次修 A 模块留下的特殊癖好就会去污染 B 模块;划太窄,正文里明明写了通用规则,就因为元数据标签只打了 TSV,换个 CSV 任务它就装看不见。呵呵
每个消费者臂都只有一次合成任务,而且 A0 与 MCP 组的隐藏检查均失败。两组同为 FAIL,既不能说明记忆带来了改善,也不能说明读取记忆让结果变差。本轮能确认的是:跨 Harness 的记忆读取发生了,但消费者任务的独立验收结果没有改善。 样本不足以估计 Beacon 的总体效果;如果把“检索成功”直接当成“复用成功”,就会把工具调用链误认为有效的工程交付。
这组观察仍有复核边界:筛选后的 Beacon Trace 能看到提示词、补丁调用和测试命令,但没有保留对应的 tool_result 或 error 事件;完整原始 MCP JSON-RPC、隐藏检查器的内部断言和本机运行轨迹也没有作为公开复现包发布。因此,本文记录的是有本地执行摘要与控制器回执支撑的单次观察,不是一键可复现的实验包。
过期记忆能被 Agent 绕过去,不等于 Beacon 会治理它
另一个测试把 Makefile 目标从 gen 改成了 generate,但旧 Skill 仍然写着 make gen。带着旧规则的会话先执行了过期命令,看到:
make: *** No rule to make target 'gen'. Stop.
它随后重新查看 Makefile,改用 make generate,该轮 make test 的 4 项测试全部通过;恢复 Makefile 后,独立的 python3 -m unittest discover -s tests 也报告 4 项通过。这里的 4/4 属于过期记忆夹具,不是第三轮 CSV/TSV 测试套件。这说明 Agent 能在命令报错后回头读取当前仓库,并自行恢复;它不说明 Beacon 自动更新了旧 Skill。过期记忆仍在,真正纠正行为的是 Agent 重新检查当前事实。
这一区别影响工程设计。如果某条记忆会随着代码变化而失效,就不该只依靠模型“应该会发现冲突”。至少需要明确的适用范围、来源和时间边界;当前事实仍以仓库和测试为准。更关键的历史约束应进入版本化决策记录,或在冲突时要求 Agent 停下来核对,而不是继续把旧记忆当作事实。
Local 日志也不是通用的秘密检测器
实验使用合成标记检查本地日志,未放入真实凭据,也没有连接 Beacon Cloud。第一轮在 ~/.beacon/endpoint/logs/runtime.jsonl 中统计到:
$ grep -c 'PLUMOTTER9917' ~/.beacon/endpoint/logs/runtime.jsonl
7
$ grep -c 'sk-canaryfake' ~/.beacon/endpoint/logs/runtime.jsonl
0
$ grep -c 'REDACTED' ~/.beacon/endpoint/logs/runtime.jsonl
1
第二轮结束后,累计计数变为 25、4、6。普通文本标记 PLUMOTTER9917 在本地日志中逐字出现;形状类似 Token 的 sk-canaryfake 匹配行数从 0 变成 4。但我没有检查这四行的内容,因此无法判断命中来自待测值、脱敏后残留的前缀,还是日志中被记录的测试/检索文本。canary 的脱敏结论仍是不确定。
固定版本源码显示,脱敏依赖字段名和已知模式匹配,而不是对任意自然语言进行通用秘密识别。可以直接检查 脱敏实现 与内容保留逻辑。本地日志出现某段文本,也不能证明它被转发到云端;本轮没有连接 Cloud。
同样需要分清源码审计与运行期测试。我把 Beacon 源码固定在 提交 d7a3a72。其 Harness 捕获矩阵、Codex hooks 和 OTLP 事件转换器没有给出 Codex File/MCP 事件的对应捕获映射。这张矩阵描述 Beacon 从各 Harness 采集哪些运行事件,不是 Harness 作为 MCP 客户端调用本地 MCP 服务的能力;两者不是同一条路径。这是固定版本源码检查,不是逐类运行抓包。
Jev 的评估实现也只做了源码核查;没有配置密钥,没有真正运行打分,所以没有评估器分数或自动蒸馏精度数据。在本次使用 tarball 安装 Beacon 1.3.46 并配置 Local endpoint 的本机环境中,未找到 beacon-memory-distill Skill;第二轮隔离子 shell 又因该环境下 beacon 不在 PATH 而无法运行蒸馏。会话恢复参数也曾因 CLI 参数不匹配和 trusted-directory 检查失败,导致纠正没有送达目标会话。这些是本次安装路径和实验编排中的具体观察,不代表所有安装路线都会失败。
记忆应该补仓库的缺口,而不是复制仓库
三轮实验没有证明 Agent Memory 能普遍提高任务成功率,也没有证明它毫无价值。它们把值得付出维护成本的范围缩小了:
- 仓库已经能回答的问题,放在 README、AGENTS.md、Makefile、测试和版本化决策记录里。这样当前事实可以被代码审查和 CI 验证,避免多份记忆互相冲突。
- 仓库没有记录的历史知识,才是独立记忆更有希望发挥作用的地方。比如某项兼容性决定为何做出、曾经否决过什么方案、某个外部流程里有哪些不明显的约束。但记忆必须保留证据来源,并把适用范围写得足够准确。
- 过期或互相冲突的记忆,必须允许被识别、限制和退役。Agent 偶然在命令报错后重新读了 Makefile,不等于系统已经建立了可靠的过期治理。
- 数据边界之外的信息,不应该为了跨会话便利就自动外发。Local 日志、Local MCP 和托管评估器是不同路径,必须分别核对实际配置与数据流。
第一篇讨论把工程上下文放进 GitHub,第二篇讨论数据与执行权限的边界;这次实验补上了最后一个判断:独立记忆不是工程事实的替代品,而是对那些当前仓库无法表达的历史知识的一种候选补充。它是否值得保留,不能只看捕获数量、候选条数或一次成功的读取调用,必须看它能否在明确适用范围内改变新任务的结果,并且经得起独立验收。
实验跑到这我就停了,没有再去手动改那条记忆的 applicability 标签来强行刷出一个 PASS。道理很简单:如果我看着隐藏测试挂了,再人工进去把标签改宽、直到喂到 CSV 任务跑通为止,那我测的根本不是“Agent Memory 能不能从历史会话里自然捕获并跨端复用”,而是在测“我本人对着答案调优提示词的能力”——这就是纯属自我意淫自己骗自己了。
与其硬凑一个大团圆结局,不如把话停在证据能撑住的地方:仓库里写清楚的规矩,不需要额外记忆来抢功;跨工具读记忆的路子确实通了,但怎么让读出来的历史记忆真正帮新任务拿分,这还没跑通。
相关背景:把工程上下文留在 GitHub:AI 编程跨工具接力与多分支协作、代码不上云,网页端 AI 能参与到哪一步?Local-first 与 GitHub-first 的接入边界,以及 Coding Agent 记住上次怎么改代码,就能省 Token 吗?我拆了 Singularity 的检索逻辑。
实测时间说明:第一、二轮于 2026 年 10 月 26 日完成,Antigravity MCP 消费者实验于 2026 年 10 月 27 日完成。