☰
Codex 上下文压缩机制:先限流工具输出,再用本地或远端 compaction 接续任务
2026/10/13 0:00:11 网站建设 项目流程

1. Codex 长会话为什么会撑爆上下文:工具输出限流与 compaction 的真实链路

Codex 上下文压缩机制,说白了就是一套让长任务能跨过 context window 限制继续跑的续航方案。它能做什么?把几万行终端输出、几十轮工具调用、反复的 diff 和测试结果,收拢成一份能接续任务的压缩表示。适合谁?适合用 Codex 跑长链路工程任务的人——修一个跨多文件的 bug、盯一个 PR 反复跑测试、让 Agent 连续改代码直到通过。

我先把结论摆出来:Codex 不是把整个 session 永远原样塞回模型。它先控制单个工具输出体积,再在上下文接近阈值时压缩 active history。本地压缩有明文 handoff prompt,远端压缩没有 Codex 本地可见的明文压缩 prompt。

长任务能继续跑,靠的是这条链路:

工具输出限流 -> token 使用量达到阈值 -> 触发本地或远端 compaction -> 压缩结果替换 active history -> 下一次请求重新注入当前权限、环境、AGENTS.md、skills、plugins 等运行上下文

这里有个容易混淆的点:压缩解决的是当前会话的 active context 过大问题,不是长期记忆。长期记忆、AGENTS.md、skills、rollout 和 compaction 是不同层。你把它们混在一起想,就会得出「Codex 会记住一切」或者「压缩后权限就丢了」这种错误结论。

举个真实场景。你说「把失败测试修到通过」,模型跑测试,终端输出几万行。Codex 不会把这几万行完整放进模型下一轮上下文,而是先对工具输出做体积控制。模型后续看到的通常是这种形态:

Total output lines: 999 EXEC-LINE-0001 ... EXEC-LINE-0002 … 8941 tokens truncated… EXEC-LINE-0998 ... EXEC-LINE-0999

这里有三个关键信息。开头保留,模型能看到命令最早输出了什么;结尾保留,模型能看到最终失败、错误尾部、最后状态;中间标记,模型知道这里发生了截断,不会误以为日志本来就这么短。

这一步不是 compaction。它发生在 compaction 之前,目标是防止单个工具结果先把上下文撑爆。很多人一看到「上下文压缩」就以为只有一层,其实 Codex 是两层:先限流单条工具输出,再压缩整体历史。第一层是预防,第二层是收拢。

相关配置字段是tool_output_token_limit和truncation_policy。前者可以覆盖模型 metadata 里的默认截断预算,后者决定按 bytes 还是 approximate tokens 截断。这段不是模型可见 prompt,而是运行时策略。模型并不会「决定要不要截断工具输出」;工具返回进入 active history 前,Codex 已经做了截断。

需要注意:这里的 token 是工程近似值,不是精确 tokenizer。Codex 用近似预算换取稳定、快速、足够保守的输出控制。你如果拿精确 tokenizer 去核对,数字会对不上,这是正常的。

那为什么限流之后还需要压缩?因为即使每个工具输出都被截断,整个会话还是会增长:用户输入、模型解释、工具调用、工具输出、代码 diff、测试结果、用户纠正、下一轮工具调用……所以 Codex 还需要第二层机制:当 active history 接近模型上下文窗口时,把旧历史替换成更短的压缩表示。

控制这个触发点的是model_auto_compact_token_limit。没有显式配置时,Codex 会根据模型 context window 推导默认阈值,通常按窗口的 90% 左右触发。比如模型 context window 是 400k,默认自动压缩阈值约 360k。

压缩触发位置有三类。pre-turn:新一轮采样前发现上下文已经太大,先压缩再发请求。mid-turn:模型刚调用完工具,还需要继续 follow-up,但上下文已到阈值,于是同一轮中途压缩。model-downshift:用户切到更小上下文窗口的模型,Codex 先按旧模型能力压缩,再交给新模型继续。

mid-turn 很重要。它解释了为什么长任务中工具循环还没结束时,Codex 也能先「收拢上下文」再继续做下一步。你如果只理解 pre-turn,就会觉得「一轮没结束怎么压缩」,其实 mid-turn 就是为工具循环设计的。

2. TaoToken 前置:把 Base URL、Key、Model ID 三件套配好

在动手调 compaction 之前,得先让 Codex 能正常发请求。这一步是把接入信息配齐,不是注册教程。你需要三样东西:Base URL、API Key、Model ID。缺任何一个,后面看到的报错都会指向不同方向,排查起来很费时间。

TaoToken 的 API 地址是https://taotoken.net/api,官网入口是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。API Key 在控制台生成,模型对话入口可以用来先验证模型是否通,接入文档里有各客户端的配置样例。

我建议的顺序是:先去模型对话页面发一条最简单的消息,确认 Key 有效、模型能回。这一步能排掉 401 和模型名写错两类问题。然后再去配 Codex 的配置文件。

Codex 的配置通常落在~/.codex/config.toml,认证信息在~/.codex/auth.json。如果你用的是 CC Switch 这类多配置切换工具,或者 Cline MCP、Codex auth.json 这套组合,记住三件套必须同时对齐:Base URL 指向https://taotoken.net/api,Key 用控制台生成的,Model ID 用你实际要调的模型名。三者里任何一个和另外两个不匹配,都会出现「Key 没错但请求失败」的迷惑现象。

这里有个坑我踩过:有人把 Base URL 写成带/v1的完整路径,有人写成不带/api的裸域名,结果一个 404 一个连不上。以接入文档里的样例为准,别自己拼。

配好之后,先别急着跑长任务。用一条短请求验证链路通不通,再进入 compaction 的调参环节。顺序反了的话,你分不清是配置问题还是压缩问题。

3. 可复制配置:工具输出限流阈值与 compaction 触发条件

这一节给可直接复制的片段。路径和字段名以你本地 Codex 版本为准,字段含义按上一节讲的对应。

先看工具输出限流。核心是两个字段:tool_output_token_limit和truncation_policy。前者是单条工具输出的 token 预算,后者决定截断单位。

# ~/.codex/config.toml # 工具输出限流:控制单条工具结果进入 active history 的体积 tool_output_token_limit = 8000 truncation_policy = "tokens" # 可选 "bytes" 或 "tokens" # 自动压缩阈值:active history 接近该值时触发 compaction # 不写则按模型 context window 的约 90% 推导 model_auto_compact_token_limit = 360000

tool_output_token_limit调小,单条日志截得更狠,上下文增长慢,但模型可能看不到中间关键错误。调大,模型信息更全,但更容易提前触发 compaction。8000 是个偏保守的起点,你可以按任务类型调。跑测试日志多的任务,可以压到 4000 到 6000;读代码、看 diff 为主的任务,可以放到 12000。

truncation_policy选tokens更贴近模型预算,选bytes更贴近原始输出体积。两者都不是精确 tokenizer,别拿它当计费依据。

再看 compaction 触发。model_auto_compact_token_limit是自动触发线。如果你想让压缩更早发生、留更多余量,把它调低,比如 300000。如果你想让单次会话尽量少压缩、多保留原始历史,把它调高,但别超过模型窗口,否则请求会直接超限报错。

如果你用的是 JSON 形式的配置(部分客户端或 MCP 场景),结构类似:

{ "model": "your-model-id", "base_url": "https://taotoken.net/api", "tool_output_token_limit": 8000, "truncation_policy": "tokens", "model_auto_compact_token_limit": 360000 }

注意base_url用https://taotoken.net/api,不要自己加/v1。model填你实际要调的 Model ID。这三件套和上一节说的一致。

关于本地压缩和远端压缩的差异,配置层面你控制不了远端行为。远端压缩走 provider 原生能力,Codex 不追加本地 handoff prompt。本地压缩才会用那段明文提示词。你能配的是触发阈值和工具输出预算,压缩走哪条路由由 provider 决定。

本地压缩的 handoff prompt 长这样,你可以把它当成理解压缩行为的参照:

You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task. Include: - Current progress and key decisions made - Important context, constraints, or user preferences - What remains to be done (clear next steps) - Any critical data, examples, or references needed to continue Be concise, structured, and focused on helping the next LLM seamlessly continue the work.

这段 prompt 的重点不是「总结聊天记录」,而是「写给接手模型的 handoff summary」。它要求保留的是继续任务最关键的信息:当前进展、已做出的技术决策、用户约束和偏好、剩余任务、关键文件与错误与命令与测试结果与例子。

本地 summary 生成后,Codex 会在前面加一段固定前缀:

Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:

这段前缀的作用是给后续模型一个解释框架:这不是普通用户闲聊,这不是新任务,这是接手任务时必须使用的交接状态。

本地压缩后,active history 大致变成:最近一段真实用户消息 + 带 SUMMARY_PREFIX 的压缩摘要。最近用户消息会保留一段预算,当前常量约是 20000 tokens。这解释了为什么 Codex 通常不会忘掉最近用户刚刚纠正过什么。

远端压缩则不同。远端 v1 调用/responses/compact,请求里带模型、当前输入历史、当前 instructions、当前 tools、reasoning 与 service tier 等请求设置,但不追加本地那段 handoff prompt。远端 v2 不调用/responses/compact,而是在普通 Responses 输入末尾追加一个协议项ResponseItem::CompactionTrigger,服务端返回ResponseItem::Compaction { encrypted_content }。所以你在远端压缩历史里经常看到compaction:encrypted=true,而不是一段可读的 handoff summary。

4. 验证请求:压缩前后 token 占用对比怎么做

配好之后要验证。验证的目标不是「压缩有没有发生」,而是「压缩前后 token 占用变化是否符合预期,任务能不能接续」。

第一步,跑一个会产生大量工具输出的任务。比如让 Codex 跑一个会打印很多行的测试命令,或者读一个超大日志文件。观察工具输出是否被截断成头尾保留、中间带 truncated marker 的形态。如果没截断,检查tool_output_token_limit是否生效、truncation_policy是否写对。

第二步,看 token 使用量。Codex 在会话中会显示或记录 token 使用情况。你要观察的是:随着轮次增加,token 使用量是否在接近model_auto_compact_token_limit时触发压缩。触发后,active history 的 token 占用应该明显下降,而不是继续线性增长。

第三步,对比压缩前后。压缩前记录一次 token 占用,压缩后再记录一次。正常情况下,压缩后占用会回落到阈值以下,留出继续跑的空间。如果压缩后占用没降,可能是压缩没真正替换 active history,或者你看到的只是 rollout 里的历史事件而不是 active context。

第四步,验证任务接续。压缩后继续发「继续」,看模型是否还记得当前进展、下一步该做什么。如果它开始重复已完成的工作,或者忘了用户约束,说明 summary 没覆盖到关键信息。这时候可以检查是不是本地压缩的 handoff prompt 没生效,或者远端压缩的 encrypted item 让信息不可读。

远端压缩的验证要换个思路。因为你看不到明文 summary,只能通过行为判断:压缩后模型是否还能接续任务、是否还遵守 AGENTS.md 和权限约束。如果行为正常,说明 provider 的 compaction 工作正常。如果行为异常,先确认是不是走了远端路径,再考虑切到本地压缩路径对比。

这里有个实用技巧:在长任务里定期手动记录一次「当前进展 + 下一步」,相当于你自己写一份 handoff。这样即使压缩丢了细节,你也能用这份记录快速恢复。这不是替代 compaction,而是给自己留一份可读的备份。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节对照真实报错。每个报错指向不同层,别混着改。

401 Unauthorized。这是认证问题。先检查 API Key 是否有效、是否过期、是否复制时带了空格。再去模型对话页面发一条消息验证 Key。如果模型对话能通但 Codex 报 401,检查auth.json里的 Key 和config.toml里的 Base URL 是否配套。三件套里 Key 和 Base URL 必须来自同一套配置。

local proxy failed。这通常是本地代理或网络层问题。检查你的 Base URL 是否写成了本地地址、是否有多余的端口、是否有本地服务没启动。如果你用了 CC Switch 或类似工具切换配置,确认切换后的配置指向https://taotoken.net/api,而不是残留的旧地址。这个报错和 compaction 无关,别去调压缩阈值。

reading choices 相关报错。这类错误通常出现在响应解析阶段,模型返回格式和客户端预期不一致。先确认 Model ID 是否写对,再确认 Base URL 是否带了多余的路径。如果最近改过truncation_policy或tool_output_token_limit,先改回默认值排除配置干扰。压缩本身不会导致 reading choices 错误,但如果压缩后返回的 item 形态和客户端解析逻辑不匹配,也可能触发。这时候对比压缩前后的请求形态。

OAuth 相关报错。如果你用的是需要 OAuth 的客户端或 MCP 场景,检查 token 是否过期、回调地址是否配好。OAuth 问题和 API Key 是两套认证,别把 OAuth 报错当成 Key 问题去改。Cline MCP 场景下,确认 MCP server 配置里的 Base URL、Key、Model ID 三件套完整。

还有一个隐蔽的坑:压缩后权限或 AGENTS.md 约束看起来「失效」了。这通常不是压缩丢了权限,而是你把运行规则和任务状态混在一起了。运行规则由下一次请求前重新注入,不靠 summary 保存。如果确实失效,检查注入环节,而不是压缩环节。

远端压缩的 encrypted item 不可读,这是设计如此,不是 bug。你如果需要在压缩后审计内容,切到本地压缩路径,或者自己维护一份 handoff 记录。

6. 语义一致 CTA:按你的场景选入口

排障和接入类问题,先去 API Keys 页面拿 Key,再对照接入文档配三件套。文档里有各客户端的配置样例,比你自己拼路径靠谱。API Keys 入口在控制台里,接入文档在文档区。

验证模型是否通、想先发一条消息试试,用模型对话入口。这一步能快速排掉 Key 和 Model ID 问题,再进入 Codex 配置。

长期编码、跑 Agent 任务、需要 Coding Plan 的场景,去 Coding Plan 入口看。长任务正是 compaction 发挥作用的场景,配好阈值和工具输出预算,能让会话跑得更久。

具体入口:模型对话、coding-plan、console、api-keys、doc 都在官网导航里。API 地址统一用https://taotoken.net/api,不要自己加路径。

最后说个真实经验:压缩是续航机制,不是无限记忆机制。同一个 bug 没修完、同一个 PR 还在跑测试、目标稳定文件范围稳定,适合继续压缩。任务目标换了、旧线程经历过多次压缩、需要审计很早以前的完整细节、远端 encrypted compaction 让你无法确认内容、上下文里混了多个不相关的大任务,更适合开新会话。判断标准很简单:最近上下文比早期闲聊更重要,就继续;早期细节比最近进展更重要,就开新会话。

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

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

立即咨询