
Claude Code 真正厲害的不是某一段神秘 prompt,而是一整套把 prompt、tool、permission、agent、memory 統一起來的工程系統。
先講結論
2026 年 3 月 31 日,Claude Code 的 512,000 行 TypeScript 原始碼意外洩漏。
大家第一反應是找有沒有藏什麼神奇 prompt。結果發現:沒有。
它厲害的地方是一套 Agent Operating System——把確定性的工程系統包在機率性的 LLM 外面,讓整體行為變得可預測、可治理。
這篇不是功能介紹,而是從原始碼分析整理出來的設計哲學筆記——這些決策為什麼這樣做,以及做 AI 產品的時候可以學什麼。
第一個關鍵轉換:從確定性到機率性
Web 開發是確定性的:你寫一個函數,給固定 input,永遠回傳固定 output。架構圖是靜態的,資料流可預測,debug 就是找「哪行壞了」。
AI agent 是機率性的:LLM 的輸出每次都可能略有不同。「邏輯」是用自然語言寫的,「debug」是調文字,「架構」的核心是怎麼讓模型做出正確決策。
Claude Code 的解法很清楚:LLM 決定「做什麼」,程式決定「允不允許」,然後執行。把機率性的部分隔離在 LLM 裡,外面用工程系統做治理。
Agent Loop:骨幹很簡單
while (true) {
呼叫 Claude API
if (stop_reason == "tool_use") {
執行工具
把 tool_result 追加到 messages[]
繼續循環
} else {
回傳文字給使用者
break
}
}
這就是整個 agent 的骨幹,query.ts 裡的 while-true 迴圈。
真正的工程量在外面那層 harness:permission 系統、streaming 處理、context 壓縮、sub-agent 編排、memory 管理——每一層都是獨立解決一個問題。
為什麼用 AsyncGenerator:token 透過 yield 流出,tool call 是遞歸的,中斷也很乾淨。比用 callback 或 state machine 簡單很多,而且天生支援 streaming。
Tool 設計:每個工具是一個治理單元
工具不是「直接裸調」,每個 tool 都有自己的生命週期:
validateInput() → 最早失敗,拒絕無效參數
checkPermissions() → 工具專屬授權檢查
call() → 執行並回傳結果
而且每個工具必須聲明自己的能力屬性:
| 屬性 | 問的問題 |
|---|---|
isConcurrencySafe() | 可以和其他工具同時跑嗎? |
isReadOnly() | 有沒有副作用? |
isDestructive() | 不可逆嗎? |
interruptBehavior() | 中斷時應該怎麼處理? |
為什麼重要:StreamingToolExecutor 靠這些屬性決定哪些工具可以在 streaming 還沒結束時就並行執行。這不是效能優化,是架構決策——讓 agent 的操作感完全不同。
Permission System:不是開關,是決策鏈
validateInput()
↓
PreToolUse Hooks(使用者定義,可批准 / 拒絕 / 修改輸入)
↓
規則比對(alwaysAllow / alwaysDeny / alwaysAsk)
↓
(沒有規則命中)→ 互動式提示
↓
checkPermissions()(工具專屬邏輯,路徑沙盒等)
↓
tool.call()
這個設計讓 agent 可以在「自動執行」和「需要人類確認」之間做細緻控制,不是二元開關,是一個可配置的決策鏈。
YOLO Mode 的真相:名字叫 YOLO,但它其實是一個 ML-based 快速分類器,自動判斷是否允許某個操作。不是「允許一切」,命名有點誤導。
System Prompt:靜態 + 動態分層
很多人以為 AI 產品的核心是一段超厲害的 system prompt。Claude Code 的答案是:不是文字,是動態組裝架構。
getSystemPrompt() {
// 靜態前綴(適合 prompt cache)
身份定義、基礎系統規範、工具使用規範 ...
// 動態後綴(按 session 條件注入)
session_guidance、memory_prompt、env_info、
language_preference、mcp_instructions、token_budget ...
}
SYSTEM_PROMPT_DYNAMIC_BOUNDARY 這個 marker 把 prompt 切成靜態和動態兩段——靜態部分可以被 prompt cache 命中,大幅降低費用。
還有一個函數叫 DANGEROUS_uncachedSystemPromptSection()。命名本身就說明這是踩過坑學到的。 加 DANGEROUS_ 前綴是他們用命名來表達架構約束的慣例,比寫文件更有效。
Memory:Index 而非 Storage
MEMORY.md(永遠在 context,~150 字/行,只存指針)
↓
topic files(按主題分檔的實際內容)
↓
daily logs(原始觀察,autoDream 的輸入來源)
核心原則:Memory 是 index,不是 storage。 MEMORY.md 保持 ≤ 200 行 / 25KB。
他們還做了一個叫 Dream System 的東西。是的,字面意義的「做夢」——在使用者閒置時,agent 在背景跑 memory consolidation,把零散的觀察整合成結構化的記憶。
三門觸發條件(三個同時滿足才跑):
- 時間門:距上次 dream 超過 24 小時
- Session 門:至少 5 個 session 後
- Lock 門:取得 consolidation lock,防並發
Sub-Agent:乾淨的 Context 隔離
主 Agent
├── Fork Agent(子進程,全新 messages[],共享 file cache)
├── Remote Agent(透過 bridge,完全隔離)
└── In-Process Teammate(同一進程,共享狀態)
關鍵設計:子 agent 有自己的 messages[],不污染主對話。每個子任務在乾淨的 context 裡思考,失敗也不影響主 agent。
Fork 的 cache 優勢:子 agent 的 context 是主 agent 的 byte-for-byte 複製,API 可以 cache 這個共享部分——spawn 5 個並行 agent 的費用接近 1 個循序 agent。
Context Compaction:Context 是有限資源,要精打細算
Context 滿了怎麼辦?不是直接截斷,而是五種策略按壓力程度選擇:
- snipCompact — 移除重複 system message 和過時標記
- microCompact — 選擇性修剪最近的 tool result
- autoCompact — 用另一個 API call 總結舊訊息
- contextCollapse — 重構整個 context
- 截斷 — 最後手段
目標是盡量保留最多有用的資訊,不是能省就省。
一個值得特別記住的工程決策
Claude Code 上新模型(代號 Capybara)的時候遇到一個問題:模型在 tool result 之後有過早停止生成的 bug。
解法不是等模型修好,而是prompt shape surgery:
- 注入
Tool loaded.sentinel 建立安全 boundary - 重排 token 順序避免觸發 premature stop
- 每個修法都有 kill-switch(
tengu_*前綴 flag)可以快速 rollback
這就是 AI 產品工程的日常——不等模型,用工程繞過模型缺陷。而且每個 workaround 都要可以快速關掉。
結語
看完整份原始碼分析之後,最大的感受是:
AI agent 的護城河不在模型,在 harness。
模型會進步,競爭對手可以用同樣的模型。但一套把 prompt architecture、tool runtime、permission model、agent orchestration、context management、memory system 統一起來的工程系統,才是真正難以複製的東西。
工程的最高境界不是讓 AI 更聰明,而是讓不夠聰明的 AI 也能穩定做對事。