如何讓各種 Coding Agent 更好的幹活?
在常規的對話外,Claude Code(也可以是 Codex)其實還提供了一些別樣的控制(或者說:上下文注入)方法,比如:CLAUDE.md、Rules、Skills、Subagents、Hooks、Output Styles、以及 System Prompt Append
接下來,我會具體聊聊這些奇奇怪怪的東西,用最不繞彎子、最把你穩穩接住🫴的方法,嘗試講清楚這些玩意兒都是個啥,讓你最聽人話👂的知道:
→ 這些方法各自適合放什麼樣的指令
→ 為什麼在 CLAUDE.md 裡寫「永遠不要做 X」不靠譜
→ Skills 和 Subagents 到底怎麼玩
→ Hooks 是怎麼做到確定性執行的
→ Dynamic Workflows 怎麼讓 Claude 自己寫編排指令碼
此外,最近 Claude 最近還多了一個叫 Dynamic Workflows 的能力,可以讓 Claude 自己寫編排指令碼、協調多個 agent 平行幹活,這裡也會嘗試講清楚
劇前提要
首先,我們必須要理解大模型的工作原理,簡單來說就是【塞進去足夠的上文】,模型就能夠【給出足夠好的結果】:我在央媒的分享:上下文即一切
AI 的能力、問題和用法,本質都由上下文決定。使用者發一條請求,AI 把請求和它能拿到的所有材料拼在一起,組成一段完整的上下文,再往下生成結果...循環往復
而 Agent,則是在你給到初始的目標、背景資訊、限定條件等等之後,它去自己建構上下文
劃重點:Agent 和 ChatBot 的區別在一件事上【誰來建構上下文】
ChatBot 靠人喂,你給它什麼材料它就用什麼材料
Agent 會自己搜網頁、讀文件、調工具,把有用的內容寫進上下文,發現不夠還會自動回頭繼續找
對於 Agent 來說,它只能看到自己上下文內的內容;那麼通過一些工程手段,去限定 Agent 在那些步驟下,能看到那些東西,就變得尤為重要,於是我們就有了如 claude.md、skill 等上下文注入方法
這裡我做了一個表,方便大家更好的進行比較不同的上下文注入方法
如果追一下這幾個東西的設計方法的話,會發現更多有趣的點:
CLAUDE.md 是唯一一個「全程載入、全程佔 token」的方法。你寫的每一行,不管這次任務用不用得上,都在消耗上下文窗口
Skills 的設計很聰明:只有名字和描述在啟動時載入,完整內容等到被呼叫時才進上下文。用完之後如果上下文滿了,最舊的 skill 會被踢掉
Subagents 也是一種上下文注入,它是另起一個對話,在自己獨立的上下文窗口裡跑,跑完只把最終結果返回給主會話,所以從主會話角度來看,的上下文成本是零
Hooks 完全繞過了上下文窗口。它是程式碼,由 harness 在外部執行
下面,我們來具體的講解每一種上下文注入
CLAUDE.md算是項目的「說明書」,Claude Code 啟動時自動讀入
【全程都把你穩穩接住】
這東西非常類似於 ChatGPT 裡面的 Instruction/自訂指令,或者 API Call 裡的 System Prompt,在項目啟動時就會讀取
在 Claude 裡,這個叫做 CLAUDE.md
在 Codex 裡,這個叫 agents.md
這些個檔案時放在根目錄裡的,Claude Code 啟動後就會自動讀取,你可以在裡面去約定一些裡面寫上建構命令、目錄結構、編碼規範、團隊約定什麼的
然後這裡得說一下,CLAUDE.md 分兩種載入模式:
始終載入根目錄的 CLAUDE.md,加上你本地個人偏好的 CLAUDE.md。啟動即載入,壓縮後重新讀取,全程都在
按需載入子目錄下的 CLAUDE.md(比如 app/api/CLAUDE.md),只在 Claude 讀取該目錄下的檔案時才載入。壓縮後丟失,等到再次碰那個目錄才重新載入
對此,官方建議給每個團隊的目錄放自己的 CLAUDE.md,開發者用 claudeMdExcludes 配置跳過不相關團隊的檔案,團隊之間不互相佔用上下文
也如同會不斷膨脹的 instruction 一樣,CLAUDE.md 也可能會像所有沒有 owner 的配置檔案一樣不斷膨脹...畢竟人總喜歡不斷的積累規則、加規則,然後這個 CLAUDE.md 也會不斷膨脹,讓指令遵循率也下降
CLAUDE.md 的正確用法
告訴 Claude 項目長什麼樣、建構命令是什麼。流程和約束放到 Rules、Skills 這些按需載入的機制裡
對於組織等級的安全策略和合規要求,可以通過 MDM 或配置管理工具統一部署一份集中管理的 CLAUDE.md 到開發者機器上,這份檔案不能被個人配置排除
Rules
這給特定檔案或目錄設定的約束,可以做到「碰到這類檔案才生效」
Rules 是 .claude/rules/ 目錄下的 markdown 檔案。你可以把它理解成更精細的 CLAUDE.md:CLAUDE.md 是全域生效的,Rules 可以只在碰到特定路徑的檔案時才載入
不加路徑限定的 Rule 跟寫在 CLAUDE.md 裡沒區別:啟動即載入,全程佔 token。加了路徑限定就不一樣了
--- paths: - "src/api/**" - "**/*.handler.ts" --- 所有 API handler 必須用 Zod 做輸入校驗
只有當 Claude 讀取 src/api/ 下的檔案時,這條 Rule 才會載入。做文件的時候,這條規則壓根不在上下文裡,不浪費 token
至於什麼時候該用 Rule?
當一條約束是跨目錄的(比如所有 migration 檔案只能追加、所有測試檔案必須用某個 mock 庫),但又不需要全域生效時,path-scoped rule 就是最好的選擇
Skills
這個算是大家最熟悉的「技能包」了,只在被呼叫時才載入完整內容,平時只佔幾十個 token
Skills 的位置在 .claude/skills/ 目錄下,每個 skill 是一個資料夾,裡面有一個 SKILL.md 定義名字、描述和完整指令
然後,這裡我必須要說一點,也是常見的誤區:
Skill 不是提示詞 ,也通常不作為資料來源,通常不會有「小紅書搜尋 Skill」的
Skill 的本質,是把一堆檔案,按約定的結構打包成 .zip,然後把後綴改成了 .skll,所以當你呼叫別人的 Skill 時,本質是把別人打包資料夾喂給大模型:如果資料夾裡有提示詞,當然可以把 Skill 當提示詞用,但絕對不能說 Skill 是提示詞
說回來,當 Agent 啟動的時候,並非載入 Skill 的全部內容,而只是載入其名字和描述(幾十個 token 的事),完整內容等到 skill 被呼叫時才進上下文
Skill 呼叫方式有兩種:人工斜槓命令(比如 /code-review)或者 Claude 自動匹配任務
Skill 跟 CLAUDE.md 的核心區別是「流程 vs 事實」。CLAUDE.md 放的是 Claude 需要隨時知道的事實(建構命令、目錄結構)。Skill 放的是需要按步驟執行的流程(部署清單、發佈流程、review checklist)。流程不需要全程佔 token,用到的時候載入就行
當對話內容過長,對話內容被壓縮時,不同的內容會被以不同的方式壓縮:
- 根目錄 CLAUDE.md 不會丟失,精準說壓縮的時候快取會被清掉,但緊接著 Claude Code 會重新讀取這個檔案,所以它永遠在上下文裡
- 子目錄 CLAUDE.md 會丟失,但等到 Claude 再次碰那個子目錄它還會重新載入
- Skills 壓縮後也會被重新注入,但有一個共享的 token 預算上限。如果呼叫了太多 skill,最早的會被踢掉
Anthropic 有一份完整的 skill 建構指南:查看指南 https://claude.com/blog/complete-guide-to-building-skills-for-claude
Subagents
這個也相對容易理解,就是讓 Agent 多開幾個窗口幹活,在獨立的上下文窗口裡跑任務,跑完只把結論交回來
Subagents 是 .claude/agents/ 目錄下的 markdown 檔案,用 YAML frontmatter 定義名字、描述、模型選擇和可用工具。你可以把它理解成一個專門處理某類任務的獨立助手
跟 Skills 的關鍵區別在於隔離性。Skill 在主線程裡執行,你能看到每一步的中間過程。Subagent 在自己獨立的上下文窗口裡跑,主會話看不到它的中間過程
一個 subagent 做了 50 輪搜尋、讀了 200 個檔案,主會話的上下文窗口裡只多了一段摘要,這也是為什麼要用它:SubAgent 做髒活累活,不污染主會話,並且能加快效率
在實際使用中,有三個典型場景可以去嘗試:深度搜尋(大量中間結果不需要保留)、日誌分析(翻幾百行 log 找問題)、依賴審計(逐個檢查庫版本)
Subagent 這東西時真的很好用,跑測試什麼的非常省心。這幾天我正在弄 AGI Bar 的 Drinking Plan,然後做了個小程序,完全是 SubAgent 叢集在弄,這裡我放個圖大家感受下(其實中間我中斷了次,實際上已經跑了 40+ 個小時了)
然後,Subagent 可以巢狀,最深五層,後面講 Dynamic Workflows 的時候會看到,這個巢狀能力是大規模編排的基礎
怎麼選?
需要看到每一步的中間結果嗎?需要就用 Skill
不需要,讓它自己跑完給你一個結論,用 Subagent
Hooks
這東西的本質,是觸發指令碼:當遇到特定的問題,就自動執行,跟模型的判斷力無關
Hooks 是 Claude Code 裡最不像 AI 的機制。你在 settings.json 裡註冊一個 hook,指定「當某個事件發生時,執行這條命令」。IFTTT 知道吧?就是那種: if this, then do that
可以先看一下上面這張圖,有八種 Hook 事件:
PreToolUse工具執行前觸發。攔截危險命令、驗證檔案路徑、自動批准安全操作。exit code 2 直接阻止執行
PostToolUse工具執行後觸發。寫檔案後自動跑 Prettier,改程式碼後自動跑 linter
PermissionRequest權限對話方塊彈出前觸發。npm test 跑了第一百遍還在問你要不要允許?自動批准
SessionStart會話啟動時觸發。自動注入 git status、TODO 列表
PreCompact上下文壓縮前觸發。把完整對話備份到檔案,防止重要決策丟失
Stop回覆完成時觸發。檢查任務是否做完、測試是否通過。返回 "continue": true 讓 Claude 繼續幹
SubagentStop跟 Stop 一樣,但針對 subagent
UserPromptSubmit提交 prompt 時觸發。自動追加當前 sprint 資訊
而 Hook 動作本身有五種類型:command(執行命令)、HTTP(調介面)、mcp_tool(調 MCP 工具)、prompt(讓模型判斷)、agent(啟動 agent 判斷)。前三種完全確定性執行,後兩種用模型的判斷力
如果某件事絕對不能發生,用 hook 或 permission 做硬護欄
比如,之前我在弄「龍蝦大逃殺」的時候,不是被踢了麼...艹...龍蝦大逃殺:存活下來的,拿 Mac mini|群裡有只會踢人的龍蝦
當時我是圖個懶省事兒,直接寫在系統提示詞裡面的,除此之外沒加任何防護,但江湖險惡、人心難測...屮屮屮屮屮....被踢了之後痛定思痛,才上了 permission 硬護欄,活動才能順利進行
對了,忘了說了,當時比賽最終贏家是【四毛】,我加了一個月好友才加上
然後那段時間 Mac Mini 無現貨(這可惡的龍蝦潮),訂等了好久才到
之後還會有類似的活動,歡迎大家來參加:中獎機率倍兒高,獎品也嘛倍好~
話說回來,做安全防護的時候,任何的提示詞防護都是不靠譜的,都很有可能在長會話、壓力大、或被 prompt injection 干擾時失效。而 PreToolUse hook 攔截就是確定性的,作為大守密者,永遠幫你把握住「永遠不要執行 rm -rf」這樣的資訊
更多 hook 配置細節:查看指南 https://claude.com/blog/how-to-configure-hooks
Output Styles
你可以通過這個,修改 Claude Code 的「人設」為貓娘,注入到 system prompt 裡,權重最高但影響面也最大
Output Styles 這個東西的位置,在 .claude/output-styles/ 下面,能夠注入到 system prompt 裡、永遠不會被壓縮,且指令遵循權重最高
但在另外的一方面,你得知道:自訂 output style 會替換掉默認的 system prompt
這裡說一下 system prompt,這是 Claude 裡的內建基礎提示詞,包含了很多定義,比如:怎麼限定改動範圍、安全問題怎麼處理、改完程式碼先跑測試
除非你在 frontmatter 裡加 keep-coding-instructions: true
對此如果你想進一步研究的話,可以先看一下三個內建的 style:Proactive(自主決策多)、Explanatory(教學模式)、Learning(協作編碼)
System Prompt Append
一句話解釋:通過 CLI 參數臨時往 system prompt 後面追加內容,不修改默認指令,只對當次呼叫生效
如果覺得 Output Styles 改動太大,append-system-prompt 是一個更甜品的選擇。它只往默認 system prompt 後面追加一段內容,不替換任何東西。Claude Code 原本的軟體工程指令全部保留
在 CLI 裡,你可以這麼輸入:
claude --append-system-prompt "所有回覆使用中文,程式碼註釋也用中文"
這條指令只對當次呼叫生效,不寫檔案,不跨 session。適合加編碼規範、輸出格式、語氣偏好這類輕量指令
壓縮行為跟 Output Styles 一樣:永遠不會被壓縮
但要注意一個遞減效應:追加的指令越多,Claude 對每條指令的遵循率越低。特別是指令之間有衝突的時候,遵循率下降得更快
常見誤區
對於這些注入方法,其實也有些常見的配置誤區的,這些來自官方,我給翻譯&補充了下:
錯誤:「每次 X,必須做 Y」寫在 CLAUDE.md 裡
比如你希望每次編輯檔案後自動跑 formatter。這類行為應該用 PostToolUse hook。模型選擇做一件事跟自動執行一件事完全是兩碼事
錯誤:「絕對不要做 Z」寫在 CLAUDE.md 裡
絕對性約束用 PreToolUse hook 做硬護欄,exit code 2 直接阻止。組織等級的護欄用 Managed Settings,管理員部署,使用者不能覆蓋
錯誤:30 行的流程寫在 CLAUDE.md 裡
部署流程、review checklist 放 skill。CLAUDE.md 放事實,skill 放流程
錯誤:Rule 沒加路徑限定
只適用於 src/api/** 的約束,沒加 paths: 就跟寫在 CLAUDE.md 裡一樣,全程載入白費 token
錯誤:個人偏好寫在項目級檔案裡
個人偏好(比如 commit message 格式)放使用者級的本地檔案,項目級檔案只放團隊共識
Dynamic Workflows
前段時間,Anthropic 發佈了 dynamic workflows/動態工作流,簡單來說就是讓 Claude 自己寫編排指令碼,協調多個 subagent 平行工作,解決複雜任務
其誕生,是為瞭解決默認 harness 的三個老問題:
→偷懶Agentic laziness,安全審查要查 50 項,Claude 查到第 35 項就宣佈完成了
→自我偏好Self-preferential bias,讓 Claude 檢查自己寫的程式碼,它傾向於覺得沒問題
→目標漂移Goal drift,長會話中每次壓縮都是有損的,邊緣需求和約束容易在壓縮中丟失
在這個過程中,三個核心函數起到了作用:
- Agent(prompt,opts?)
- parallel([fns])
- pipline(items,...)
Dynamic workflow 用獨立上下文窗口隔離每個子任務,從結構上消解這三個問題。觸發方式很直接:跟 Claude 說「用一個 workflow」,或者用觸發詞 ultracode
至於 Dynamic workflow 的編排方式,A社總結有以下六種:
Classify-and-act
先用一個 classifier 判斷任務類型,再分發給對應的專用 agent 處理
Fan-out-and-synthesize
把任務拆成 N 個子任務,每個跑一個 subagent,最後一個 agent 彙總結果
Adversarial verification
每個執行 agent 配一個驗證 agent,按標準對抗性檢查輸出
Tournament
N 個 agent 用不同方法做同一件事,逐對比較選出最優
Generate-and-filter
先大量生成,再過濾去重,只留驗證過的高品質結果
Loop until done
不設固定輪數,循環 spawn agent 直到滿足終止條件
實際案例
以之前 Bun 從 Zig 重寫到 Rust 用了 dynamic workflows 這個事兒為例,過程中每個修復跑一個 subagent 在獨立 worktree 裡改,另一個 agent 對抗性 review,通過後合併
Deep research 是 Claude Code 內建的一個 workflow skill(/deep-research)。扇出搜尋、抓取源文件、對抗驗證每條聲明、彙總成帶引用的報告
還有一個反向用法:讓 workflow 翻你最近 50 個 session,找出你反覆修正 Claude 的模式,聚類成規則候選,對抗驗證每條(能不能真的防止之前的錯誤?),通過的寫進 CLAUDE.md
最後
這些上下文注入的方法,本質是延續一個思路:需要的時候,出現;不需要的時候,消失
對應到工程上,就是:不同的指令,要有不同的生命周期
有的需要全程在場(CLAUDE.md),有的只在特定場景出現(path-scoped Rules),有的用到才載入(Skills),有的在獨立窗口裡跑(Subagents),有的完全不佔上下文(Hooks)
把所有指令塞進一個 CLAUDE.md 是最簡單的做法,但也是最浪費、且會污染上下文的做法,做正式項目的時候,就不推薦了
事實放 CLAUDE.md,流程放 Skill,護欄放 Hook,隔離任務給 Subagent
然後,如果整套 Agent 系統是整個團隊在用,就可以嘗試著把這些東西打包成一個 plugin,方便共享/分發 (賽博禪心)
