
做科研的人大概都有过这种体验一个课题做三个月真正花在“想问题”上的时间可能不到三成剩下七成全耗在重复动作上——翻文献、对格式、重跑一遍不知道哪里出错的脚本、把同一张图按不同期刊要求导出五个版本。这两年命令行 AI 编程助手火了Codex、Claude Code 这类工具能读文件、能执行命令、能改代码很多人第一反应就是“那我是不是可以让它帮我干这些活”。试过之后多数人的结论是能干一点但不敢信。它跑得挺欢结果经不起核对。问题不在模型本身而在于你丢给它的是一个光秃秃的会话窗口里面没有任何关于“你们这个领域该怎么干活”的约束。Scientific Agent Skills 想解决的正是这一层——把科研流程里那些固定的动作、规范、检查项写成 AI 助手能够按需加载的技能包让 Codex、Claude Code 从“会写代码的聊天机器人”变成“知道规矩的科研助手”。下面这套东西我在几个数据分析型项目里反复打磨过从目录怎么摆、技能文件怎么写到脚本怎么防跑飞、结果怎么验证都是可以直接抄的结构。适合两类人看一类是有一定编程基础、想把 AI 真正嵌进研究流程的研究生和博后另一类是带学生、希望把实验室的隐性规范固化成工具链的导师。1. 先搞清楚科研助手缺的到底是能力还是规矩1.1 从“能聊天”到“能干活”中间隔着什么很多人对 AI 助手的失望来源于一个错误预期以为它读得懂论文、写得出代码就该能直接接手科研任务。实际用下来你会发现它确实读得懂、写得出但它不知道该按什么顺序读、按什么标准写。举个最常见的场景你让它处理一批实验数据它会很自然地写出一段 pandas 代码跑出均值、标准差、p 值然后给你一段通顺的解释。看起来很完美问题在于——它没有做正态性检验就上了 t 检验没有记录随机种子没有保存中间结果也没告诉你它把缺失值悄悄 drop 掉了。这套操作在代码层面完全正确在科研层面完全不合格。这就是关键差异。编程助手优化的是“代码能不能跑通”科研助手要优化的是“结论能不能经得起复核”。前者是能力问题后者是规矩问题。而规矩这件事恰恰是通用大模型最缺的因为它不在训练语料的显眼位置——没人会把“我们实验室处理离群值必须先画箱线图再决定”这种话写进公开文档。Scientific Agent Skills 的思路就是把这些规矩从人的脑子里、从实验室的口口相传里抠出来写成文件放进项目目录让 AI 在需要的时候自己去读。它不是什么新框架本质上就是一套约定用固定目录结构组织领域知识用元数据告诉模型“什么时候该用我”用脚本把易错操作固化下来。Codex 和 Claude Code 这类工具本身支持读取工作目录下的文件、按指令执行命令这就给了技能包落地的土壤。我建议你先接受一个前提不要指望一次对话解决一个课题。把 AI 助手当成一个刚进组的、手很快但不懂规矩的新人你的任务是给它写一份足够细致的 SOP而不是指望它天生懂事。1.2 一个技能包的目录长什么样为什么这么设计技能包的组织方式我试过三种全塞进一个大提示词、写成单个长 Markdown、拆成目录按需加载。前两种都死在同一个地方——上下文。你把实验室三年的规范全写成两万字提示词模型每次对话都要吃掉这两万字真正留给数据的内容所剩无几而且它对这么长的文本注意力是衰减的越靠后的规则越容易被忽略。目录式方案是目前最稳的。一个技能一个目录结构大致是这样skills/ ├── lit-review/ │ ├── SKILL.md │ ├── scripts/ │ │ └── dedupe_refs.py │ └── references/ │ └── screening_rules.md ├── stat-analysis/ │ ├── SKILL.md │ └── scripts/ │ ├── assumption_check.py │ └── report_stats.py └── figure-export/ ├── SKILL.md └── scripts/ └── export_figure.pySKILL.md是入口里面分两部分文件头的元数据名称、一句话描述和正文的详细说明。关键在于加载是分层的——模型一开始只看到所有技能的“名称 一句话描述”判断当前任务需要哪个技能才会去读那个技能的完整正文正文里如果提到某个脚本它再去读脚本。这套机制通常叫渐进式披露好处很直接你有二十个技能日常对话的上下文开销也只相当于二十行描述而不是二十篇文档。注意这套机制能成立的前提是那句“一句话描述”写得足够准。描述写虚了模型就路由不到正确的技能后面的精心设计全部白费。这是整个体系里最容易被低估的一环。1.3 技能边界怎么划宁可窄不要宽我最早写技能的时候犯过一个典型错误做了个叫“数据分析”的技能里面塞了清洗、统计、绘图、导出四块内容。结果模型每次触发这个技能都会把四块内容全读一遍然后在清洗阶段就开始考虑图表配色注意力被严重稀释输出质量反而不如不加载。后来改成按动作切分>--- name: stat-analysis description: 当需要对实验数据进行组间比较、相关性分析或回归建模时使用包含假设检验流程、效应量计算与结果表输出规范 ---name用小写加短横线别用中文和空格description是最关键的一行写法后面单独讲。三条横线少一条、缩进错一个空格都可能解析失败。第三个坑是编码。路径里有中文、文件用 GBK 保存都可能让解析器读出一堆乱码然后静默失败。统一用 UTF-8路径尽量用英文这个成本很低收益很大。2.3 那句描述到底该怎么写description不是简介是路由条件。写成“数据分析相关技能”几乎等于没写因为模型无法判断什么时候该用它。正确的写法是描述触发场景包含三要素动作、对象、产出。对比一下就明白了写法内容效果差数据统计分析技能几乎不触发或者乱触发中用于统计检验触发不稳定同类任务时灵时不灵好当需要对两组或多组实验数据进行差异比较、相关性检验或回归建模并输出含效应量与置信区间的结果表时使用触发准确且能区分于清洗、绘图技能好的写法里其实藏着排他信息——“输出含效应量与置信区间的结果表”这句让模型知道这个技能不是只算个 p 值就完事它还负责结果表。当任务只是“把数据里的空值处理掉”时它就不会误触发。我自己的习惯是每写一个新技能先拿三个不同类型的任务去试一个该触发的、一个不该触发的、一个边界模糊的。三个都判对了这个描述才算过关。这个过程花不了几分钟但能省掉后面大量的调试。3. 六个核心技能的具体拆解3.1 文献整理技能把“读过”变成“可检索”文献这块最容易被做成花架子。让 AI 总结论文它总结得很漂亮但你过两周回头看那些总结既不能支撑论证也无法定位到原文位置。所以这个技能的核心不是“总结”而是结构化留存。我在技能里定的规矩是三条。第一任何一条来自文献的判断必须同时记录三样东西文献标识、原文片段、以及这个片段支撑的是哪个论点。缺一样就不算完成。第二摘要和结论分开记不要混在一起因为这两者的可信度完全不同——摘要里的表述往往是作者的主观概括结论里的数据才是硬货。第三建立淘汰记录被筛掉的文献也要记下筛掉的理由否则三个月后你会重新读一遍同一篇。配套脚本做的是去重和格式化。去重不能只按标题字符串比对A study of X和A Study of X.在字符串层面完全不同得先归一化转小写、去标点、压缩空格再算相似度。相似度阈值我一般设在 0.9高于这个值判为重复。低于 0.85 的基本是不同文献中间那段灰色地带交给人工判断不要自动合并——误合并的代价远高于漏合并。注意技能里必须明确写死“不得凭空生成文献信息”。这类助手在补全参考文献格式时编造作者、年份、卷期页码是很常见的行为而且编得非常像真的。凡是涉及文献元数据一律要求从已有文件中提取提取不到就留空并标注待补绝不允许“推测填写”。3.2 数据清洗技能把所有隐式决定变成显式记录清洗环节是科研可复现性最容易崩的地方。一个人处理缺失值可能顺手就删了、可能均值填补了、可能前向填充了做完自己都记不清。半年后别人问起来只能含糊说“处理过了”。技能文件里我会强制要求输出一份清洗日志逐条记录做了什么操作、影响了多少行、为什么这么做。日志不是给人看的备注是分析流程的一部分跟结果表一起归档。缺失值处理的判断链条要写清楚不能一句“酌情处理”打发过去。我常用的顺序是先算缺失比例单列缺失超过三成的直接剔除该列并记录剩下的看缺失机制如果是完全随机缺失且比例低用中位数或众数填补同时保留一个标记列如果缺失本身携带信息比如高收入人群更不愿意填收入那就不能简单填补得单独提出来讨论。这套逻辑写进技能模型就不会无脑dropna()。离群值同理。技能里明确禁止“直接删除 3 个标准差之外的点”要求先画分布图再决定是保留、缩尾还是剔除并且必须在日志里写明判断依据。这条规矩救过我好几次——有好几个所谓的离群点其实是稀有但真实的极端案例删掉就把最有意思的发现删掉了。3.3 统计检验技能先检查假设再谈 p 值这个技能是整个包里价值最高的一个也是最需要写细的。原因很简单统计检验的选择和解读是 AI 最容易给出“教科书答案但实际错误”的地方。技能里的执行顺序是固定的。第一步永远是描述性统计加分布检查输出样本量、均值、中位数、标准差、四分位距加上正态性检验结果。第二步判断检验方法两组独立样本且都近似正态、方差齐走常规 t 检验方差不齐走校正版本样本量小于三十且明显偏态走非参数检验。多组比较先做整体检验显著了才做事后两两比较并且必须做多重比较校正。这里有个参数要算清楚——多重比较的校正阈值。做 k 次比较如果按 Bonferroni 校正单次检验的显著性水平就是 0.05/k。k6 时阈值降到 0.0083很多原本“显著”的结果会瞬间不显著。这不是保守这是必要的。我见过太多把六组两两比较全做一遍、然后只报那一个 p0.04 的做法这不是分析这是挑数据。更推荐用 FDR 校正它控制的是错误发现率而不是族错误率在探索性分析里更合理。技能里可以两个都算输出时并排列出让人自己判断。第二块是效应量。技能强制要求每个检验都附带效应量t 检验给 Cohens d方差分析给 η²非参数给秩相关效应量。理由很实在——p 值只告诉你“有没有差异”效应量才告诉你“差异有多大、值不值得关心”。一个 p0.001 但 Cohens d0.05 的结果在实际意义上基本等于没有。第三块是结果表模板。技能里固定一个输出格式列包括比较组、方法、统计量、自由度、p 值、校正后 p 值、效应量、置信区间、样本量。表格直接产出为 CSV不用人再手工誊抄。这一步看起来琐碎但它是防错的关键——手工誊抄是转录错误的高发区。3.4 出图技能把期刊要求翻译成参数出图这件事看着是审美问题实际全是参数问题。技能要做的是把“符合期刊要求”这种模糊说法翻译成具体的数值。先算尺寸。多数期刊的双栏图宽度要求是 170 毫米左右单栏 85 毫米左右。按 300 dpi 的印刷要求换算成像素85 毫米 ÷ 25.4 × 300 ≈ 1004 像素170 毫米对应约 2008 像素。所以脚本里的 figsize 应该按英寸设单栏 85/25.4 ≈ 3.35 英寸双栏约 6.7 英寸配合 dpi300 正好对上。字号同理正文一般要求 7 到 9 磅标题略大这个范围在缩放后仍然可读。再算配色。技能里直接禁用那套经典的红绿对比改用对色觉障碍友好的方案并且在技能文件里写清楚“同一张图内的类别不超过六个超过就换分面”。这条不是审美洁癖类别一多颜色区分度必然下降读者根本分不清谁是谁。字体是最容易翻车的地方。中文字体在很多环境里默认缺失脚本一跑满屏方块。稳妥做法是在脚本开头做一次字体探测列出系统里可用的中文字体取第一个命中的设置进去一个都没有就明确报错退出而不是画出一堆方块还继续往下走。报错比沉默的错误输出好一百倍。导出格式也要定死矢量图存 PDF 或 SVG 用于排版位图存 300 dpi 的 PNG 用于预览和投稿系统上传两个都要出文件名保持一致。别用 JPEG压缩伪影在线条图上特别明显。提示所有这些参数与其写在技能正文里让人读不如直接固化进脚本的默认值。正文只需要说明“什么时候用这个脚本、需要传什么参数”具体数值让代码去保证。人记不住参数代码记得住。3.5 可复现性技能让每次运行都留下痕迹这个技能不产出任何研究结果它只负责记录但它是整个体系里最该早点做的一个。做法很简单每次分析运行自动创建一个带时间戳的目录里面放五样东西。输入数据的文件清单和每个文件的哈希值本次运行的脚本副本不是引用是复制环境快照包括语言版本和关键依赖包的版本号完整运行日志含起止时间和警告信息输出文件清单哈希值这一步很多人会跳过觉得多余。但当你三个月后发现结果对不上第一件要确认的事就是“数据文件有没有被改过”。有哈希一秒钟就能确认没哈希你就得靠文件修改时间猜而修改时间是可以被复制操作覆盖的完全不可靠。环境快照同样重要。Python 生态里同一个包的小版本升级导致数值结果变化的情况并不罕见。技能里可以直接调命令把当前环境的包版本全导出来存成文本文件几秒钟的事省掉后面无数的扯皮。日志这块有个细节值得写进技能警告信息不能吞掉。很多人写脚本习惯加个忽略警告的设置图个清爽。但那些警告里经常藏着真问题——除零、类型转换、数据截断全在那儿。技能里应该要求日志完整保留并且在结束时统计警告数量非零就在日志末尾标一行提示。3.6 写作检查技能统一口径比润色重要写作技能最容易写成“帮我改改语法”价值有限。真正有用的是一致性检查因为长篇稿件里最要命的错误不是语法是前后不一致。技能里我列了几条硬检查。术语一致性同一个概念全文只能有一种叫法不能前面叫“处理组”后面叫“实验组”。缩写规范首次出现给全称加缩写之后统一用缩写不能混着来。数字格式小数点位数、单位空格、百分比写法全文统一。时态方法用过去时普遍结论用现在时这个在中文稿里体现为“本研究中我们采用了”和“结果表明”的区别要一致。图表引用正文里提到的每个图号必须真的存在反过来每个图正文里必须至少引用一次。这些检查用脚本做比用模型做更可靠。写个小脚本扫全文把疑似不一致的地方列出来比让模型通读一遍更快也更准。模型的优势在语义层面——判断一句话是不是表述含糊、逻辑是不是断裂、图注是不是没交代清楚关键信息这些才该交给它。审稿意见回应这块也可以做成技能。核心规矩只有一条逐条编号每条都给出“改了什么、改在哪个位置”。最忌讳的是笼统回复“我们已认真修改”。技能里可以要求输出固定格式的表格三列意见原文、应对说明、修改位置。这样既方便审稿人核对也方便自己复盘。4. 手把手从零搭一个能跑的最小技能包4.1 先跑通一个再考虑复制不要一上来就写六个技能。我第一次干这事花了一整晚写了八个技能文件第二天一测六个不触发两个触发了但跑飞。正确顺序是挑一个你每周都要做、且流程固定的动作先把它做成技能跑通再复制结构。选统计检验技能做第一个最合适因为它有明确输入数据表、明确输出结果表、明确检查项假设检验边界清晰容易验证对错。目录建好后先写入口文件--- name: stat-analysis description: 当需要对两组或多组实验数据进行组间差异比较、相关性检验或回归建模并输出含效应量与置信区间的结果表时使用 --- # 统计分析 ## 何时使用 用户提供了数据表并要求比较组间差异、检验相关性或建立回归模型时使用。 仅做数据清洗或仅做绘图时不要使用本技能。 ## 执行顺序 1. 先跑 scripts/assumption_check.py得到描述统计与分布检查结果 2. 根据检查结果选择检验方法选择依据见 references/method_choice.md 3. 跑 scripts/report_stats.py 生成结果表 4. 检查结果表是否包含效应量与置信区间缺失则重跑 ## 硬性约束 - 不得跳过假设检查直接选检验 - 多组比较必须做多重比较校正校正方法与原始 p 值并列输出 - 结果表必须包含样本量列 - 所有输出写入 outputs/ 目录不得写入 data/raw/这份文件里description负责路由正文的“何时使用”负责二次确认“硬性约束”负责兜底。三层的分工要清楚不要把约束写进描述里那会把路由条件搞乱。references/method_choice.md单独放方法选择的判断树因为它内容长、且不是每次都需要读全。这样拆开日常调用只加载技能正文只有真正需要选方法时才去读那一篇。4.2 脚本层把易错操作焊死脚本的作用不是替模型思考是把那些“每次都要记得做、但每次都容易忘”的动作变成默认行为。以假设检查脚本为例核心逻辑大概是这样import pandas as pd from scipy import stats def check_assumptions(df, group_col, value_col, alpha0.05): groups [g[value_col].dropna().values for _, g in df.groupby(group_col)] report {n_groups: len(groups), sizes: [len(g) for g in groups]} # 正态性样本量小于 5000 用 Shapiro否则用偏度峰度判断 normality [] for g in groups: if len(g) 3: normality.append(None) elif len(g) 5000: normality.append(stats.shapiro(g).pvalue) else: normality.append(stats.normaltest(g).pvalue) report[normality_p] normality # 方差齐性两组用 Levene多组同样用 Levene对偏态更稳健 if len(groups) 2: report[levene_p] stats.levene(*groups).pvalue # 给出建议但不替人做决定 all_normal all(p is not None and p alpha for p in normality) homo report.get(levene_p, 1.0) alpha report[suggestion] ( 参数检验 if all_normal and homo else 非参数检验或校正版本 ) return report注意最后那段suggestion的措辞——给建议不给结论。这是我在实际使用中调整出来的早期版本直接返回“用 t 检验”模型拿到就照做人也不再核对。改成给建议之后人会被迫看一眼依据误判率明显下降。方差齐性检验这里用了 Levene 而不是 Bartlett理由是 Bartlett 对非正态数据非常敏感稍微偏一点就报方差不齐实践中误报率偏高。Levene 基于绝对偏差稳健性好得多。这个选择本身就该写进技能的参考文档里让读的人知道为什么。结果表脚本里有个参数值得算一下置信区间的计算方式。两组均值差的置信区间用 Welch 方法时自由度不再是简单的 n1n2-2而是按方差和样本量加权算出来的近似值。脚本里直接调库函数就行但技能文档里要说明“输出的是 Welch 区间而非等方差区间”否则读表的人会按错误的自由度去理解。4.3 联调怎么判断技能真的生效了写完不等于能用得有一套验证动作。我的验证清单是四步。第一步问它“你能看到哪些技能”确认清单正确。第二步给一个明确该触发的任务比如“比较 A 组和 B 组的测量值差异”观察它是否调用了统计技能、是否先跑了假设检查。第三步给一个不该触发的任务比如“把这份数据的列名改成英文”看它会不会错误地调用统计技能。第四步给一个边界任务比如“看看这两组数据分布有没有差别”这句话既可以是描述统计也可以是检验看它怎么判断——这一步最能暴露描述写得含糊的地方。四步里有任何一步不对先改description别急着改脚本。九成的触发问题都出在描述上。跑通之后还有一件事要做记录一次完整对话。把从提问到出结果的整个过程存下来包括它调了哪些脚本、中间报了什么错、你怎么纠正的。这份记录后面会成为你优化技能的第一手材料比凭记忆改有效得多。5. 踩过的坑和排查速查表5.1 那些让人抓狂的典型故障技能完全不触发。这是最高频的问题。排查顺序先确认文件路径和文件名再确认元数据格式最后看描述。前两个是硬错误一眼能看出来描述问题最隐蔽典型表现是“问它有什么技能它能列出来但干活时就是不用”。这种情况八成是描述里全是“支持”“相关”“辅助”这类无信息量的词。改法是把动作和产出写具体。技能触发了但脚本跑不动。多数是路径问题。脚本里用了相对路径但执行时的工作目录不是项目根目录data/raw/x.csv就找不到了。解决办法是在技能里明确要求“所有脚本以项目根目录为工作目录执行”或者在脚本内部自己做路径解析基于脚本自身位置推算根目录不依赖调用方的工作目录。中文路径或中文列名报编码错误。这类问题在跨平台时特别常见。根治办法是数据文件和列名统一用英文中文只出现在最终报告里。如果确实绕不开读写时显式指定编码并且不要指望系统默认值。画图出来全是方块。中文字体缺失前面说过。补充一点即使系统装了字体绘图库的字体缓存也可能没更新需要清一次缓存再重试。技能里可以直接写一条“先跑字体探测脚本探测失败就中止”。长表格被截断。数据行数一多输出到对话里就会被截。技能里应该规定超过一定行数的表格一律写文件对话里只报“已写入某路径共 N 行”需要看细节时再单独读。这条规矩能省掉大量“咦怎么少了几行”的困惑。模型自作主张改了原始数据。这是最危险的一类。除了前面说的只读权限技能里还应该加一条任何写操作前必须先打印将要修改的文件路径和目标路径等确认后再执行。多这一句能挡住绝大多数误操作。5.2 速查表现象最可能的原因处理动作列不出技能路径层级不对或文件名不符确认入口文件在技能目录第一层且命名正确列得出但不触发描述信息量不足改写描述加入动作、对象、产出三要素误触发到别的技能两个技能描述重叠收窄边界在描述里加排他说明脚本报文件不存在工作目录不一致脚本内基于自身位置解析路径中文显示为方块字体缺失或缓存未更新字体探测加缓存清理表格行数不全对话输出截断改为写文件对话只报路径和行数原始数据被改动缺少写保护目录只读加技能内写前确认结果无法复现未记录环境与种子强制生成运行目录与环境快照5.3 长期维护技能包是会烂的这一点很少有人提但很实际。技能包写完不是一劳永逸它会随三件事慢慢失效工具本身升级导致加载机制变化、依赖库升级导致脚本报错、你的分析流程变化导致技能不再匹配。我的做法是给技能包建一个自己的版本记录每次改动写一行改了什么、为什么改。同时每隔一段时间做一次“冷启动测试”——换一台干净的机器或者清空环境重装从零跑一遍核心流程。这个测试能暴露出一堆隐藏依赖比如某个包其实是你手动装过但没写进依赖清单的换个环境就崩。我吃过这个亏本地跑得好好的换台机器重装环境脚本直接报缺包查了半天才发现是三年前手动装的一个小库。另一个经验是技能文件里的示例要定期更新。很多技能会附带一个“输入输出示例”用来告诉模型期望的格式。这些示例如果用真实数据写时间一长就会和当前数据结构脱节模型照着旧格式输出你还以为是它理解错了。示例要么用完全虚构的结构要么定期同步。用虚构结构更省事反正模型看的是格式不是内容。最后说一个心态上的体会。这套东西的价值不在于让 AI 替你做科研而在于逼你把“自己到底是怎么做科研的”这件事说清楚。我写完第一版技能包的收获不是多了个助手而是发现自己原来有那么多操作是凭直觉做的、根本说不出来由。把这个过程显式化之后即使不用 AI分析质量也会上去一大截。后面想扩展的话最值得先做的是把审稿意见回应也固化成技能——那部分格式最固定、重复度最高收益最直接。