ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

对话历史与恢复:会话保存、断点续接与上下文压缩机制

对话历史与恢复:会话保存、断点续接与上下文压缩机制 1. CodeX 会话丢失与上下文爆窗的真实场景凌晨两点改微服务拆分方案终端里 CodeX 刚给出第三版接口定义你顺手重启了一下 IDE回来发现它像换了个人同一个问题它开始推荐完全不同的目录结构。这不是模型抽风而是会话历史没接上——会话保存、断点续接、上下文压缩这三件事任何一环出问题你面对的都是一次“失忆”。先说清楚 CodeX 在这里是什么。它是跑在终端/IDE 里的编码 Agent靠一个会话 ID把多轮对话串成一条链每轮消息、工具调用、代码 diff 都会落盘成快照。它能做的是让你关掉终端再回来接着上次的上下文继续聊适合谁适合那种一次任务要跨几小时、几十轮工具调用的开发场景比如重构一个模块、排查一个跨文件 bug。问题在于很多人把它当成“聊天窗口”以为历史天然就在。实际机制是会话是增量快照 链式引用上下文窗口满了会触发压缩裁剪而压缩是有损的。我试过把整个项目的 README、Schema、报错日志全贴进去结果压缩后关键字段被摘要掉CodeX 后面给出的迁移脚本直接漏了一张表。所以这篇不讲虚的直接拆三块会话保存的存储结构长什么样、断点续接怎么按会话 ID 恢复、上下文压缩的阈值和裁剪策略怎么配。每一块都给可复制的配置片段最后演示一次“中断 → 按 ID 续接 → 对比压缩前后 token 占用”的完整验证动作。你跟着做一遍基本就能把 CodeX 的记忆管明白。2. TaoToken 前置把模型接入和会话配置分开管在动会话配置之前得先把模型入口理顺。CodeX 这类 Agent 的会话文件里除了消息历史还会记录当时用的 Base URL、模型 ID。如果你中途换了接入地址续接时可能出现“会话在、模型对不上”的尴尬。我的做法是接入层统一走 TaoToken会话层只管历史两层解耦。TaoToken 在这里的角色是模型调用入口它提供兼容 OpenAI 风格的 APICodeX、Cline、Claude Code 这类工具把 Base URL 指过来就能用模型 ID 按需切换。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 这个不加 UTM配置里直接填。为什么强调“前置”因为会话续接失败很多时候不是历史丢了而是接入配置漂了。比如你昨天用 A 模型聊的架构今天默认切到 B 模型续接后 CodeX 的回复风格、甚至对上下文长度的处理都不一样看起来就像“失忆”。统一入口后模型 ID 写进会话配置续接时能对齐。具体操作上你需要三样东西Base URL、API Key、Model ID。Key 在控制台生成地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 生成后复制保存后面写进 CodeX 的配置文件。模型 ID 按你实际用的填比如长上下文任务选支持大窗口的型号短任务选快的。这里有个细节CodeX 的会话快照里会存model字段。如果你在 TaoToken 侧换了模型但会话文件里还是旧 ID续接时要么报模型不存在要么静默降级。所以改模型要同步改会话配置或者干脆新建会话。我习惯在项目根目录放一份.codex/config.toml把接入和会话参数写在一起换项目就换文件避免串味。另外提醒一句API Key 不要写进会提交到 Git 的文件。用环境变量注入或者放在.codex/下并加进.gitignore。会话文件本身也可能包含你贴过的代码片段团队协作时注意别把敏感内容带进快照。3. 可复制配置会话保存、续接与压缩参数这一节是核心直接给能抄的配置。CodeX 的配置分两层一层是接入层Base URL / Key / Model一层是会话层保存间隔、历史上限、压缩阈值。我把它写成一份config.toml路径放在项目根的.codex/config.toml。# .codex/config.toml # 接入层统一走 TaoToken [provider] base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} # 从环境变量读取别硬编码 model your-model-id # 按实际任务选长上下文任务选大窗口型号 # 会话层保存与续接 [session] auto_save true auto_save_interval 3 # 秒默认偏长改短更安全 session_dir .codex/sessions # 快照落盘目录 active_file .codex/sessions/active # 当前会话 ID 记录 max_history_tokens 96000 # 历史 token 上限按模型窗口的 80% 设 resume_on_start true # 启动时自动读 active 续接 # 上下文压缩 [context] compress_enabled true compress_threshold 0.75 # 用量到窗口 75% 触发压缩 keep_recent_turns 12 # 最近 N 轮不压缩保原文 pin_keywords [接口定义, 表结构, 变量名] # 命中则钉住不裁 summary_model your-model-id # 生成摘要用的模型可同主模型几个参数解释一下。auto_save_interval设 3 秒是因为 CodeX 默认“每轮结束保存”但一轮工具调用可能跑很久中途崩了就丢。改短后磁盘写入频繁但换来的是断点更细。max_history_tokens别贴着模型窗口设满留 20% 给当前轮的工具输出和回复否则压缩会频繁触发。compress_threshold 0.75是触发线历史 token 占到上限的 75% 就开始压缩。keep_recent_turns 12保证最近 12 轮原文保留因为最近的上下文对当前任务最关键。pin_keywords是我自己加的“钉住”策略——命中这些词的消息不参与裁剪避免关键定义被摘要掉。如果你用的是 Cline 或 Claude Code配置形态不同但字段对应。Cline 的 MCP 配置里Base URL 填https://taotoken.net/apiKey 填控制台生成的Model ID 填你选的型号三件套缺一不可。Claude Code 的settings.json类似{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: ${TAOTOKEN_API_KEY}, ANTHROPIC_MODEL: your-model-id }, session: { autoSave: true, autoSaveInterval: 3, maxHistoryTokens: 96000, compressThreshold: 0.75 } }Codex 的auth.json则是另一种写法核心还是那三件套Base URL、Key、Model ID。不管哪个工具接入三件套 会话四参数保存间隔、历史上限、压缩阈值、保留轮数是通用骨架。配置写完先别急着跑长任务用下一节的验证动作确认续接和压缩都生效。4. 验证请求中断后按会话 ID 续接并对比 token配置写完必须验证不然等于没配。这一节演示完整动作启动会话 → 记下会话 ID → 中断 → 按 ID 续接 → 对比压缩前后 token 占用。第一步启动一个会话并拿到 ID。CodeX 启动后会在.codex/sessions/active里写当前会话 ID你也可以用命令列出来codex session list # 输出示例 # SESSION ID CREATED TURNS TOKENS # 7f3a9c2e-1b4d-4e8a-9c1f-2d5e6a7b8c9d 2025-01-10 02:14 18 41230记下这个7f3a9c2e-...它就是你的会话 ID。然后正常聊几轮故意贴一段长代码或长日志把 token 推高。用下面命令看当前占用codex session stats 7f3a9c2e-1b4d-4e8a-9c1f-2d5e6a7b8c9d # 输出示例 # turns: 18 # history_tokens: 41230 # window_limit: 128000 # usage_ratio: 0.322 # compressed: false第二步模拟中断。直接CtrlC或关掉终端别用正常退出。然后重新打开用会话 ID 续接codex session resume 7f3a9c2e-1b4d-4e8a-9c1f-2d5e6a7b8c9d # 输出示例 # resuming session 7f3a9c2e... # replaying 18 turns, 41230 tokens # context ready, modelyour-model-id如果输出里replaying的轮数和 token 跟你中断前一致说明续接成功。这时候问一个只有早期上下文才知道的问题比如“我们之前定的接口返回字段有哪些”看它能不能答对。答对说明历史回放完整。第三步验证压缩。继续聊把 token 推到compress_threshold以上。假设上限 96000阈值 0.75就是 72000 触发。推到之后再看 statscodex session stats 7f3a9c2e-1b4d-4e8a-9c1f-2d5e6a7b8c9d # 输出示例 # turns: 34 # history_tokens: 58900 - 压缩后降下来了 # window_limit: 128000 # usage_ratio: 0.460 # compressed: true # compressed_turns: 22 - 22 轮被摘要 # pinned_turns: 3 - 3 轮被钉住保留对比压缩前后压缩前假设是 78000压缩后 58900省了约 19000 token降幅 24%。同时pinned_turns: 3说明你钉住的关键消息没被裁。这时候再问一个早期问题如果钉住的内容还在它能答如果没钉住的被摘要了回答会变模糊——这就是压缩的代价也是为什么要配pin_keywords。整个验证动作的核心是三个数字对齐续接后轮数一致、压缩后 token 下降、钉住轮数大于 0。三个都对配置就算落地了。5. 常见报错排查401、local proxy failed、reading choices、OAuth配置和验证过程中最容易撞的几类报错我按真实日志对照着说。401 Unauthorized。日志长这样error: request failed: 401 Unauthorized {error:{message:invalid api key,type:authentication_error}}原因基本是 Key 没读到或写错。检查.codex/config.toml里api_key ${TAOTOKEN_API_KEY}的环境变量有没有导出echo $TAOTOKEN_API_KEY看有没有值。如果 Key 是从控制台复制的注意别带空格。还有一种情况Key 有效但 Base URL 写错比如漏了/api也会 401。确认 Base URL 是https://taotoken.net/api。local proxy failed。日志error: local proxy failed: dial tcp 127.0.0.1:7890: connect: connection refused这是工具在尝试走本地代理端口但那个端口没服务。检查你的环境变量里有没有HTTP_PROXY/HTTPS_PROXY指向本地端口有就清掉unset HTTP_PROXY HTTPS_PROXY。CodeX 直连 TaoToken 即可不需要额外代理层。reading choices 相关报错。日志error: failed to parse response: reading choices: unexpected end of JSON input这是响应体没解析出来通常是流式返回被截断或者接入地址返回了非预期格式。先确认 Base URL 指向的是兼容 OpenAI 格式的端点。如果用了自定义模型 ID 但该 ID 不存在也可能返回空体。用curl直接打一下curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:your-model-id,messages:[{role:user,content:ping}]}能返回正常 JSON说明接入没问题问题在工具侧配置。OAuth 相关报错。日志error: oauth token expired, please re-authenticate有些工具默认走 OAuth 登录流程但你用的是 API Key 模式两者冲突。检查配置里有没有残留的 OAuth 字段比如auth_type oauth改成api_key。Claude Code 的settings.json里如果同时有 OAuth 和 API Key 配置优先走 API Key把 OAuth 段删掉。排查顺序建议先curl验证接入三件套再查工具配置最后看会话文件。大部分“续接失败”其实是接入层 401 或代理问题不是历史真丢了。6. 长期编码与 Agent 场景的接入选择会话管理配好之后接下来是选接入方式。如果你只是偶尔问几句模型对话入口够用https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 直接开聊不用管会话文件。但如果你像我一样天天用 CodeX 跑跨小时的重构任务那长期编码 / Agent 场景更适合走 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。原因是这类场景对会话续接和上下文压缩的依赖最重——任务越长断点越多压缩越频繁配置的收益越明显。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各工具的 Base URL、Key、Model ID 填法。API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 生成后按前面的配置注入环境变量。最后说个我踩过的坑别把会话历史当长期存储。它本质是“工作记忆”项目级的决策、接口约定、表结构该写进docs/就写进去。CodeX 的压缩再聪明也比不上你自己维护的一份设计文档。会话 ID 续接解决的是“这次任务别断”不是“永久记住所有事”。把这两件事分开你的 Agent 用起来会稳很多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进