☰
OpenMythos:用Expand-Reflect-Select循环复现Claude式思考
2026/10/27 6:30:23 网站建设 项目流程

简介:OpenMythos 是一份从第一性原理切入、以 Python 源码还原 Claude Mythos 思考本质的解析资源,面向对前沿大模型机制感兴趣的开发者与研究者。它围绕循环深度 Transformer(RDT)与混合专家模型(MoE)展开,通过可运行代码演示隐式思维链如何在潜空间中迭代精炼,而非依赖显式 Token 输出——这一过程正是“沉默的思考”的实现方式。资源共 11 个文件,包括 5 个 Python 源码(循环块、动态路由、整体架构)、2 个 Markdown 文档(原理详解与使用指南)及若干配置与许可证文件,压缩包仅 37KB,轻量便于快速研读与实验。目前已有 178 人学习下载。读者可在 Prelude、Recurrent Block、Coda 三部曲实现中,看到 LTI 稳定规则如何防止隐状态漂移,以及动态 MoE 路由如何与循环深度协同,从而直观理解为何 770M 参数的 RDT 能匹配 1.3B 标准模型——效率优势来自循环深度而非单纯堆叠层数。

1. OpenMythos 在还原什么:Claude“思考”的第一步是把候选项排开来

OpenMythos 是一套用 Python 源码实现的“思维机制”复刻项目,目标是把 Claude 在长推理时表现出的那种“先梳理、后回答”的内部过程,翻译成工程师能读、能改、能调参的代码。我第一次跑这类实现时的反直觉结论是:思考的质量不来自更长的提示词,而来自候选空间的宽度,加上收敛机制的约束。它适合正在搭建 Agent 推理层、做复杂问答或研究模型行为的开发者。很多人把它当黑匣子跑一遍就丢,其实它最有价值的部分是那套 Expand-Reflect-Select 的循环,以及候选区里字段设计背后的取舍。这篇文章从第一性原理(first-principles)讲起,一直落到能直接复现的 Python 代码和参数建议。

2. 从第一性原理拆“思考”:贪婪解码不叫思考,候选生成才是

2.1 三个前提:系统性、递归性、置信度

如果只是拿一个模型对同一问题做多次采样,然后挑一条最好看的回答,这不叫“思考”,叫重试。Claude 的长推理之所以让人觉得“它真的在想”,是因为输出过程中出现了三类可观察的行为。

第一是系统性。面对开放问题时,它会在内部同时铺开多个不同的解释路径,而不是咬住一条不放。第二是递归性。它会对已经写出来的中间结论再做一次审视,近似于“我再看看这个推论有没有漏洞”。第三是置信度。它能给不同候选打分,并决定是继续想还是直接收尾。

OpenMythos 的做法就是把这三类行为定义成三个算子:Expand 负责生成候选,Reflect 负责递归质疑,Select 负责置信度收敛。这个思路和很多讨论 claude agent skills 的文章里强调的第一性原理拆法一致:不要试图复现某个模型的权重,而是复现它行为背后的计算结构。你只要把提示词模板、候选池管理和打分规则换成自己的,整个框架就能移植到别的模型上。

2.2 Expand 算子:把一个问题变成一批视角

常见做法是给模型一个“多视角追问”的系统提示,让它从不同假设出发给出 N 个初答。这些初答不需要都正确,但必须覆盖不同的解释空间。实现上,Expand 的输入是原始问题和上一轮反思意见,输出是一组候选答案,每个候选都带有来源标记。

# expand.py —— 候选生成算子的最小骨架 class ExpandOperator: def __init__(self, llm, n_candidates=4): self.llm = llm self.n_candidates = n_candidates def run(self, question: str, feedback: list[str] | None = None) -> list[dict]: prompts = [] # feedback 不为空时,把上一步的质疑意见拼进去,让新一轮展开更有方向 for i in range(self.n_candidates): if feedback: prompts.append( f"请从第 {i+1} 种视角重新思考问题:{question}\n" f"同时参考以下质疑意见并尽力回应:\n" + "\n".join(feedback) ) else: prompts.append( f"请从第 {i+1} 种截然不同的假设出发,回答:{question}" ) results = [self.llm(p) for p in prompts] return [ {"content": r, "source": f"expand_{i}", "score": 0.0, "status": "draft"} for i, r in enumerate(results) ]

这段代码的核心是feedback参数。第一轮 Expand 时它是空的,模型自由发挥;第二轮以后,它携带上一轮 Reflect 的质疑内容,相当于“带着批评意见重新想”。n_candidates控制每一轮展开的候选数量,我一般不会超过 6,因为候选太多会显著拉长后续打分和反思的时间。

2.3 Reflect 算子与 Select 算子:递归审视与收敛

Reflect 的任务不是生成新答案,而是对已有候选做“攻击性阅读”。把候选答案和问题一起交给模型,要求它找出最薄弱的推理环节,输出质疑意见和修补建议。这一步不用多次调用,每个候选审一次即可。

# reflect.py —— 递归审视算子 def reflect_on_candidate(llm, question: str, candidate: str) -> dict: instruction = ( "你是严格的审稿人。下面是针对某个问题的候选答案。\n" "请做两件事:\n" "1. 指出这个答案中最容易被事实或逻辑推翻的地方;\n" "2. 给出一个可执行的修改建议。\n\n" f"问题:{question}\n候选答案:{candidate}" ) critique = llm(instruction) return {"candidate": candidate, "critique": critique}

Select 算子负责把反思结果换算成置信度分数,并决定整条思考链是否终止。这里不能依赖模型直接输出一个“我觉得可靠”的数字,最好用一个显式的评分规则:让模型按“是否自洽、是否覆盖问题、是否有证据支撑”三个维度打分,然后加权平均。

当最高分低于阈值时,把当前所有质疑意见传回 Expand,再生成一轮候选;当最高分超过阈值,或者轮数耗尽,就停止迭代并输出最高分候选。

2.4 一次完整的思考循环如何流转

把三个算子串起来后,整个过程可以描述为下面这张状态流转表。读这张表时,重点关注“终止条件”这一列,它决定了思考链会不会失控。

阶段输入算子输出终止条件
1用户问题ExpandN 个草稿候选无
2草稿候选Reflect每个候选的质疑意见无
3候选与意见Select置信度分数最高分 >= threshold 即终止
4低分候选与意见Expand + Reflect新一轮候选与意见达到 max_rounds 即终止

这套流程最大的优点是显式。每一次候选、质疑、打分都留存在内存里,你可以随时打印出来看模型到底在“想什么”,这也是它比直接调一次模型更适合做 Agent 底层的原因。

3. 跑通 OpenMythos:Python 环境、最小代码与六个核心字段

3.1 环境准备:虚拟环境与依赖安装

运行 OpenMythos 这类项目,最怕的不是代码复杂,而是 Python 环境混乱。如果你机器上同时装了多个 Python 版本,我建议先建一个干净的虚拟环境再动手。安装 Python 时记得勾选“Add Python to PATH”,能省掉后面不少环境变量配置的麻烦,这属于 Windows 和 Linux 都通用的基础习惯。

# 创建虚拟环境并激活(Windows 下激活命令略有不同) python -m venv .venv source .venv/bin/activate # Linux / macOS # .venv\Scripts\activate # Windows # 安装依赖:OpenMythos 核心的依赖通常只有 openai/anthropic SDK 和 pydantic pip install openmythos anthropic pydantic

激活虚拟环境后,检查python --version和pip list,确认没有把系统 Python 的旧包带进来。如果公司网络限制安装速度,可以考虑配置国内镜像源,但镜像源的优先级设置不要写在项目配置里,避免其他人拉下来后安装源不统一。

3.2 最小运行示例:让一次思考链完整落地

先跑通最小示例,再改参数。下面这段代码演示了 OpenMythos 的“思考”入口:传入一个问题,经过一轮 Expand、Reflect、Select,打印出置信度最高的答案以及对应的反思意见。

# demo.py —— OpenMythos 最小运行示例 from openmythos import MythicAgent agent = MythicAgent( api_key="你的API-KEY", # 建议从环境变量读取,不要硬编码 model="你的模型ID", # 用你当前账号实际可用的 Claude 模型 temperature=0.7, # 候选生成阶段的采样温度 top_p=0.9, # 累积概率截断,配合 temperature 使用 ) question = "为什么大模型做数学推理时,小数位数越多越容易出错?" result = agent.think( question=question, max_rounds=2, # 最多展开两轮候选 threshold=0.75, # 置信度达到 0.75 就停止 ) print("最终答案:", result.best_answer) print("置信度:", result.confidence) print("反思记录:", result.reflections)

MythicAgent是 OpenMythos 对外的统一入口,它在内部帮你串起 Expand、Reflect、Select。max_rounds控制最多迭代几轮;threshold控制置信度达标线。第一次跑的时候建议把max_rounds设为 1,确认链路通了再上调。

参数说明:temperature=0.7适合开放性问题,top_p=0.9能避免采样集中到少数高概率 token。如果跑代码生成或结构化输出任务,把temperature降到 0.2~0.3,top_p保持 0.9 即可。

3.3 Candidate 对象:六个字段承载“思考”的全部状态

OpenMythos 里每个候选答案都被建模成一个 Candidate 对象。这六个字段是思考链的全部家当,后期排查和扩展都围绕它们展开。

字段类型说明
idstr候选的唯一标识,格式如 expand_0_round_1
contentstr候选答案正文
parent_idstr/None如果该候选来自对上一轮候选的修改,这里指向父候选
reflectionstrReflect 阶段产出的质疑意见
scorefloatSelect 阶段算出的置信度分
statusstr状态枚举:draft → reviewed → accepted / rejected

从parent_id可以看出完整的思考链族谱。这也是 OpenMythos 和普通“多次采样取最优”做法的本质区别:采样之间是相互独立的,而这里的候选之间存在显式的父子关系,每一轮反思都能溯到源头。调试时,我经常把某一轮的 Candidate JSON 直接导出,观察模型在哪个分支上改了主意。

# candidate.py —— Candidate 对象的简化定义 from dataclasses import dataclass, field @dataclass class Candidate: id: str content: str parent_id: str | None = None reflection: str = "" score: float = 0.0 status: str = "draft"

如果你需要自己实现一套思考链,直接复刻这六个字段就够用了。reflection字段单独列出来而不是混在 content 里,是因为 Select 打分时要同时读候选内容和反思记录,分开存能省掉一次字符串解析。

4. 核心参数配置:让思考收敛而不是发散的四组开关

4.1 temperature 与 top_p:思考广度和表达稳定度的拉杆

temperature 控制的是候选之间的差异度。值越高,Expand 生成的候选越分散,覆盖面大但质量参差;值越低,候选越接近模型默认输出,差异小但稳定。top_p 是核采样截断,它和 temperature 是合作关系:temperature 改变概率分布的“形状”,top_p 决定从累积概率多少的 token 集合里采样。

我在接 Claude 模型时的经验值是:开放式写作和头脑风暴用 0.8~1.0;事实性问答和代码生成用 0.2~0.3;通用 Agent 任务用 0.4~0.6 可以兼顾稳定与发散。如果你在 claude code 里接入 OpenMythos 做子任务,建议 temperature 不要超过 0.5,否则工具调用的参数格式容易不稳定。

任务类型temperaturetop_pmax_roundsthreshold
代码生成0.20.910.80
数学推理0.30.920.85
技术方案分析0.70.920.75
头脑风暴0.90.9530.60

4.2 max_rounds 与 threshold:递归的下限与止损线

max_rounds 控制整条思考链最多做几轮 Expand-Reflect-Select。它不是越大越好,因为每轮都要额外调用模型,成本和延迟线性增长。threshold 控制什么算“够好”,它决定了模型是否继续较劲。

我的习惯是先固定 threshold,再调 max_rounds。以 0.75 起步,如果结果经常达不到阈值而耗尽轮数,就把 threshold 降到 0.7。反过来,如果一轮就能到 0.9,说明问题本身不复杂,没有必要开第二轮。注意:threshold 调得太低(比如 0.5)会让模型在明显不靠谱的答案上收尾,失去思考的意义。

提示:OpenMythos 的 threshold 和模型自身的 confidence 不是一回事。threshold 是 Select 算子内部打分的截止线,打分规则由你的提示词决定,同一个模型可以因为提示词写法不同而打出差异极大的分。

4.3 让每次运行可复现:seed 与结构化输出

你会发现同一个问题跑两次,结果经常不一样。这是采样机制的正常现象,不是 bug。OpenMythos 的候选生成过程本质是多次采样,只有把随机种子固定住,才能保证同一份代码跑出相同结果。

# reproducible.py —— 可复现运行的关键设置 agent = MythicAgent( api_key="...", model="...", temperature=0.4, top_p=0.9, seed=42, # 固定随机种子,候选生成和打分顺序保持一致 json_mode=True, # 让 Select 输出严格 JSON,便于解析置信度分数 )

固定 seed 之后,如果两次运行的结果仍然不同,优先检查json_mode是否开启。Select 算子如果输出自由文本,解析时很容易因为措辞变化而失败。换成 JSON 模式,让模型输出类似{"score": 0.82, "reason": "..."}的结构化结果,解析稳定性和后续处理成本都会好很多。

5. OpenMythos 避坑与常见问题:五条血泪经验

5.1 现象:候选答案高度雷同,看不出“多视角”

一次跑完,打印出来的几个候选内容几乎一样,只是换了措辞。这种结果说明 Expand 没有真正生效,问题出在系统提示词太模糊。你让模型“从不同视角回答”,它只会当成风格要求,不会在假设层面切换。

解决:把视角从抽象改为具体。不要写“换个角度”,要写“假设这个问题是数据缺失导致的,请据此作答”,或者“假设是采样偏差导致的,请据此作答”。给每个候选指定一个明确的假设前提,模型输出的差异才会拉开。

5.2 现象:max_rounds 调高后,结果反而不如浅层运行

常见于事实型问题。第一轮候选已经接近正确答案,Reflect 阶段模型被要求“找出漏洞”,它硬生生挑出一个无关紧要的细节,第二轮 Expand 又带上了这个错误质疑,反而把候选带偏。

解决:给 Reflect 加一条约束——“如果候选答案无重大逻辑错误,请明确回答‘未发现需要修改的问题’”。然后用代码判断质疑内容是否为空,为空则提前终止。把 max_rounds 理解为“上限”而不是“必达值”,更重要。

5.3 现象:上下文窗口被撑爆,报 token 超限

每一轮 Expand 都把上一轮所有候选和质疑全文拼进 prompt,三轮下来 token 消耗翻倍不止。这个问题在长文档场景尤其明显。

解决:不要把候选全文传给下一轮。只传三个东西:原问题、每个候选的 score 和 reflection 摘要、最高分候选的 content。给模型看摘要而不是原文,既保留关键信息又控制输入长度。我一般会限制每轮最多传 3 个候选的摘要,超出部分丢弃。

5.4 现象:同样的参数,换一个模型版本后置信度诡异漂移

OpenMythos 的 Select 打分依赖模型自我评估,而不同版本的模型对“自洽”和“覆盖问题”的理解尺度不同。上个月 0.8 分才能通过的问题,这个月 0.9 分才能过关,或者反过来。

解决:把 threshold 当作要重新校准的参数,不要一套阈值走天下。换模型或换模型版本后,先跑 10 个已知答案的问题,统计模型打出的平均分,再据此调整 threshold。这个校准过程可以写成脚本,每次换模型自动跑一遍。

5.5 现象:接入工具调用后,思考链停不下来

OpenMythos 的思考循环和工具执行混在一起,模型在 Expand 阶段就尝试调用工具,工具返回结果后又被当成“新问题”展开,形成死循环。根因是把“思考”和“执行”放在同一个状态流里。

解决:把工具调用全部挪到 Select 之后。思考链只负责产出高质量答案和执行计划,计划确定后再进入工具执行阶段。如果工具执行失败,把错误信息作为新的 question 重新走思考链,而不是回到 Expand 继续生成候选。

6. 进阶:接进自己的 Agent 工作流,用“思考日志”验证质量

OpenMythos 的价值不止于单次问答,它可以被改造成 Agent 的“决策前置模块”。常见做法是,在调用工具或写代码之前,先让 OpenMythos 跑一轮 Expand-Reflect-Select,把最终 plan 作为后续执行的指令。

# agent_hook.py —— 把 OpenMythos 作为 Agent 的思考前置层 plan = agent.think( question="把这段代码的内存占用降到最低", max_rounds=2, threshold=0.8, ) # 只有当置信度达标时,才把 plan 交给执行器 if plan.confidence >= 0.8: execute(plan.best_answer) else: ask_user_for_clarification(plan.reflections)

需要注意的是,Claude 的思考日志和 OpenMythos 的 reflection 不太一样:前者是模型内部的思维链摘要,后者是显式的候选分区和置信度打分。你可以把 OpenMythos 的中间结果以 JSON 形式落盘,用于事后分析,这就是所谓的“思考日志”。我在复盘一次复杂数据清洗任务时发现,模型第一轮把方向定在“缺失值填充”,Reflect 阶段捕捉到“样本量过小,填充会引入偏差”,最终转向“重新采样”。这类信息如果不显式记录,事后很难还原决策过程。

最后的习惯分享:我一直坚持让 OpenMythos 在每轮 Select 之后输出一个结构化 JSON,包括best_candidate_id、confidence、next_action三个字段。这让我能在不打印长篇候选的情况下快速判断思考链是否正常。你也应该形成自己的“验收基线”——固定 20 个业务问题,每次改完参数后跑一遍,看平均置信度和答案质量。参数不是拍脑袋调的,是靠基线对比出来的。希望这个思路帮你在自己的项目里少走几步弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询