核心结论
AI 生成的科研代码“能够运行”只通过了最低门槛。结果可信还需要任务规格、测试数据、版本环境、随机性、输入输出校验和与独立实现的结果对照。研究者必须能说明每一步代码对应什么研究决定,不能把无法理解的脚本直接用于正式数据和论文。
最稳妥的工作方式是把代码当作可检验的研究产物:先写输入、规则和预期,再让 AI 生成小模块;先在人工可计算的样本上测试,再运行完整数据;每次修改都重跑测试并保存环境。
科研代码错误为什么特别隐蔽
普通软件错误可能让程序崩溃,科研代码错误更危险的情况是程序顺利运行、图表也很漂亮,但样本筛选、单位、分组、缺失或统计方向已经错了。
常见例子包括:
- 把参与者级重复测量当成独立样本;
- 合并表格时产生一对多扩张,样本被重复计算;
- 将缺失值默认为零;
- 分类标签顺序变化后,模型参照组被调换;
- 在计算比值或对数时静默丢弃非法值;
- 使用全体数据做标准化后再划分训练和测试,产生泄漏;
- 随机种子、包版本和外部接口变化,结果无法重现。
这些错误不能靠阅读最终图表发现,需要在代码运行前后设置具体测试。
教学案例:重写神经科学数据脚本
**教学模拟案例:**神经科学研究者江澈有一段旧脚本,用于把每名参与者多个实验试次汇总成条件均值。脚本由前任学生编写,缺少说明。她希望 AI 重写为更清楚的 Python 代码。
江澈没有只上传旧代码并说“优化一下”,而是写任务规格:
| 项目 | 教学示例 |
|---|---|
| 输入单位 | 一行代表一个试次;参与者、条件、反应时、正确与否 |
| 纳入规则 | 只纳入正确试次;按预先阈值标记反应时,不自动删除参与者 |
| 汇总单位 | 每名参与者、每个条件一行 |
| 输出 | 有效试次数、均值、中位数、标记数量和排除原因 |
| 不允许 | 覆盖原始文件;静默删除缺失;改变条件标签 |
| 测试 | 两名虚拟参与者共12个试次,结果可手工计算 |
AI 生成第一版代码后,测试发现它先按全体试次计算均值,再筛选错误反应,导致结果与预期不同。因为任务有小型参考答案,错误在处理正式数据前被发现。
规格必须连接研究决定
一份代码任务说明至少包括:
- 输入文件、字段、类型、单位和主键;
- 研究单位与数据行之间的关系;
- 每个筛选、转换和汇总规则的来源;
- 期望输出、允许的缺失和错误消息;
- 不得发生的静默行为;
- 测试样本及其预期结果;
- 运行环境、依赖和可接受性能。
“清理异常值”不是规格,因为它没有说明异常定义、是否排除、谁批准。“按照方案2.1的反应时规则生成标记列,保留原值和原因”才可以实现和测试。
把代码拆成能够单独验收的模块
长脚本一次生成,很难定位错误。可以按数据加载、结构验证、规则转换、统计汇总、图表输出拆开。每个模块明确输入输出,并在合并前通过测试。
拆分不是为了追求工程形式,而是减少科研判断被隐藏。例如“识别疑似异常”与“决定排除”应是两个模块;前者生成标记,后者依据冻结规则和批准记录形成分析集。
最低测试集合
正常样本
确认典型数据产生预期输出。江澈的样本中,每个条件有已知正确试次数和均值。
边界样本
值恰好位于阈值、只有一个有效试次、一个条件完全缺失时,程序应按明确定义处理。
错误样本
重复主键、非法条件、无法解析的数值或缺列时,程序应停止并说明问题,而不是继续生成部分结果。
不变量
处理前后必须保持的关系,例如参与者集合不应无记录消失、汇总试次数加总应等于有效输入数、条件标签只能来自允许集合。
回归测试
修改代码后,过去已经通过的输入仍应得到相同结果,除非修改说明明确改变预期。
结果要与独立实现对照
关键统计量至少用另一种方式复算:人工小样本、成熟软件、独立函数或团队已有结果。对照不应只是同一个 AI 再写一段相似代码,因为两段代码可能共享同一错误假设。
江澈用电子表格手工计算 12 个测试试次,又用旧脚本在经过确认的子集上运行,比较每名参与者的有效试次和均值。差异必须逐项解释,不能选择更符合预期的一边。
保存环境和随机性
代码、数据相同,依赖版本、操作系统、硬件、外部模型和随机过程不同,结果仍可能变化。至少保存:编程语言和版本、依赖锁定文件、操作系统或容器信息、随机种子、关键配置、输入数据版本和运行命令。
美国国家科学院关于可复现性的报告把计算可复现理解为使用相同输入数据、计算步骤、方法、代码和分析条件获得一致结果。Software Sustainability Institute也强调记录依赖、环境、输入输出和运行方法。
对于调用外部 AI API 的分析,还要记录模型版本、访问日期、关键参数、提示和原始响应。无法固定的服务要保存实际输出,并承认之后可能无法完全重复。
代码审查要审“科学含义”
普通代码审查关注可读性和错误,科研代码还要逐行对应方法:这一筛选是否与纳排规则一致;这个变量是否用了正确时间点;这个模型是否与设计匹配;图中的样本数是否和正文一致。
最佳审查人不一定是最会写代码的人。领域研究者确认变量和实验逻辑,统计人员确认分析,软件人员确认实现和测试。AI 可以生成解释草稿,但团队必须能够自行说明关键代码。
填写完成的代码验收记录
任务:按参与者和条件汇总正确试次
代码版本:0.3
输入数据版本:demo-trials-1.1
规则来源:分析方案2.1,第5节
测试T01:正常12试次
预期:2名参与者×2条件;有效试次数和均值见人工表
实际:通过
测试T02:一个条件全缺失
预期:保留参与者,输出缺失状态,不生成零均值
实际:通过
测试T03:重复试次编号
预期:停止并列出重复键
实际:通过
独立复算:人工表与脚本关键统计量一致
环境:Python及依赖版本保存在锁定文件
未解决:正式数据中3个未知条件标签,运行前需数据负责人处理
核验人:领域研究者+代码审查者
从空环境重跑一次才算可复现
开发电脑上运行成功,可能依赖未记录的包、缓存文件、手工点击或环境变量。交付前应在新的虚拟环境、容器或另一台受控机器上,从说明文档开始执行:安装依赖、获取允许共享的输入、运行测试、生成主要结果,并比较输出校验值或关键统计量。过程中任何“我电脑上原来就有”的步骤都要补入环境或文档。
若真实数据不能离开安全环境,可以准备结构一致的合成数据验证完整流程,再由获批人员在安全环境运行真实数据。合成数据证明的是软件接口和部分规则,不证明真实结果正确;真实运行仍需记录输入版本、日志和结果核验。
最低可复现包通常包括:机器可读依赖版本、固定的入口命令、配置示例、数据字段说明、测试、随机种子策略、主要输出位置和已知限制。不要只保存 AI 对代码的解释,因为解释可能与实际实现不同;代码、测试和运行记录才是主要证据。
修改一处代码,要追踪所有下游结果
一个清洗阈值、参照组或随机种子策略的变化,可能影响多个表图。建议建立输出清单,标记每项结果依赖的脚本和数据版本。合并代码前运行全部回归测试,并重新生成受影响产物;禁止只手工替换正文中的一个数字。
AI 可以根据依赖关系提出受影响文件候选,但研究者要确认科学含义。例如改变时间窗口不仅影响一张图,也可能改变纳入样本、主要结局和方法描述。若无法确定影响范围,应冻结发布并由代码与领域负责人共同审查。
代码审查通过后,还应保留一份“已知限制”清单:支持哪些输入范围,遇到哪些缺失或编码会拒绝,尚未覆盖哪些平台和边界,以及输出不能用于什么判断。它比笼统写“代码仅供参考”更有用。后续复用者改变数据结构或研究问题时,必须重新验证,不能把一次项目内通过理解为普遍正确。
若 AI 生成了第三方代码片段或依赖,还需核对许可证、安全性与来源。不要把模型给出的包名、函数签名或版本当作真实;先查正式文档,在锁定环境中安装并测试,避免为了运行一段代码泄露凭据或引入未经评估的组件。
必须停止的情况
- 研究者无法说明代码对应的研究规则;
- 程序直接覆盖原始数据或没有版本;
- 关键输出没有测试样本和独立复算;
- 合并、筛选或缺失处理静默改变样本数;
- AI 建议删除失败测试、忽略警告或硬编码结果;
- 软件和模型版本无法记录,结果又高度依赖它们;
- 代码涉及高维、临床决策或复杂统计,团队缺乏相应审查能力。
此时应缩小模块、补齐规格和测试,或请研究软件和统计人员审查。让 AI 再解释一次无法替代可执行的证据。
可直接复用的科研代码任务说明
科研目的与代码任务:
规则来源和版本:
输入文件、字段、类型、单位和主键:
实验/观察单位:
允许值、缺失和异常:
处理步骤:
每步输入与输出:
不得发生的静默行为:
错误时怎样停止:
正常、边界和错误测试:
每个测试的预期结果:
需要独立复算的关键结果:
语言、依赖、环境和随机种子:
数据与代码版本:
运行命令:
审查人和放行日期:
科研代码完成的标准,是另一名研究者能够从原始输入和记录重新运行、得到一致结果,并理解每个关键数字怎样产生,而不是“这段代码由更强的模型写成”。