Skip to content

AI 工具鏈的翻轉:從存取到架構

26 min read · AI 代理人 ·記憶粒度 ·工具鏈設計 ·治理

分享

六個月前,我寫了關於香港 AI 設定的文章,內容涵蓋電話號碼、DNS 路由、付款變通方案。當時的瓶頸是地理位置。你甚至能連上工具嗎?

現在那個問題已經解決了。一台 5 美元的 VPS 加上 Shadowsocks 就能輕鬆存取。工具到處都是。但解決存取問題並沒有讓事情變簡單,反而浮現了下一個問題。當你能存取所有模型、執行所有 agent 時,困難的問題就不再是「我能連上嗎?」,而是「什麼該連到什麼,由誰決定?」一個瓶頸消失了,取而代之的是十幾個協調問題。

這就是翻轉。失敗模式轉移到環境內部。存取問題解決了;協調與信任才是真正的挑戰。正如我在〈Agent 需要架構,不是 Prompt〉中所主張的,真正的失敗不是來自你在 prompt 裡寫了什麼,而是來自你的架構允許了什麼。我接下來要描述的技術棧,就是當我認真看待這個主張並將其應用到自己的環境時,所長出來的東西。

這個翻轉是漸進的。每一項新能力都移除了一個外部限制,同時揭露了一個內部限制。付款變通方案解鎖了模型存取。模型存取揭露了一個 agent 無法同時處理多個上下文。拆分 agent 揭露了一個記憶系統無法服務三種不同的回憶。拆分記憶揭露了工具鏈本身需要分類。每個解決方案都創造了下一個問題,而技術棧也隨之成長。

四個瓶頸依序驅動了這個成長:上下文碰撞——當一個系統提示試圖容納所有東西,領域互相滲透。記憶碎片化——當單一嵌入儲存無法回答三種不同的問題。工具蔓延——當不斷增長的執行環境、模型和訂閱方案列表變成一個等待發生的分類錯誤。信任模糊——當本地和代管元件並存,卻沒有明確的邊界。

以下就是浮現出來的技術棧。它在紙面上看起來很複雜:三個 agent 設定檔、三個記憶系統、一個模型路由器、一個協調器、一個 ADE,以及橫跨執行環境、模型和訂閱方案的工具鏈。沒有一個元件是因為我在收集而存在的。每一層都是因為先嘗試了更簡單的替代方案,但失敗了。

一個 Agent,三個設定檔

臨界點出現在一個系統提示試圖容納所有東西的時候——運維指令、寫作風格指南、社群媒體角色、營養追蹤邏輯,全部互相拉扯。

兩種污染模式讓單一 agent 方法變得不可行。第一,社交上下文洩漏到私人的運維決策中。先前互動的對話語氣會滲入基礎設施指令。Agent 並沒有當機,而是產出看起來正確但稍微錯誤的輸出——這是最難察覺的失敗,因為沒有任何東西會警示你。你事後才會發現,當某個決策浮現時,它已經被錯誤的上下文軟化了。

第二,營養的專用邏輯與治理規則衝突。卡路里追蹤和部署政策放在同一個 prompt 裡,兩個領域都沒有得到完整的關注。系統提示變成了競爭利益之間的協商,而 agent 正在輸掉這場協商,而且只有在事後才會顯現出來。

上下文碰撞

單一系統提示
運維 + 寫作 + 社交 + 營養

污染:
社交洩漏到運維
營養與治理衝突

拆分為三個設定檔

Norty
私人、完整權限
治理 / 程式開發 / 運維 / 基礎設施
OmniRoute → GLM 5.2

Nora
對外
社群、朋友圈
SearXNG + Firecrawl

Bento
單一用途
營養追蹤
Telegram + SQLite

解決方案是結構性的:為不同的關注點設立不同的 agent。一個系統提示不足以構成邊界。跨領域共用一個 prompt 會讓 agent 的上下文變得可滲透——無論你多麼仔細地撰寫指令,領域之間還是會互相滲透。一個 prompt 可以說「不要混合這些上下文」,但結構性的拆分讓混合變得不可能。

所以我將一個 agent 拆分為三個設定檔,每個都是 Hermes(Nous Research 的開源 agent 框架,作為技術棧的協調器)的一個配置。它們不是獨立的程式,而是不同的角色,擁有不同的工具存取權限,在同一個執行環境上執行。

Norty 是私人的、完整權限的設定檔。負責治理、程式開發、運維、基礎設施。使用 OmniRoute 路由,預設模型為 GLM 5.2,透過 Ollama Cloud Pro 提供。Norty 擁有所有權限,因為 Norty 的範圍是我建構和操作的所有東西。沒有社交上下文,沒有營養邏輯,只有工作。

Nora 是對外的設定檔:社群、朋友圈,工具有限。SearXNG 用於搜尋,Firecrawl 用於網頁爬取。Nora 不是權限較少的 Norty——她是一個獨立的角色,有明確的職責。工具限制就是重點。Nora 不需要基礎設施存取權限,給她反而會造成範圍違規。

Bento 是單一用途的設定檔:營養追蹤。Telegram 介面,SQLite 資料庫。沒有模型路由複雜度,沒有治理規則,沒有社群媒體。Bento 只知道卡路里和巨量營養素,其他一概不知。當 Bento 做出決策時,完全不可能受到運維上下文或寫作風格指南的影響——那些上下文在 Bento 的世界裡根本不存在。Bento 無法洩漏它不包含的東西。

每個設定檔都獲得一組不同的工具集。一個設定檔能存取的工具定義了它能做什麼,而且沒有另外疊加一層權限系統。工具列表就是邊界。這是技術棧第一次撞上兩個結構性障礙:權限——誰能做什麼——以及範圍——防止上下文互相污染。設定檔拆分之所以存在,是因為一個 agent 試圖無所不在,結果到處都不可靠。

三種粒度的記憶

拆分設定檔解決了上下文污染,但浮現了下一個瓶頸:記憶。

單一記憶系統無法服務三種不同的回憶。一個為對話相似度而建的平面嵌入儲存,當被問到「三個月前為什麼做出那個架構決策?」時,會回傳語義上最相似的對話,而那可能是關於完全不同專案的討論,只是用了相似的詞彙。程式碼庫的結構和決策的時間線對它來說是不可見的。失敗不在於它什麼都沒回傳,而是它回傳了看似合理但錯誤的內容。

Agent 需要三種回憶粒度:跨 session 的對話連續性、對程式碼庫的結構理解,以及關於過去決策的時間推理。這些是不同的問題。一個記憶系統無法涵蓋全部。因此技術棧有三個記憶系統,各自對應不同的回憶範圍。

Honcho 處理跨 session 的對話記憶。透過 Docker 自架,基於對等架構,具備辯證推理能力,能回答「我們上週聊了什麼?」它直接與 Hermes 整合,讓每個設定檔在 session 之間有連續性,同時不會在設定檔之間洩漏上下文。對話記憶無法告訴你哪個模組裡有哪個函式,因為它本來就不是設計來做這個的。

Graphify 處理程式碼結構索引。它建立基於圖的程式碼庫知識表示,顯示哪些函式呼叫哪些函式、哪些模組依賴哪些模組、邊界在哪裡。它取代了已棄用的 Codebase-Memory MCP。當程式碼 agent 需要在修改前了解架構時,Graphify 提供那張地圖。但程式碼索引無法重建上週的推理;它知道結構,不知道歷史。

Graphiti 處理時間知識。由 Zep 建構,是一個基於 Neo4j 的雙時間知識圖譜,同時追蹤有效時間(某件事為真的時間)和系統時間(我們得知它的時間)。它填補了其他兩個系統無法觸及的缺口:某個時間點的知識狀態,包括在當時已知的背景下為什麼做出那個決策。但時間知識圖譜無法容納當前的對話上下文。它是為跨時間推理而建,不是為 session 內的連續性。

這不是三個競爭的解決方案。它們是三個系統,對應三種不同的回憶粒度,類似於一個大腦中的短期、長期和程序記憶。每一個之所以存在,是因為單一記憶系統被要求涵蓋全部三種時,回傳的答案看似合理但錯誤。

工具鏈是拓撲,不是列表

一旦設定檔拆分、記憶專門化之後,下一個瓶頸浮現了:工具蔓延。元件的列表不斷增長,包括執行環境、模型、訂閱方案、路由器、協調器、ADE,而把它們列出來卻不說明它們之間的關係,造成了分類混淆。模型不是執行環境,訂閱方案不是路由器,協調器也不是這些東西。問題不再是「技術棧裡有哪些工具?」,而是「什麼連到什麼,以及什麼連?」

以下是所有 agent 層級的元件,按類別和功能分組。

元件類別功能
Claude Code CLI執行環境/CLI主要開發、深度推理、多檔案修改
Kimi Code CLI執行環境/CLI次要、快速修補、外部審查
OpenCode CLI執行環境/CLI供應商無關的開源程式碼 agent(MIT 授權,GitHub 約 165K 星)
Codex CLI執行環境/CLI僅驗證與程式碼審查,稽核路徑
GLM 5.2模型Norty 的預設模型,透過 Ollama Cloud Pro 提供
Kimi K3模型零樣本程式碼模型,透過 Kimi Code CLI 在 Allegro 方案存取
MiniMax M3模型次要輔助,100 萬 token 上下文,透過直接 API 和 OpenCode Go
OpenCode Go訂閱方案每月 10 美元,14 個模型,與所有供應商簽訂 ZDR 協議
Ollama Cloud Pro訂閱方案代管 Ollama 層,提供 GLM 5.2 和開放權重模型
Claude Max 20x訂閱方案每月 200 美元,解鎖 Claude Code
Kimi Allegro訂閱方案每月 99 美元,解鎖 Kimi Code
OmniRoute模型路由器自架於 localhost:20128,依任務和成本路由
Hermes協調器管理設定檔、記憶、排程、多平台閘道
OrcaADE在隔離的 git worktrees 中平行執行 agent,自備 agent CLI
Cortex編輯管線第二個獨立的 OmniRoute 消費者,與 Hermes 不同

類別防止了分類錯誤。OpenCode CLI 是一個免費、MIT 授權的執行環境。OpenCode Go 是一個付費訂閱方案,同一個品牌,但不同類別。OmniRoute 是路由器,不是執行環境。Orca 是 ADE,不是 IDE。模型不是執行環境,訂閱方案不是模型。把它們全部扁平化成一個列表,會失去讓拓撲可讀的資訊。

但類別之所以有趣,是因為它們之間的邊。

經由

經由

產生

產生

產生

直接計費

直接計費

直接計費

MCP 內部

獨立 CLI

GitHub 應用程式

Norty

Hermes

Nora

Bento

OmniRoute

Cortex

GLM 5.2, DeepSeek V4, Kimi K3, ...

Orca ADE

Claude Code
主要

Kimi Code
次要

OpenCode CLI

Anthropic

Kimi Allegro

各家供應商

Codex
僅審查

直接審查

PR 觸發

三個設定檔各自作為 Hermes 的配置執行。當一個設定檔需要模型時,Hermes 呼叫 OmniRoute,後者根據任務和成本選擇供應商和模型。Cortex(驅動這個網站內容工作流程的編輯與雷達管線)是第二個獨立的 OmniRoute 消費者。它不經過 Hermes。Hermes 和 Cortex 是兄弟關係,不是鏈狀。

Orca 將程式碼 CLI 作為平行 agent 在隔離的 git worktrees 中產生。Claude Code 是主要的:深度工作、多檔案專案。Kimi Code 是次要的:快速修補。OpenCode CLI 是供應商無關的備用方案。每個程式碼 CLI 直接呼叫自己的供應商:Claude Code → Anthropic(Claude Max 20x),Kimi Code → Kimi Allegro。這些不經過 OmniRoute 路由。它們是各自訂閱方案下的供應商產品。

Codex 僅用於審查,有三個介面:Claude Code 內部的 Codex MCP 用於 session 內審查、獨立 CLI 用於直接審查、以及由 PR 事件觸發的 GitHub 應用程式。第三個介面值得注意:它是由儲存庫事件觸發的,而不是由技術棧中的任何元件呼叫。一個沒有被任何元件呼叫的審查者,連接到儲存庫事件而不是呼叫圖。

程式碼層級:Claude(主要)> Kimi(次要)> Codex(輔助,僅審查)> MiniMax M3(輔助,廣上下文助手,非日常使用)。

然後是那些非連線,它們和連線一樣重要,因為它們是拓撲設計要防止的錯誤。

OmniRoute 不路由程式碼 CLI。 它們是各自訂閱方案下的供應商產品。OmniRoute 服務的是我建構的東西——透過 Hermes 的設定檔和 Cortex——而不是我購買的東西。

沒有東西呼叫 Orca。 它是一個手動操作的環境,不是自動化鏈中的服務。Orca 向外呼叫,產生 CLI;沒有東西向內呼叫。

不存在 OmniRoute → Orca → Codex 管線。 這三個東西位於不同的層面:一個路由器、一個手動操作的環境、一個審查者。它們不形成鏈。

這個拓撲不是因為我在收集元件而存在的。它是因為工具蔓延迫使我們給出結構性答案。當你同時擁有執行環境、模型、訂閱方案、路由器、協調器和 ADE 時,唯一能把它們理清的方法,就是知道每個東西是什麼、它連到什麼、以及它不連到什麼。IDE 是給你的。ADE 是給你和你的 agent 的。 這就是 Orca 的區別。IDE 承載你的 session。ADE 平行承載多個 agent session,每個都在自己的隔離工作目錄中,各自有自己的執行環境和模型指派。

信任是邊界,不是功能

第四個瓶頸是信任模糊。當本地和代管元件並存,卻沒有明確的邊界時,預設假設會變成「全部私有」或「全部暴露」,而兩者都是錯的。

技術棧橫跨兩個世界。有些元件在本地的 GMKtec NucBox M7 Ultra(一台 AMD Ryzen 7 PRO 6850U 迷你 PC,64GB DDR5)上執行。其他則是代管服務,有自己的政策。邊界不是一個可以切換的功能。它是每個元件所在位置以及它能觸及範圍的結構性屬性。

元件執行位置信任模型
Ollama BGE-M3本地完全私有,僅嵌入,無網路路由
OmniRoute本地(路由器)橋接兩邊,依任務路由到本地或代管
OpenCode Go代管(第三方)依服務而定,已與所有供應商簽署 ZDR 協議
Claude Code代管(Anthropic)依服務而定,受 Anthropic 資料政策規範
Kimi Code代管(Moonshot)依服務而定,受 Kimi 資料政策規範

Ollama BGE-M3 真正在本地執行,處理語義搜尋和程式碼索引的嵌入,沒有網路路由。那就是私有。OpenCode Go 是代管服務。模型推理透過他們的 API 進行,雖然他們已與所有供應商簽署零資料保留協議,但信任模型與本地程序不同。OmniRoute 橋接兩邊:它可以路由到本地的 Ollama 進行嵌入,或路由到代管後端進行推理,取決於任務。技術棧中沒有一概而論的「零資料保留」聲明。每個服務都有自己的政策。重要的是知道哪個是哪個。

信任邊界也在設定檔層級強制執行。每個設定檔的工具集定義了它能存取什麼,而那個工具集就是它的信任邊界。Norty 有完整權限,擁有所有鑰匙,符合其範圍。Nora 只有 SearXNG 和 Firecrawl,對外,沒有基礎設施存取權限。Bento 只有 Telegram 和 SQLite,信任邊界最小,無法存取模型或基礎設施。

對外的存取控制層是一個單一整合的元件:Cloudflare Tunnel 加上 Google SSO,以 Google Workspace 作為身份提供者進行閘控。cloudflared 建立一個對外連線到 Cloudflare 的邊緣,沒有入站埠,沒有在公開介面上監聽。Cloudflare Access 放在前面,只有通過 Google Workspace 認證的身份才能通過。免費方案,最多 50 個使用者。

信任不是一次設定就好的設定。它是在每一層劃定的邊界:元件在哪裡執行、設定檔能存取什麼、以及網路允許什麼進入。技術棧不做一概而論的隱私聲明。它做出明確的邊界,而每個邊界都有理由。

塑造它的三道牆

這個技術棧看起來很複雜。三個設定檔、三個記憶系統、執行環境和路由器與訂閱方案的拓撲、多層次的信任邊界。自然的問題是:為什麼需要這麼複雜?

答案不是個人偏好。而是每個多 agent 設定最終都會撞上的三道結構性障礙。

第一道牆:權限。 誰能做什麼?當一個 agent 有所有權限時,問題很簡單。答案是「所有東西」。但一旦你拆分為設定檔,權限就變成設計問題。Norty 可以部署基礎設施。Nora 不行。Bento 甚至無法存取模型。工具列表就是權限邊界,而且必須透過結構強制執行,而不是透過一個說「不要使用這些工具」的 prompt,而是透過讓使用它們變得不可能的設定。

第二道牆:範圍。 每個 agent 持有什麼上下文?單一 prompt 方法失敗,因為範圍有漏洞。社交上下文洩漏到運維,營養與治理衝突。拆分為設定檔解決了 agent 層級的範圍問題,但浮現了記憶層級的範圍問題:一個記憶系統無法服務三種回憶粒度。範圍不只是讓 agent 彼此分開,而是讓每個元件只持有它需要的上下文,沒有其他。

第三道牆:驗證。 你怎麼知道輸出是正確的?當一個 agent 產生所有東西時,驗證是臨時的。你閱讀輸出並判斷它是否正確。當多個 agent 產生的輸出互相餵入時,驗證需要結構。Codex 作為僅審查路徑存在,與主要程式碼 CLI 分開。拓撲中的非連線——OmniRoute 不路由程式碼 CLI、沒有東西呼叫 Orca、不存在 OmniRoute → Orca → Codex 管線——就是驗證邊界。它們確保寫程式碼的元件不是審查它的元件。

這三道牆直接對應到四個瓶頸。上下文碰撞是範圍問題,領域互相滲透,因為邊界是 prompt 而不是結構。記憶碎片化是不同粒度的範圍問題,一個儲存被要求服務三種回憶。工具蔓延是權限問題,當元件沒有分類、它們的邊不明確時,你不知道誰能存取什麼。信任模糊是權限和驗證問題,沒有本地和代管之間的明確邊界,沒有設定檔範圍的工具存取,你只能猜測什麼是私有的。

這些牆不是 bug。它們是無論你是否承認都存在的限制。技術棧就是當你不再繞過它們,而是開始與它們一起建構時所產生的結果。

這篇文章描述了技術棧。下一篇文章將描述當你正面撞上每道牆時會發生什麼:失敗模式、設計決策,以及當權限、範圍和驗證成為首要關注事項而非事後想法時所浮現的模式。

分享