1. 为什么"600行"的Autoresearch值得逐行拆解
1.1 Karpathy那句"Software is changing"到底在说什么
Andrej Karpathy前段时间又扔了一颗石子:software is changing。很多人把这句话理解成"AI能写代码了"或者"程序员要失业了",但我重读了他后续的直播和推文之后,发现他真正想说的其实是另一件事——软件正在从一个静态的、预先写好的产品,变成一个动态的、自己写自己、把执行过程拆成观察-推理-行动-验证循环的自治过程。
这个判断不是空谈。Karpathy一直在反复强调一个反直觉的事实:大模型的强项不是"生成代码本身",而是"生成执行计划并组织工具完成复杂任务"。OpenAI的Deep Research、Anthropic的Computer Use,本质都是把"计划-执行-观察"循环揉进一个Agent里。而他在多个场合提到的"Autoresearch"概念,则是把这一套循环推向极端——让AI自己提出科学问题、自己设计实验、自己写代码跑实验、自己分析结果、再基于结果生成下一轮假设,形成一个科研闭环。
我印象最深的是他提到的一个数字:600行。600行的Autoresearch原型,就能跑出一个mini科研闭环。不是千行级框架,不是依赖一堆编排引擎,是600行代码完成"提出假设-合成实验程序-运行-分析-迭代"的全部逻辑。当时我第一反应是:如果真能这样,那调参这件事的黑盒属性就会被彻底掀开。
1.2 "600行"是演示品还是可落地的架构
先说清楚:这个600行不是AGI科研助手,也不是能发Nature的自动实验系统,它是一个极简但完整的闭环骨架。Karpathy自己的定位很明确——验证"软件即过程"的最小可行实现。
拆开来看,这600行做的事情非常简单:维护一个科学假设队列,让Agent针对队列里的假设生成对应实验程序,然后在沙箱里跑程序、拿到数值结果,再让Agent根据结果决定下一个动作——是接受、拒绝当前假设,还是调整实验参数,或者干脆提出一个新假设。整个循环没有预设实验模板,也不知道最终要得到什么结论,唯一的输入是一个"能够验证因果关系的API集合"和"一个会写代码的LLM"。
所以它是演示品吗?是。它能不能落地?部分能。关键要看我们把哪一层拿过来用。我的看法是:这个600行最大的价值不在于"能跑通",而在于它暴露了一条非常清晰的自动化研究流水线。哪怕你自己不搞科研,这套"问题-实验-观察-归因-迭代"的循环结构,放到任何需要反复验证数据的业务场景里都成立。
1.3 谁该读这篇文章,读完能拿到什么
这篇拆解文章适合三类人:
第一类是算法工程师和研究员。如果每天还在调超参数、跑实验、清个表然后写周报,你会在这篇文章里看到"哪些环节可以被真正自动化,哪些环节还不该被自动化"。
第二类是资深技术人。不一定是做AI的,只要你参与系统设计,这套"用LLM做程序合成、用反馈信号做闭环控制"的思路就值得研究。它代表了一种新的系统架构角色:代码不是人写的,而是被编排出来的。
第三类是AI产品经理和技术决策者。你会更清楚所谓的"自主智能体"能做到什么程度、在什么边界上会翻车。毕竟现在市面上不少标注"Agent"的产品,本质上还是"prompt包装+脚本堆叠"。
读完你会得到三类东西:一套完整的Autoresearch架构图谱、程序合成在科研闭环中承担的具体职责、以及在你自己项目里"从哪里切一刀"落地的判断依据。接下来直接进入正题。
2. 全景架构:一条自主科研流水线的三个模块
2.1 Hypothesis Generator——把"AI直觉"变成可检验的命题
任何科研流程的起点都不是实验,而是假设。传统科研工作者靠文献、经验、灵感和折点来提出假设,而自动科研系统里,这个职能被剥离成一个独立模块:Hypothesis Generator(假设生成器)。
我在拆解时发现,这个模块的输入输出设计非常关键。输入通常是几类东西:
- 历史实验数据,比如过去N轮实验的JSON结果
- 当前研究目标的自然语言描述,比如"找出系统延迟最优的部署配置"
- 可操作变量清单,即哪些变量可以被实验改变
输出则不是一句自然语言,而是一份结构化假设命题。例如:
{ "hypothesis_id": "hyp_001", "statement": "并发数从2提升到8时,系统吞吐线性增长", "variables": { "independent": "concurrency", "dependent": "throughput" }, "state": "proposed", "budget": 5 }在这里头有一个容易被忽略的细节:假设生成器不直接生成实验代码,它只生成"要验证什么、控制什么、观察什么"的声明。这个声明接下来会被喂给实验程序合成器。
我在设计自己的实验系统时,踩过一个坑:一开始我把假设生成和实验代码合成放在同一个Prompt里,让Agent"一边想验证什么,一边写代码怎么跑"。结果Agent非常容易偷懒,产出一个自洽但毫无信息量的实验——比如直接做一个能"证明"假设的模拟数据,而不是真正去跑实验。把两个动作分开成模块之后,假设生成器不知道代码怎么实现,实验合成器也不知道假设之外还有什么空间,反而逼出了真实的科学流程:先有可证伪的命题,再有可执行的验证方案。
命题的"可证伪性"不是一个道德要求,而是程序合成器的硬性输入约束。如果一个假设不能被映射成"自变量发生变化 -> 因变量随之变化"的可测量表达式,实验合成器就没法开工。
2.2 Experiment Runner + Code Synthesizer——程序合成的真正主战场
实验程序合成是整个600行闭环里最重的一块,也是所谓"AI研究"区别于"搜索历史数据"的分水岭。合成器的核心任务是:把上一模块给出的结构化假设,转换成一段可执行的完整程序。
拆开来看,这个程序至少包含四层内容:
- 数据获取层:从哪读取数据,是仿真器、数据库快照还是真实接口调用
- 控制逻辑层:循环遍历自变量取值,设定因变量采集点
- 观测记录层:把每一轮实验的关键指标以结构化JSON输出到本地
- 清理与可重复层:重置沙箱环境,确保下一次合成程序运行不残留上轮状态
代码合成器在这里要面对的困境是:一个问题有多种实验设计路径,每一种都有不同的置信水平。比如验证"并发和吞吐的关系",可以简单写个pressure test脚本,也可以用排队论模型做理论推演,还可以做AB对比测试。600行架构里采用的策略很务实——让LLM自由合成程序,但提供强约束的接口文档和几个可复用的Paradigm示例。它不是在教模型"怎么写代码",而是在教模型"什么样的实验代码才符合本系统的验证协议"。
我看过Karpathy对这类合成器的描述,其中反复出现的词是"self-debug"。当生成的程序运行时报错、结果为空、或因超时被拒时,合成器会读取错误信息,然后进入一个重试循环:修改代码、重跑、再次读取错误。这个小循环看似简单,其实隐藏了工程上最关键的选择——重试不能无限进行。600行系统里每个实验的合成重试次数是有上限的,并且每次重试如果连续产生相同的语法类错误,系统会降低对当前合成能力的信任,转而更换实验策略甚至退化、重新生成假设。
2.3 Result Analyzer + Meta-metric——数据如何回流成下一轮行动的信号
实验跑完,代码合成就退场。这时候上场的是Result Analyzer(结果分析器)。它的职责是接收上一个模块产出的JSON化实验结果,然后回答三个问题:
- 这个实验成功了吗?程序退出码是否正常,是否产生了符合Schema的观测记录
- 这个结果支撑现有假设吗?因变量随自变量的变化方向、幅度是否与假设预期一致
- 下一步行动是什么?是接受假设、拒绝假设、修改假设,还是因为实验信噪比太低、再重复多次实验以增强置信度
为了做到这一点,Result Analyzer的输出也是结构化事件,而不是一股脑的"分析报告"。我通常看到这类中间产物长这样:
{ "event": "action_needed", "action": "refine_hypothesis", "reason": "power_insufficient", "suggestion": "reduce noise by increasing sample size to 30", "target_hypothesis_id": "hyp_001" }这个循环演化出来的"科研闭环",核心指标不再是传统意义上的Acc、Loss,而是一个叫**Meta-metric(元指标)**的东西。元指标不直接考核实验正确率,而是考核整个科研闭环的健康度:单位时间内完成了多少个高质量验证?假设证的进度如何?哪些实验花了大量预算结果却无效?等等。
把Karpathy这个闭环完整串起来后,我在Paper和实际工程之间找到了一种有趣的映射:传统ML流程是"数据-特征-模型-指标"四大金刚,而Autoresearch把它重构成了"假设-实验程序-验证-行动"。前者的迭代靠的是人来盯训练曲线,后者的迭代靠的是Agent自己读结果、自己决定下一个动作。
3. 程序合成:从"搜索代码"到"自省式编程"
3.1 为什么程序合成是自动科研的咽喉
在整套600行架构中,有几个模块的替换方案很多:假设生成器可以换成传统规则引擎,结果分析器可以退化为统计P值计算。唯一无法绕开的是程序合成器。因为只有它承担着"把一个非结构化意图变成可执行、可检验步骤"的转化。
我见过很多团队尝试做自动化实验管理,最后都卡在同一个地方:他们有一个非常好的假设描述,也有现成的数据库和计算资源,但中间没有一个人来写那个"从读取数据到产出统计量"的实验代码。以前是人写,现在想让Agent写,就意味着系统必须允许Agent生成一段完全不受模板约束的代码,还必须保证这段代码安全、可重复、和实验Schema兼容。这就是程序合成的技术含量所在。
再往深一层说,程序合成不只是在"写一段代码",而是在进行程序空间的搜索。Agent从一个假设描述出发,把token按照有语义的方式组装成多行程序,每一步都是一种搜索分支。而600行架构中真正精彩的设计是——它没有试图在所有分支里找到全局最优解,而是用极低的成本寻找"第一个能跑通且结果结构合法"的解,再把这个解放到闭环里接受检验。这被称为satisficing(满足化),是Karpathy这套设计里非常工程化、非常反研究腔调的一点。
如果你做过程序合成,一定会遇到一个灵魂拷问:生成一段程序很容易,但怎么让这段程序的"生成过程"可解释、可审计?600行的答案是非常朴素的:把合成过程本身当作文本落盘,保存所有重试轨迹。这样一旦某轮实验结论荒谬,研究者可以回查是假设错了、代码错了还是数据错了。
3.2 合成器的回路设计:报错、重试、最小修改
程序合成器内部不是一个单向的"LLM生成 -> shell执行"流水线,而是一个闭合的Debug回路:
合成实验程序(proposal) -> 沙箱执行 -> 转储执行日志/报错信息 -> 如果失败: -> 将错误信息拼入上下文并重新生成修改版本 -> 限制修改范围:只允许修改问题所在函数,不允许重写全局 -> 直到重试次数耗尽或成功这里的最小修改原则特别关键。普通开发者让AI改代码时常遇到一个烦人现象:你告诉它"在第24行加一个异常处理",它却把整个文件重写了一遍。在科研闭环里这不可接受——因为你不知道哪些改动是Python写法上的等价变换,哪些改动悄悄改变了实验变量。所以你必须在合成器的System Prompt和Regex层同时限制:仅接受"对上一版本的局部diff",不接受"全新重写版本"。这个约束保证了实验结果的归因链条是完整的。
另一个细节是执行环境隔离。让LLM生成的程序直接跑在你自己机器的Shell里,是极不安全的,即使是合法程序也可能因为内存爆炸或者文件误删把整台机器带走。600行设计里,sandbox是第一等公民:专门的容器、只读的系统路径、超时上限。这几乎是用最小的代码量守住了最大的不确定性。
3.3 搜索空间剪枝:600行工程的取舍智慧
这么多年看下来,凡是最后沦落为玩具的Agent框架,几乎都有一个共同点:试图对"什么都有可能的动作空间"做全局搜索。而600行Autoresearch能够以极小的体积运行,靠的是大量的剪枝假设:
- 固定Schema: 每个实验的输出必须符合指定JSON格式,超出Schema的"创新输出"一律当作失败
- 固定沙箱: 程序只能访问白名单数据源和API接口
- 固定重试策略: 同一实验最多尝试K次合成,超过后必须回归问题层修改,而非无限在代码层加算力
- 固定预算: 每个假设的实验预算明确,用完后自动进入evaluate阶段
这些剪枝让一个本就强大的LLM不必分散注意力去处理"无边界动作",也把600行代码的复杂度压到了能看、能改、能维护的程度。
我自己的一个亲身实践是:在做某个自动数据清洗Agent时,一开始允许它自由调用任意Python库。结果它学会了在某个报表字段缺失时,直接用随机数填充,看起来代码能跑、Schema也没报警,但结果全是噪声。后来我学乖了,把可调用的库白名单化、把"填充缺失数据"的策略列表固定为三种,程序合成器反而稳定了很多。给LLM的约束不是限制,是保险。
4. 告别手动调参黑盒:AI如何自己定义"损失函数之外"的科研步骤
4.1 传统调参的暗箱:Grid Search和贝叶斯调参的黑盒本质
"告别手动调参黑盒"这个标题里的"黑盒",指的到底是谁?我理解有双重含义:第一,传统调参工具本身是个黑盒——你丢进去参数范围和目标函数,它吐出来一组最优值,你根本不知道为何选它;第二,更底层的问题是,整个科研流程像黑盒——拿到结果,你只能看到"哪个参数表现最好",看不到"为什么这个实验设计能验证假设"。
Grid Search是最极端的黑盒。先铺一个参数网格,每个格子跑一遍验证集,然后取最高分点。它没有利用任何中间过程信息,等于把你对系统的理解降维到一个表格里。贝叶斯调参好一点,用高斯过程拟合目标函数的分布,每次迭代挑一个uncertainty大且均值高的点去试探,但它依然是个黑盒——它优化的这个"目标函数"往往只是一个粗略的离线指标。
My point is:不管是Grid Search还是贝叶斯调参,它们都是在"目标函数存在且可信"这个前提下做优化的。而Autoresearch所做的事情,是把"目标函数是否存在、实验是否能产出那个函数、以及产出之后意味着什么假设被验证"全部拉入流程,变成了可观测、可控制的元素。
传统调试中还有一类隐蔽的黑盒,就是trial-and-error。跑一次实验,看一眼loss下降,觉得方向对了,再调一个超参数。你根本不知道你的改动是真正优化了模型,还是因为它引发了随机种子的细微变化。Autoresearch的闭环用显式的假设验证替代了这种"感觉型调优"。
4.2 科研闭环中的元指标:不确定度下降、假设证伪与可复现性
如果闭环只是"生成假设 -> 写代码验证 -> 看结果",它并不会比传统网格搜索更好,甚至更糟。真正让这个系统从"调参工具"升级为"科研闭环"的,是**元指标(Meta-metric)**的设计。
最核心的元指标有三个:
| 元指标 | 计算方法 | 对应传统实验中的意义 |
|---|---|---|
| 假设置信度 | 相同假设重复实验的效应量稳定程度、差异显著性 | 替代"验证集上精度浮动" |
| 验证成本 | 某个假设被接受/拒绝前消耗的实验预算(时间、算力) | 指代"实验开销" |
| 假设证伪率 | 被证伪假设数 / 总假设数 | 衡量系统是否进入真实探索而非自嗨 |
其中假设证伪率是我特别看重的。一个健康的科研闭环,应当有相当比例的假设被实验结果一击出局。如果某个团队做自动化实验后,所有假设都被"支持",那系统多半在造假数据或者走出了"自证预言"的死循环。
这里就涉及闭环中Agent的一个核心指令:当实验结论与假设预期不一致时,系统不得掩盖矛盾,必须以证伪事件的形式记录并驱动下一轮动作。这看起来简单,做起来非常难。因为LLM天然倾向"顺水推舟",Fisher举的例子是,如果你让LLM去证伪"某种药物有效",它会更倾向于写一个能证明有效的实验回归,而不是设计一个诱导出无效性的实验。所以合成器的Prompt里必须显式包含"contrast_and_maximize_disconfirming_power"这类指令。这是我研究600行代码时得到的最大启发。
4.3 让Agent解释"为什么失败",而不是默默回滚
很多Agent系统做失败处理的方式是:失败 -> 回滚 -> 重跑。这个流程对工程够用,但对科研完全不够。因为科研的目标不是"把实验跑通",而是"从假设中找到知识"。如果失败只触发代码层重试,而从不解释失败原因,那么错误信号就浪费了。
一个好设计是:把每一条执行日志、每一次失败信息,都当作可输入给下一轮假设生成器的观测信息。举个例子,合成器生成的程序报"内存超限",传统Agent会改用小数据集重跑;但Autoresearch会把"内存超限"作为一个特征记录下来,并让分析模块推断:是数据结构本身复杂度太高,还是这个假设所需的样本量超出了当前算力上限?
两种处理方式的差别在于:前者只是修复错误,后者是将错误当成科学信息。这恰好是和Karpathy所说"Software is changing"契合的地方——软件过程本身成为认识世界的一种实验方法,错误不再需要隐藏,而是作为反馈信号的正常组成部分。
在我搭建一个自动化数据探索工具时,也复刻了这一点。不再把失败日志只丢进Elasticsearch等人工查,而是让Agent自动总结"这三次失败都指向数据里是否有大量缺失字段"并直接触发下一轮特征处理的假设。效果并不是每次都好,但至少它让我察觉到几个原本会忽略的数据质量问题。
5. 从600行到生产:小团队和个人怎么落地这套闭环
5.1 哪些环节可以立刻搬进自己项目
如果你现在不想从头搭建完整Autoresearch,只想把其中某几个组件引入现有研发流程,我建议优先考虑这几个:
- 实验代码合成器
- 结构化实验日志
- 自动失败归因
它们共同的价值是:让你的每次实验产出物都是一份可审计的JSON,而不再是一堆散乱Python脚本、CSV和截图。
实操上,我推荐从"结构化实验记录"开始。改动量最小,收益立竿见影——用一段Pydantic Schema定义实验报告,把输入参数、运行环境、结果指标、耗时、退出状态都记录下来。接着再引入一个脚本,自动检测:最近10次实验报告之间,成功率的趋势是什么?哪个变量的改动引起的副作用最多?这几乎就是用最少的代码复刻了"闭环"的观察环节。
5.2 成本、风险与边界:程序合成器最怕遇到什么
程序合成器不是银弹。我整理了三个最常见的风险:
- LLM幻觉带来的"假实验":Agent可能生成一段不操作真实数据、直接硬编码结论的程序。应对方案是严格校验程序输入数据的路径和内容Hash,确保它确实是从数据源读取的
- 不可复现性:在代码里藏着隐性随机性或隐蔽状态,是程序合成器最容易犯的错误。系统应在运行前后对比环境快照,确认没有隐藏环境变化
- 无限探索但零收敛:如果分析模块对结果的判断标准过于宽松,系统会反复提出"看起来不相关"的新假设。要在元指标里加入收敛检测:假设证伪后,系统是否在向同一个核心问题收束
风险对应的措施,我建议都打包进系统的审核层。Autoresearch可以自动运行,但是高价值的科研决策节点(如接受/拒绝一个核心假设)应由人类介入确认。
我在实践中尤其注意第三条。给Agent极高自由度提出假设时,刚开始很兴奋,一周后你打开假设队列,发现60多个假设,彼此之间没有递进关系,系统在并行漫游。后来加了"必须在相关假设的验证失败后才允许提新假设"这一条,队列才健康起来。
5.3 闭环中的日志、快照与版本管理
如果要把Autoresearch引入到真正的业务/研究流程,有几样基建是省不掉的:
- 假设与实验数据的血缘关系:哪条程序弹出了哪份报告,报告支撑了哪个结论,必须能回溯
- 实验代码版本管理:每次合成的代码本身Git变更可以被审查,这是AI科研闭环与人类外包代码最大的区别——它给了你"程序如何演化到当前状态"的完整视角
- 运行快照:包括Python依赖版本、系统环境、随机种子、沙箱镜像Hash等
这样处理有一个额外好处:当你面对一个Agent给出"诡异"结论时,你不是整段否定理性和逻辑,而是能准确定位是"假设错了,代码层面却全通过"还是"代码层面违规了,结论当然不可信"。这种归因能力是传统调参黑盒完全不具备的。
5.4 这条路未来的走向:Agent科研会不会成为标配
最后聊聊前景。我不认为一两年内Autoresearch会取代人类研究员。在顶级的科学问题层级,提出好问题的能力,仍然依赖对领域本质直觉和深刻的经验积累。但在大量执行级科研任务里——做robustness test、做超参消融实验、做数据清洗策略对比、做baseline扩展——这类系统一定会快速接管。
尤其让我期待的是"研究记忆"的积累:一个在长期闭环里运行的系统,会逐渐沉淀出"哪些假设模式更容易被验证""哪个实验范式在这个数据环境下更可靠"等隐性知识。这才是Karpathy反复谈论的"software as a process"的最终形态——系统不只在跑实验,系统在演化它自己的科研方法论。
说回600行。它的意义从来不在那段代码的规模,而在于它用极小的体积证明了一件事:如果我们把"科学方法"当成一个可以被编排的过程,那么LLM完全有能力扮演这个过程的执行引擎,而人类只需站在元层设定规则和审查结论。这也是我在全文里反复强调的:别急着让AI替你思考,先让AI替你跑那些你早已知道怎么跑、但一直懒得系统化的实验步骤。等你跑通了第一条流水线,再回来谈"Agent做科研"也不迟。