Sakana AI连续思考机器源码级评审:从代码到推理实验 📅 发布时间:2026/8/30 14:48:54 👁 浏览次数: Hacker News 上有一个 Show HN 标题很值得研究A Source-Level Review of Sakana AIs Continuous Thought Machine。翻译过来就是“对 Sakana AI 连续思考机器做一次源码级评审”。这个标题最值钱的部分是Source-Level——它不看论文摘要不跑个 demo 就结束而是直接翻源码从代码层面确认这个项目究竟做了什么、怎么做、跑起来是什么表现。这次的关注对象是 Sakana AI 的 Continuous Thought Machine。Sakana AI 是 Transformer 论文作者之一 Llion Jones 和 Google Brain 前研究员 David Ha 联合创办的日本 AI 公司研究方向偏自然启发算法、进化模型合并、替代性训练框架。从项目命名看Continuous Thought Machine 的核心思路是把模型的“思考”从离散 token 序列扩展到连续状态空间。也就是说模型不一定把每一步推理都写成文字而是在内部隐状态里做多步迭代思考再在合适的时机把状态解码成最终输出。本文会把“源码级评审”这套方法论完整拆开结合 Continuous Thought Machine 这个案例讲清楚以下内容连续思考类模型在技术路线里处于什么位置要解决什么问题拿到一个开源 AI 仓库后怎么分层读源码而不是从头读到尾怎么定位核心机制验证“思考步数”这个参数真的在起作用怎么搭最小复现环境、跑对比实验、记录显存和耗时批量任务和接口化怎么做常见问题怎么排查源码评审报告怎么整理。如果你正在做论文复现、想深入理解推理机制源码或者准备写一份自己的源码评审报告这篇可以直接收藏。1. 核心信息速览项目维度说明研究对象Sakana AI 的 Continuous Thought Machine评审方式源码级评审Source-Level Review核心关注点连续思考机制、状态更新、训练与推理实现、真实资源占用技术背景让模型在潜在空间/隐状态中进行多步思考再解码为输出前置技能Python、PyTorch、机器学习基础、Git 基础硬件要求视模型规模而定最好有 NVIDIA GPU也可用 CPU 先跑小配置本文产出源码分析方法论、最小复现流程、性能观察清单、问题排查表需要说明的是当前公开渠道关于这个项目的具体实现细节比较有限。下面所有关于“连续思考”的机制说明是基于项目命名、Sakana AI 研究方向、以及同类模型技术背景的合理推断不是源码结论。具体结构、参数、接口都要以你实际拉下来的仓库为准。这也是源码级评审的第一个原则不猜去读代码。2. Continuous Thought Machine 在解决什么问题想理解这个项目先理清主流语言模型的推理方式。现在的大语言模型基本都是自回归生成模型每次只产生一个 token然后把已经生成的 token 拼回去继续预测下一个。思维链Chain-of-Thought也是靠“在输出里写思考过程”实现的——模型把中间逻辑拆成文字步骤再给出最终答案。这个方式有两个明显问题。第一思考过程消耗输出 token。模型每一步推理都要写成文本推理成本和文本长度成正比。对于复杂问题思维链可能很长生成延迟和算力消耗都会变大。第二模型只能在 token 层面显式表达思考。有些推理步骤适合用自然语言描述但很多内部推演并不适合语言化。强行把连续的计算过程压成离散文本既低效又容易失真。Continuous Thought Machine 从命名上看是对这两个问题的一种替代回答把思考从 token 空间搬到连续状态空间。模型在生成第一个 token 之前可以对输入做多轮内部状态更新。这些更新发生在“看不见”的潜在空间里等于让模型先反复推演最后再把状态解码成输出。这种思路和扩散模型有些相似也带有循环神经网络迭代演化的味道。扩散模型是在噪声和图像之间做多步去噪Continuous Thought 则是在输入状态和输出状态之间做多步迭代。两者的共同点是把“过程”从一步变成多步让模型有更多计算空间来逼近正确答案。Sakana AI 做这个方向并不奇怪。这家公司从成立起就在探索和主流 Transformer 路线不一样的架构思路强调自然启发、群体优化、小模型高效训练。如果 Continuous Thought Machine 的目标是在连续空间里构建一种可训练的“思考机器”那它要解决的核心问题可以拆成四个连续状态如何初始化状态如何更新更新后的状态如何解码成输出训练时如何让这个内部思考过程产生可监督的信号。源码评审的价值就在于这四个问题的答案全部在代码里不在 README 里。3. 为什么源码级评审比只看论文更有价值论文是项目的“广告”源码是项目的“事实”。两者的差距在不同项目里大小不一但几乎永远存在。常见的情况有下面几类。实现细节缺失。论文会写模型用了多少层、多宽的隐层但不会写初始化方式、学习率调度、数据预处理顺序、注意力掩码的具体组织方式。这些细节往往决定训练能不能收敛、推理性能是不是达标。没有源码复现很容易卡在“看起来都和论文一样但就是跑不出论文的效果”。宣称和现实有出入。论文里可能写“我们提出的方法高效”但实际代码里没做 KV Cache、没做低精度推理、没做 batch 优化。只有把代码跑起来看真实的显存和耗时才能确认效率宣称是否成立。架构描述模糊。“我们引入了一个思考机制”这句话既可能是一个复杂的状态机也可能只是简单的几轮循环调用同一个模块。两者实现复杂度和效果完全不同。源码能告诉你真实复杂度。二次开发的基础。你如果想把连续思考机制接入自己的模型或项目不能只靠论文理解接口。你需要知道核心状态从哪里接入、哪些函数可以复用、哪些地方耦合严重。源码阅读是二次开发的必经步骤。复现实验的参考线。别人做源码评审记录了基础环境的 CUDA 版本、PyTorch 版本、显存占用和推理耗时。你照着同样的配置跑一遍如果结果差别很大至少能排除一部分环境因素。没有这个参考线问题排查就没有起点。以 Continuous Thought Machine 为例假设论文说“模型在内部进行连续思考然后输出答案”你从源码里真正要确认的是三个具体问题连续状态用什么数据结构表示更新状态的循环写在模型前向路径的哪个位置训练 loss 如何传递给这个内部状态。这三个问题不读代码光读论文是答不出来的。4. 源码级评审总体流程源码评审不能拿到仓库就从头读到尾。那样会陷入细节出不来。建议按下面六个步骤走。4.1 先读抽象层建立全局认知先看 README、论文、项目主页、GitHub Issues。确认三件事项目解决什么问题、代码分为哪几个模块、怎么启动。这一步不求理解全部只求画出模块关系。如果 README 里有架构图或推理示意图先把图保存下来作为后续读代码的坐标。模型类项目要重点确认两样东西入口脚本在哪里配置文件路径是什么。4.2 分析目录结构定位关键文件拿到仓库后先克隆到本地再用树形命令看目录结构。git clone repository-url cd repository-dir tree -L 2tree -L 2能快速看到代码结构。模型类项目关注几个固定位置模型定义文件、训练脚本、推理脚本、数据处理模块、配置文件、依赖清单。如果系统没有tree可以用find . -maxdepth 2 -type d替代。4.3 从结果反向定位代码不要按文件顺序读。先看推理脚本或 demo找到模型对象的创建和调用位置然后跳进模型类的 forward 方法。这是最快定位核心机制的方法。对于 Continuous Thought Machine 这类项目核心机制一定出现在推理过程的前向路径上。要么是 forward 里出现循环要么是调用了某个update方法。找到这个位置就找到了整个项目的核心。4.4 精读核心循环和状态更新一旦定位到 forward 路径重点看状态如何维护。每一轮更新使用了哪些输入、哪些参数、最后如何输出。这是判断“机制是真创新还是包装”的关键。需要记录的信息包括状态张量的形状、循环次数是否固定、每轮更新是否共享参数、更新过程中是否读取了新增的 token。4.5 回到训练脚本理解了推理路径后再看训练脚本。核心问题是这个连续思考过程在训练时如何被监督。可能的情况有三种端到端直接更新所有步骤只在最后一步计算 loss中间步骤没有直接监督引入辅助损失对中间状态做额外约束。不同训练方式会影响模型的收敛行为和推理表现。源码评审报告里训练监督方式是必须记录的条目。4.6 跑最小实验验证读完核心代码后立刻按 README 跑一个最小配置的实验。这一步能验证你的理解是否正确也能拿到真实的显存和耗时数据。评审结论必须建立在实验数据上而不只是代码阅读。这套流程不只适用于 Sakana AI 的项目任何开源 AI 仓库都可以套用。5. 从源码中定位连续思考的关键模块拿到 Continuous Thought Machine 源码后不要漫无目的地读。按关键词搜索是最有效的定位手段。5.1 状态初始化连续思考一定存在一个随输入变化的状态对象。在代码里搜索state、init_state、thought_state、latent等关键词先找到状态的数据结构定义。常见实现是单个张量或者是包含多个张量的封装类。看到状态变量后要注意它的形状变化是batch_size * hidden_dim还是带步数维度的batch_size * steps * hidden_dim。如果是后者说明每一步的中间状态都被保存内存开销会明显增加。5.2 状态更新核心机制在更新逻辑里。搜索update、step、iterate、thought_step、for循环。需要判断四件事更新是顺序执行还是可以并行每一轮更新是否共享同一组参数更新轮数是固定值还是由配置项控制更新过程中是否读入新信息还是只在初始输入上反复迭代。这些细节决定模型的可扩展性和显存占用。固定轮数可以直接用range(num_steps)展开动态轮数则需要额外设计终止条件。5.3 状态解码思考完成后状态要转换成输出。搜索decode、unembed、logits、generate等关键词重点看解码逻辑是否依赖完整的历史 token还是只从最终状态出发。这个区别很重要。如果解码过程仍然需要读取所有历史 token那么连续思考节省的只是“思考阶段”的开销最终生成的成本并没有下降。5.4 损失函数训练相关代码里搜索loss确认思考状态是否参与梯度计算。如果源码对连续状态加了辅助损失或者允许梯度流经所有思考步骤那训练成本会明显上升如果只在最后一步接 loss训练实现相对简单。下面给一个通用的源码快速搜索流程# 在仓库中搜索关键实现词按项目实际关键词调整 grep -rn def forward --include*.py | head -20 grep -rn thought_step\|num_steps\|update_state --include*.py | head -50# 定位推理入口 rg generate|infer|sample --type py -l# 查看配置文件里的思考步数等关键参数 cat config/*.json注意这些命令是通用模板。具体关键词、文件路径要根据实际仓库调整不要照抄。6. 本地复现环境与最小运行配置写源码评审报告之前要先把环境搭起来跑通一个最小实验。否则你读到的代码只是纸面推断。6.1 基础环境准备建议使用 conda 管理 Python 环境避免依赖污染。Python 版本方面模型仓库通常都会指定版本优先看 README。如果没有指定python3.10是当前兼容性较好的选择。conda create -n continuous-thought python3.10 conda activate continuous-thoughtGPU 环境检查nvidia-smi python -c import torch; print(torch.__version__, torch.cuda.is_available())如果 PyTorch 还没安装按 PyTorch 官网给出的命令安装对应 CUDA 版本。这里不写死版本号因为仓库依赖会变安装前以官网最新说明为准。6.2 安装项目依赖大多数仓库会提供requirements.txt或pyproject.toml。pip install -r requirements.txt依赖装完后先确认模型定义能否正常实例化。可以写一个快速 smoke testimport torch import importlib # 示例按仓库实际模块导入这里只展示骨架 # model_module importlib.import_module(ctm.model) # model model_module.ContinuousThoughtMachine(vocab_size100, hidden_dim64) # dummy_input torch.randint(0, 100, (1, 16)) # out model(dummy_input) # print(out.shape)这个骨架不能直接运行因为每个仓库的导入路径、类名、参数完全不同。它只用于说明 smoke test 的写法用尽可能小的参数创建模型跑一次 forward确认没有报错。6.3 启动推理脚本找到 README 里推荐的推理命令。如果没有具体命令就按通用模板python run_inference.py --prompt What is 7 * 8? --steps 4如果仓库把参数放在配置文件里先改配置再启动python run_inference.py --config configs/demo.yaml关键是把“思考步数”这个参数找出来。后续的对比实验都靠这个参数驱动。6.4 目录管理建议在项目外部建一个实验目录把输入、输出、日志和模型权重分开。例如experiments/ ├── inputs/ │ └── prompts.txt ├── outputs/ │ ├── step_1/ │ ├── step_4/ │ └── step_8/ ├── logs/ └── models/这样批量实验时不会污染仓库也更方便整理报告。7. 功能验证与效果对比实验最小实验跑通只是起点。源码评审最有说服力的部分是能不能验证某个机制确实在起作用。对 Continuous Thought Machine关键实验是调整思考步数观察输出变化。7.1 开关对比测试第一个实验把思考步数设为 0也就是禁用连续思考记录输出。然后开启思考步数比如 4 步再记录输出。如果两组输出几乎一样说明当前实现中这个机制影响不大或者模型权重还没学会使用它。如果输出差异明显说明机制确实改变了生成路径。输入建议选择需要推理的题目比如数学题、逻辑题而不是简单的文本补全。因为连续思考的目标是提升推理能力用推理类题目更容易看出差异。示例实验表编号思考步数输入 Prompt输出摘要显存GB耗时s107 * 8 ?待实测待实测待实测247 * 8 ?待实测待实测待实测387 * 8 ?待实测待实测待实测这个表格里的“待实测”是说明实际数值需要在确定模型版本和硬件后填写不要拍脑袋填。7.2 思考步数扫描问题集建议准备 20 到 50 条测试数据涵盖四类数学计算逻辑推理简单事实问答长文本理解。然后用思考步数 0、1、2、4、8 分别跑一遍重点观察四件事输出是否变长正确率是否有变化耗时的增长曲线是线性还是超线性显存随步数增长后的变化是否可接受。这个扫描可以手动跑也可以写成脚本。脚本思路是准备好 prompt 列表循环调用推理函数把每一步的输入、输出、延迟、显存快照记录到文件。import csv import time import torch results [] prompts [ 如果今天是周三3天后是星期几, 一个长方形的长是6宽是4面积是多少, ] for steps in [0, 1, 2, 4, 8]: for prompt in prompts: start time.time() # 调用项目自带的推理接口这里替换为实际函数 output generate(promptprompt, stepssteps) latency time.time() - start mem torch.cuda.max_memory_allocated() / 1024**3 results.append({ steps: steps, prompt: prompt, output: output, latency: latency, gpu_mem_gb: round(mem, 2), }) with open(scan_results.csv, w, encodingutf-8, newline) as f: writer csv.DictWriter(f, fieldnamesresults[0].keys()) writer.writeheader() writer.writerows(results)这段代码里的generate、torch.cuda都需要按实际环境调整。如果仓库的推理函数不接受steps参数就通过配置文件控制。7.3 输出质量评估不要只依赖主观感受。对每一组结果做三项判断正确性有明确答案的问题是否正确逻辑连贯性生成内容是否有自相矛盾与 prompt 的相关性有没有答非所问。如果项目支持批量评估脚本用脚本统计正确率更客观。如果没有至少用表格记录避免凭记忆下结论。7.4 判断源码和论文一致性完成实验后回到源码。对照检查论文是否声称“思考步数越大效果越好”实验数据是否支持这个结论如果步数增大后输出反而崩溃去检查实现细节。常见原因有三个状态更新没有用残差连接步数增大后数值不稳定步数增大后计算图的梯度消失或爆炸训练时只在固定的小步数上做过优化模型没学会使用大步数。这是源码评审最出成果的部分也是最能体现“源码级”价值的环节。8. 接口化与批量评估如果 Continuous Thought Machine 仓库只提供了 Python 脚本没有 HTTP 服务你可以在本地包一个简单接口方便批量测试和后续工具集成。8.1 快速包一层 HTTP 服务如果项目本身没有 API可以按这个思路自己包一层。先用 FastAPI 或 Flask 把推理函数包成 HTTP 接口再把模型加载、思考步数、温度、输出长度作为请求参数最后启动服务用 curl 验证。pip install fastapi uvicornfrom fastapi import FastAPI, Request app FastAPI() app.post(/generate) async def generate(payload: dict): prompt payload.get(prompt) steps payload.get(steps, 4) temperature payload.get(temperature, 0.8) # 这里替换为项目实际的推理函数 output generate_text(prompt, stepssteps, temperaturetemperature) return {prompt: prompt, output: output}# 启动服务按实际文件调整 uvicorn api_server:app --host 127.0.0.1 --port 8000# 用 curl 测试接口 curl -X POST http://127.0.0.1:8000/generate \ -H Content-Type: application/json \ -d {prompt: What is 7 * 8?, steps: 4}注意如果没有实际的generate_text函数这段代码无法运行。它只是一个结构示例用来演示包接口的思路。8.2 批量任务设计批量评估建议写成“输入文件 输出文件 日志”的结构python run_eval.py \ --input ./experiments/inputs/prompts.jsonl \ --output ./experiments/outputs/results.jsonl \ --steps 4 \ --config