Codex 源码解析 · 第 36 讲
Codex 源码解析系列 第 36 讲:记忆系统——两阶段 LLM 蒸馏与 git baseline 工作区 基于 OpenAI Codex 源码 · 2026-10-30 💡 本讲一句话: Codex 的记忆是一条"两阶段蒸馏流水线"——Phase1 用便宜模型并行把旧会话压成 raw memory,Phase2 拿全局锁、靠 git diff 判断有没有变化,再派一个被彻底关进沙箱的 agent 把它们合并成每次新会话都注入的摘要。读完你能说清一条记忆从 rollout 文件到 prompt 的全路径。 一、启动闸门:谁有资格触发记忆流水线 前面几讲拆过 rollout(第 40 讲会细讲录制)、state runtime store(第 29 讲的 SQLite 状态库)。记忆系统正好架在这两块之上: 输入是旧会话的 rollout 文件,账本记在 state DB 。整条流水线的入口只有一个函数—— start_memories_startup_task (memories/write/src/start.rs 第 24-94 行),由 app-server 的 turn_processor 在根会话启动时调用: 📄 codex-rs/memories/write/src/start.rs (第 33-92 行) pub fn start_memories_startup_task( // 入口:根会话启动时由 app-server 调用,整条记忆流水线从这里开始 thread_manager: Arc<ThreadManager>, // 线程管理器:Phase2 要靠它派生一个独立的"整理 agent" auth_manager: Arc<AuthManager>, // 凭证管理:限流护栏和模型 provider 都依赖登录态 thread_id: ThreadId, // 触发流水线的根会话 id(后面认领任务时当 worker id 用) thread: Arc<CodexThread>, // 根会话句柄:Phase1 采样要读它的上下文 config: Arc<Config>, // 全量配置:模型、记忆参数、feature flag 都从这里取 parent_permission_profile: PermissionProfile, // 父会话权限画像:决定整理 agent 的沙箱上限(第五节) source: &SessionSource, // 会话来源:子代理会话不允许触发,防止重复抽取 ) { if config.ephemeral // 临时会话(如一次性 exec)不产生记忆——没有长期价值 || !config.features.enabled(Feature::MemoryTool) // feature flag 关闭 → 整条流水线禁用 || source.is_non_root_agent() // 子代理一律排除:只有根会话能触发,避免 N 个子 agent 各抽一遍 { return; // 三个条件命中任意一个就静默跳过——后台任务不打扰用户 } let versions = if config.memories.dual_write { // dual_write 模式:V1/V2 两条流水线并行跑,用于灰度对比 vec![MemoryVersion::V1, MemoryVersion::V2] } else { vec![config.memories.version] // 常规模式:只跑配置里指定的版本 }; for version in versions { // 每个版本有独立记忆根目录(memories/ vs memories_v2/),互不污染 let mut pipeline_config = config.as_ref().clone(); // clone 一份配置,让每条流水线各自改自己的 version 字段 pipeline_config.memories.version = version; // 把这条流水线钉死在目标版本上 let context = Arc::new(MemoryStartupContext::new( // 组装启动上下文…
阅读全文:Codex 源码解析 第 36 讲