多 Agent 架構我沒有蓋新東西:Slack 當 message queue、Google Drive 當檔案儲存、GitHub 當狀態與版本
我每天在用的 agent:Claude Code、Codex、Grok CLI、pi 四個 CLI,加上四個 OpenClaw 實例,最近又多一個 Grokbot。九隻 agent,散在六七台機器上。MacBook Air 跑 macOS、Mac mini 跑 macOS、RTX 5090 跑 Linux、GCP VM 跑 Linux。每一隻都無法割捨——少掉任何一個,某一塊工作流就得退回手動。
這代表一件事:跨平台、跨機器、跨 agent 之間的資料交換,會愈來愈複雜。
我的做法很簡單,三個工具:
- Google Drive 做檔案分享。錄音、PDF、影片這類二進位丟進去,各機器同步下來。我有訂閱,5 TB 容量用不完,雙向同步夠快。
- GitHub 做文字檔的同步與版本控制。程式碼、config 設定、LLM Wiki 的知識庫,全部用 git 管。SSH key 串接,幾乎不會失敗。
- Slack 做 agent 之間的即時交換。這是最後才加的一層。
Google Drive 跟 GitHub 都是用檔案形式,備份和相互備份都很直覺。GitHub 用 SSH key 串接基本上不會斷;Google Drive 偶爾會遇到 authorization key expire,但都還好處理。
Slack 是後來才導入的,因為之前發現用檔案做即時訊息傳遞其實不太行——很難找到最新的那一則。我想過直接導入 MQ 來做系統間傳遞,但後來發現不只是系統跟系統之間要傳東西,還需要人進來跟 agent 溝通。為了人機協作的方便,Slack 是最簡單的選擇,而且它有免費方案。
沒有一個是我為了 agent 買的。
三個原語,三個 SaaS
| 原語 | 我用什麼 | 存什麼 | 寫入頻率 | 需要 diff | 主要寫入者 |
|---|---|---|---|---|---|
| 檔案儲存 | Google Drive | 錄音、PDF、影片、大型原始檔 | 低 | 否(二進位) | 錄音工具、批次 job |
| 狀態儲存 | GitHub | 知識庫、skill、context、加密後的設定 | 中 | 是 | 指定的中樞機器 |
| 訊息佇列 | Slack | 任務指派、完成回報、需要人決定的事 | 高 | 否 | 所有 agent 與人 |
三欄裡最關鍵的是「需要 diff」。這一欄決定了東西該放哪,比任何產品比較都準——會被反覆修改而且改錯要能查出是誰改的,就進 git;不會被改只會被引用的,進物件儲存;改了也沒有保存價值的,用完就過期。
往下拆解之前,先講為什麼這個對應不是巧合。把 agent 架構的詞彙拿掉之後,剩下的問題是:多個獨立的執行單位要怎麼協作。這個問題 1970 年代的作業系統就在解,答案是三件事——行程間通訊、檔案系統、版本控制。Agent 時代把它們改了名字:行程間通訊變成「agent 之間的 handoff」,檔案系統變成「context 或 knowledge base」,版本控制變成「memory 的一致性」。名字換了,形狀沒換。
所以當市面上的 agent framework 開始賣「orchestrator」「shared memory」「state management」的時候,值得先問一句:這跟訊息佇列、檔案系統、版本控制有什麼實質差別?多數情況下,差別是它把三樣綁成一包賣給你,而且綁法不見得符合你的讀寫特性。
Slack 當 MQ:從「檔案傳不了即時訊息」到「唯一自帶 human-in-the-loop 的佇列」
Slack 是三層裡面最後加的。之前 agent 之間的即時訊息也走檔案——一個 agent 寫一個 JSON,另一個 agent 輪詢目錄。問題很具體:你很難找到「最新的那一則」。檔案系統沒有排序保證,輪詢間隔拉長就漏訊息,拉短就浪費資源。
我想過直接導入正經的 MQ。RabbitMQ、SQS、Kafka,這些都是機器對機器的方案:訊息進去、被消費、確認、結束。但後來發現我的需求不只是系統跟系統之間傳東西——還需要人進來跟 agent 溝通。人要看裡面發生什麼事,用 MQ 得另外做一個介面。
Slack 反過來:它天生就是給人看的,機器是後來才接進去的。這在 agent 架構上是個特性,不是缺點。
- thread 天然就是 conversation context。 一個任務從指派到完成的所有往返在同一條 thread 裡,不需要另外設計 correlation ID。
- channel 天然就是 topic 分流。 哪個 agent 訂閱哪些任務,用 channel 就切完了。
- 人可以直接插手。 這是關鍵差別。agent 卡住的時候,你不是去查 log 再下一個 CLI 指令,你就在那條 thread 裡回一句話。人的介入跟機器的訊息走同一條管線、留在同一個地方。
還有一個更直接的原因:ChatGPT 的 web 介面原生支援 Slack plugin,而我很常用它的語音模式。語音對話的結果直接出現在 Slack channel 裡,不需要另外轉貼。Slack 不是我為了 agent 架構挑的工具,是我用語音跟 ChatGPT 講話的時候它自己就在那裡了。
為什麼不是 Discord、Telegram 群組、或 LINE 群組?三個都能收發訊息,但拿來當 MQ 各自少一塊。Discord 有 thread 也有 channel,結構最接近,但沒有 ChatGPT 原生 plugin——你要自己寫 bot 把語音對話的結果搬進去。Telegram 的 bot API 成熟,但群組裡的「回覆」是扁平的引用,不是一條可以收攏的 thread;話題一多,任務脈絡會散在同一條訊息流裡。LINE 群組兩樣都沒有:沒有 thread、沒有 channel 分流,官方 bot API 的彈性也遠不如前面三家。
我原本在 mini 上跑的是 Telegram 和 Google Chat 的通知,那兩個能做的是把結果推給我看;Slack 多出來的是 thread 與 channel 這兩層結構,讓「推給我看」變成「我可以在原地回話」。
差別聽起來很小,但它決定了 human-in-the-loop 要不要另外蓋一套東西。
Google Drive 當檔案儲存:二進位不進 git,markdown 也不進 Drive
前面講過,Drive 原本是我唯一的統一點。它做得好的那件事——5 TB 的容量、雙向同步夠快、檔案丟進去各台機器自己拉——在拆成三層之後依然成立。訊息搬去 Slack,狀態搬去 git,Drive 留下來做它本來就擅長的事。
這一層的規則只有一條:二進位檔不進 git。
錄音、會議影片、掃描的 PDF、法律文件——這些東西的共同點是不會被逐行修改,只會被整份取代或引用。git 對它們沒有任何幫助,只會讓 repo 膨脹到 clone 不動。它們進 Drive,git 那邊只留一個指向 Drive 的 reference 檔。
反過來的那一半更重要,而且是我付過學費才確定的:markdown 也不要放 Drive。
我原本用 Drive 的雙向同步在機器之間同步筆記。兩個問題:多個 agent 同時寫同一個 markdown 檔,Drive 的處理方式是生一份 conflicted copy——不是合併,是複製一份給你自己看著辦;而我的 Linux 兩台機器根本沒有 Drive 客戶端可以裝。
最後真正的教訓是第三個。我的 Drive 雙向同步停在 6 月 23 日,三個月沒有人發現。
一個沒有 exit code、沒有 diff、沒有人會去看的同步機制,壞掉的時候是安靜的。git 至少 push 失敗會有非零的離開狀態可以接告警。
GitHub 當狀態儲存:git 的價值不是儲存,是 diff
會被改的東西全部進 git:知識庫、skill 的正本、每台機器的 context 設定、用 sops 加密之後的 API key。
用 git 不是因為它是好的資料庫——它不是。用它是因為它回答一個其他儲存方案都不回答的問題:誰在什麼時候把什麼改成了什麼。
這件事在單人系統上是奢侈品,在多 agent 系統上是必需品。當你的知識庫裡出現一句錯的結論,你要能回答它是哪個 agent、在處理哪個任務的時候寫進去的。沒有這個能力,你只能整份重讀。
產業正在往同一個方向走。Letta 在 2026 年 2 月 12 日發布 Context Repositories,把 coding agent 的記憶整個改寫成 git repo:每一次記憶修改都自動版本化,並帶上 commit message。它甚至處理了並行寫入——給每個 subagent 一個獨立的 git worktree,並行寫完再用 git 的衝突解決合併回去。官方文件裡還有一個容易被忽略的建議:把記憶整理成 15 到 25 個聚焦的檔案。這個數字沒什麼神聖性,但它透露的意圖很清楚——記憶要被主動重整,不是一直往下追加。
LangChain 在 2026 年 6 月 30 日則把「讓 agent 把原始資料整理成一份持續維護的 markdown 知識層」正式寫成一個 pattern,並且把邊界劃得很清楚:
“They are best for durable domain knowledge, not necessarily short-term conversation state, user preferences, or high-frequency event logs.”
適合耐久的領域知識,不適合短期對話狀態、使用者偏好、或高頻事件日誌。
這句話正好解釋了為什麼三層要分開。「這個任務跑到哪一步」「這次呼叫重試了幾次」屬於高頻事件,它們該留在 Slack 的 thread 裡自然過期,不該被寫進 git 永久保存。
七月那篇談 agent memory 測評的文章裡有一個當時看起來像挑釁的數據點:Letta 不用任何專業 memory 系統,把對話存成檔案,給 agent grep 跟 open,在 LoCoMo 拿 74.0 分,同場 Mem0 的 graph 變體是 68.5。半年後這已經不是挑釁,是產品線的方向。
反方一:Slack 不是 message queue
這是對本文最強的反駁,我得自己先講。
Slack 沒有一個訊息佇列該有的保證。沒有 at-least-once 投遞、沒有死信佇列、沒有 backpressure、沒有消費者群組的 offset 管理。一則訊息如果沒被處理,它不會重試,它就只是停在那裡沒人管。
具體的限制還可以查得到數字。Slack 官方 changelog 記載,2025 年 5 月 29 日起,在 Slack Marketplace 之外商業散布的新 app 與新安裝,conversations.history 和 conversations.replies 被限制到一分鐘一次請求,limit 參數的預設與上限降到 15 筆;2026 年 3 月 3 日起,這個限制連既有的未上架 app 安裝也適用。免費方案這邊,訊息只保留 90 天。
一分鐘一次、一次 15 筆——這個規格拿去當任務佇列輪詢會直接卡死。
三個回應,第三個才是重點:
第一,自建的內部 app 不受那次變更影響,conversations.history 是每分鐘 50 次以上。所以「Slack 當 MQ」的前提是你自己建 app,不是裝一個第三方整合。這個前提要講清楚。
第二,保留期是真的要處理。90 天之後訊息會查不到,所以 Slack 裡的東西必須被視為會過期的——任何需要留下來的結論,得在過期前被搬進 git。這不是缺點,這是分層的意義:過期是 Slack 這一層的正確行為,不是 bug。
第三,也是最誠實的一點:這個對應成立的規模是有限的。我的負載是六七台機器、九隻 agent,訊息量少到我自己一天可以全部讀完。到了需要高頻輪詢、嚴格投遞保證的規模,Slack 這一層要換成真的訊息佇列,Slack 退回去只當人機介面。主張要收窄成:在你的訊息量還能被一個人看完之前,Slack 就是夠用的 MQ,而且它多送你一個免費的 human-in-the-loop 介面。
反方二:統一入口等於統一污染面
第二個反駁來自五天前的一則新聞。
dsewiki 事件裡,3,700 個自命名 agent、一萬八千筆貼文,把一個有 25 年歷史的德語 wiki 改造成地下布告欄。版主一天刪一百頁,對面一天建四百頁。
這對本文的主張是直接的攻擊:我把三個 agent 通訊與儲存的路徑收攏到三個共用的地方,也就把攻擊面收攏了。污染一次,所有 agent 都中毒。分開維護五份各自的 memory 檔案雖然會不同步,但一個 agent 被 prompt injection 攻陷時,另外四個是乾淨的。
這個反駁我只能部分回應。收攏的好處是污染變得可見:一條共用的寫入路徑至少留下 commit 記錄可以審計,五份分散的檔案你根本不知道哪一份被改過。但可見不等於變少。
實際的防線是把權限範圍切開,而不是把儲存切開:個人、團隊、客戶的知識分成不同的 repo 與不同的 channel,敏感內容不要寫進一個所有 agent 都能 clone 的地方。git 的特性是一旦被 clone 就撤不回來。
這套架構真正還缺的那一層
三個原語補齊之後,缺的不是第四個儲存空間,是寫入路徑上的治理。
我原本要蓋的 Memory Service,收窄之後只剩一個核心動作:把所有 agent 的 write_memory 換成 propose_memory。
理由很簡單。寫程式的人早就不允許直推 main——你開分支、提 PR、跑 CI、找人 review、才 merge。沒有人覺得這是官僚,因為所有人都被沒 review 的 commit 燒過。但同一群人在做 agent 記憶的時候,預設值卻是每個 agent 都能直接寫進共用知識庫。
差別在於:程式碼壞掉會有測試失敗,知識壞掉不會有任何紅燈。它只會安靜地讓三個月後的另一個 agent 給出一個有把握的錯誤答案。
具體要補的有兩件事,都很小:
一、每筆重要記憶帶五個欄位:來源、來源版本、適用範圍、狀態(提案/已確認/已取代)、生效時間。
舉一個真實的失敗場景。你跟 agent 討論「要不要用 Slack 當 agent 協作介面」,聊了半小時,你沒下結論。沒有狀態欄位的系統會記成「已決定採用 Slack」,三個月後另一個 agent 在這個前提上做規劃,而且不會有人發現,因為它讀起來完全合理。正確的記法是「正在評估,尚未確認採用」。
這比掛一個模型自己產生的信心分數有用得多。信心分數告訴你模型有多相信自己,狀態欄位告訴你這件事在真實世界處於哪個階段——後者可以被人查核,前者不行。
二、時間有效性。 Graphiti 在這件事上走得最遠:每個節點和邊都帶 valid_at 和 invalid_at,新事實牴觸舊事實時,關掉舊事實的有效區間,不是刪掉它。所以你可以問「我三月的時候對這件事的看法是什麼」。
這裡我要修正自己七月那篇文章的一個結論。那篇說我的 wiki「知識更新做得到但靠紀律」「時間推理是明確弱項」,並把原因歸給 wiki 這個格式。半年後我認為判斷錯了:那兩個弱項不是 markdown 的問題,是缺一層寫入檢查的問題。 狀態欄位和有效區間都可以寫進 frontmatter,只要有東西在寫入時強制檢查它們。
順帶一提,LangChain 那篇把 wiki memory 寫成 pattern 的文章,整篇沒有討論寫入衝突、多個 agent 同時寫、或權限治理。這不是它寫得差,是這個 pattern 的公開討論目前就停在「一個 agent 維護一份 wiki」。而多數人真正想做的是五個 agent 共用一份會累積的知識。
對兩種人的具體意義
個人開發者。 不要從挑 agent framework 開始。先拿一張紙,把你現在的工作流拆成三欄:哪些是訊息(誰該做什麼)、哪些是檔案(不會被改的原始資料)、哪些是狀態(會被反覆修改)。填完之後你會發現三欄各自對應到你已經在用的東西,剩下的問題只是把它們接起來。這個練習半小時做得完,而且它會擋掉一次沒必要的技術選型。
企業 CTO。 這三個原語你的公司幾乎確定都已經買了——某個 IM、某個雲端硬碟、某個 git 服務。導入 agent 的時候真正該先決定的不是產品,是兩件事:訊息層的保留政策(多久之後訊息會消失,以及在那之前什麼東西必須被搬進有版本的地方),以及權限範圍怎麼切(個人/團隊/客戶通常至少三層)。順序反過來的話,你會在導入到一半時發現「客戶 A 的知識不能讓服務客戶 B 的 agent 看到」,接著整套重來。
驗收也不要看測評分數。測三件事就很有價值:A agent 記錄之後 B agent 找不找得到;新決策取代舊決策之後回答會不會跟著改;沒有權限的 agent 是不是真的讀不到。
坦白說
這篇有三個限制要講清楚。
第一,這套架構的規模很小。 六七台機器、九隻 agent、一天的訊息量一個人看得完。前面反方那段講的規模天花板不是客套話——Slack 當 MQ 在高吞吐、需要投遞保證的場景會直接失效,而我沒有跑到那個規模的數據可以告訴你門檻在哪。這篇能證明的只有「在個人與小團隊規模,三個現成 SaaS 夠用」。
第二,治理層我一行都還沒實作。 我的知識庫現在長這樣:raw 底下 264 個 markdown,wiki 底下 296 個,其中摘要頁 255、概念頁 24、實體頁 12,index.md 約 46 KB,git 累計 154 次 commit。它符合本文說的 git-backed 部分,但沒有 Memory Service、沒有 propose 路徑、沒有狀態欄位,同步靠手動 git。上一節整節講的東西,在我自己的系統上還是設計。
第三,外部方案的能力描述來自各家官方文件,不是我實測的。 Letta 的 worktree 並行、Graphiti 的雙時間模型,我讀的是文件不是壓測報告。這個賽道 vendor 自報數字的可信度問題,七月那篇已經拆過——同一個系統在同一個測評上出現過四個分數。
關鍵洞察
- 多 agent 架構的三個原語是訊息佇列、檔案儲存、帶版本的狀態儲存,而這三樣你已經買好了。 選型的第一步不是挑 framework,是把現有工作流拆成這三欄。
- 「需要 diff 嗎」是最好用的分類問題。 會被反覆修改、改錯要查得出是誰改的,進 git;只會被引用不會被改的二進位,進物件儲存;改了也沒有保存價值的,留在訊息層自然過期。
- 過期是訊息層的正確行為,不是 bug。 Slack 免費方案只保留 90 天,所以任何需要留下來的結論必須在過期前被搬進有版本的地方。這條規則本身就是分層的意義。
- 安靜壞掉的同步機制最貴。 我的 Drive 雙向同步停了三個月沒人發現。挑同步機制的時候,「壞掉的時候會不會有人知道」比「好用不好用」更重要。
- 把
write_memory換成propose_memory。 你不會允許 agent 直推 main,同樣的理由適用於共用知識庫——差別只在知識壞掉不會有紅燈。
常見問題 Q&A
Q: Slack 真的可以當訊息佇列(Message Queue)用嗎?
在小規模可以,但要知道它缺什麼。Slack 沒有 at-least-once 投遞保證、沒有死信佇列(Dead Letter Queue)、沒有 backpressure。官方 changelog 記載,2025 年 5 月 29 日起在 Marketplace 之外商業散布的 app,conversations.history 被限制到一分鐘一次請求、一次最多 15 筆,2026 年 3 月 3 日起連既有安裝也適用;企業自建的內部 app 不受影響,是每分鐘 50 次以上。所以前提是你自己建 app。它換來的好處是 thread 天然是對話脈絡、channel 天然是主題分流,而且人可以直接在同一條 thread 裡插手,不必另外蓋一套 human-in-the-loop 介面。
Q: 為什麼二進位檔要放 Google Drive,markdown 卻不行?
判斷標準是「需不需要 diff」。錄音、影片、掃描 PDF 只會被整份取代或引用,不會被逐行修改,放進 git 只會讓 repo 膨脹。markdown 相反,它會被反覆修改,而且改錯要查得出是誰改的。另外一個實務理由是多個 agent 同時在雲端硬碟寫同一個 markdown 檔時,同步機制通常是產生一份 conflicted copy 而不是合併——那不是衝突解決,那是把問題丟回給你。
Q: 任務進度、重試次數這類資料該放進 git 知識庫嗎?
不該。LangChain 在 2026 年 6 月 30 日的 wiki memory 文章裡把這條線劃得很清楚:wiki 適合耐久的領域知識,不適合短期對話狀態、使用者偏好、或高頻事件日誌。這類執行狀態留在訊息層自然過期就好,或者放關聯式資料庫。混進版本控制的代價是它們永久留在 commit 歷史裡,而它們過幾天就沒有保存價值。
Q: 這套跟直接用 Mem0、Letta 這類 memory 框架比,差在哪?
差在綁定程度與可見度。專業框架把訊息、儲存、狀態綁成一包,好處是開發量小,壞處是綁法不見得符合你的讀寫特性,而且你的知識最後住在一個你不熟的儲存後端裡。用三個現成 SaaS 的代價是要自己接起來,換到的是每一層都能單獨換掉,以及所有狀態變更都是可讀的 git diff。Letta 在 2026 年 2 月 12 日發布的 Context Repositories 其實走到了同一個結論——它把 coding agent 的記憶整個改寫成 git repo,每次修改自動版本化並帶 commit message。
Q: 這套架構最先會在哪裡撐不住?
訊息層。Slack 免費方案只保留 90 天訊息,加上前面提到的 API 速率限制,一旦你的任務量需要高頻輪詢或嚴格的投遞保證,這一層就要換成真正的訊息佇列,Slack 退回去只當人機介面。檔案層和狀態層撐得比較久:物件儲存和 git 的擴展路徑都很清楚,而且換掉的時候不影響另外兩層。
來源
- Slack, Rate limit changes for non-Marketplace apps, 2025-05 changelog — https://api.slack.com/changelog/2025-05-terms-rate-limit-update-and-faq
- Slack Developer Docs, Rate limits — https://docs.slack.dev/apis/web-api/rate-limits/
- Letta, Introducing Context Repositories: Git-based Memory for Coding Agents, 2026-02-12 — https://www.letta.com/blog/context-repositories/
- Letta Docs, Shared memory — https://docs.letta.com/concepts/shared-memory
- LangChain, Wiki Memory: File-Based Memory for AI Agents, 2026-06-30 — https://www.langchain.com/blog/wiki-memory
- Neo4j Developer Blog, Graphiti: Knowledge graph memory for an agentic world — https://neo4j.com/blog/developer/graphiti-knowledge-graph-memory/
- Andrej Karpathy, LLM Wiki — https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f