
最近在調研多智能體協作和 AI 編程工作流時注意到一個挺有意思的項目Murmell。它把自己定義為 Collaborative cloud canvas for coding agents也就是“面向編碼代理的協作式云端畫布”。這個定位很有意思它不像傳統 IDE 那樣強調本地編輯也不像聊天窗口那樣只有對話流而是把人和 AI 編碼代理的工作空間抽象成一塊共享畫布所有任務、變更、審查意見都在上面流動。這篇文章會從一個相對系統的角度來拆解這類工具它到底解決什么問題、核心能力有哪些、比較通用化的架構和實現思路是什么以及如果要接入 Claude Code、Codex 這類編碼代理有哪些值得注意的集成方式和坑點。1. 背景與核心概念1.1 什么是 Collaborative Cloud Canvas先解決概念問題。Collaborative Cloud Canvas翻譯過來是“協作式云端畫布”。它本質上是一個運行在云端的、支持多端同步的共享可視化空間這個空間里的所有元素——節點、連線、卡片、評論、狀態標記——都會實時同步給所有參與者。和傳統的“白板類”協作工具不同Murmell 這類畫布的核心參與對象不只是人還包括編碼代理Coding Agent。也就是說它打破了“只能人畫給人看”的限制讓 AI 代理也能在這個畫布上創建節點、推送進度、請求審批甚至留下中間決策的理由。1.2 Coding Agents 是什么Coding Agents 是指能夠自主完成代碼修改、文件讀寫、命令執行、測試運行等任務的 AI 智能體。和普通的代碼補全工具不同Agent 擁有“規劃 - 執行 - 觀察結果 - 再規劃”的循環能力。比如Claude Code在終端中以會話方式執行編碼任務。OpenAI Codex云端沙箱里的編碼代理可以操作倉庫、運行命令。Copilot Workspace以任務為中心生成計劃并提交 PR。這類工具的問題是人和 Agent 交互的界面很割裂。Agent 的輸出通常是日志流人看到的是一串文字Agent 做了什么、改了什么文件、為什么要這么改很難一眼看清。Murmell 想解決的正是這個問題。1.3 它解決什么問題用一個開發場景來理解假設你讓一個編碼 Agent 幫你實現“用戶登錄接口”。Agent 會做這些事情讀取代碼、創建文件、修改路由、寫測試、跑測試。如果所有動作都只出現在終端里作為人類開發者你很難在過程中及時判斷方向對不對。而在 Murmell 這類畫布中Agent 的每個關鍵動作都會變成一個可視節點“讀取了 src/auth/login.ts”“創建了 interfaces/login-payload.ts”“修改了路由配置”“測試通過等待審批”每個節點旁邊可以掛上代碼片段預覽、執行日志、審批按鈕。人工開發者只需要像看一張項目管理圖一樣就能理解 Agent 的完整動作鏈。所以Murmell 解決的問題可以總結為三點讓 AI 編碼過程可視化。讓人類可以低成本地介入、審批和糾偏。讓多個 Agent 或人與 Agent 的協作有一個統一的共享空間。2. 核心能力拆解作為一類產品面向編碼代理的協作畫布通常會包含下面這些核心能力模塊。了解這些模塊有助于理解 Murmell 的設計思路也有助于后續做二次開發或者自建類似系統。2.1 實時畫布渲染畫布不只是“一塊白板”它需要支持多種節點類型、分組、連線甚至支持縮放平移Pan Zoom。節點通常包括任務節點描述一個待辦目標。文件節點展示某個文件或某個代碼片段。審批節點人工審查后才能繼續。狀態節點標記當前 Agent 的執行狀態。評論節點人類或 Agent 留下的備注。2.2 Agent 狀態可視化一個長期運行的編碼任務可能有多個階段規劃中 - 讀取文件 - 生成代碼 - 運行測試 - 等待評審 - 完成畫布需要將這些狀態以可視化方式呈現同時把關鍵動作序列記錄下來。這種“動作流”回放能力對調試 Agent 的行為、定位錯誤決策點非常有價值。2.3 人工介入與指令通道人類開發者需要能在畫布上直接給 Agent 下達指令暫停當前任務。修改某個文件節點的內容。駁回當前的實現方案。追加一條新的約束說明。這就是“Human-in-the-loop”機制。畫布不只被動展示還要能反向控制 Agent。2.4 多會話與歷史回放同一個項目可能同時跑多個 Agent 會話。每個會話在畫布上表現為一組獨立的“圖層”或者“泳道”。同時每次操作都需要有歷史記錄支持回放和審計。2.5 權限與協作邊界當畫布上了云端權限就變得很重要。誰可以看誰可以編輯誰能審批這些都需要通過角色來區分。比如角色查看編輯節點審批控制 Agent開發者????技術負責人????訪客????Agent????3. 架構設計原理如果你想真正跑通一個類似 Murmell 的最小系統核心不是畫布 UI而是“如何把 Agent 的事件流同步到畫布上”。3.1 事件驅動架構畫布上的每一個變化本質上都是一條事件。常見的事件類型{ type: node.create, payload: { id: node_123, kind: task, title: 實現登錄接口, position: { x: 120, y: 200 } } }再比如 Agent 推送一條狀態變更{ type: agent.status.update, payload: { agentId: agent_001, status: running, currentAction: 正在修改 src/auth/login.ts } }這種“事件 畫布對象”的做法可以讓前端只負責渲染代理端只負責產生事件雙方解耦。3.2 狀態同步模型畫布狀態同步有幾種常見方案各有優劣方案優點缺點適用場景全量快照輪詢實現簡單流量大、延遲高低并發小團隊WebSocket 增量事件實時性好需要處理亂序與重連主流實時協作場景CRDT無沖突復制數據類型離線合并且無沖突實現復雜、學習成本高多人同時編輯同一節點Operation Transform經典協作算法需要中心服務器Google Docs 類產品對 Murmell 這類場景實際應用中更推薦“WebSocket 增量事件 服務端存快照”的方案。畫布上很多節點是 Agent 自動產生的人擠人的高頻沖突場景并不多CRDT 反而會讓系統復雜度上升。3.3 Agent 適配層這是理解這類工具最關鍵的模塊。編碼 Agent 通常都有自己的工具調用機制比如Tool Use協議Function CallingMCPModel Context Protocol畫布系統需要把 Agent 的工具調用轉換成畫布事件。舉個例子如果 Agent 調用了read_file工具Agent 調用 read_file(src/auth/login.ts)適配層可以把它轉換成{ type: node.create, payload: { id: file_node_001, kind: file, title: 讀取文件 src/auth/login.ts, content: export async function login() {}, parentId: task_node_001 } }這樣Agent 執行過程中訪問過的每一個關鍵文件都會在畫布上形成一條可視鏈路。3.4 認證與審計因為云端畫布會承載項目源代碼片段和決策過程認證和審計是必須考慮的安全邊界。推薦的安全基線使用 OIDC 或云廠商統一的身份提供商。Agent 接入使用獨立的 API Key最小權限范圍。所有 Agent 操作寫入不可篡改的審計日志。畫布中的代碼內容加密存儲。對敏感倉庫禁止將完整代碼內容同步到畫布只允許同步文件路徑或摘要。4. 最小原型實現方案上面聊了很多概念但空談沒有意義。這一節我提供一個“最小可運行的云端畫布 Agent 事件源”原型實現思路。這里要說明一下下面的實現不是 Murmell 的源碼而是為了幫助你理解同類產品的實現思路用 Node.js WebSocket 寫一個能跑的最小示例。如果你只是使用 Murmell 產品可以跳過這一節如果你打算研究它的架構或者自建類似工具這部分就非常關鍵。4.1 創建項目結構murmell-demo/ ├── package.json ├── server.js ├── agent-worker.js └── public/ └── index.html4.2 初始化項目mkdir murmell-demo cd murmell-demo npm init -y npm install express ws uuid4.3 WebSocket 服務端實現服務端負責兩件事維護畫布狀態把 Agent 產生的事件廣播給所有前端畫布。// 文件server.js const express require(express); const http require(http); const { WebSocketServer } require(ws); const { v4: uuidv4 } require(uuid); const app express(); const server http.createServer(app); const wss new WebSocketServer({ server }); app.use(express.static(public)); // 保存畫布中的節點對象 const canvasState new Map(); function broadcast(message) { const data JSON.stringify(message); wss.clients.forEach(client { if (client.readyState client.OPEN) { client.send(data); } }); } wss.on(connection, (ws) { console.log(畫布客戶端已連接); ws.send(JSON.stringify({ type: canvas.snapshot, payload: Array.from(canvasState.values()), })); ws.on(message, (raw) { try { const msg JSON.parse(raw.toString()); if (msg.type node.create) { const node { id: msg.payload.id || uuidv4(), kind: msg.payload.kind || task, title: msg.payload.title || , content: msg.payload.content || , position: msg.payload.position || { x: 0, y: 0 }, createdAt: Date.now(), }; canvasState.set(node.id, node); broadcast({ type: node.create, payload: node }); } } catch (err) { console.error(消息解析失敗, err.message); } }); }); server.listen(3000, () { console.log(murmell-demo 運行在 http://localhost:3000); });4.4 模擬編碼代理的推送腳本Agent 并不需要知道 WebSocket 細節它只需要向本地端口發送事件。我們可以用一個腳本模擬一個 Agent 先后讀取文件、生成代碼、修改狀態的動作。// 文件agent-worker.js const WebSocket require(ws); const ws new WebSocket(ws://localhost:3000); const sleep (ms) new Promise(resolve setTimeout(resolve, ms)); ws.on(open, async () { console.log(Agent 已連接到畫布服務); await sleep(500); ws.send(JSON.stringify({ type: node.create, payload: { kind: task, title: 實現用戶登錄接口, content: 目標新增 POST /api/login 接口, position: { x: 100, y: 100 }, }, })); await sleep(1000); ws.send(JSON.stringify({ type: node.create, payload: { kind: file, title: 讀取 src/auth/login.ts, content: export async function login() { /* auth 邏輯 */ }, position: { x: 300, y: 200 }, }, })); await sleep(1000); ws.send(JSON.stringify({ type: node.create, payload: { kind: status, title: 測試通過等待人工審批, content: npm test 全部通過共 12 個用例, position: { x: 500, y: 300 }, }, })); console.log(Agent 事件推送完成); });4.5 前端畫布頁面前端渲染層不需要多復雜核心是監聽 WebSocket 事件把它們渲染成畫布上的卡片。!-- 文件public/index.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleMurmell Demo Canvas/title style body { margin: 0; background: #1e1f22; color: #d4d4d4; font-family: sans-serif; } #canvas { position: relative; width: 100vw; height: 100vh; overflow: hidden; } .node { position: absolute; min-width: 180px; max-width: 260px; background: #2d2d30; border: 1px solid #4c4c4e; border-radius: 8px; padding: 12px; font-size: 13px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); } .node h3 { margin: 0 0 6px 0; color: #8dc5e3; font-size: 14px; } .node pre { white-space: pre-wrap; color: #a8a8a8; margin: 4px 0 0 0; } .tag { display: inline-block; margin-top: 8px; padding: 2px 8px; border-radius: 10px; font-size: 11px; color: #fff; } .tag.task { background: #7a5b1f; } .tag.file { background: #4d6b5a; } .tag.status { background: #34567a; } /style /head body div idcanvas/div script const canvas document.getElementById(canvas); function addNode(node) { const div document.createElement(div); div.className node; div.style.left node.position.x px; div.style.top node.position.y px; div.innerHTML h3${node.title}/h3 pre${node.content || }/pre span classtag ${node.kind}${node.kind}/span ; canvas.appendChild(div); } const ws new WebSocket(ws://localhost:3000); ws.onmessage (event) { const msg JSON.parse(event.data); if (msg.type canvas.snapshot) { msg.payload.forEach(addNode); } if (msg.type node.create) { addNode(msg.payload); } }; /script /body /html4.6 運行與驗證開啟兩個終端# 終端 1 node server.js # 終端 2 node agent-worker.js打開瀏覽器訪問http://localhost:3000你會在畫布上看到 Agent 依次創建的三個節點。如果同時打開多個瀏覽器窗口它們會保持實時同步。這個原型雖然簡單但它已經具備了 Murmell 這類工具的核心鏈路Agent 產生事件 - WebSocket 同步 - 畫布實時渲染 - 多端可見。5. 與真實 Coding Agents 的集成思路真實項目里你不會只用一個模擬腳本來推送事件。Murmell 的真正價值是接入真實的編碼代理。這一節討論常見的集成模式。5.1 工具調用攔截模式大多數編碼 Agent 都支持工具調用Tool Use。你可以在 Agent 的工具執行層加一層“事件旁路”也就是在調用read_file、write_file、run_command等工具時額外向 Murmell 畫布推送一條事件。偽代碼思路def on_tool_call(tool_name, payload): if tool_name write_file: canvas.push_event({ type: node.create, kind: file, title: f寫入文件 {payload[path]}, content: payload[content][:200], # 只取摘要避免畫布過載 }) elif tool_name run_command: canvas.push_event({ type: node.create, kind: status, title: f執行命令 {payload[command]}, })這種模式的好處是侵入性低不用改 Agent 的核心邏輯。5.2 審批攔截模式對于需要人工確認的高風險操作比如刪除文件、修改生產配置、批量遷移數據可以通過畫布實現“攔截式審批”。實現思路Agent 在準備執行高風險操作前先向畫布發起一個審批請求節點。畫布顯示“等待審批”狀態。人類開發者點擊“通過”或“駁回”。結果回傳給 AgentAgent 再繼續執行。這種模式在真實場景中很關鍵。比如在自動化代碼遷移或者大規模重構時人工審批點可以顯著降低誤操作風險。5.3 倉庫級會話關聯模式每個畫布會話可以關聯一個 Git 倉庫、一個分支甚至一個具體的 PR。這樣 Agent 產生的每個節點都可以關聯到具體的代碼提交。在這類產品中比較實用的設計是讓每個畫布節點攜帶 Git 元信息{ id: node_456, kind: file, title: 修改 login.ts, repo: code-platform/user-service, branch: feat/login-api, commit: a3f4d5e6f7a8b9c0 }這樣方便回溯這個畫布節點是在哪一次提交、由哪個 Agent 產生的是否經過人工批準。6. 常見問題與排查思路這類云端畫布工具在使用和自建過程中經常會遇到下面這些問題。這里整理成表格方便查閱。問題現象常見原因解決思路畫布一片空白Agent 端沒有連接到服務檢查 WebSocket 連接地址和 Agent 日志節點出現重復Agent 重發同一事件事件寫入采用冪等方式按事件 ID 去重畫布更新有明顯延遲WebSocket 無法連接前端輪詢兜底檢查網絡代理、防火墻確認 WebSocket 路徑Agent 推送大量節點畫布卡頓單次同步節點過多做節點壓縮、分頁加載只渲染可視區域兩個 Agent 同時編輯同一節點內容互相覆蓋客戶端無沖突處理策略增加節點級鎖或改用 CRDT 算法前端顯示狀態和實際 Agent 狀態不一致狀態事件丟失或亂序服務端維護有序事件流前端按 sequence 排序打開多個瀏覽器標簽頁部分頁面不同步重連后未重新拉取全量快照連接建立后先推送 canvas.snapshot6.1 事件丟失問題在 WebSocket 連接不穩定的場景下事件可能丟失。緩解方式服務端為每條事件分配自增序號。客戶端記錄最后一條序號重連后從斷點處補齊。對敏感操作審批、修改文件使用“事件 確認”機制。6.2 節點內容過大Agent 讀取一個大型文件時如果直接把全文推到畫布會導致網絡開銷大、渲染卡頓。比較穩妥的辦法節點只保存文件路徑。開發者在畫布中點擊節點時再按需拉取文件內容。或者只推送文件開頭 N 字節 摘要。6.3 權限邊界模糊如果畫布已經接入了真實代碼倉庫權限失控會直接導致源碼泄露。務必做到訪問畫布必須先通過統一身份認證。Agent 推送的節點遵循“最小內容”原則。內網部署時通過防火墻限制畫布服務端口。所有畫布請求記錄操作者 ID 與 IP。7. 最佳實踐與工程建議7.1 事件模型先于 UI 設計在搭建 Murmell 這類工具時一定要先定義清楚事件模型再寫 UI。建議用 JSON Schema 約束每一種事件類型。事件類型越規范后續接入不同 Coding Agent 時成本越低。7.2 冪等寫入是基本要求Agent 網絡重試、斷線重連很容易導致同一事件被發送兩次。服務端在寫入畫布節點時必須做冪等。常見做法是使用eventId作為唯一鍵重復寫入時直接忽略。7.3 畫布與代碼倉庫分離存儲不要把畫布節點直接存進代碼倉庫。畫布有自己獨立的數據庫代碼倉庫只存儲源碼。這樣可以避免畫布操作污染 Git 歷史也能避免非開發人員誤操作倉庫。7.4 審計日志必須獨立所有 Agent 產生的畫布操作都應該有獨立審計日志。尤其在高權限操作場景比如“允許 Agent 推送代碼到 release 分支”必須能回答四個問題誰哪個 Agent在什么時候、通過哪個會話、做了什么事情。7.5 灰度發布與安全回滾如果你在自建一個面向團隊的工具建議采用“會話級別灰度”方式先讓一個項目組試用再逐步推廣。每個畫布版本都要支持快照回滾避免一次錯誤的狀態變更影響了多個正在運行的 Agent 任務。7.6 對接 Agent 時的協議選擇如果 Agent 已經支持 MCPModel Context Protocol優先通過 MCP 接入畫布。這樣可以避免直接修改 Agent 源碼用一套統一的工具協議把 Agent 能力“暴露”給畫布。目前主流的編碼 Agent 都在往 MCP 方向演進。Murmell 這類 canvas 工具如果做成 MCP Server就可以低成本接入大量支持 MCP 的 Agent這個方向值得重點觀察。8. 對使用者的建議8.1 關注畫布的“人工審批點”在使用 Murmell 時建議把畫布審批點當作任務推進的閥門。不要讓 Agent 連續執行超過 5 個步驟才創建一次審批點。步驟越短、審批越頻繁越容易在早期發現方向性錯誤。8.2 注意畫布中代碼片段的敏感程度畫布可能會保存 Agent 讀取過的代碼片段。務必確認你的代碼倉庫里沒有把明文密碼、密鑰、Token 寫入源碼。如果有接這種畫布工具會加劇敏感信息擴散風險。建議先在團隊里執行一輪密鑰掃描。8.3 小團隊先用輕量模式如果團隊只有 3 到 5 人不太需要一上來就部署一整套權限系統和審計平臺。可以先讓畫布工作在“只讀 審批”模式Agent 產生的節點不能被普通成員編輯所有寫操作統一由負責人完成。這個模式對系統性能的要求低也更容易被團隊接受。編碼代理和人類開發者的協作界面正在從“純終端日志”走向“可視化畫布”。Murmell 這個名字雖然還比較新但它代表的“Collaborative Cloud Canvas”方向很可能就是未來 AI 編程工具鏈條上重要的一環。如果你正在做 Agent 相關工作花點時間研究這類畫布工具的設計思路一定會對如何構建更可控的 AI 編碼流程有新的啟發。