Skip to content

上下文窗口分解 — Context Window Breakdown(cc context) ​

版本:公开 CLI 0.166.48;请求级窗口增强已进入 0.166.49 源码候选 · 状态:✅ 只读报表 | 对已存无头会话按角色桶估算 token;候选版优先使用最近主模型请求记录的实际窗口 |

cc context [id] 把一次无头会话的对话重建出来,按角色分桶估算 token,并显示它把某个模型的上下文窗口占满了多少——用了百分之几、还剩多少余量、是否溢出。它是 Claude Code /context 的平价视图,帮你判断「这个会话还能不能继续,还是该压缩了」。

上下文、压缩和持久记忆的关系,以及模块 108 已完成设计但尚未完成跨端切换的边界,见上下文与记忆。

概述 ​

上下文窗口是有限的。会话越长,system prompt、历史消息、工具调用/结果堆积得越多,离塞满窗口就越近,塞满就得压缩(compact)。cc context 就是这块「油表」:

  • 从 ~/.chainlesschain/sessions/<id>.jsonl 重建对话消息(从最近一次 compact 快照起,回放其后的 user/assistant/system 消息)。
  • 按角色分五个桶估算 token:system / user / assistant / tool results / tool calls。
  • 公开版从每模型的上下文窗口表取窗口大小(不认识的模型走 provider 默认,再不行硬回退 32768)。0.166.49 源码候选会优先读取最近一个无 attribution 的主模型 token_usage.contextWindow;显式 --model / --provider 与记录不一致时仍重新解析,避免把旧窗口套到新模型。
  • 显示每桶占 total 的份额、total 占窗口的百分比(绿 ≤70% / 黄 >70% / 红 >90%)、剩余余量,溢出时红字提示「需要压缩」。

它不产生新数据——只读会话已写下的事件。消息角色分桶仍使用启发式 token 估算;窗口分母在候选版可来自请求时持久化的实际配置,因此“估算的消息占用”和“请求实际容量”会明确分层。

核心特性 ​

  • 📏 窗口占用一眼看全:五个角色桶 + total 占窗口百分比 + 剩余余量 + 溢出告警。
  • 🧩 消息重建:从最近 compact 快照 seed,回放其后消息(每条须含 {role, content} 才回放)。
  • 🎨 色码油表:total 条 green ≤70% / yellow >70% / red >90%;溢出红字「⚠ exceeds the model context window — compaction required」。
  • 🏷️ 模型/provider 自动识别:默认取会话 session_start 记录的 model/provider,--model / --provider 可覆盖。
  • 🗂️ 内建窗口表:Ollama/OpenAI/Anthropic/DeepSeek/DashScope/Gemini/Kimi/豆包 等常见模型有已知窗口,未知走 provider 默认,再不行回退 32768。
  • 🧮 启发式 token 估算:中文字 ÷1.5、其它字符 ÷4 向上取整——无需真 tokenizer、零 API 调用。
  • 🎯 主请求窗口优先(0.166.49 源码候选):只消费无 attribution 且 source 为空或为 model 的最后一条用量,子 Agent 与语义压缩调用不会覆盖主窗口;持久值必须是 1024..16777216 的安全整数。
  • 🔒 只算不外泄:读消息正文估 token,但输出只含各角色 token 数与计数,不吐任何消息文本。

系统架构 ​

              cc context [id]   (省略 id → getLastSessionId())
                     │
                     ▼
 ┌───────────────────────────────────────────────────────────┐
 │ rebuildMessages(id)   harness/jsonl-session-store.js        │
 │  ~/.chainlesschain/sessions/<id>.jsonl                      │
 │  从最近 compact 快照 seed → 回放其后 user/assistant/system   │
 │  session_start → model / provider(--model/--provider 覆盖)│
 └───────────────────────────────┬───────────────────────────┘
                                 ▼
 ┌───────────────────────────────────────────────────────────┐
 │ categorizeContext(messages, estimateTokens)  context.js     │
 │  桶:system / user / assistant / tool / toolCalls           │
 │  estimateTokens:中文 ÷1.5,其它 ÷4,ceil(启发式,无 API)  │
 │  total = 五桶之和                                           │
 └───────────────────────────────┬───────────────────────────┘
                                 ▼
 ┌───────────────────────────────────────────────────────────┐
 │ window = getContextWindow(model, provider)                  │
 │  CONTEXT_WINDOWS 精确模型 → provider 默认 → 32768 回退       │
 │  used = total/window · remaining = max(0, window−total)     │
 │  overflow = total > window                                  │
 └───────────────────────────────┬───────────────────────────┘
                                 ▼
   人类油表(色码条 + 每桶份额 + total 占窗口 %)  |  --json 结构化对象

命令参考 ​

单命令、无子命令:cc context [id]。

bash
cc context                                   # 最近一个无头会话
cc context session-1720000000-ab12cd         # 指定会话
cc context --model claude-sonnet-4-6         # 按 200k 窗口衡量
cc context session-1720000000-ab12cd --json  # 机器可读
参数 / 旗标说明默认
[id]会话 id(可选)getLastSessionId() 最近无头会话
--model <model>按此模型的上下文窗口衡量会话记录的 model,否则 null
--provider <provider>provider(决定窗口默认值)会话记录的 provider,否则 ollama
--json结构化 JSON 输出(否则人类油表)关

无会话 → 报错退出码 1;会话不存在或非无头 → 报 No headless transcript for session… 退出码 1。

--json 输出结构:

jsonc
{
  "sessionId": "...",
  "model": "claude-sonnet-4-6",       // 或 null
  "provider": "anthropic",
  "contextWindow": 200000,
  "totalTokens": 0,
  "usedFraction": 0.0000,             // 4 位小数
  "remainingTokens": 0,
  "messageCount": 0,
  "breakdown": { "system", "user", "assistant", "tool", "toolCalls" },  // token 数
  "counts":    { "system", "user", "assistant", "tool" },               // 条数
  "overflows": false
}

配置参考 ​

项机制默认备注
会话存储~/.chainlesschain/sessions/<id>.jsonl—仅无头 JSONL 会话;非无头会话被拒
配置/env无(本命令不读专用 config 键或 env)—存储根来自 os.homedir()
窗口回退provider 默认 → 硬回退32768见下表

内建模型上下文窗口表(getContextWindow:精确模型 → provider 默认 → 32768):

从 0.166.49 源码候选开始,解析还会纳入请求的 baseUrl 与 contextMemoryModelWindowTokens。下表是没有可信请求记录或用户显式切换模型/provider 时的回退依据,不再是唯一窗口来源。

provider代表模型 → 窗口provider 默认
ollamaqwen2.5:7b/14b · mistral:7b = 32768;llama3:8b = 8192;codellama:7b = 1638432768
openaigpt-4o / gpt-4o-mini / gpt-4-turbo = 128000;gpt-3.5-turbo = 16385;o1 = 200000128000
anthropicclaude-opus-4-6 / sonnet-4-6 / haiku-4-5 = 200000200000
deepseekdeepseek-chat/coder/reasoner = 6400064000
dashscopeqwen-turbo / qwen-plus = 131072;qwen-max = 32768131072
geminigemini-2.0-flash/pro / 1.5-flash = 10485761048576
kimi/moonshotmoonshot-v1-auto/128k = 131072;-8k = 8192;-32k = 32768131072
豆包/volcenginedoubao-seed-1-6 / 2-1-pro = 3276832768
未知—32768

性能指标 ​

维度特性
扫描重建消息 + 单遍分桶,O(消息数)
token 估算启发式(中文 ÷1.5 / 其它 ÷4),无真 tokenizer、无网络
重建从最近 compact 快照 seed,只回放合法 {role, content} 消息
桶数五桶:system / user / assistant / tool results / tool calls
色码阈值total 条 green ≤70% / yellow >70% / red >90%

测试覆盖 ​

测试文件数量覆盖
__tests__/unit/cc-context.test.js6纯 categorizeContext:角色分桶 · tool_calls 单独计 · tool 角色桶 · 未知角色→assistant + 空值跳过 · 非字符串内容 stringify · total = 五桶之和
__tests__/unit/context-recorded-window.test.js2最近主请求窗口优先 · attributed 子调用排除 · 显式模型覆盖时不用旧窗口
__tests__/unit/context-window-budget.test.js4endpoint/显式覆盖参数化解析 · 大窗口按 token 压力触发 · 小窗口保留消息数保护

命令 I/O 是分类器之上的「薄渲染」,故只单测分类器;estimateTokens 与窗口表在 prompt-compressor 自己的套件里测。

安全考虑 ​

  • 读正文但不外泄:为估 token 会把消息内容 stringify 后喂给估算器,但人类油表与 --json 输出都不含任何消息文本——只有各角色 token 数、消息条数、窗口大小与占比(breakdown/counts 均为数字)。
  • 路径穿越硬化:isUnsafeSessionId 拒绝含 /、\、.. 的 id;对不安全 id,readEvents 返回 [] 而非抛错,无法逃出 sessions 目录。
  • 全程本地:只读 ~/.chainlesschain/sessions/*.jsonl,无任何网络调用。

故障排除 ​

现象原因处理
No session found(退出 1)还没有任何无头会话先 cc agent -p ... 跑一个无头会话
No headless transcript for session…(退出 1)id 错,或该会话非无头 JSONLcc session list 查正确 id;仅无头会话可分析
total 百分比看着偏差大token 是启发式估算(非真 tokenizer)用于趋势/预警足够;精确计费看 cc cost / cc insights
未知模型窗口显示 32768模型不在窗口表,走回退用 --model 指定一个已知模型来衡量
红字「exceeds the model context window」会话已溢出窗口跑 cc compact <id> 压缩后再 --resume

关键文件 ​

文件职责
packages/cli/src/commands/context.js命令 + 纯函数 categorizeContext + 油表渲染
packages/cli/src/harness/prompt-compressor.jsestimateTokens · CONTEXT_WINDOWS · getContextWindow(估算器 + 窗口表)
packages/cli/src/harness/jsonl-session-store.jsrebuildMessages / readEvents / getLastSessionId / sessionExists

使用示例 ​

1. 看最近一个无头会话的窗口占用 ​

bash
cc context
# Context — session session-1720…
# model claude-sonnet-4-6 · provider anthropic · window 200000 tokens · 42 messages
# system        1234  ███░░░░░░░  8% (1)
# user          5600  ██████░░░░ 36% (12)
# assistant     8900  █████████░ 57% (12)
# ...
# total        15734  ██░░░░░░░░  7.9% of window     headroom 184266 tokens remaining

2. 指定会话 ​

bash
cc context session-1720000000-ab12cd

3. 按某个模型的窗口衡量 ​

bash
cc context --model claude-sonnet-4-6     # 200k 窗口
cc context --provider openai             # 用 openai provider 默认窗口 128000

4. 机器可读 ​

bash
cc context session-1720000000-ab12cd --json | jq '.usedFraction, .overflows'

5. 溢出后压缩再续 ​

bash
cc context <id>            # 红字提示溢出
cc compact <id>           # 离线压缩
cc agent --resume <id>    # 压缩后继续

相关文档 ​

基于 MIT 许可发布