← 工作原理 · 原文件 notes/architecture/13_records.md(Markdown 源文件已渲染;链接到其他文档的会跳转,指向源码的只显示路径)
13 实验记录、溯源与消融协议(G27)
用户要求(2026-10-01):一切都能通过 git 追溯;消融要有重复、要有事先写清楚的「改进」定义;所有轨迹(对话、文件、权重)都要记下来,而且分门别类,不混在一起。
本文件回答三件事:每类记录放在哪、什么格式、留多久;一个 run 怎么追溯到代码;消融怎么做、怎么判定。
1. 四类轨迹 + 两张总账
| 类别 | 记的是什么 | 位置 | 格式 | 谁写 | 保留 |
|---|---|---|---|---|---|
| (a) run 内轨迹 | Agent 在一次 run 里的全部对话、计划、代码、打分 | run 目录(Spark:~/vec/runs/{formal,test}/<run_id>/,虚拟机:agent/runs/<run_id>/;按 run id 查找见 agent/paths.py) | JSONL、SQLite、git bundle | harness / 控制器自动写 | run 目录永久保留;节点 work/ 与预测文件在节点结束后清理(G23) |
| (b) 操作日志 | 人对 run 做过的每个动作 | <run_dir>/operator_log.jsonl(G23 起);更早的 run 是 OPERATOR_NOTES.md | JSONL | harness 每个子命令自动写 | 跟 run 目录走,打进证据包 |
| (c) 开发日志 | 每个 G 任务做了什么、为什么 | notes/reports/dev/;拍板在 notes/changelogs/decisions.tsv | Markdown、TSV | Claude(审查子 agent 报告后) | git 永久 |
| (d) 官网提交 | 交了哪份预测、拿了多少分 | notes/changelogs/submissions.tsv | TSV,只追加 | scripts/record_submission.py | git 永久 |
| 运行登记表 | 每个 run 的目的、假设、代码版本、配置、结果、官网分 | notes/changelogs/runs.tsv | TSV,只追加 | harness launch / package、record_submission(Part B);python -m agent.records backfill | git 永久 |
| 迭代报告 | 每个 run / 每次提交的中文复盘 | notes/reports/runs/<date>_<run_id>.md | Markdown | 报告 Agent(G28) | git 永久 |
分开的原则:(a) 是 Agent 自己的东西,只在 run 目录里,锁定后人不读中间结果;(b) 是人的动作,和 (a) 物理上分文件,证据包里也分文件;(c) 是开发期(锁定前)的工程记录,只在主仓库 notes/,永远不进 Agent 上下文;(d) 和登记表是结果台账,只追加不改写。四类之间只用 run_id、G 编号、ledger 行号互相引用,不复制内容。
2. (a) run 内轨迹
搜索模式(mode: search)一个 run 目录里:
| 路径 | 内容 |
|---|---|
nodes/<id>/{researcher,engineer,analyst,reviewer}.jsonl | 每个节点、每个角色一份 LLM 会话轨迹(opencode JSON 事件流);同名 .stderr 是 CLI 错误输出 |
nodes/<id>/PLAN.json、ANALYSIS.json、METHOD.md、DELTA.md、analysis/diff.patch | Researcher 计划、Analyst 结论、方法说明、与父节点的分数差、代码改动 |
nodes/<id>/exec*、promo_seed*、final_* | 执行 / 复测 / 终选的结果文件(大文件在节点结束后清理,保留日志和 json) |
archive.sqlite | 搜索树:节点、分数、各把尺子、事件(晋级、终选) |
programs.git | 每个节点的程序是一次 commit;证据包里是 programs.bundle |
research_log.jsonl | 文献检索服务(lit-search,G17)的每次查询 |
scoring_log.jsonl | 打分服务的每次调用(谁、哪道题、哪半真值、分数) |
egress_log.jsonl | 出网代理的每次连接(只放行 LLM 域名) |
controller.log、service.log、heartbeat.json | 控制器与服务日志 |
config.lock.json、run_meta.json | 锁(配置、代码哈希、评分器指纹、模型 id)与运行状态 |
final/SELECTION.md | 控制器写的终选说明(无人工输入) |
evidence/ | 打包证据:MANIFEST.json、trajectories_index.json、lineage_trajectories.tar.gz(胜者祖先链上全部节点的轨迹,含跨 run 接续导入的)、各日志副本 |
单 Agent 模式(mode: agent):trajectory.jsonl(整段会话)、prompts/、workspace/(含 Agent 自己的 git、experiments.tsv、final/SELECTION.md)、evidence/。
保留:run 目录不删。磁盘紧张时只删节点 work/ 和预测 .h5ad(G23 已实现,日志与轨迹保留)。正式提交时按 prepare_submission.py 选证据子集(单文件 ≤ 200 MB,全队 600 MB 上限);没上传的部分仍在 run 目录。
3. (b) 操作日志
- G23 起,
harness.py每个作用于 run 的子命令(launch、resume、package、verify 等)都往<run_dir>/operator_log.jsonl追加一行:时间、argv、主机、用户、pid、systemd 单元。 - 人工动作若改动了 run 受保护的文件,run 标记 tainted(G23;G29 改为写入时登记哈希的只追加台账)。
- 更早的 run(run1)用手写
OPERATOR_NOTES.md。 - 操作日志和 Agent 轨迹不在同一文件;证据包里各自一份。
4. (c) 开发日志
- 每个 G 任务验收后,Claude 把子 agent 的最终报告整理成
notes/reports/dev/<YYYY-MM-DD>_<G-id>.md(日期 = 验收日),写清:做了什么、验收结果、遗留问题、提交 commit、对应 decisions 行。 - G1–G29 的补录只做索引(一行一个任务,链到任务书、commit、decisions 行),见 reports/dev/README.md。
- 拍板(为什么、否决了什么)仍只写
decisions.tsv;开发日志只引用行号,不重复。 - 开发日志在主仓库
notes/,run 的沙箱读不到主仓库notes/(G1、G4 的隔离验收项),所以不会进 Agent 上下文。
5. (d) 官网提交与运行登记表
提交账本 submissions.tsv:上传时一行,出分时再追加一行 score_of=<上传行号>,不改旧行(G8)。
运行登记表 runs.tsv(G27,列见 agent/records/README.md):
| 何时 | 谁写 | status |
|---|---|---|
| launch 写完锁之后 | harness.py(Part B,调用 append_start) | started |
| package 打完证据之后 | harness.py(Part B,append_end) | ended:<state>:带节点数、最好排序分、胜者在每把尺子上的分 |
| 官网出分 | record_submission.py --score(Part B,append_score) | official:<上传行号> |
| G27 之前的 run | python -m agent.records backfill --spark | backfill:<state>;目的写「[回填] + 配置文件开头注释」 |
- 配置文件必须有
purpose:(这次 run 为了什么)和hypothesis:(预期结果);可选ablation_of:(基线 run_id 或消融组名,如G21)和changed_factor:(这一臂改了什么)。缺字段的可提交 run,launch 拒绝启动(Part B 调check_config)。 - 只追加、不改写;更正就追加新行。一个 run 的当前状态 = 按文件顺序把它的各行叠起来(后写的非空格子覆盖前面的;官网分按题目收集)。
- Spark 克隆上 harness 写的是 Spark 那份
runs.tsv;VM 上用python -m agent.records merge --ssh spark:vec/2026_virtual_embryo/notes/changelogs/runs.tsv合并后再提交(逐行去重)。
看板「实验登记」页直接读这张表(每 5 分钟)。
6. git 溯源(计划:Part B + G29)
- 可提交 run 的 launch 在锁定的 commit 上建附注 tag
run/<run_id>(VM 仓库建,sync_spark.sh推到 Spark 裸仓库);锁里记git_commit与git_tag,登记表同步记两列。 - Spark 克隆必须和锁定 commit 一致,否则 launch 拒绝(不再允许「VM 上改了、Spark 上跑的是另一版」)。
- G29:launch 时为每个 run 建只读的代码检出(锁定 commit 的完整副本),run 期间读 prompts、ideas、knowledge、代码都从这份检出读,
sync_spark.sh更新主克隆不再影响在跑的 run。 dirty(有未提交改动)的 run 不可提交;登记表git_commit后缀+dirty。- 追溯路径:官网分 →
submissions.tsv行 →run_id→runs.tsv(commit、tag、config 哈希)→git show run/<run_id>→ 锁里的文件哈希逐一可核。
G27 之前的 run 没有 tag,用锁里的 harness_git_sha 追溯(backfill 已写入 git_commit)。
7. 模型权重(计划:Part B,建在 G29 的 ARTIFACTS.json 上)
- 候选程序可以在
solution/或节点工作目录写训练好的权重;G29 要求 >20 MB 的权重在solution/ARTIFACTS.json里声明(路径、sha256)。 - 保留:晋级复测的前 5 名、最终胜者及其整条祖先链的权重,复制到
<run_dir>/weights/<node_id>/,旁边一份清单(文件、大小、sha256、产出节点、框架)。 - 每个 run 设上限(配置
weights.cap_gb,默认 20 GB);超了先删最早的非祖先链权重。 - 证据包只放清单(小于阈值的权重才放本体);权重本体留在 run 目录。
8. 消融协议
定义:一次消融 = 只改一个因素(changed_factor),其他配置、种子集合、预算都相同;每一臂 ≥ 3 次重复 run(不同 search_seed,各臂用同一组 seed)。各臂在登记表里用同一个 ablation_of(基线 run_id 或组名)连起来。
流程:
- 写配置:每个 run 都有
purpose、hypothesis、ablation_of、changed_factor(G21 的 12 个配置已按此生成)。 - 看结果之前把判定规则写进
decisions.tsv(预注册),之后不改。 - 跑完、提交、记分后:
python scripts/ablation.py summary <组名或 run_id…> [--by changed_factor] [--metric all]。 - 把输出结论写进
decisions.tsv新行,引用登记表行。
「改进」的事先定义(agent/records/stats.py):A 臂比 B 臂有改进,当且仅当
- 每臂 n ≥ 3(否则输出「样本不足」,不下结论);
- 均值差 mean(A) − mean(B) 大于噪声阈值 T:T1 题 2 分、T2 题 1 分(本地尺子单次打分噪声,k014 /
agent/prompts/analyst_spec.md;T3 未测,暂按 1 分); - 均值差的 bootstrap 95% 置信区间不含 0(两臂各自有放回重抽,10000 次,百分位区间,随机种子 0,可复现)。
均值差够大但区间含 0 → 「未确立」;均值差 ≤ T → 「不超过噪声」。官网分和每把本地尺子都单独算一遍(--metric all)。
本地尺子可信度:全部已提交点(登记表里有官网分的 run)上,每把尺子分与官网分的 Spearman ρ(处理并列名次),bootstrap 95% CI(重抽 1000 对);不到 3 个点不计算。这是 G21 判定规则 ② 要的数。
G21 的预注册判定(decisions.tsv 第 74 行,脚本对 ablation_of = G21 的 run 自动套用):① 12 小时 run 的目标 = 官网均分最高的臂;前两臂均分差 < 1 分时,选本地尺子标准差平均更小的那臂;③ 所有臂官网均分都 < 50 → 不开 12 小时 run,先回到方法与尺子问题。
9. 保留期汇总
| 东西 | 保留 |
|---|---|
| run 目录(轨迹、存档、日志、锁、证据) | 永久(磁盘紧张时只删节点 work/ 与预测文件) |
| 权重 | 晋级前 5 + 胜者 + 祖先链,单 run ≤ 20 GB(Part B) |
runs.tsv、submissions.tsv、decisions.tsv、experiments.tsv | git,永久,只追加 |
notes/reports/(runs/、reviews/、dev/) | git,永久 |
run/<run_id> tag | 永久,不删不移 |
看板缓存(~/vec/dashboard/) | 可随时重建,不算记录 |