记忆与预算¶
Codex 仓库里有两类容易被忽略的后台机制:memories 和 rollout budget。前者把历史工作提炼成可复用记忆,后者给同一个 root-thread session tree 施加共享 token 预算。它们共同体现了一个设计方向:agent 不只要会执行当前 turn,还要能管理长期上下文和成本边界。
Memories 总览¶
memory 写路径在 codex-rs/memories/write,读路径在 codex-rs/memories/read。两者刻意拆成不同 crate:读路径负责注入、引用解析和 telemetry 分类;写路径负责 startup pipeline、文件 artifact、两阶段 prompt 和 workspace diff。
memory 根目录是:
${CODEX_HOME}/memories
主要 artifact:
| 文件/目录 | 作用 |
|---|---|
raw_memories.md |
Phase 1 raw memory 的合并视图 |
rollout_summaries/ |
每个 rollout 的摘要文件 |
extensions/ |
memory extension 的 source-specific instructions |
phase2_workspace_diff.md |
Phase 2 consolidation agent 的只读 diff 输入 |
Startup pipeline¶
start_memories_startup_task 只在符合条件的 root session 启动:
| 跳过条件 | 原因 |
|---|---|
config.ephemeral |
临时会话不应产生长期记忆 |
MemoryTool feature disabled |
功能开关关闭 |
source.is_non_root_agent() |
sub-agent 不递归生成记忆 |
| state DB 不可用 | 无法 claim job 或记录状态 |
启动后顺序是:
- 创建 memory root。
- seed extension instructions。
- prune 过期且未使用的 Phase 1 输出。
- 检查 Codex backend rate limit,剩余额度不足则跳过。
- 运行 Phase 1 抽取。
- 运行 Phase 2 合并。
rate limit guard 使用 backend 返回的 primary/secondary window,只有使用量低于配置阈值时才允许启动后台记忆任务。这避免了“用户正在交互时后台任务抢额度”。
Phase 1:按 rollout 抽取 raw memory¶
Phase 1 的输入是历史 rollout。它会从 state DB claim eligible jobs:
| 参数 | 来源 |
|---|---|
| scan limit | THREAD_SCAN_LIMIT = 5_000 |
| startup 最大 claim 数 | config.memories.max_rollouts_per_startup |
| rollout 最大年龄 | config.memories.max_rollout_age_days |
| 最小 idle 小时 | config.memories.min_rollout_idle_hours |
| allowed sources | interactive session sources |
| lease | JOB_LEASE_SECONDS = 3_600 |
抽取任务用 buffer_unordered(CONCURRENCY_LIMIT) 并发执行,当前并发上限是 8。每个 job 会:
- 读取 rollout JSONL。
- 过滤可持久化的 response item。
- 构造 stage-one prompt。
- 要求模型返回严格 JSON:
| 字段 | 含义 |
|---|---|
raw_memory |
详细 markdown 记忆 |
rollout_summary |
用于路由和索引的摘要 |
rollout_slug |
可选,用于摘要文件名 |
输出会经过 redact_secrets,再写入 state DB。
Phase 2:受限 agent 合并 memory workspace¶
Phase 2 是全局锁保护的 consolidation。它先 claim global phase-2 job,再准备 memory workspace。workspace 是一个 git baseline repository,Codex 用 git diff 判断本次同步是否真的改变了输入。
Phase 2 的关键步骤:
- claim global lock。
prepare_memory_workspace初始化或复用.gitbaseline,并删除旧 diff artifact。- 构造 consolidation agent config。
- 从 DB 选择 Phase 2 输入。
- 同步
raw_memories.md和rollout_summaries/。 - 用 git diff 判断 workspace 是否变化。
- 写入有界
phase2_workspace_diff.md,上限4 MiB。 - spawn internal consolidation agent。
- heartbeat global lock,等待 agent final status。
- 成功后 reset git baseline,并把 job 标记为 succeeded。
consolidation agent 的 config 被刻意锁死:
| 配置 | 值/策略 |
|---|---|
cwd |
memory root |
ephemeral |
true |
generate_memories/use_memories |
false |
| MCP servers | 空集合 |
| approval policy | Never |
| disabled features | spawn/collab/memory/apps/plugins/skill dependency install |
| sandbox | workspace-write,仅 memory root 可写,network disabled |
| reasoning effort | medium |
这说明 Codex 把后台智能任务当成“内部 worker”,仍然套完整的权限、sandbox、feature 和 heartbeat 管理,而不是直接给它文件系统自由写入。
Memory citation 与使用统计¶
读路径提供两类能力:
parse_memory_citation解析<citation_entries>、<rollout_ids>或兼容的<thread_ids>。memories_usage_kinds_from_command通过 shell parser 判断命令是否安全读了 memory 文件,并分类 telemetry。
可分类的 memory 使用:
| kind | 识别路径 |
|---|---|
MemoryMd |
memories/MEMORY.md |
MemorySummary |
memories/memory_summary.md |
RawMemories |
memories/raw_memories.md |
RolloutSummaries |
memories/rollout_summaries/ |
Skills |
memories/skills/ |
注意它只统计 known safe command 中的 read/search/list 行为,避免把任意 shell 字符串当成可靠信号。
Rollout Budget¶
rollout budget 在 codex-rs/core/src/rollout_budget.rs。它是 root-thread session tree 共享的账本,不是单 turn 计数器。
每次模型返回 token usage,Codex 会调用:
weighted_tokens_used += output_tokens * sampling_token_weight
+ non_cached_input_tokens * prefill_token_weight
如果超过 limit_tokens,Session::record_rollout_budget_usage 返回 TurnAborted,当前 turn 被中止。
预算提醒¶
预算提醒不是 UI toast,而是写入会话历史的 developer contextual fragment:
<rollout_budget>
You have N weighted tokens left in the shared session token budget.
</rollout_budget>
pending_reminder(thread_id, window_id) 会根据 reminder_interval_tokens 计算当前 reminder index,并用 (thread_id, window_id) 去重。只有在 history insertion 成功后才调用 mark_reminder_delivered,如果取消发生在插入前,下次还会重试。
rearm_reminder(thread_id) 可以强制某个 thread 下次采样时重新声明剩余额度。
可学习的设计点¶
- memories 用 DB job lease + git baseline workspace + sandboxed internal agent,把长期记忆生成拆成可恢复流水线。
- Phase 1 和 Phase 2 使用不同模型、reasoning effort 和并发策略,避免“一次性大 prompt”。
- memory consolidation 禁用递归 memory、插件、MCP、网络和 delegation,防止后台任务失控。
- rollout budget 把成本约束转成 developer context,让模型在接近预算时主动收敛。
- 预算按 non-cached input 和 output 加权,比简单 total token 更贴近真实成本。
关键源码¶
| 主题 | 文件 |
|---|---|
| memory write root | codex-rs/memories/write/src/lib.rs |
| startup pipeline | codex-rs/memories/write/src/start.rs |
| Phase 1 | codex-rs/memories/write/src/phase1.rs |
| Phase 2 | codex-rs/memories/write/src/phase2.rs |
| memory workspace | codex-rs/memories/write/src/workspace.rs |
| memory storage artifacts | codex-rs/memories/write/src/storage.rs |
| memory read usage/citation | codex-rs/memories/read/src/usage.rs、citations.rs |
| rollout budget | codex-rs/core/src/rollout_budget.rs |
| budget context | codex-rs/core/src/context/rollout_budget.rs |