一切皆外掛:官宣與原始碼對照
發布文裡說的四種模式、外掛生態,在 deepseek-harness 倉庫裡對應哪個檔案?本課一條條對上。
下面的演示把四份外掛清單做成了可切換的面板。點上面四個模式按鈕,看外掛卡片怎麼亮、怎麼滅:綠色是新增,紅色是移除,琥珀色是同名但配置變了。底部字幕會告訴你每一步發生了什麼。先玩明白,後面講的思路都在這塊面板裡演過一遍。
它解決什麼問題。想像你在用一個單體架構的 Agent 產品,想換掉它的會話日誌格式。你得 fork 倉庫,在幾十萬行原始碼裡找到日誌實現,改完重新構建,之後官方每發一版你都要重新合併一次補丁。這還只是日誌這種邊角能力,要是想換 agent loop 主迴圈,基本等於重寫產品。能力和產品原始碼焊死在一起,任何深度客製都會變成長期維護負擔。
思路是什麼。DSH 把核心縮到最小。vendor 進倉庫的 Cordis 框架只做三件事:把外掛裝進共享上下文、把外掛卸下來、把每次註冊記成可逆的副作用,外掛解除安裝時自動回滾。業務邏輯一行都沒有。然後所有能力搬進 packages/,49 個分組、219 個包,全部以外掛形式存在:模型轉接器是外掛,工具是外掛,會話日誌是外掛,連 agent loop 主迴圈本身也是外掛。根 AGENTS.md 第 3 行用加粗英文寫著「everything is a plugin」。官方文件的原話:
Cordis 是 dsh 底層的框架:外掛向共享上下文貢獻服務、型別化事件和可逆的副作用。產品的每一部分都是外掛,包括模型轉接器、工具註冊表、會話日誌,以及 agent loop(智慧體迴圈)本身,因此每一部分都可以從配置替換。
不存在需要打補丁的特權核心:擴充 dsh 的方式是把外掛掛載到其他外掛旁邊,而各項註冊都是副作用,會在其外掛解除安裝時撤銷。
docs/architecture.zh.md · 第 11、13 行想給 DSH 加能力,也不用碰它的倉庫。樹外(out-of-tree,指官方倉庫之外的)外掛用 dsh plugin --profile <name> add <package> 裝進 profile,執行時掛載,解除安裝時註冊的副作用自動回滾。README 還約定外掛倉庫統一打 dsh-plugin 話題標籤,方便互相發現。發布文邀請大家共建生態,機制是現成的。
為什麼長期成立。微核心思想比這份程式碼老得多。作業系統課上的 Mach 和 L4,瀏覽器的擴充套件體系,VS Code 的外掛生態,走的都是同一條路:變化快的能力放外圈,幾乎不變的裝卸機制放核心。DSH 明年把 agent loop 重寫一遍,Cordis 的裝卸邏輯一行不用動;換個語言把整個 harness 再寫一遍,這個分層照樣管用。所以記這門課的結構比記它的程式碼划算,程式碼只是這個思路的某一版實現。
它解決什麼問題。多數產品的模式是硬編碼的:程式碼裡散著一堆類似 if (mode === 'lite') 的分支,模式數量在寫程式碼的那一刻就定死了。想新增一個模式,要改程式碼、過測試、等發版;想微調某個模式裡的一個能力,還是這套流程。使用者更沒得選,只能在官方給的幾個套餐裡挑。
思路是什麼。DSH 裡一個模式就是 apps/cli/config/agent-presets/ 下的一個目錄,目錄裡兩個檔案。preset.yml 只有 3 行,管 UI 上的展示名和排序;agent.cordis.yml 是外掛清單,啟動時 Cordis 照著清單逐行掛載,輸出一個組裝好的 Agent。切換模式就是換一份清單重新組裝,原始碼裡沒有任何模式分支。四種模式的差異,看四張卡就夠了:
標準模式
agent-presets/standard/ · 251 行- 給誰用
- 日常寫程式碼的人,這是預設檔。
- 與其他模式的關係
- 它就是基準:23 個外掛全開(macOS 視角),檔案編輯、shell、檢索、計劃、子代理、工作流都在。其餘三個模式全部描述成對它的加減。
- 背後的思路
- 先定義一個能力齊全的參照系,別的組合才有資格用一句話說清自己。
PTC 模式
agent-presets/code/ · 262 行- 給誰用
- 跑多步長任務、嫌一次一個工具呼叫往返太慢的人。
- 比標準多了什麼少了什麼
- standard 一行不動,末尾多掛一個 tool-presentation,配置
mode: code。模型改寫一段 TypeScript 小程式,run_code 一次執行原本要五次往返的操作。 - 背後的思路
- 改的只是工具的呈現方式,能力本身沒變,所以差異只配擁有一行。
極簡模式
agent-presets/minimal/ · 62 行- 給誰用
- 跑模型基準測試的人。
- 比標準多了什麼少了什麼
- 只剩 6 個外掛。persona 一句話寫死(
complete: true,別的外掛想追加提示詞也加不進去),工具只有持久 bash 和 str_replace_editor,沒有 compaction(上下文壓縮)。 - 背後的思路
- 把 harness 的變數排乾淨,剩下的表現就是模型本身。
創造模式
agent-presets/cordis/ · 262 行- 給誰用
- 想讓 Agent 造 Agent 的人。
- 比標準多了什麼少了什麼
- standard 全套之上加 tool-cordis 工具集、一個教組合寫法的 skill,persona 也換了版本。Agent 能在執行時檢查並掛載自己的外掛,寫出的組合能存成新 preset。
- 背後的思路
- 組裝器自己也是外掛,所以能開放給 Agent 用。檔案頭註釋提醒把這個模式的會話當 shell 權限對待。
順帶點破一個行銷詞。code/preset.yml 第 1 行寫 name: PTC 模式,但目錄叫 code,原始碼註釋和文件裡這套機制叫 Code Mode,全倉庫找不到名為 PTC 的實現。PTC 只活在 UI 文案層,跟人聊原始碼時說 Code Mode 才對得上號。
為什麼長期成立。這條思路有個通行的名字,配置即架構:把系統之間的行為差異收斂進一份宣告式清單,架構問題就降維成文字問題。想知道兩個模式差在哪,diff 兩份 YAML;想造新模式,複製目錄改幾行;出了問題,回滾清單就行。Kubernetes 用 YAML 宣告叢集,Docker 用 Dockerfile 宣告映像,同一個思路在不同層面反覆出現。DSH 的外掛實現哪天全部重寫,清單這層抽象照樣成立。
一切皆外掛的價值放到同行裡才看得清。同一個問題,想給 Agent 加一個新能力,需不需要動它的倉庫原始碼,三家給出三種答案:
DSH:外掛樹
不需要改倉庫能力就是一個樹外 npm 包。dsh plugin --profile <name> add <package> 裝進 profile,執行時掛載,解除安裝時註冊副作用自動回滾。模式級差異也只是 YAML 裡增刪幾行。
出處:packages/bundle/README.zh.md 第 13 行;docs/architecture.zh.md 第 13 行
Claude Code:產品單體
看情況還原原始碼是一棵 TypeScript 單體原始碼樹(restored-src/src/,入口 main.tsx),改內建功能要動產品原始碼。對外留了 hooks、MCP、Skills 這些擴充點,能加工具和攔截點,換不掉會話日誌這類深層實現。基於已公開證據(還原原始碼目錄結構)。
Grok Build:Cargo Workspace
需要改倉庫根 Cargo.toml 的 members 陣列列了 79 個 workspace 成員(本地計數),能力按 crate 切分、編譯期組合。新增能力要新建 crate、改根清單、重新編譯。切分細節見 12-1 · 79 個 Workspace 成員如何組成產品。
三家沒有絕對優劣。Grok 用編譯期組合換 Rust 的型別和效能保證,Claude Code 用單體換產品迭代速度,DSH 用外掛樹換執行時可拔插。只是如果你想要一個可替換、可審計的執行時,DSH 是三家裡唯一讓第三方無需 fork 倉庫就能替換深層能力的。
從清單推演行為差異
把 standard/agent.cordis.yml 裡 id: compaction 的整個 group(第 137 至 155 行)刪掉,得到的會話和極簡模式在上下文壓力下的表現是否等價?再對照 minimal/agent.cordis.yml 的 persona 三個欄位(第 8 至 13 行),說出除了壓縮之外還差哪兩點。