OpenClaw 深度剖析:一個 Self-Hosted AI 助理平台的技術全貌
OpenClaw 是一個開源的 self-hosted AI 助理平台,主張「在你自己的裝置上、在你習慣的通訊管道裡、按你自己的規則運行 AI」。它不是又一個 ChatGPT wrapper,而是一整套從 Gateway 控制平面、多頻道訊息路由、Agent 執行引擎、Plugin 生態到跨平台 Companion App 的完整架構。本文將以原始碼為依據,深入拆解這個專案的技術全貌。
專案規模
在展開分析之前,先看看數字:
| 維度 | 數值 |
|---|---|
| TypeScript 原始碼(src/) | ~399,000 行 / 2,326 檔案 |
| 測試程式碼 | ~274,000 行 / 1,404 檔案 |
| 擴充套件(extensions/) | ~73,500 行 / 418 檔案 |
| Swift(macOS + iOS) | ~89,000 行 / 497 檔案 |
| Kotlin(Android) | ~14,000 行 / 82 檔案 |
| 內建 Skills | 54+ 個 |
| 支援頻道(built-in + extension) | 20+ 個 |
| Commits | 14,700+ |
這是一個接近 85 萬行程式碼的大型專案,且測試覆蓋率要求 70% 以上(lines / branches / functions / statements,透過 Vitest + V8 coverage)。
核心架構:Gateway 控制平面
OpenClaw 的架構核心是一個 WebSocket 控制平面(Gateway),所有的 Agent、Channel、Client 都透過它進行通訊。這個設計將「路由」與「執行」集中在同一個受信任的 operator boundary 內。
架構概覽
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Telegram │ │ Discord │ │ Slack │
│ Channel │ │ Channel │ │ Channel │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└─────────────────┼─────────────────┘
│ Inbound Messages
┌─────▼─────┐
│ Channel │
│ Router │
└─────┬─────┘
│ Resolve Agent + Session
┌─────▼─────────────────┐
│ Gateway Server │
│ (WebSocket Control) │
│ │
│ ┌──────────────────┐ │
│ │ Session Store │ │
│ │ Event Broadcast │ │
│ │ Auth & Rate │ │
│ │ Limit │ │
│ └──────────────────┘ │
└─────┬─────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Agent │ │ Canvas │ │ Browser │
│ Runtime │ │ (A2UI) │ │ Control │
└───────────┘ └───────────┘ └───────────┘
WebSocket 連線生命週期
Gateway 在 src/gateway/server.impl.ts(這是整個 Gateway 的核心實作,超過 27,000 行)中建立 WebSocket 伺服器。連線流程:
- 客戶端發起 WebSocket 連線
- 分配唯一
connId(UUID),記錄 headers:host、origin、user-agent、x-forwarded-for - Handshake timeout 限制(防止空連線佔資源)
- 透過
attachGatewayWsMessageHandler()掛載訊息處理器 - 客戶端狀態追蹤:
pending→connected→failed(或 closed)
認證機制
Gateway 支援多種認證模式,在 src/gateway/auth.ts 中實作:
- none -- loopback-only 場景,不需認證
- token -- Bearer token 認證
- password -- 密碼認證
- trusted-proxy -- 反向代理信任模式
- tailscale -- Tailscale whois 身分識別
- device-token -- Companion App 裝置配對 token
還有完整的速率限制機制(auth-rate-limit.ts),基於 IP 的 fixed-window rate limiter 防止暴力破解。
事件廣播系統
src/gateway/server-broadcast.ts 實作了事件分發:
broadcastInternal(event, payload, opts?, targetConnIds?):
// 建立 JSON frame: {type: "event", event, payload, seq, stateVersion}
// 序列號碼追蹤(非定向廣播)
// 遍歷所有 clients Set 進行發送
背壓處理(backpressure):
- 偵測慢速消費者:
socket.bufferedAmount > MAX_BUFFERED_BYTES dropIfSlow: true-- 跳過傳送dropIfSlow: false-- 關閉連線(code 1008)
事件還有 scope guard 控制:
exec.approval.requested/resolved→ 需要operator.approvalsscopedevice.pair.requested/resolved→ 需要operator.pairingscope- Admin scope(
operator.admin)可繞過所有限制
Session 管理
Session 是 OpenClaw 的核心狀態單元。每個對話都對應一個 session,session 透過 composite key 識別。
Session Key 格式
{agentId}:{channel}:{accountId}:{chatType}:{peerId}
例如:
main:telegram:default:direct:123456789default:discord:main:channel:987654321main:slack:bot:thread:ts1234567890.thread001
DM Scope 模式
針對私訊(DM),提供四種 scope 模式:
| 模式 | 說明 |
|---|---|
main | 所有 DM 共用一個 session |
per-peer | 每個對話對象一個 session |
per-channel-peer | 按頻道 + 對話對象隔離 |
per-account-channel-peer | 完全隔離 |
持久化
- 儲存格式:
sessions.json在~/.openclaw/agents/{agentId}/sessions/ - Transcript:
{sessionId}-{topic}.jsonl(JSONL 格式,支援串流追加) - Stale lock 清理:30 分鐘閾值
- 安全性:Session ID 驗證拒絕
../、/、\\等路徑穿越字元
多頻道整合架構
OpenClaw 最有野心的設計之一,是它的多頻道架構。支援超過 20 個通訊平台,每個都透過統一的 ChannelPlugin 介面接入。
雙層抽象
系統維護兩層 Channel 定義:
- ChannelDock(輕量級 metadata)
定義在 src/channels/dock.ts,提供路由、設定讀取、allowlist 等共用邏輯,不需要載入完整的 plugin:
type ChannelDock = {
id: ChannelId;
capabilities: ChannelCapabilities; // chatTypes, nativeCommands, blockStreaming
outbound?: { textChunkLimit?: number };
config?: { resolveAllowFrom, formatAllowFrom, resolveDefaultTo };
threading?: { resolveReplyToMode, buildToolContext };
// ...
};
- ChannelPlugin(完整實作)
每個頻道的完整整合,包含 config adapter、security adapter、gateway adapter、outbound adapter、pairing adapter 等:
type ChannelPlugin<T> = {
config: ChannelConfigAdapter<T>;
security?: ChannelSecurityAdapter;
gateway?: { startAccount: (ctx) => Promise<void> };
outbound?: ChannelOutboundAdapter;
pairing?: ChannelPairingAdapter;
threading?: ChannelThreadingAdapter;
// ...
};
內建頻道
| 頻道 | 文字分塊上限 | 特殊能力 |
|---|---|---|
| Telegram | 4,000 chars | 原生 /command、Channel 類型 |
| Discord | 2,000 chars | Guild + Role 路由、按鈕互動 |
| Slack | 4,000 chars | Thread 支援、Workspace 路由 |
| Signal | 4,000 chars | E2E 加密(via signal-cli) |
| iMessage | 4,000 chars | macOS only(via BlueBubbles) |
| 4,000 chars | Web 版整合(Baileys SDK) | |
| IRC | 350 chars | 最小文字塊限制 |
| Google Chat | 4,000 chars | Workspace 整合 |
擴充頻道(Extensions)
透過 Plugin SDK 實作的外部頻道,以獨立的 workspace package 形式存在:
- MS Teams (
extensions/msteams/) - Matrix (
extensions/matrix/) - Zalo (
extensions/zalo/) - Feishu/Lark (
extensions/feishu/) - Mattermost (
extensions/mattermost/) - LINE (
extensions/line/) - Nostr (
extensions/nostr/) - Twitch (
extensions/twitch/) - Nextcloud Talk (
extensions/nextcloud-talk/) - Voice Call (
extensions/voice-call/)
Plugin 開發者只需實作 ChannelPlugin 介面:
const plugin = {
id: "matrix",
name: "Matrix",
register(api: OpenClawPluginApi) {
api.registerChannel({ plugin: matrixPlugin });
}
};
DM 配對安全模型
OpenClaw 預設啟用 pairing-based DM policy:陌生發送者必須通過配對才能與 bot 對話。
配對流程:
- 陌生人發送訊息 → bot 生成 8 字元配對碼(
ABCDEFGHJKLMNPQRSTUVWXYZ23456789,排除易混淆字元) - 配對碼透過
crypto.randomInt()生成,最多 500 次嘗試確保唯一 - 配對碼有效期 1 小時,每個頻道最多 3 個 pending 碼
- operator 在其他管道核准配對碼 → 發送者加入
allowFrom清單 - 原子檔案鎖確保沒有 race condition
訊息路由
src/routing/resolve-route.ts 實作了多層級的 binding 路由:
優先順序(由高到低):
- Peer binding -- 直接指定某對話對象走某 agent
- Parent peer binding -- Thread 繼承父訊息的路由
- Guild + Roles -- Discord 伺服器 + 角色組合
- Guild binding -- Discord 伺服器級別
- Team binding -- Slack workspace / Teams 級別
- Account binding -- 帳號級別預設
- Channel binding -- 頻道級別預設
- Default -- 預設 agent
AI Agent 系統
多 Provider 抽象
src/providers/ 抽象了多個 AI 模型供應商:
- Anthropic Claude(推薦,原生整合)
- OpenAI GPT-4o / o1
- Google Gemini
- GitHub Copilot(OAuth 認證)
- Qwen Portal
- Mistral、Groq、DeepGram
- 本地模型(via node-llama-cpp)
Provider 選擇採用 Auth Profile 機制:
// 多 profile 認證,帶 fallback 排序和 cooldown
authProfiles: [
{ provider: "anthropic", apiKey: "sk-..." },
{ provider: "openai", apiKey: "sk-..." }, // fallback
]
當某個 provider 認證失敗時,自動 cooldown 並切換到下一個。
Plugin 系統
OpenClaw 的 Plugin 系統是整個平台可擴充性的基礎:
三種 Plugin 來源:
- Bundled -- 隨 OpenClaw 核心一起發佈(
src/plugins/) - Managed -- 從 npm 安裝到
~/.openclaw/plugins/managed/ - Workspace -- 使用者在 Agent workspace 的
.plugins/目錄自建
Plugin 載入機制:
- 使用
jiti進行 TypeScript 的動態 import,不需要預先 build - Registry 層級快取,以 workspace + plugin config hash 為 key
- Plugin SDK alias 解析(
openclaw/plugin-sdk)
Plugin 能力:
- CLI 指令擴充
- Gateway 請求處理器
- 自訂 Agent 工具(ToolFactory)
- 生命週期 Hook
- 記憶體插槽
- Config schema 驗證(Zod)
Memory 系統
src/memory/ 實作了混合搜尋記憶體:
- 向量搜尋 -- sqlite-vec 擴充(1536 維 embeddings)
- 全文搜尋 -- SQLite FTS5(BM25 排序)
- 混合搜尋 -- 結合兩者結果,以 MMR(Maximal Marginal Relevance)重新排序
Embedding 供應商支援 OpenAI ada-002、Gemini、Voyage、Mistral、本地模型,且有自動 fallback。
記憶體來源:
- 明確指定的目錄(例如
~/.notes/) - Session 歷史(JSONL)
- 支援時間衰減加權
Skills 生態系統
OpenClaw 內建 54+ 個 Skill,涵蓋:
| 類別 | Skill 範例 |
|---|---|
| 系統整合 | apple-notes、apple-reminders、bear-notes、things-mac |
| 訊息 | discord、slack、voice-call |
| 開發工具 | coding-agent、github、gh-issues |
| AI / LLM | gemini、openai-image-gen、openai-whisper |
| 生產力 | notion、obsidian、trello |
| 基礎設施 | clawhub、mcporter、model-usage |
此外還有 ClawHub(clawhub.ai)作為社群 Skill 發布平台。
Canvas / A2UI
Canvas 是 OpenClaw 的互動式視覺工作區,使用 A2UI(Anthropic UI)框架:
- HTTP + WebSocket 雙協定伺服器
- 路徑:
/__openclaw__/canvas/(HTTP)、/__openclaw__/ws(WebSocket) - 支援 Live Reload 開發模式
- 沙箱式檔案解析,限制在 root directory 內
Browser Automation
基於 Playwright 的瀏覽器自動化:
- CDP(Chrome DevTools Protocol)橋接
- 角色式元素選擇(role-based,比 XPath 更穩定)
- 操作:點擊、雙擊、懸停、拖曳、表單輸入、截圖
- 進階功能:元素高亮、頁面狀態觀察、網路活動監控、檔案下載攔截
- Chrome Extension 注入(Manifest v3)
Voice / TTS
多供應商 TTS 整合:
| 供應商 | 模型 | 特色 |
|---|---|---|
| OpenAI | gpt-4o-mini-tts | alloy、echo、nova 等 6 種聲音 |
| ElevenLabs | 多語言模型 | stability / similarity boost 調整 |
| Microsoft Edge TTS | Neural 聲音 | 支援語言/地區選擇 |
輸出格式會根據頻道自動適配(Telegram 用 Opus voice note、預設 MP3)。
Agent Client Protocol(ACP)
OpenClaw 實作了 ACP 協定,讓 IDE 和外部工具能透過標準化介面驅動 Agent:
# 在 Gateway 上啟動 ACP bridge
openclaw acp --url wss://gateway-host:18789 --token <token>
ACP 到 Gateway 的映射:
prompt→chat.sendcancel→chat.abortlistSessions→sessions.list
Session 映射:
- 預設
acp:<uuid>隔離 session - 可自訂
--session agent:main:main指向特定 agent
支援 Zed Editor 整合:
{
"agent_servers": {
"OpenClaw ACP": {
"type": "custom",
"command": "openclaw",
"args": ["acp"]
}
}
}
跨平台 Companion App
OpenClaw 不只是一個 CLI 工具,它有完整的跨平台 App 生態。
macOS Menu Bar App(Swift)
- 使用 Swift
@Observable框架的現代 SwiftUI 架構 - 連線模式:
unconfigured→local(loopback)→remote(SSH / WebSocket) - Config File Watcher 監控
~/.openclaw/config.json變動,自動套用 - Voice Wake 語音喚醒(觸發詞:Claude、Computer、Jarvis、自訂)
- 透過
LaunchdManager管理 launchd daemon
iOS App(Swift)
最有趣的是 iOS 的 雙 Gateway Session 設計:
┌──────────────────┐
│ iOS App │
│ (Single Process)│
└────────┬─────────┘
│
┌────┴────────────────────────┐
│ │
▼ ▼
Node Session Operator Session
(device capabilities) (chat, talk mode)
- Camera - Message send/recv
- Location - Voice wake sync
- Screen record - Config updates
- SMS
Node Session 負責裝置能力(相機、定位、螢幕錄影、SMS),Operator Session 負責對話和設定。兩者獨立運作,chat 不會被 device 操作阻塞。
裝置能力透過 NodeCapabilityRouter 路由到平台 handler:
- CameraHandler、ScreenHandler、LocationHandler、SmsHandler
- CalendarHandler、ContactsHandler
- A2UIHandler(Canvas 互動 UI)
Android App(Kotlin)
與 iOS 類似的架構,但使用 Kotlin Coroutine + StateFlow:
NodeRuntime中央協調器GatewayDiscovery透過 mDNS 掃描區域網路上的 Gateway- Foreground Service 維持背景語音操作(Android API 31+ 要求)
- 安全儲存:
SecurePrefs+DeviceAuthStore
通訊協定
所有 Companion App 與 Gateway 之間使用版本化的 WebSocket 協定(目前 v3):
Handshake 流程:
- Client 發送
ConnectParams(min/max protocol version、client metadata、capabilities) - Server 回應
HelloOk(negotiated version、features、initial snapshot、canvas host URL)
Frame 格式:
// Request
{ type: "request", id: "uuid", method: "chat.send", params: {...} }
// Response
{ type: "response", id: "uuid", ok: true, payload: {...} }
// Event (server-initiated)
{ type: "event", event: "agent.stream", payload: {...}, seq: 42 }
CLI / TUI
- CLI:完整的指令系統(
src/cli/),支援 channel 管理、browser 控制、model 設定、skill 管理 - TUI:使用
@mariozechner/pi-tui的終端 UI,支援多行輸入、語法高亮、slash command、bash mode(!prefix)
Web UI
基於 Lit Element 的 Web 介面:
- Vite + Lit(Custom Elements)架構
- Legacy decorators(
@state()、@property()) - WebSocket 即時連線 + 自動重連
- 回應式設計
Daemon 與部署
跨平台 Daemon
| 平台 | 服務類型 | 管理指令 |
|---|---|---|
| macOS | LaunchAgent(launchd) | launchctl |
| Linux | systemd user service | systemctl --user |
| Windows | Scheduled Task | schtasks |
macOS 生成 .plist(~/Library/LaunchAgents/ai.openclaw.gateway.plist),設定 KeepAlive 自動重啟。Linux 生成 ~/.config/systemd/user/openclaw-gateway.service。
Docker 部署
# docker-compose.yml
services:
openclaw-gateway:
image: openclaw/openclaw:latest
ports:
- "18789:18789" # Gateway
- "18790:18790" # Bridge
volumes:
- ~/.openclaw:/home/node/.openclaw
command: gateway --bind lan --port 18789
restart: unless-stopped
安全加固:
- 以非 root 使用者(
node)執行 - 支援
--read-only+--cap-drop=ALL - 支援 Fly.io 部署(
fly.toml已包含)
安全模型
OpenClaw 的安全模型是 personal assistant(單一受信任 operator),而非多租戶系統。
信任邊界
- 通過 Gateway 認證的呼叫者被視為受信任的 operator
- Session ID 是路由控制,不是使用者級別的授權邊界
- 建議每個使用者一台主機 / 一個 Gateway
- 插件在 Gateway 進程內執行,視為受信任程式碼
防禦措施
- SSRF 防護:URL 提取時驗證 hostname / IP,阻擋內網存取
- 路徑沙箱:Canvas 檔案解析限制在 root directory 內
- 速率限制:ACP session 建立、auth 嘗試都有 fixed-window limiter
- Prompt 大小限制:2MB 上限(DoS 防護)
- Exec 審批系統:工具執行可要求 operator 核准
工具與檔案系統硬化
tools:
exec:
applyPatch:
workspaceOnly: true # apply_patch 限制在 workspace 內
fs:
workspaceOnly: true # 檔案操作限制在 workspace 內
技術棧總覽
| 層級 | 技術選擇 |
|---|---|
| Runtime | Node.js 22+(Bun 亦支援) |
| 語言 | TypeScript(ESM、strict typing) |
| 建構 | tsdown(build)、Vitest(test)、Oxlint + Oxfmt(lint/format) |
| 套件管理 | pnpm(monorepo workspace) |
| Schema 驗證 | Zod 4 |
| HTTP | Express 5 |
| WebSocket | ws |
| 資料庫 | SQLite(FTS5 + sqlite-vec) |
| 瀏覽器自動化 | Playwright |
| macOS / iOS | Swift + SwiftUI + @Observable |
| Android | Kotlin + Jetpack Compose + Coroutine |
| Web UI | Lit Element + Vite |
| 文件 | Mintlify |
| CI/CD | GitHub Actions |
| 部署 | Docker / Fly.io / launchd / systemd |
設計哲學
從原始碼和 VISION.md 中,可以提煉出幾個核心設計哲學:
1. Terminal-First
OpenClaw 刻意選擇終端優先的設計,讓使用者在設定時能明確看到認證、權限、安全態勢。他們不想用「便利的包裝」隱藏關鍵的安全決策。
2. 為什麼選 TypeScript
官方解釋是:OpenClaw 本質上是一個 編排系統(orchestration system)-- prompts、tools、protocols、integrations。TypeScript 廣為人知、迭代快速、容易閱讀和修改。這是一個務實的選擇。
3. 核心精簡、擴充外掛
Plugin 系統的設計原則是:核心保持精簡,可選能力透過 plugin 發佈。新 skill 應該先上 ClawHub,不是直接加到核心。Plugin 進入核心的門檻刻意設得很高。
4. MCP 橋接而非原生
OpenClaw 透過 mcporter(外部工具)支援 MCP,而非在核心中實作 MCP runtime。這讓 MCP 整合保持彈性和解耦,減少 MCP 頻繁變動對核心穩定性的衝擊。
5. 單使用者信任模型
這是一個重要的架構決策:OpenClaw 不做多租戶隔離。每個 Gateway 對應一個受信任的 operator。如果需要多使用者,就用多個 Gateway。這大幅簡化了安全模型,但也意味著它不適合作為 SaaS 平台。
訊息處理的完整流程
最後,用一張流程圖總結一條訊息從進入到回覆的完整路徑:
使用者在 Telegram 發送訊息
↓
Telegram Webhook 接收
↓
解析 MsgContext(提取 sender、chatType、text、media、thread info)
↓
DM 安全檢查(pairing policy → allowFrom 驗證)
↓
路由解析(binding 優先級:peer → guild+role → account → channel → default)
↓
Session Key 生成(main:telegram:default:direct:123456789)
↓
Agent 處理
├─ Link 提取 + SSRF 驗證
├─ Media 理解(Gemini / OpenAI / Anthropic)
├─ Memory 搜尋(hybrid vector + keyword)
└─ Model 選擇(auth profile fallback chain)
↓
工具執行(browser、TTS、bash、custom plugin tools)
↓
回覆生成(LLM prompt + tools)
↓
文字分塊(按頻道限制:Telegram 4000 / Discord 2000 / IRC 350)
↓
Outbound 遞送(plugin adapter → channel SDK)
↓
Threading 裝飾(reply-to mode、cross-context prefix)
↓
使用者收到回覆
結語
OpenClaw 展現了一個 self-hosted AI 助理平台可以走多遠。它不只是一個 chatbot framework,而是一個完整的作業系統級別的 AI 整合層 -- 從底層的 WebSocket 控制平面、到中間的多頻道路由和 Agent 編排、到上層的跨平台 Companion App。
幾個值得技術團隊參考的設計亮點:
- ChannelDock 雙層抽象 -- 將輕量 metadata 和完整 plugin 分離,讓路由邏輯不需要載入所有頻道的完整程式碼
- Binding-based 路由 -- 支援從 peer level 到 channel level 的多層級路由,配合 DM scope 實現彈性的 session 隔離
- Auth Profile 帶 cooldown 的 fallback chain -- 多 provider 切換時的可靠性保證
- Hybrid Memory Search -- 向量搜尋 + 全文搜尋 + MMR re-ranking 的實用組合
- Dual Gateway Session(iOS/Android) -- 裝置能力和對話分離,不互相阻塞
當然,85 萬行程式碼的專案也帶來挑戰:Gateway 核心的 server.impl.ts 超過 27,000 行(雖然專案指南建議 500-700 行),文件散落在多個位置。但從工程成熟度來看 -- 70%+ 測試覆蓋率、完整的 CI/CD、Cross-platform 支援、活躍的社群 -- 這是一個值得認真對待的開源專案。