08 - Claude 當大腦、Codex 當雙手(核心架構)

07-Agent-Skill讓AI自己操控Herdr | 00-Index | 下一篇 → 09-實戰-刷題網站Taiwan-IM-board

這是整份教學的核心章節。 前七章都是為了讓這一章能落地。


為什麼要這樣分工

你有兩個訂閱:Claude ProChatGPT Plus。它們的特性不同:

Claude Pro(Claude Code)ChatGPT Plus(Codex CLI)
額度感受較緊,長任務容易撞上限較寬鬆,可以長時間跑
你已建立的資產12 個 skill(note-orchestrator、neizhan-solver、google-med…)、PubMed MCP、兩個 repo 的 CLAUDE.md一般 coding agent
強項規劃、判斷、遵守複雜規則、醫學查證大量、重複、規格明確的產出

所以最佳分工不是「誰比較強」,而是額度要花在刀口上

Claude(貴、稀缺、懂規矩)  →  想事情、切任務、驗收、commit
Codex(多、便宜、聽話)      →  照規格幹活,一次好幾個

🔑 關鍵洞察:Claude Code 內建的 subagent(Task tool)也是燒 Claude 的額度。所以「用 subagent 平行處理」省的是時間,不是額度。 而 Herdr 開出去的 Codex pane 走的是完全不同的訂閱帳單——這才是真正的額度轉移。


架構圖

┌─────────────────────────────────────────────────────────────┐
│ Herdr Session (背景常駐 server)                              │
│                                                              │
│ Workspace w1  "vault"                                        │
│ └── Tab w1:t1 "agents"                                       │
│     ├── Pane w1:p1  ★ Claude Code = 大腦 / orchestrator      │
│     │    · 讀 CLAUDE.md、切任務、寫 prompt                    │
│     │    · 用 herdr CLI 開/餵/等/讀 底下的 worker            │
│     │    · 查 PubMed、驗收醫學正確性                          │
│     │    · 唯一一個負責 commit / push 的人                   │
│     │                                                        │
│     ├── Pane w1:p2  ○ codex "worker-a"  ← 只寫檔             │
│     ├── Pane w1:p3  ○ codex "worker-b"  ← 只寫檔             │
│     └── Pane w1:p4  ○ codex "worker-c"  ← 只寫檔             │
│                                                              │
│ └── Tab w1:t2 "validate"                                     │
│     └── Pane w1:p5  □ shell(跑 validate.py / lint.py)      │
└─────────────────────────────────────────────────────────────┘
        ↑                                    ↑
   你的電腦(Windows Terminal → WSL)    iPhone SSH 巡場

三條鐵律

  1. Claude 是唯一的 commit 者。 Codex 只寫檔。(這也符合 Obsidian-med-note/CLAUDE.md §3「orchestrator 做唯一一次 commit」。)
  2. Codex 不做需要事實查證的判斷。 沒有 PubMed MCP 的環境不准猜 PMIDObsidian-med-note/CLAUDE.md §4 已經明文規定)。
  3. Claude 驗收的依據是「檔案」,不是「agent 說它做完了」。05-Agent偵測與狀態機制

完整編排腳本(可直接用)

把這段存成 ~/bin/herdr-fanout.sh,Claude 可以直接呼叫它、也可以自己寫類似的:

#!/usr/bin/env bash
# herdr-fanout.sh — 開 N 個 codex worker,各自跑一個任務檔,等全部做完
# 用法:herdr-fanout.sh <任務目錄>
#   任務目錄裡每個 *.task.md 就是一個 worker 的 prompt
set -euo pipefail
 
TASK_DIR="${1:?需要任務目錄}"
: "${HERDR_ENV:?必須在 Herdr pane 裡執行}"
 
declare -a NAMES=()
 
i=0
for task in "$TASK_DIR"/*.task.md; do
  i=$((i+1))
  name="worker-$i"
 
  # 1) 決定切的方向:前兩個往右,之後往下(避免切出細長條)
  dir=$([ "$i" -le 2 ] && echo right || echo down)
 
  # 2) 開背景 pane,保留目前工作目錄,不搶焦點
  split=$(herdr pane split --current --direction "$dir" --cwd "$PWD" --no-focus)
  pane=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')
 
  # 3) 啟動 codex(會等到它真的準備好才回傳)
  herdr agent start "$name" --kind codex --pane "$pane"
 
  # 4) 讓 sidebar 直接顯示它負責什麼
  herdr pane report-metadata "$pane" \
    --source user:fanout \
    --display-agent "$(basename "$task" .task.md)" \
    --token summary="$(basename "$task" .task.md)" \
    --ttl-ms 86400000
 
  # 5) 送任務(不等,讓它們平行跑)
  herdr agent prompt "$name" "$(cat "$task")"
 
  NAMES+=("$name")
done
 
echo "已派出 ${#NAMES[@]} 個 worker,開始等待……"
 
# 6) 逐一等待(總時限各自 30 分鐘)
for name in "${NAMES[@]}"; do
  if herdr agent wait "$name" --until idle --until done --timeout 1800000 >/dev/null; then
    echo "✅ $name 已 settle"
  else
    echo "⚠️  $name 逾時或出錯,請人工檢查"
  fi
done
 
herdr notification show "fanout 完成" --body "${#NAMES[@]} 個 worker 已結束" --sound done

幾個設計決定的理由

決定理由
agent prompt 不加 --wait要平行。加了 --wait 就變成一個一個做
分開的等待迴圈agent wait 若現況已符合會立刻回傳,所以順序等待不會漏
--until idle --until done不接受 unknown——unknown 不代表完成
--timeout 給足不給 timeout 會無限等
report-metadata讓 sidebar 顯示「誰在做哪批」,手機上巡場一眼就懂
用任務檔而非行內字串prompt 太長時 shell 引號會很痛苦;而且任務檔可以留下來 review

驗收:不要相信狀態,要相信檔案

agent prompt --waitagent wait 回來 不等於任務完成。原因在 05-Agent偵測與狀態機制 講過:

  • Codex 是 screen manifest 偵測,狀態是「讀畫面猜的」
  • blocked 偵測刻意嚴格,沒命中規則會退回 idle
  • agent prompt --wait 追的是 lifecycle 狀態,不是單一 turn

所以驗收流程長這樣:

# ❌ 錯的驗收
herdr agent wait worker-a --until idle && echo "做完了!"
 
# ✅ 對的驗收:檢查它應該產生的東西
herdr agent wait worker-a --until idle --until done --timeout 1800000
 
# 1. 檔案存在嗎?
test -f tmp_drafts/114-心臟-001-012.json || { echo "沒產出"; exit 1; }
 
# 2. 內容通過機器驗證嗎?
herdr pane run w1:p5 "python3 tools/validate.py"
herdr pane wait-output w1:p5 --regex "PASS|FAIL|Error" --timeout 300000
herdr pane read w1:p5 --source recent-unwrapped --lines 60
 
# 3. 語意 / 醫學正確性 → 由 Claude 自己讀檔審(這步不能外包)

💡 量產型任務天生適合這個模式,因為「產出檔案」本來就是任務本體。這同時繞開了 06-CLI與自動化基礎 講的 alternate screen 讀取限制——你根本不需要從畫面把長回應撈出來。


Prompt 怎麼寫(給 Codex 的任務檔範本)

Codex 拿不到 Claude 的 skill 和 CLAUDE.md 記憶,所有規格都要寫在任務檔裡

# 任務:114 年心臟血管科 第 001–012 題 詳解草稿
 
## 你的角色
你是內科專科考試詳解的起草者。**只寫檔,不要 git commit、不要 git push。**
 
## 輸入
- 題目:`tmp_drafts/input/114-心臟-001-012.json`
- 撰寫規範:`docs/詳解撰寫規範.md`**必讀,逐條遵守**
- 品質標竿範例:`src/data/explanations.113.json` 裡的 `113-037`
 
## 輸出(唯一)
`tmp_drafts/out/114-心臟-001-012.json`
格式:`{ "114-001": { "text": "...", "status": "draft" }, ... }`
 
## 硬規則
1. 固定五段式:### 本題觀念 / ### 選項分析 / ### 答案解析 / ### 核心知識點 / ### 參考資料
2. **每一個選項都要分析**,指出錯誤選項是哪個概念的陷阱
3. `status` **一律 `draft`**,禁止寫成 `reviewed`
4. 正解依「該考試年度當時的標準」判定
5. ⚠️ **絕對禁止捏造 PMID / DOI / trial 數據。**
   不確定的引用一律改成原則性描述,並在該處標 `[需查證]`
   (你沒有 PubMed 存取權,查證由審核者負責。)
6. 禁止罐頭字句:「此選項常是相近疾病」「供後續醫師逐題校閱」「以下為 AI 起草」
 
## 完成條件
輸出檔存在、是合法 JSON、包含全部 12 題、每題五段齊全。
做完只要回覆「DONE <檔案路徑>」,不要貼出全文。

幾個關鍵設計

  • 「只寫檔,不 commit」 寫在最前面
  • [需查證] 標記機制 —— Codex 沒有 PubMed,所以與其讓它猜,不如讓它明確標記出來給 Claude 收尾。這完全符合 Obsidian-med-note/CLAUDE.md §4 的「不要猜 PMID → 明確告知待查證」
  • 「回覆 DONE + 路徑,不要貼全文」 —— 避免 alternate screen 撈長文的問題

常見踩雷(血淚整理)

1. agent start 失敗:pane 不在 shell prompt

agent start 要求 pane 停在互動 shell prompt——shell 自己擁有前景,沒有前景指令、編輯器或 agent 在跑。

如果你剛 pane run 了什麼東西還沒結束,agent start 就會失敗。先讓 pane 回到 prompt。

2. agent_prompt_stalled

agent prompt --wait 從非 working 狀態送出時,五秒內必須觀察到 lifecycle 變化,否則回這個錯。

常見原因:agent 其實還沒真的準備好、或者畫面偵測沒認出它動了。處理方式:

herdr agent get worker-a          # 看目前狀態
herdr agent explain worker-a --verbose   # 看偵測命中哪條規則
herdr agent read worker-a --source visible   # 直接看畫面

3. Codex 卡在 approval 但顯示 idle

blocked 偵測嚴格,Herdr 沒學過的新提示畫面會 fallback 到 idle。症狀是「wait 立刻回來但什麼都沒做」。

防禦做法:在等待迴圈之後,額外檢查產出檔案(見上面的驗收段)。真的常撞到就用 --source visible 讀畫面確認。

4. 忘了 --no-focus,畫面被搶走

背景工作一律加 --no-focus。這在你正在別的 pane 打字時特別重要。

5. 忘了 --cwd "$PWD"

不給 --cwd 時,新終端跟隨 terminal.new_cwd 政策(預設跟隨來源 pane / workspace)。在 worktree 情境下這可能不是你要的目錄。明確寫出來。

6. pane 被搬動後 ID 變了

pane move 跨 workspace 之後,pane ID 會變。用 .result.move_result.pane.pane_id。 而且已經在等待中的 agent wait 會以 agent_not_running 結束

7. 一次開太多 pane,切成細長條

herdr pane layout 看形狀。超過 3–4 個 worker 時,改用「一個 worker 一個 tab」或「一個 worker 一個 workspace」,而不是一直切同一個 tab。

8. 多個 worker 改到同一個檔案

這是最貴的錯。解法是 git worktree

herdr worktree create --cwd . --branch codex/worker-a --no-focus

每個 worker 拿一個獨立 checkout,Claude 最後統一 merge。細節見 10-實戰-Obsidian醫學筆記庫


什麼時候「不要」用這個架構

誠實列一下,免得過度工程:

情況建議
任務 < 5 分鐘直接讓 Claude 做完,開 pane 的成本更高
子任務彼此有依賴(B 要等 A 的結論)序列跑,或讓 Claude 自己做
需要 PubMed / 醫學事實查證Claude 自己做,不能外包
只有一個子任務開一個 Codex pane 還是有意義(省 Claude 額度),但別為它寫 fanout 腳本
需要遵守大量 repo 慣例(CLAUDE.md 那些)慣例要完整寫進任務檔,否則 Codex 不會知道。規則太多太細時,Claude 自己做比較快

成本直覺(給你自己抓感覺)

一次「114 年某科 24 題詳解」的粗略分工:

工作誰做大概花費
CLAUDE.md + 規範、切成 2 批任務檔Claude小(幾千 token)
產出 24 題五段式詳解Codex ×2大(Codex 額度)
validate.py、檢查 JSON 合法性shell pane幾乎零
逐題查證 PMID / guideline 年份Claude(+ PubMed)
合併進 explanations.114.json、commit、pushClaude

重點:最貴的那格(大量產出)被移到 Codex 帳單上了,而 Claude 只花在「頭」和「尾」。


一句話總結

Herdr 不會讓 AI 變聰明,它讓你的兩份訂閱可以同時工作。 Claude 想事情、Codex 幹活、Herdr 讓你看得到誰在幹嘛。


🔗 相關筆記


最後更新:2026-08-04