返回風格版文章列表

同時駕馭 10+ 個 CLI 程式設計 agent 的設定方式 — 李宏毅老師經典的教學風格版

受李宏毅教學風格啟發。這一講我們不把 10+ 個 coding agents 當成「很多 chatbots」,而是當成一套需要排程、觀測、遠端 I/O 與恢復機制的 computer system。

本文是受李宏毅教學風格啟發的改寫版本,不是李宏毅老師本人撰寫、審閱或背書。也可閱讀 English 原文、 Lee Hung-yi-inspired English teaching-style version繁體中文 一般版本。

抽象深色技術插圖,呈現透過 tmux 式格狀面板與手機控制台同時駕馭多個 CLI 程式設計 agent。

各位同學大家好啊,那我們就開始來上課吧。

今天這堂課呢,我們要來看一個聽起來很帥、實際上很容易變成災難的東西:同時跑 10+ 個 CLI coding agents。

你可能會想說,這有什麼難?我開十個 terminal,十個 Claude Code、Codex、Gemini CLI,全部叫它們去做事,然後我就變成十倍工程師了。

欸,理論上很美。實務上你很快會發現,十個 agent 不是十倍產能。十個 agent 比較像你開了一間小小的軟體外包公司,然後所有員工每五分鐘都跑來問你:「老闆,這個要按 y 嗎?」

你沒有看錯。最後的 bottleneck 不是 model 會不會寫 code,而是你找不找得到它、知不知道它卡在哪裡、能不能在手機上回它一句話,以及它跑出來的東西有沒有被你驗證。

一言以蔽之

今天的一言以蔽之是這樣:

同時駕馭 10+ 個 CLI agent,不是 prompt engineering 問題。它其實就是一個 operating system 問題。

你要幫這些 agents 做 process management。誰在跑?誰 idle?誰等 input?誰應該被 kill?誰的 output 值得看?這些都不是 prompt 本身可以解決的。

所以今天的 roadmap 很簡單。我們先講為什麼 naive 的「開很多 terminal」會失敗。接著看我用哪四層把這件事情撐起來:tmux、Tailscale、Termius、還有一個 PWA panel。最後我們走一遍可以照做的設定指南。

講完你會發現,這整件事情沒有什麼神奇的。每一層都很普通。神奇的是把摩擦力一路壓下來,壓到你真的願意同時管理很多 agent,然後就結束了。

為什麼 10 個 agents 會先壞在人身上

我們先從問題開始。假設你今天有十個 CLI agents:

如果只有一個 agent,事情很單純。你盯著它。它問問題,你回答。它跑完,你驗收。

但十個 agent 的時候,問題變了。不是「agent 會不會做事」,而是「你怎麼知道哪一個現在需要你」。

比如說,你打開 Termius,SSH 進主機,attach 到 tmux,切 session,切 window,往回 scroll。一次也許 20 秒。聽起來沒什麼嘛。

但是 20 秒乘以 10 個 session,再乘以一天幾十次檢查。你想想看,這不是什麼高深的 ML 問題,這是排隊買飲料的問題。每杯飲料只等 20 秒,十杯就變成你站在櫃檯前面發呆。

所以我們需要一個 system。這個 system 的目標不是讓 agent 更聰明。目標是讓你跟 agent 之間的每一步都變短。

整套 stack 其實就是四層

好,那整套 stack 長這樣:

  ┌──────────────┐                              ┌─ home box ──────────────────────┐
  │ Mac          │                              │ tmux                            │
  │ (iTerm /     │ ◀───────┐                    │  ├─ session: project-a          │
  │  Ghostty)    │         │                    │  │   ├─ window: Claude Code     │
  └──────────────┘         │                    │  │   ├─ window: tests / logs    │
                           │      Tailscale     │  │   └─ window: git ops         │
  ┌──────────────┐         ├──── (private ─────▶│  ├─ session: project-b          │
  │ Phone        │ ◀───────┤      mesh)         │  │   └─ ...                     │
  │ (Termius +   │         │                    │  └─ session: ...                │
  │  PWA panel)  │ ◀───────┘                    │                                 │
  └──────────────┘                              └─────────────────────────────────┘

這張圖看起來很多東西,但其實只有四層。

第一層,tmux。它讓每個 agent 活在主機上,不會因為你的 laptop 關掉、網路斷線、手機切 Wi-Fi 就死掉。

第二層,Tailscale。它讓你從 Mac 或手機連回自家主機,而且不用把 SSH、Streamlit、Jupyter、prototype server 亂丟到公網。

第三層,Termius。它讓手機變成一個 emergency console。不是讓你在手機上寫整個 feature,而是讓你在火車上可以回 agent 一句:「yes, run the tests」。

第四層,PWA panel。它把所有 agent 攤成卡片,讓你不用一直在 tmux 裡面迷路。

四層加起來,就從「十個 terminal」變成「一個可以被你排程的 agent farm」。

tmux:讓每個 agent 有固定座位

我們先講 tmux。tmux 聽起來很像老派 terminal 工具,對不對?但在這個 workflow 裡,它其實就是 process table。

所謂 tmux,它有三個概念:session、window、pane。這三個字如果你第一次聽,可能會覺得很煩。沒關係,我們用教室來想。

一個 session 就是一間教室。比如說 home-page 這個 project 一間,research-agent 另一間。Window 是教室裡的白板區:一塊白板給 Claude Code,一塊白板給 tests/logs,一塊白板給 git ops。Pane 則是白板切成左右上下幾格。

這個比喻到這裡就好。真實世界裡 session 活在 tmux server 裡,不是活在你的 terminal app 裡。所以你把 laptop 蓋起來,agent 還在。手機 SSH 進去,也可以 attach 回同一個 session。

我的 layout 很固定:

tmux new -s <project>

每個 project 一個 session。裡面通常有幾個 windows:

好,那這樣做的好處是什麼?好處是每個 agent 都有地址。你不是「某個 terminal 裡面好像有一個 agent」。你是 project-a:agent。它有名字,有房間,有座位。

這件事非常重要。因為當 agent 變多,混亂通常不是來自 code,而是來自沒有地址。

Tailscale:把門關起來,不要把 prototype 丟到公網

接下來第二層,Tailscale。

Agent 跑在自家主機上,因為 GPU、磁碟、資料都在那裡。那你人在外面,怎麼連回去?最直覺的做法是 port forwarding,或者開一堆 public hostname。

怎麼辦呢?這就是 Tailscale 很好用的地方。

Tailscale 其實就是把你的 Mac、手機、自家主機放到同一個 private mesh 裡。白話文就是,它們像在同一個宿舍 LAN 裡一樣互相看得到,但外面的人看不到。

比如說我在自家主機上跑一個 Streamlit prototype,port 8501。手機上直接打:

http://homebox:8501

就可以看。不用 nginx。不用 Let's Encrypt。不用公開 hostname。也不用半夜突然想起來:「欸,我那個沒有 auth 的 prototype 是不是還在 internet 上?」

欸你知道嗎,很多 local prototype 根本沒有 auth。它不是設計成給陌生人看的。你把它放到公網上,它就像把宿舍房門拆掉,然後說反正我只是去樓下買宵夜。這個比喻不是很 technical,但意思很清楚。

所以 Tailscale 在這裡做的事情,就是讓你遠端工作,但不要把門打開。

Termius:手機不是主要戰場,是 emergency console

第三層,Termius。

你可能會想說,在手機上操控 CLI agent,聽起來很痛苦。對,真的痛苦。所以重點不是把手機變成主要開發環境。重點是讓手機可以處理小型 interrupt。

比如說 agent 問你:

這種事情不需要你打 200 行 code。你只要有一個好用的 SSH console,就可以把流程推下去。

Termius 真正讓 tmux 在 iPhone 上能用的關鍵,是 shortcut bar。EscTabCtrlAlt、方向鍵、Shift+Tab 放在鍵盤上方。

沒有這排鍵,你在手機上用 terminal 會像戴拳擊手套打字。有這排鍵,你至少可以在火車上切 tmux、回一句 prompt、detach,然後繼續看窗外。

iPhone 上的 Termius 顯示 tmux 中的 Claude Code CLI session,shortcut bar(esc/tab/ctrl/alt/方向鍵)就在 iOS 鍵盤上方。
Termius on iOS。它不是完整 IDE,但作為 emergency console 很夠用。

再加一個小技巧:SSH 連進來的時候,自動 attach 到 tmux。

if [[ -z "$TMUX" && -n "$SSH_CONNECTION" && $- == *i* ]]; then
  tmux attach -t main 2>/dev/null || tmux new -s main
fi

這段的意思很簡單。你如果是透過 SSH 互動式登入,而且現在不在 tmux 裡,那就 attach 到 main。沒有 main 就開一個。就結束了。

真的需要 GUI 的時候

大部分工作都在 terminal 裡。但是你偶爾還是會遇到真的需要畫面的情況。

比如說 agent 起了一個 dashboard。或者 Jupyter UI。或者某個工具就是不肯 headless 跑。這時候你硬要用 terminal 解決,會很像用筷子修腳踏車。不是完全不可能,但你會懷疑人生。

所以我在自家主機上留 Chrome Remote Desktop 和 VNC server。CRD 比較簡單,瀏覽器就能用。VNC 也可以,只要記得綁在 Tailscale interface,不要暴露在公網。

這一層不是每天用。但那 5% 真的需要螢幕的工作,它會救你。

PWA panel:缺的不是 terminal,是總控台

講到這邊,我們已經有 tmux,有 Tailscale,有 Termius。那問題解決了嗎?還沒有。

因為真正麻煩的不是「能不能打字進某個 session」。真正麻煩的是「我怎麼知道哪個 session 值得我現在去看」。

這時候 PWA panel 就出現了。

我寫了一個小型 PWA,把每個正在跑的 CLI agent 變成一張卡片。卡片上有:

點進去就是一個 chat-style view,可以直接送下一條指令。你不用 SSH,不用切 tmux session,不用 scroll 半天找它剛剛問什麼。

PWA 中所有 CLI agent session 以卡片呈現,依狀態分組 — idle、working、needs input、offline,每張卡片都有專案 tag。
列表視圖:不是炫技,是把「哪個 agent 需要我」這件事直接顯示出來。
PWA 中打開單一 CLI agent session 的詳細視圖,包含訊息輸入框與一排終端機快捷鍵。
Session 視圖:不用 SSH 也能補一句指令,讓 agent 繼續跑。

你可以把這個 panel 想成動畫裡那種作戰指揮室。不是每一台機器都要你親手操作。你要的是雷達圖:哪裡亮紅燈,哪裡可以放著跑,哪裡要派人去看。

不過這個類比到這裡就好。真實系統裡,panel 沒有幫你做判斷。它只是把分散在十個 terminal 裡的狀態集中起來,讓你少浪費 attention。

這個更完整、開源版的計畫我叫做 vmux。目前 repo 還只是 placeholder。如果星數突破 100,我就會開始把它整理成真正可發佈的開源專案。

接下來還想補上的能力

接下來我最想加三個東西。

第一個,讓一個 agent 可以讀另一個 agent 的 output,不用你在中間 copy-paste。因為人類在這裡如果只是傳話,其實就是很貴的 message bus 而已。

第二個,broadcast mode。你選一群 sessions,對它們送同一個 prompt。比如說:「全部跑一次 tests,回報 failure summary。」這不是每天都需要,但需要的時候很爽。

第三個,voice input。公車上真的需要。你不會想在晃來晃去的車上打很長的 prompt。你只想說:「把剛剛那個 branch push 上去,開 draft PR。」然後就結束了。

設定指南:tmux、Tailscale、Termius

好,前面講完概念,接下來我們進入可以照做的部分。這裡不是要你把所有設定背起來。你只要把最小可用版本跑起來,再慢慢加東西。

tmux

macOS:

brew install tmux

Windows 就透過 WSL。Linux 用你的 package manager。

如果你想要一套舒服的預設值,可以直接用 Oh My Tmux:

git clone https://github.com/gpakosz/.tmux.git ~/.tmux
ln -s -f ~/.tmux/.tmux.conf ~/.tmux.conf
cp ~/.tmux/.tmux.conf.local ~/

真正會一直用到的指令,其實就這幾個:

tmux a                # attach 到上一個 session
tmux new -s <name>    # 開新 session
<C-b> z               # 放大目前 pane
<C-b> s               # 挑 session
<C-b> q               # 顯示 pane 編號,然後跳過去
<C-b> <n>             # 跳到第 n 個 window

驗證方式也很簡單:

tmux new -s test

看到下面有綠色 status bar,就代表你進去了。按 Ctrl-b 再按 d detach。再跑:

tmux a -t test

attach 回去。這就是最小 loop。

Tailscale

  1. tailscale.com 註冊。個人 100 台裝置以內免費。
  2. 自家主機安裝 Tailscale。macOS 用 brew install --cask tailscale,Windows 到 tailscale.com/download 下載 installer。
  3. 手機安裝 Tailscale app,用同一個帳號登入。
  4. 打開 MagicDNS,這樣你可以用 hostname 連,不用記 IP。

驗證方式:手機上的 Tailscale app 看到自家主機是 Active。然後在手機 Safari 打開:

http://<home-box>:<port>

如果看得到你的 local dev server,就代表 private mesh 起來了。

Termius

  1. App Store 安裝 Termius。免費 tier 就夠。
  2. Hosts → New Host。填 Tailscale MagicDNS hostname、port 22、username,貼上 SSH private key。
  3. Settings → Terminal → Bottom bar。加入 EscCtrlTab、方向鍵、Shift+Tab
  4. Settings 裡打開 Auto-Reconnect。手機在 Wi-Fi 和行動網路之間切換時比較不會斷。

最小測試:

  1. 自家主機:tmux new -s claude,啟動 Claude Code。
  2. Ctrl-b d detach,關掉 terminal。
  3. 手機打開 Termius,連線後 tmux a -t claude
  4. 對 agent 打一句話。

你現在已經可以從手機透過私有網路操控桌面上的 CLI agent。整套最小版本就是這樣子。

SSH 連線時自動 attach 到 tmux

如果你不想每次都手動打 tmux a,可以把這段加到自家主機的 ~/.bashrc~/.zshrc

if [[ -z "$TMUX" && -n "$SSH_CONNECTION" && $- == *i* ]]; then
  tmux attach -t main 2>/dev/null || tmux new -s main
fi

Termius 也可以在 Hosts → Edit → Startup Command 放:

tmux attach -t main || tmux new -s main

兩種做法選一個就好。不要兩邊都做得太複雜。設定這種東西,最怕的是你三個月後自己也看不懂。

讓 session 在重開機後恢復

tmux server 活在記憶體裡。斷電、OS update、或你手滑跑了 killall tmux,sessions 就會不見。

這對 agent workflow 很痛。因為消失的不只是一個 terminal layout,而是跑到一半的 context。

怎麼辦呢?可以用三個 plugin:

先安裝 TPM:

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

把下面加到 ~/.tmux.conf.local(如果你用 gpakosz config)或 ~/.tmux.conf

# Plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'

# Capture pane scrollback so output is restored too
set -g @resurrect-capture-pane-contents 'on'

# Restore vim/nvim sessions and keep ssh panes alive
set -g @resurrect-strategy-vim  'session'
set -g @resurrect-strategy-nvim 'session'
set -g @resurrect-processes 'ssh psql mysql sqlite3 "~vim->vim" "~nvim->nvim"'

# Autosave every 15 min, auto-restore on tmux server start
set -g @continuum-save-interval '15'
set -g @continuum-restore 'on'

# TPM init must be the LAST line
run '~/.tmux/plugins/tpm/tpm'

重新載入:

tmux source-file ~/.tmux.conf

然後在 tmux 裡按 prefix + I 安裝 plugins。

驗證 loop:開一個 session,跑幾個指令,按 prefix + Ctrl-s 存 snapshot,然後跑 killall tmux。再開新 shell。Continuum 應該會恢復 layout、working directory,還有可見 scrollback。

但是這裡有一個 caveat。@resurrect-capture-pane-contents 'on' 會把 pane scrollback 用純文字寫到 ~/.local/share/tmux/resurrect/。如果你的 pane 裡會出現 API key 或其他 secret,要嘛關掉這行,要嘛確認 FileVault / disk encryption 有打開。

這不是小題大作。Agent 很常會把奇怪的東西印出來。你不要讓恢復機制變成 secret archive。

總結

好,講到這邊我們來總結一下。

第一,10+ 個 CLI agents 的問題,不是單純讓 model 更強。問題是 orchestration。誰在跑、誰卡住、誰要回覆,這些都要被管理。

第二,tmux 給每個 agent 固定座位。Tailscale 給你安全的私有連線。Termius 讓手機變成 emergency console。PWA panel 則把所有狀態集中起來。

第三,真正的 punchline 是:把你和 agent 中間的每一步都壓短。少切一次 session,少 scroll 一次 log,少找一次 terminal,你就比較願意同時養很多 agents。

所以同時駕馭 10+ 個 CLI agent,聽起來像很厲害的 AI workflow。打開來看,其實就是很樸素的 system design 而已。

以上就是我今天想跟大家分享的內容。

延伸閱讀

如果 shell、vim、tmux、整套「住在 terminal 裡」的思維對你來說是新的,我推薦 MIT 的 Missing Semester(2020 版)。這是每個 CS 系都應該有、但常常沒有的一門課。也可以看 2026 版