对比一下codex和claude code在记忆提取方面的不同
回复 群友 1463: 最大的差别不在"记什么",而在提取的时机和组织方式:Claude Code 是回合结束当场提取、一条记忆一个文件加索引,Codex 是会话闲置几小时后台跑两阶段流水线,先抽原料再合并。 一、触发时机 Claude Code 挂在 Stop hook 上:主 Agent 回复完、没有更多工具调用时,fork 一个提取 Agent 出来干活。但不是每轮都跑。先做互斥检查,主 Agent 自己在这一轮已经写过记忆(比如你说"记住这个",它直接调 Write),提取就跳过,免得同一段对话生成重复条目;还有 turnsSinceLastExtraction 计数器节流,简单问答不值得提取。上一次提取还在跑又来了新回合时,不并发,而是把上下文暂存成 pendingContext,等这次跑完再补一次 trailing run,只处理游标之后的新消息。 Codex 是时间驱动的批处理:会话必须闲置一段时间(默认六小时)才有资格进入整合,活跃会话永远不触发。跑的时候还有阈值判断,用户自己的 API 额度低就先不跑,后台活不跟前台请求抢配额。一次整合只看有上限的最近 rollout 集合(默认 256 条)。 二、提取路径 Claude Code 有两条写入路径:模型在对话里直接写(系统提示词里带完整的保存规则:四类型、什么不该存、怎么存),后台提取 Agent 是兜底,防止模型该写没写。Codex 只有后台一条路,AGENTS.md 是手写的静态层,Agent 不会自己去改它——这也是它必须有 Memories 的原因。 三、流水线形态 Codex 是明确的两阶段。Phase 1 逐个 rollout 跑:用一个严格 schema 的提取提示词采样对话,返回 raw_memory、rollout_summary、rollout_slug 三个字段,先落 SQLite 的 stage1_outputs,再同步成 raw_memories.md,写盘前做密钥脱敏。Phase 2 拿全局锁、准备 workspace、跑一个整合 sub-agent,把候选并进 MEMORY.md 和 memory_summary.md。它用了两个模型分工:一个判断什么值得记,一个负责合并。另一个细节(来自对源码的解读,属于实现层,版本会变)是 Phase 2 靠对记忆目录做 git diff 来判断哪些材料新增、更新、消失。 Claude Code 是单阶段的 forked agent:Turn 1 并行把所有该读的读了,Turn 2 并行把所有新记忆写了,通常两个回合干完,硬上限五个回合。而且它只从游标之后的新消息里提取,不回头重读整段历史。提取 Agent 用 runForkedAgent 创建,共享父级的 prompt cache,省下的正是系统提示词那部分 token。 四、记忆的结构 Claude Code 是封闭四分类:user(身份偏好)、feedback(纠正和肯定)、project(项目动态决策)、reference(外部系统位置)。分类是硬约束,因为自由标签越堆越多、召回时匹配含糊。feedback 必须写清 Why 和 How to apply,源码里的理由是"知道为什么才能在边界情况下自己判断,而不是死守规则";project 要求把相对日期转成绝对日期,因为这条记忆几周后才会被读到,"周四"早就没意义了。存储上一条记忆一个 md 文件,带 name/description/type 的 frontmatter,description 就是召回时的主要依据;MEMORY.md 只是索引,每次会话完整加载,所以有 200 行和 25KB 的双层截断。 Codex 没有公开的封闭分类法,产物是固定几个文件:memory_summary.md(整篇读的那个)、MEMORY.md(长文合并版)、raw_memories.md(未整合的原料)、rollout_summaries/<slug>.md,还有 skills/<name>/SKILL.md 这种按技能存的记忆。 五、去重和遗忘 Claude Code 在提取提示词里注入已有记忆清单,要求先查是否已有类似的再决定新建;长期清理靠 auto-dream,目前是研究预览、每 24 小时跑一次,四个阶段:orient(读索引看现状)、gather(读日志和 transcript,找哪些漂移了、哪些偏好变了)、consolidate(合并、删矛盾项、相对日期转绝对)、prune and index(更新索引,控制在 200 行内)。 Codex 把这件事交给 Phase 2 的合并模型,另外有老化规则:三十天没被用到的 rollout 会被清掉,三十天没被召回的单条记忆会被剪掉。 六、召回方式(这块差别最直观) Claude Code 是语义检索:扫描记忆目录,每个文件只读前 30 行拿 frontmatter,按 mtime 倒序取最新 200 条,格式化成清单(带 ISO 时间戳,让选择器能感知新鲜度),交给 Sonnet 做一次 sideQuery 语义筛选,最多返回 5 条,再作为 meta user message 注入对话,超过一天还会带新鲜度警告。整个召回是异步预取的,模型开始生成的同时后台就在查,延迟基本藏掉了。限 5 条是召回价值和上下文成本之间的平衡。 Codex 走的是确定性路线:会话开始读整篇 memory_summary.md,按 token 截断到预算内,然后指示 agent 需要细节时自己 grep MEMORY.md。快、可预测、省 token,但没有语义召回——你换个说法问同一个事实,它可能就 grep 不到了。 七、权限和边界 两边都做密钥脱敏。Claude Code 给提取 Agent 的权限是很窄的白名单:Read/Grep/Glob 不限,Bash 只允许只读命令,Edit/Write 被校验只能落在记忆目录内,其他工具全拒。另外记忆目录路径刻意不读项目级 settings,因为项目设置会签进仓库,恶意仓库可以设成 ~/.ssh 骗写权限。Codex 那边公开文档提到的是脱敏、开关(写入和读取可以分别关)和地理限制——EEA、英国、瑞士上线时只有 AGENTS.md 层。 八、你插手的入口 Claude Code 有 /memory、/remember,你明确说"忽略记忆"时它要把记忆当不存在;记忆目录本身是普通 markdown,可以自己去看。Codex 这边,你对主 Agent 说"以后这个项目用 pnpm",它不会当场改 MEMORY.md,而是追加一个 extensions/ad_hoc/notes/<时间戳>-<名称>.md,等下一次 Phase 2 整合才吸收进去——写入便宜、不打断对话,代价是不立刻生效。 一句话收口:Claude Code 的取向是"即时、分类、语义召回",成本是每轮多一次提取判断和一次召回注入;Codex 的取向是"延迟批处理、文件可 grep、行为可预测",省上下文也更确定,代价是召回吃措辞、要 agent 主动去查。你要的是"别忘了"就偏前者,要的是"别乱记、别乱花 token"就偏后者。 补一句口径:Claude Code 这边的一手来源是官方 memory 文档加上对源码结构(memdir、extractMemories)的社区解读,auto-dream 官方还没正式文档;Codex 那边是官方 memories 文档加第三方拆解,raw_memories.md、ad_hoc/notes 这些属于实现细节,不是稳定接口,换版本可能改名改结构。