mcpField
R
research-codebase

research-codebase

github.com/jurgendn开发1166 次安装6 周前更新
代码仓库

关于 research-codebase

research-codebase 面向需要可复现实验流程的研究者,尤其适合非程序员。它规定固定的流水线、按配置运行实验,并将结果汇总为论文表格。

主要功能

  1. 01固定的四阶段流水线约定
  2. 02按配置与随机种子运行实验
  3. 03自动记录运行来源与指标
  4. 04汇总生成 CSV 和 LaTeX
  5. 05原型运行与合理性检查

适用场景

  1. 01搭建可重复的研究实验
  2. 02运行参数与随机种子批次
  3. 03从结果生成论文表格

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jurgendn/agent-skills --skill research-codebase

安装后在 Claude Code 中输入/research-codebase确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/project-template/
.gitignore
aggregate.py
configs.py
data.py
metrics.py
README.md
requirements.txt
run.py
sanity_check.py
assets/project-template/algorithms/
__init__.py
mean_baseline.py
ridge.py
assets/project-template/results/
README.md
references/
codebase-cleanup-guide.md
evidence-base.md

详细介绍

研究代码库

围绕科学研究构建实验框架:固定的流程契约、可执行多种配置的运行器,以及将已完成的运行汇总为论文表格的聚合器。用户提供数学内容;此技能确保数学内容被多次运行并得到正确报告。

有两条规则至关重要:

  • 提前固定契约,此后绝不再修改共享代码。 添加实验只能是在列表中添加一行,或在字典中添加一个条目。如果需要修改入口点,说明契约有问题。
  • 来源追踪要靠机制,而非自觉。 每次运行都会记录生成它的信息。不依赖用户记得记录任何内容。

这就是为什么这里不采用“只有遇到问题时才添加结构”的立场。推迟添加结构,意味着有人能够识别问题并完成重构。当用户不会编程时,重构就永远不会发生——项目只会不断积累 train_v2_final_REAL.py。一次性提供小而固定的骨架,确保其正确,并禁止继续扩展。

关于已发表证据支持和不支持的内容,请阅读 references/evidence-base.md。关于如何整理现有的混乱代码,请阅读 references/codebase-cleanup-guide.md。

步骤 0 — 信息收集(一次询问,编写任何文件之前)

将以下问题放在一起,一轮问完。使用论文中的术语,而不是软件术语。

  1. 主要表格或图是什么? 行、列,以及单元格中的内容。以此为基础反向设计聚合器;这是最终交付物。
  2. 一次运行是什么? 它会计算什么、返回哪些数值——包括诊断信息,而不只是核心指标(收敛所需迭代次数、运行时间、秩、稀疏度、最终间隙、是否收敛)。回答将成为结果字典中的必需键。
  3. 不同运行之间有哪些变化? 方法、数据集、一两个参数、随机种子。这将成为参数列表;运行次数决定是否值得实现完成后跳过和并行处理。
  4. 一次运行需要多久,又在哪里运行? 笔记本电脑上几秒钟/单张 GPU 上几分钟/使用调度器的集群上几小时。这是生成代码中影响最大的分支。
  5. 是新项目,还是要整理现有代码? 先检查 ls;只有确实无法确定时才询问。

不要询问:指标存放在哪里、输出目录结构、随机种子数量、是否生成 LaTeX、是否构建配置系统。每项都有下文给出的正确答案。将它们设为默认值,并用一行说明这些默认值。

只问一轮。 每一轮澄清都会要求非程序员做出他们无从判断的决定。如果回答含糊,就采用默认值,说明采用了什么,然后继续。绝不因此停下来:若 Q1 没有答案,就汇总为长格式 CSV(每次运行占一行),并说明仍需提供表格结构;若 Q4 没有答案,就使用串行循环,虽然速度可能较慢,但始终正确。

流水线契约

四个阶段,签名固定。只需按要求生成这些内容,测试框架就只需编写一次。

阶段契约扩展方式
数据load(name, seed) 或 generate(params, seed) → 问题实例新增函数
算法ALGORITHMS: dict[str, Callable],统一调用方式添加一行字典项
指标METRICS: dict[str, Callable],metric(result, data) -> float添加一行字典项
存储outputs/<run_id>/{config.json, metrics.json} → aggregate.py永不扩展 — 固定

这里用普通字典作为注册表最合适——不要在入口点写 if 链,也不要用装饰器插件系统。 每新增一种方法,if 链都要求修改共享入口点;对于不会编程的人来说,这是风险最高的改动,而且一旦出错,就会导致所有运行同时失败。字典只需一行,没有任何魔法:

# algorithms/__init__.py — add a method by adding one line.
from algorithms.ridge import ridge
ALGORITHMS = {"ridge": ridge}

指标不依赖模型。 每种算法都返回一个结果字典,指标只读取其中的内容:

{"preds": ..., "n_iters": 34, "rank": 7, "fit_seconds": 1.2}

如果某个指标“需要模型”——例如稀疏度、秩、迭代次数、运行时间——算法只要报告相应信息即可。绝不要让指标访问拟合对象:一旦某个基线使用 sklearn 估计器,而某种方法使用自定义类,读取 model.coef_ 的指标就会在某些方法上崩溃、在另一些方法上正常运行;不会编程的人无法调试这种故障。统一的结果字典从设计上杜绝了这种情况。如果某项指标确实必须重新探测拟合对象(例如在第三个数据划分上评估,或在拟合后调整阈值),可以将可选的 "model" 键作为有文档说明的例外,但绝不能作为默认路径。

这就是为什么 Q2 会要求提前确定所有数值:之后要添加新的诊断项,只需在每个算法文件中加一行,所以现在就做出这个成本很低的决定。

不可妥协的要求(及其实现机制)

  • 每次运行都写入 config.json,其中包含 argv、解析后的参数、种子和 git rev-parse HEAD。绝不要使用手动维护的映射文件——运行次数达到数百次时,手动记录溯源信息不是不可靠,而是不可能。
  • 每次运行都写入包含 Q2 所需键的 metrics.json。缺少键时要在运行时明确报错,而不是等运行 200 次后才发现表格中有空缺。
  • 设置并记录所有正在使用的随机数生成器的种子。
  • 绝不修改 data/raw/。
  • 跟踪 results/;将 outputs/ 加入 git 忽略列表,并确保其可重新生成。
  • 最终数值必须来自脚本,绝不能来自笔记本。
  • 论文中的表格必须由 aggregate.py 生成,不能手动转录。

运行器

使用一个脚本处理参数列表。不要为每次运行单独编写一个 shell 脚本——有 N 个配置 × M 个种子时,这种做法会成为瓶颈,而手动编辑 N×M 个文件正是不会编程的人容易引入隐蔽错误的地方。

# configs.py — the whole experiment plan lives here.
CONFIGS = [
    {"data": "synthetic", "algorithm": a, "n": n}
    for a in ("ridge", "lasso")
    for n in (100, 1000)
]
SEEDS = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

运行器会遍历 CONFIGS × SEEDS,根据配置生成确定性的 run_id,跳过所有已存在 metrics.json 的运行,并将结果写入 outputs/<run_id>/。如果扫描中途崩溃,只会损失尚未完成的运行。默认串行执行;只有在 Q4 表明运行时间较长时,才使用并行工作进程或调度器数组作业。

只有运行次数大致超过 50 次,或需要在多台机器间共享配置时,才改用配置文件(YAML/TOML)。低于这个规模时,Python 列表需要的基础设施更少,也更容易让用户阅读。

聚合

aggregate.py 会匹配 outputs/*/metrics.json,按配置对不同种子进行分组,并同时生成 CSV 和可直接用于 booktabs 的 LaTeX 行。始终生成 LaTeX——用户使用 LaTeX 写作,生成这些行可以避免一整类转录错误。

每种配置报告:n_seeds、均值和 bootstrap 置信区间,并将训练集和测试集的量分别作为独立列(metric_train、metric_test、sigma_train、sigma_test),而不是合并成综合分数。

以下两条规则与风格无关:

  • 聚合所有与配置匹配的运行结果。 绝不取最大值,也绝不只取排名靠前的 N 个种子。挑选多个试验中的最佳结果,是一种有明确名称的误导性结果来源。
  • 不要将种子数量硬编码为足够。 十个是合理的初始默认值,但已有研究表明,超参数相同、彼此独立的两组各含五个种子的结果,可能呈现统计上不同的分布。如果置信区间宽到与基线重叠,正确做法是增加种子,而不是提出更大胆的结论。关于“这种差异是否真实”的问题,请参考 statistical-testing-guide;关于消融结构,请参考 hypothesis-and-ablation-planner。

过拟合诊断和“这些增益看起来真实吗”的判断属于 experiment-design。此技能会输出这类诊断所需的原始训练集/测试集列,到此为止。

原型门槛

启动完整的参数扫描前,先用简单数据完整运行一次流水线——可以是生成的微型实例,也可以是裁剪过的数据集。重点不在数值,而在于端到端地检查日志记录、聚合和 LaTeX 输出,并估算运行时间,以便在付出完整扫描的成本之前了解其开销。根据这次运行推算,判断按计划进行扫描是否负担得起。

sanity_check.py

这不是测试套件,而是从快速发布到撤回之间最精简的一组检查。共有四项,每项用户都可以确认它在数学上确实是正确的检查,即使用户不会编写这些检查:

  1. 确定性——相同种子运行两次会得到逐位一致的指标。可发现未设种子的随机性。
  2. 必需键——每种算法都会返回所有 Q2 键。可发现表格中的缺项。
  3. 数据泄漏——训练集和测试集的索引集合互不相交(仅适用于学习场景)。
  4. 学习/正确性——方法能在一个小批次上将损失降至约 0,或在具有闭式解的案例中与已知参考解一致(适用于仿真和数值场景)。

可跳过的事项

除非有具体理由,否则先跳过:打包(pyproject.toml、PyPI)、持续集成、类型检查、生成式文档站点、实验跟踪服务、抽象配置系统、类层次结构。一些已发表的指南建议在机器学习研究中普遍采用前四项;但这类建议针对的是已发布的制品,其作者也明确指出,这些建议“仅在适当时”适用。对于截止日期前由非程序员进行的在研实验,这些工作的成本是实实在在的,而收益要到提交之后才会出现。在发布制品时再重新考虑——该阶段由 artifact-release-packager 负责。

同一指南中不可跳过的事项是:明确记录种子、固定依赖项,以及提供一条能够重新运行论文中所有实验的命令。运行器就是这条命令。

输出

提供建议时:

  • 先询问第 0 步的批次,然后重述填写完整的契约(四个阶段、结果字典的键、参数列表);
  • 说明未询问便采用的默认值;
  • 在加入用户的任何数学内容之前,先生成一个能在玩具数据上端到端运行的骨架——带有 TODO 空缺的模板对不会编程的人没有用;
  • 说明从命令到表格的路径:run.py → outputs/<run_id>/metrics.json → aggregate.py → results/;
  • 对于现有代码,遵循 references/codebase-cleanup-guide.md,并在删除之前说明哪些内容是关键依赖。

用户无法阅读的生成代码也必须正确。通过运行来验证测试框架,而不是只靠检查: 看起来合理、实际能执行但结果错误的代码,正是这里典型的失败模式。

评论

支持 Markdown