feat: consolidate course into 21 lessons
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) · [中文](README.zh.md) · [日本語](README.ja.md)
|
||||
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21 → s22
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21
|
||||
> *"Context will fill up — have a way to make room"* — 4層圧縮戦略、安価なものを先に、高価なものを後に実行。
|
||||
>
|
||||
> **Harness レイヤー**: 圧縮 — クリーンな記憶、無限のセッション。
|
||||
@@ -120,9 +120,9 @@ def tool_result_budget(messages, max_bytes=200_000):
|
||||
|
||||
3 ステップのフロー:
|
||||
|
||||
1. **transcript を保存**:完全な会話を `.transcripts/` に JSONL 形式で書き出す。transcript は回復可能な記録として保存されるが、モデルのアクティブなコンテキストには要約しか残らない。モデルの現在の推論にとって、詳細はすでにコンテキストにない。教学コードは transcript 検索ツールを提供しない。
|
||||
1. **transcript を保存**:完全な会話を `.transcripts/` に JSONL 形式で書き出す。transcript は完全な記録を保持する。メッセージリストには要約だけが残り、元の詳細は以降のモデル呼び出しに入らない。
|
||||
2. **LLM で要約を生成**:会話履歴を LLM に送り、現在の目標、重要な発見、変更済みファイル、残りの作業、ユーザーの制約などの重要な情報を保持するよう指示。
|
||||
3. **メッセージリストを置換**:すべての古いメッセージが 1 件の要約に置き換えられる。教学版は要約のみを保持する。実際の Claude Code は compact 後に直近のファイル、計画、agent/skill/tool などのコンテキストを再付加する。
|
||||
3. **メッセージリストを置換**:すべての古いメッセージを 1 件の要約に置き換える。
|
||||
|
||||
```python
|
||||
def compact_history(messages):
|
||||
@@ -189,7 +189,7 @@ def agent_loop(messages):
|
||||
break # 現在のターンを終了し、圧縮後のコンテキストで新しく開始
|
||||
```
|
||||
|
||||
**順序は変えられない。** L3(budget)が L2(micro)の前に実行される理由:micro は古い大きな tool_result を 1 行のプレースホルダに置換するため、budget はその前に完全な内容を退避させる必要がある。CC ソースが `applyToolResultBudget` を最初に配置する理由も同じ。
|
||||
**順序は変えられない。** L3(budget)は L2(micro)より先に実行する。micro が古い大きな `tool_result` を 1 行のプレースホルダに置き換える前に、budget が完全な内容を保存する必要があるためだ。
|
||||
|
||||
---
|
||||
|
||||
@@ -228,85 +228,5 @@ python s08_context_compact/code.py
|
||||
|
||||
s09 Memory → 3 つのサブシステム:何を記憶するかの選択、重要情報の抽出、整理と統合。圧縮を越え、セッションを越えて。
|
||||
|
||||
<details>
|
||||
<summary>CC ソースコードの詳細</summary>
|
||||
|
||||
> 以下は CC ソースコード `compact.ts`、`autoCompact.ts`、`microCompact.ts`、`query.ts` の分析に基づく。
|
||||
|
||||
### 実行順序の対応
|
||||
|
||||
教学版は説明の便宜上 L1/L2/L3/L4 と番号を振っているが、実際の実行順序は番号と完全には一致しない:
|
||||
|
||||
| 項目 | 教学版 | Claude Code |
|
||||
|------|--------|-------------|
|
||||
| 実行順序 | budget → snip → micro → auto | budget → snip → micro → collapse → auto(`query.ts:379-468`) |
|
||||
| snip_compact | 先頭 3 + 末尾 47 を保持 | CC はメインスレッドのみ有効;実装はオープンソースリポジトリにない(`HISTORY_SNIP` feature gate)、インターフェースは確認可能:`snipCompactIfNeeded(messages)` → `{ messages, tokensFreed, boundaryMessage? }`、`SnipTool` もモデルが能動的に呼び出し可能。教学版の 3/47 は簡略パラメータ |
|
||||
| micro_compact | テキストプレースホルダで置換 | 2 つのパス:time-based は直接内容をクリア、cached は API の `cache_edits` を使用(legacy パスは削除済み) |
|
||||
| micro_compact ホワイトリスト | 位置による(直近 3 件) | time-based は時間閾値でトリガー、cached はカウントでトリガー(`microCompact.ts`) |
|
||||
| tool_result_budget | 200KB 文字 | 200,000 文字(`toolLimits.ts:49`) |
|
||||
| compact_history 閾値 | 文字数で推定 | 精密な token 数:`contextWindow - maxOutputTokens - 13_000` |
|
||||
| 要約の要求 | 5 種類の情報 | 9 つのセクション + `<analysis>`/`<summary>` デュアルタグ |
|
||||
| 圧縮プロンプト | シンプルなプロンプト | 先頭と末尾に二重の安全ガードでツール呼び出しを禁止 |
|
||||
| PTL retry | あり(簡略版) | `truncateHeadForPTLRetry()` がメッセージグループ単位でロールバック(`compact.ts:243-290`) |
|
||||
| 圧縮後のリカバリ | なし(教学版は要約のみ保持) | 直近のファイル、計画、agent/skill/tool などの自動再付加 |
|
||||
| サーキットブレーカー | 3 回 | 3 回(`autoCompact.ts:70`) |
|
||||
| reactive リトライ | 1 回 | CC にはより精緻な段階別リトライがある |
|
||||
|
||||
### 実行順序の詳細
|
||||
|
||||
CC ソース `query.ts` での実際の順序:
|
||||
|
||||
1. `applyToolResultBudget`(L379):まず大きな結果を処理し、完全な内容を退避
|
||||
2. `snipCompact`(L403):中間メッセージを切り捨て
|
||||
3. `microcompact`(L414):古い結果のプレースホルダ化
|
||||
4. `contextCollapse`(L441):独立したコンテキスト管理システム(教学版にはなし)
|
||||
5. `autoCompact`(L454):LLM 全量要約
|
||||
|
||||
教学版の budget → snip → micro の順序はこれと一致する。教学版には contextCollapse メカニズムがない。
|
||||
|
||||
### read_file のトレードオフ
|
||||
|
||||
教学版の `micro_compact` は、古い `tool_result` を一律にプレースホルダへ置き換える。`read_file` も例外ではない。これは通常、機能的な正しさには影響しない。後でファイル内容が必要になれば、モデルはもう一度そのファイルを読めばよい。代償は、追加のツール呼び出しが発生し得ることと、prompt cache のヒット率が下がり得ること。
|
||||
|
||||
Claude Code は、この問題を教学版のような単純なルールでは処理していない。`Read` も microcompact 可能なツール集合に入れる一方で、別途 `readFileState` を維持している。変更されていないファイルの再読込では `FILE_UNCHANGED_STUB` を返し、compact 後には予算内で直近に読んだファイル内容を復元する(例:最大 5 ファイル、1 ファイル 5K token、合計 50K token)。これは本番実装向けのキャッシュと復元メカニズムである。教学版ではそこまで展開せず、「古い結果を圧縮し、必要なら再読込する」という単純な trade-off を残している。
|
||||
|
||||
### 完全な定数リファレンス
|
||||
|
||||
| 定数 | 値 | ソースファイル |
|
||||
|------|-----|--------|
|
||||
| `AUTOCOMPACT_BUFFER_TOKENS` | 13,000 | `autoCompact.ts:62` |
|
||||
| `MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES` | 3 | `autoCompact.ts:70` |
|
||||
| `MAX_OUTPUT_TOKENS_FOR_SUMMARY` | 20,000 | `autoCompact.ts:30` |
|
||||
| `POST_COMPACT_TOKEN_BUDGET` | 50,000 | `compact.ts:123` |
|
||||
| `POST_COMPACT_MAX_FILES_TO_RESTORE` | 5 | `compact.ts:122` |
|
||||
| `POST_COMPACT_MAX_TOKENS_PER_FILE` | 5,000 | `compact.ts:124` |
|
||||
| 時間ベース micro_compact 間隔 | 60 分 | `timeBasedMCConfig.ts` |
|
||||
| `MAX_COMPACT_STREAMING_RETRIES` | 2 | `compact.ts:131` |
|
||||
|
||||
### contextCollapse と sessionMemoryCompact
|
||||
|
||||
CC ソースコードには、この教学版では展開していない 2 つのメカニズムが存在する:
|
||||
|
||||
- **contextCollapse**:独立したコンテキスト管理システム。有効時には proactive autocompact を抑制し(`autoCompact.ts:215-222`)、collapse の commit/blocking フローがコンテキスト管理を引き継ぐ。ただし manual `/compact` と reactive fallback は独立パスのままで、contextCollapse の影響を受けない。
|
||||
- **sessionMemoryCompact**:compact_history の前に、CC は既存の session memory(s09 で解説)を使った軽量要約を先に試みる。LLM を呼び出さない。このメカニズムは s09 を学んだ後に振り返るとより理解しやすい。
|
||||
|
||||
### 圧縮プロンプトの中身
|
||||
|
||||
CC の圧縮プロンプトには 2 つの厳格な要件がある:
|
||||
|
||||
1. **ツール呼び出しの絶対禁止**:冒頭が `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.` で、末尾にも再度 REMINDER がある
|
||||
2. **先に分析してから要約**:モデルはまず `<analysis>` タグで思考を整理し、その後 `<summary>` タグで正式な要約を出力する。analysis はフォーマット時に除去される
|
||||
|
||||
### 教学版の簡略化は意図的
|
||||
|
||||
- micro_compact でテキストプレースホルダを使用 → API 層の `cache_edits` 権限がないため
|
||||
- read_file は特別扱いしない → 教学版では必要時の再読込を受け入れ、readFileState と圧縮後復元の仕組みを導入しない
|
||||
- token を文字数で推定 → 精密な tokenizer は教学の対象外
|
||||
- 圧縮後のリカバリを省略 → 教学版は要約のみを保持し、ファイルの自動再付加を行わない
|
||||
- 2 つの補助メカニズムを展開しない → 10% の細部に属する
|
||||
|
||||
コア設計思想、安価なものを先に高価なものを後に、は完全に保持されている。
|
||||
|
||||
</details>
|
||||
|
||||
<!-- translation-sync: zh@v2, en@v2, ja@v2 -->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) · [中文](README.zh.md) · [日本語](README.ja.md)
|
||||
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21 → s22
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21
|
||||
> *"Context will fill up — have a way to make room"* — Four-layer compression pipeline: cheap first, expensive last.
|
||||
>
|
||||
> **Harness Layer**: Compression — clean memory, unlimited sessions.
|
||||
@@ -120,9 +120,9 @@ All three previous layers have run, but after 30 minutes of continuous work on a
|
||||
|
||||
Three-step process:
|
||||
|
||||
1. **Save transcript**: Write the full conversation to `.transcripts/` in JSONL format. The transcript preserves a recoverable record, but the model's active context only contains the summary. For the model's current reasoning, the details are no longer in context. The teaching code does not provide a transcript retrieval tool.
|
||||
1. **Save transcript**: Write the full conversation to `.transcripts/` in JSONL format. The transcript keeps a complete record; the message list keeps only the summary, so the original details no longer enter later model calls.
|
||||
2. **LLM generates summary**: Send conversation history to the LLM, asking it to preserve key information: current goals, important findings, modified files, remaining work, user constraints, etc.
|
||||
3. **Replace message list**: All old messages are replaced with a single summary. The teaching version only keeps the summary; the real Claude Code re-attaches some recent files, plans, agent/skill/tool context after compaction.
|
||||
3. **Replace message list**: All old messages are replaced with a single summary.
|
||||
|
||||
```python
|
||||
def compact_history(messages):
|
||||
@@ -189,7 +189,7 @@ def agent_loop(messages):
|
||||
break # end current turn, start fresh with compacted context
|
||||
```
|
||||
|
||||
**The order must not be swapped.** L3 (budget) runs before L2 (micro) because micro replaces old large tool_results with one-line placeholders — budget must persist the full content before that happens. This is why CC source puts `applyToolResultBudget` first.
|
||||
**The order must not be swapped.** L3 (budget) runs before L2 (micro) because micro replaces old large tool_results with one-line placeholders, so budget must persist the full content first.
|
||||
|
||||
---
|
||||
|
||||
@@ -228,85 +228,5 @@ Context compression lets an agent run for a long time without crashing. But afte
|
||||
|
||||
s09 Memory → three subsystems: choosing what to remember, extracting key information, consolidating and organizing. Across compressions, across sessions.
|
||||
|
||||
<details>
|
||||
<summary>Deep Dive Into CC Source Code</summary>
|
||||
|
||||
> The following is based on analysis of CC source code `compact.ts`, `autoCompact.ts`, `microCompact.ts`, and `query.ts`.
|
||||
|
||||
### Execution Order Comparison
|
||||
|
||||
The teaching version labels layers L1/L2/L3/L4 for pedagogical clarity, but actual execution order does not match the numbering:
|
||||
|
||||
| Dimension | Teaching Version | Claude Code |
|
||||
|-----------|-----------------|-------------|
|
||||
| Execution order | budget → snip → micro → auto | budget → snip → micro → collapse → auto (`query.ts:379-468`) |
|
||||
| snip_compact | Keep head 3 + tail 47 | CC only enables on main thread; implementation not in open-source repo (`HISTORY_SNIP` feature gate), but interface is visible: `snipCompactIfNeeded(messages)` → `{ messages, tokensFreed, boundaryMessage? }`, also exposes `SnipTool` for model-initiated snipping. Teaching version's 3/47 are simplified parameters |
|
||||
| micro_compact | Text placeholder replacement | Two paths: time-based clears content directly, cached uses API `cache_edits` (legacy path removed) |
|
||||
| micro_compact whitelist | By position (most recent 3) | time-based triggers by time threshold; cached triggers by count (`microCompact.ts`) |
|
||||
| tool_result_budget | 200KB characters | 200,000 characters (`toolLimits.ts:49`) |
|
||||
| compact_history threshold | Character count estimate | Precise tokens: `contextWindow - maxOutputTokens - 13_000` |
|
||||
| Summary requirements | 5 categories of info | 9 sections + `<analysis>`/`<summary>` dual tags |
|
||||
| Compression prompt | Simple prompt | Double-ended hard guardrails forbidding tool calls |
|
||||
| PTL retry | Yes (simplified) | `truncateHeadForPTLRetry()` retreats by message groups (`compact.ts:243-290`) |
|
||||
| Post-compaction recovery | None (teaching version only keeps summary) | Auto re-read recent files, plans, agent/skill/tool context |
|
||||
| Circuit breaker | 3 times | 3 times (`autoCompact.ts:70`) |
|
||||
| Reactive retry | 1 time | CC has more granular tiered retries |
|
||||
|
||||
### Execution Order Details
|
||||
|
||||
The real order in CC source `query.ts`:
|
||||
|
||||
1. `applyToolResultBudget` (L379): persist large results first, ensuring full content is saved
|
||||
2. `snipCompact` (L403): trim middle messages
|
||||
3. `microcompact` (L414): old result placeholders
|
||||
4. `contextCollapse` (L441): independent context management system (not in teaching version)
|
||||
5. `autoCompact` (L454): LLM full summary
|
||||
|
||||
The teaching version's budget → snip → micro order matches this. The teaching version does not have the contextCollapse mechanism.
|
||||
|
||||
### read_file Trade-off
|
||||
|
||||
The teaching version's `micro_compact` replaces old `tool_result` blocks with placeholders uniformly, including `read_file`. This usually does not affect functional correctness: if the model needs the file contents later, it can read the file again. The cost is an extra tool call and potentially lower prompt cache hit rates.
|
||||
|
||||
Claude Code does not solve this with the teaching version's simple rule. It also puts `Read` in the microcompactable tool set, but maintains a separate `readFileState`: repeated reads of unchanged files return `FILE_UNCHANGED_STUB`, and after compaction it restores recently read file contents within a budget (for example, up to 5 files, 5K tokens per file, 50K tokens total). That is a production-level cache and recovery mechanism. The teaching version does not expand into that machinery; it keeps the simpler trade-off of compacting old results and re-reading when needed.
|
||||
|
||||
### Full Constant Reference
|
||||
|
||||
| Constant | Value | Source File |
|
||||
|----------|-------|-------------|
|
||||
| `AUTOCOMPACT_BUFFER_TOKENS` | 13,000 | `autoCompact.ts:62` |
|
||||
| `MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES` | 3 | `autoCompact.ts:70` |
|
||||
| `MAX_OUTPUT_TOKENS_FOR_SUMMARY` | 20,000 | `autoCompact.ts:30` |
|
||||
| `POST_COMPACT_TOKEN_BUDGET` | 50,000 | `compact.ts:123` |
|
||||
| `POST_COMPACT_MAX_FILES_TO_RESTORE` | 5 | `compact.ts:122` |
|
||||
| `POST_COMPACT_MAX_TOKENS_PER_FILE` | 5,000 | `compact.ts:124` |
|
||||
| Time micro_compact interval | 60 minutes | `timeBasedMCConfig.ts` |
|
||||
| `MAX_COMPACT_STREAMING_RETRIES` | 2 | `compact.ts:131` |
|
||||
|
||||
### contextCollapse and sessionMemoryCompact
|
||||
|
||||
CC source code has two additional mechanisms not covered in this teaching version:
|
||||
|
||||
- **contextCollapse**: An independent context management system that, when enabled, suppresses proactive autocompact (`autoCompact.ts:215-222`), with collapse's commit/blocking flow taking over context management. Manual `/compact` and reactive fallback remain independent paths, unaffected by contextCollapse.
|
||||
- **sessionMemoryCompact**: Before compact_history, CC first attempts a lightweight summary using existing session memory (covered in s09) without calling the LLM. This mechanism becomes clearer after learning s09.
|
||||
|
||||
### What Does the Compression Prompt Look Like?
|
||||
|
||||
CC's compression prompt has two hard requirements:
|
||||
|
||||
1. **Absolutely no tool calls**: It begins with `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.`, and appends another REMINDER at the end
|
||||
2. **Analyze first, then summarize**: The model must first reason in an `<analysis>` tag, then output the formal summary in a `<summary>` tag. The analysis is stripped during formatting
|
||||
|
||||
### Teaching Version Simplifications Are Intentional
|
||||
|
||||
- micro_compact uses text placeholders → we don't have API-level `cache_edits` access
|
||||
- read_file is not special-cased → the teaching version accepts re-reading when needed instead of introducing readFileState and post-compaction recovery
|
||||
- Tokens estimated via character count → precise tokenizers are out of scope
|
||||
- Post-compaction recovery omitted → teaching version only keeps summary, does not auto re-attach files
|
||||
- Two auxiliary mechanisms not covered → they fall in the 10% detail category
|
||||
|
||||
The core design principle, cheap first, expensive last, is fully preserved.
|
||||
|
||||
</details>
|
||||
|
||||
<!-- translation-sync: zh@v2, en@v2, ja@v2 -->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) · [中文](README.zh.md) · [日本語](README.ja.md)
|
||||
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21 → s22
|
||||
s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_memory/) → s10 → ... → s20 → s21
|
||||
> *"上下文总会满, 要有办法腾地方"* — 四层压缩策略, 便宜的先跑贵的后跑。
|
||||
>
|
||||
> **Harness 层**: 压缩 — 干净的记忆, 无限的会话。
|
||||
@@ -120,9 +120,9 @@ def tool_result_budget(messages, max_bytes=200_000):
|
||||
|
||||
三步流程:
|
||||
|
||||
1. **保存 transcript**:完整对话写入 `.transcripts/`,JSONL 格式。transcript 保留了可恢复记录,但模型的活跃上下文里只剩摘要。对模型当下推理来说,细节已经不在上下文中了。教学代码没有提供 transcript 检索工具。
|
||||
1. **保存 transcript**:完整对话写入 `.transcripts/`,JSONL 格式。transcript 保留完整记录;消息列表只保留摘要,原始细节不再进入后续模型调用。
|
||||
2. **LLM 生成摘要**:把对话历史发给 LLM,要求保留当前目标、重要发现、已改文件、剩余工作、用户约束等关键信息。
|
||||
3. **替换消息列表**:所有旧消息被替换为一条摘要。教学版只保留摘要;真实 Claude Code 会在 compact 后重新附加部分最近文件、计划、agent/skill/tool 等上下文。
|
||||
3. **替换消息列表**:所有旧消息被替换为一条摘要。
|
||||
|
||||
```python
|
||||
def compact_history(messages):
|
||||
@@ -189,7 +189,7 @@ def agent_loop(messages):
|
||||
break # 结束当前 turn,用压缩后的上下文开始新一轮
|
||||
```
|
||||
|
||||
**顺序不能换。** L3(budget)在 L2(micro)前面,因为 micro 会把旧的大 tool_result 替换成一行占位符,budget 必须在那之前把完整内容落盘。这也是为什么 CC 源码把 `applyToolResultBudget` 放在最前面。
|
||||
**顺序不能换。** L3(budget)在 L2(micro)前面,因为 micro 会把旧的大 `tool_result` 替换成一行占位符,budget 必须在那之前保存完整内容。
|
||||
|
||||
---
|
||||
|
||||
@@ -228,85 +228,5 @@ python s08_context_compact/code.py
|
||||
|
||||
s09 Memory → 三个子系统:选择记什么、提取关键信息、整理巩固。跨压缩、跨会话。
|
||||
|
||||
<details>
|
||||
<summary>深入 CC 源码</summary>
|
||||
|
||||
> 以下基于 CC 源码 `compact.ts`、`autoCompact.ts`、`microCompact.ts`、`query.ts` 的分析。
|
||||
|
||||
### 执行顺序对照
|
||||
|
||||
教学版为了讲解方便按 L1/L2/L3/L4 编号,但实际执行顺序和编号不完全对应:
|
||||
|
||||
| 维度 | 教学版 | Claude Code |
|
||||
|------|--------|-------------|
|
||||
| 执行顺序 | budget → snip → micro → auto | budget → snip → micro → collapse → auto(`query.ts:379-468`) |
|
||||
| snip_compact | 保留头 3 + 尾 47 | CC 仅主线程启用;实现不在开源仓库中(`HISTORY_SNIP` feature gate),但接口可见:`snipCompactIfNeeded(messages)` → `{ messages, tokensFreed, boundaryMessage? }`,还暴露了 `SnipTool` 工具让模型主动调用。教学版的 3/47 是简化参数 |
|
||||
| micro_compact | 文本占位符替换 | 两条路径:time-based 直接清内容,cached 走 API `cache_edits`(legacy path 已移除) |
|
||||
| micro_compact 白名单 | 按位置(最近 3 条) | time-based 按时间阈值触发;cached 按计数触发(`microCompact.ts`) |
|
||||
| tool_result_budget | 200KB 字符 | 200,000 字符(`toolLimits.ts:49`) |
|
||||
| compact_history 阈值 | 字符数估算 | 精确 token:`contextWindow - maxOutputTokens - 13_000` |
|
||||
| 摘要要求 | 5 类信息 | 9 个部分 + `<analysis>`/`<summary>` 双标签 |
|
||||
| 压缩 prompt | 简单 prompt | 首尾双重防呆禁止调工具 |
|
||||
| PTL retry | 有(简化) | `truncateHeadForPTLRetry()` 按消息组回退(`compact.ts:243-290`) |
|
||||
| 后压缩恢复 | 无(教学版只保留摘要) | 自动重新读取最近文件、计划、agent/skill/tool 等 |
|
||||
| 熔断器 | 3 次 | 3 次(`autoCompact.ts:70`) |
|
||||
| reactive 重试 | 1 次 | CC 有更精细的分级重试 |
|
||||
|
||||
### 执行顺序详解
|
||||
|
||||
CC 源码 `query.ts` 中的真实顺序:
|
||||
|
||||
1. `applyToolResultBudget`(L379):先处理大结果,确保完整内容落盘
|
||||
2. `snipCompact`(L403):裁中间消息
|
||||
3. `microcompact`(L414):旧结果占位
|
||||
4. `contextCollapse`(L441):独立的上下文管理系统(教学版无)
|
||||
5. `autoCompact`(L454):LLM 全量摘要
|
||||
|
||||
教学版的 budget → snip → micro 顺序与此一致。教学版没有 contextCollapse 机制。
|
||||
|
||||
### read_file 的取舍
|
||||
|
||||
教学版的 `micro_compact` 会把旧 `tool_result` 统一替换成占位符,包括 `read_file`。这通常不影响功能正确性:如果后续还需要文件内容,模型可以重新读一次。代价是可能多一次工具调用,也可能降低 prompt cache 命中率。
|
||||
|
||||
Claude Code 没有用教学版这种简单规则解决这个问题。它把 `Read` 也放进可 microcompact 的工具集合,但同时维护 `readFileState`:重复读取未变化文件时返回 `FILE_UNCHANGED_STUB`,compact 后再按预算恢复最近读过的文件内容(例如最多 5 个文件、每个 5K token、总预算 50K token)。这是生产级实现里的缓存和恢复机制,教学版不展开,保留“压缩旧结果,必要时重新读取”的简单 trade-off。
|
||||
|
||||
### 完整常量参考
|
||||
|
||||
| 常量 | 值 | 源文件 |
|
||||
|------|-----|--------|
|
||||
| `AUTOCOMPACT_BUFFER_TOKENS` | 13,000 | `autoCompact.ts:62` |
|
||||
| `MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES` | 3 | `autoCompact.ts:70` |
|
||||
| `MAX_OUTPUT_TOKENS_FOR_SUMMARY` | 20,000 | `autoCompact.ts:30` |
|
||||
| `POST_COMPACT_TOKEN_BUDGET` | 50,000 | `compact.ts:123` |
|
||||
| `POST_COMPACT_MAX_FILES_TO_RESTORE` | 5 | `compact.ts:122` |
|
||||
| `POST_COMPACT_MAX_TOKENS_PER_FILE` | 5,000 | `compact.ts:124` |
|
||||
| 时间 micro_compact 间隔 | 60 分钟 | `timeBasedMCConfig.ts` |
|
||||
| `MAX_COMPACT_STREAMING_RETRIES` | 2 | `compact.ts:131` |
|
||||
|
||||
### contextCollapse 和 sessionMemoryCompact
|
||||
|
||||
CC 源码中还有两个机制本教学版没有展开:
|
||||
|
||||
- **contextCollapse**:独立的上下文管理系统,启用时抑制 proactive autocompact(`autoCompact.ts:215-222`),由 collapse 的 commit/blocking 流程接管上下文管理。但 manual `/compact` 和 reactive fallback 仍是独立路径,不受 contextCollapse 影响。
|
||||
- **sessionMemoryCompact**:compact_history 之前,CC 会先尝试用已有的 session memory(s09 会讲到)做轻量摘要,不调 LLM。这个机制等学完 s09 之后回头看会更清楚。
|
||||
|
||||
### 压缩 prompt 长什么样?
|
||||
|
||||
CC 的压缩 prompt 有两个硬性要求:
|
||||
|
||||
1. **绝对禁止调用工具**:开头就是 `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.`,末尾还会再 REMINDER 一次
|
||||
2. **先分析再总结**:模型需要先在 `<analysis>` 标签里理清思路,然后在 `<summary>` 标签里输出正式摘要。analysis 在格式化时被剥离
|
||||
|
||||
### 教学版的简化是刻意的
|
||||
|
||||
- micro_compact 用文本占位 → 我们没有 API 层的 `cache_edits` 权限
|
||||
- read_file 不特殊处理 → 教学版接受必要时重新读取,避免引入 readFileState 和后压缩恢复机制
|
||||
- token 用字符数估算 → 精确 tokenizer 不在教学范围内
|
||||
- 后压缩恢复省略 → 教学版只保留摘要,不自动重新附加文件
|
||||
- 两个辅助机制不展开 → 属于 10% 的细节
|
||||
|
||||
核心设计思想,便宜的先跑贵的后跑,完整保留。
|
||||
|
||||
</details>
|
||||
|
||||
<!-- translation-sync: zh@v2, en@v2, ja@v2 -->
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
|
||||
<text x="260" y="320" fill="#1e40af" font-size="11">old tool_result → placeholder (keep latest 3)</text>
|
||||
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">compact old</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">Trigger: every turn automatically; tutorial uses text placeholder</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">Trigger: every turn; replace older results with text placeholders</text>
|
||||
|
||||
<!-- ===== Auto-compact title ===== -->
|
||||
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@@ -69,7 +69,7 @@
|
||||
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
|
||||
<text x="260" y="320" fill="#1e40af" font-size="11">古い tool_result → プレースホルダー(最新 3 件保持)</text>
|
||||
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">旧結果を圧縮</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">トリガー:毎ターン自動実行、チュートリアル版はテキストプレースホルダーで模擬</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">トリガー:毎ターン、古い結果をテキストプレースホルダーに置換</text>
|
||||
|
||||
<!-- ===== 自動圧縮タイトル ===== -->
|
||||
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -69,7 +69,7 @@
|
||||
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
|
||||
<text x="260" y="320" fill="#1e40af" font-size="11">旧 tool_result → 占位符(保留最近 3 条)</text>
|
||||
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">压旧结果</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">触发:每轮自动,教学版用文本占位符模拟</text>
|
||||
<text x="135" y="338" fill="#2563eb" font-size="9">触发:每轮自动,把较旧结果替换为文本占位符</text>
|
||||
|
||||
<!-- ===== 自动压缩标题 ===== -->
|
||||
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
@@ -50,9 +50,9 @@
|
||||
|
||||
<!-- How -->
|
||||
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">How (teaching version)</text>
|
||||
<text x="155" y="248" fill="#475569" font-size="10">Iterate through tool_result, keep only latest 3 complete, replace older ones with placeholders.</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">Real CC</text>
|
||||
<text x="95" y="264" fill="#475569" font-size="10">Clears old results via API cache_edits (without breaking prompt cache prefix), only for COMPACTABLE_TOOLS:</text>
|
||||
<text x="95" y="280" fill="#94a3b8" font-size="9">Read, Bash, Grep, Glob, WebSearch, WebFetch, Edit, Write. Teaching version uses text placeholders to simulate the same effect.</text>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">Rule</text>
|
||||
<text x="75" y="248" fill="#475569" font-size="10">Keep the latest 3 tool results complete and replace older results with placeholders.</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">Placeholder</text>
|
||||
<text x="105" y="264" fill="#475569" font-size="10">Explain that the result was compacted and that the tool can be run again if needed.</text>
|
||||
<text x="105" y="280" fill="#94a3b8" font-size="9">The message structure remains valid for the next loop iteration.</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -50,9 +50,9 @@
|
||||
|
||||
<!-- 原理 -->
|
||||
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">方法(教学版)</text>
|
||||
<text x="130" y="248" fill="#475569" font-size="10">tool_result を走査し、最新 3 件のみ完全保持、古いものはプレースホルダーに置換。</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">実際の CC</text>
|
||||
<text x="110" y="264" fill="#475569" font-size="10">API cache_edits で旧結果をクリア(prompt cache プレフィックスを破壊しない)、COMPACTABLE_TOOLS のみ対象:</text>
|
||||
<text x="110" y="280" fill="#94a3b8" font-size="9">Read, Bash, Grep, Glob, WebSearch, WebFetch, Edit, Write。教学版はテキストプレースホルダーで同様の効果を模擬。</text>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">処理規則</text>
|
||||
<text x="95" y="248" fill="#475569" font-size="10">最新 3 件の tool_result を完全保持し、古い結果をプレースホルダーに置換する。</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">プレースホルダー</text>
|
||||
<text x="125" y="264" fill="#475569" font-size="10">結果が圧縮済みで、必要ならツールを再実行できることを示す。</text>
|
||||
<text x="125" y="280" fill="#94a3b8" font-size="9">メッセージ構造を保ったまま次のループへ進める。</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
@@ -49,9 +49,9 @@
|
||||
|
||||
<!-- 原理 -->
|
||||
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">怎么做(教学版)</text>
|
||||
<text x="115" y="248" fill="#475569" font-size="10">遍历 tool_result,只保留最近 3 条完整,更旧的替换为占位符。</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">真实 CC</text>
|
||||
<text x="95" y="264" fill="#475569" font-size="10">通过 API cache_edits 清除旧结果(不破坏 prompt cache 前缀),仅对 COMPACTABLE_TOOLS 生效:</text>
|
||||
<text x="95" y="280" fill="#94a3b8" font-size="9">Read, Bash, Grep, Glob, WebSearch, WebFetch, Edit, Write。教学版用文本占位模拟同样效果。</text>
|
||||
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">处理规则</text>
|
||||
<text x="95" y="248" fill="#475569" font-size="10">遍历 tool_result,只保留最近 3 条完整,更旧的替换为占位符。</text>
|
||||
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">占位内容</text>
|
||||
<text x="95" y="264" fill="#475569" font-size="10">说明原结果已压缩,并提示需要时重新运行对应工具。</text>
|
||||
<text x="95" y="280" fill="#94a3b8" font-size="9">消息结构保持不变,后续循环仍可继续处理。</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.3 KiB |