ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Dr. Claw系统架构解析:React、Express、WebSocket三层协同与多Agent流式调度原理

Dr. Claw系统架构解析:React、Express、WebSocket三层协同与多Agent流式调度原理

【免费下载链接】dr-claw

A Super AI Lab with massive AI Doctors as Assistants. Best IDE for Research via AI Power.

项目地址:https://gitcode.com/gh_mirrors/dr/dr-claw
点击查看免费下载

Dr. Claw 是一款开源的全栈 AI 科研工作台,支持 Claude Code、Codex、Gemini CLI、OpenRouter 等多家 AI 引擎协同工作。它的系统架构采用经典的 React 前端 + Express 后端 + WebSocket 实时通道三层设计,并通过统一的多 Agent 流式调度层实现 7 种 AI 引擎的并行会话管理。本文将带你完整梳理这套架构的分工与数据流。

三层架构总览:各司其职

Dr. Claw 的架构可以概括为"一个入口、三条通道":

层核心技术职责关键入口
前端React 18 + Vite + TailwindCSS聊天、研究看板、技能库、Git 面板等 UIsrc/App.tsx
后端Express + SQLite (better-sqlite3)REST API、认证、项目管理、技能路由server/index.js
实时层ws (WebSocket)AI 流式输出、终端转发、会话状态同步server/index.js

三者通过同一个 Node.js 进程协同:Express 负责"请求-响应"类操作(登录、项目列表、Git 提交),WebSocket 负责"长连接流式"操作(AI 逐字输出、终端输入输出),前端通过 React Context 把两条通道统一封装给组件使用。

React 前端层:Provider 嵌套与懒加载

前端入口 src/App.tsx 只有一棵简洁的 Provider 树:

I18nextProvider → ThemeProvider → AuthProvider → ProtectedRoute → AuthenticatedWorkspace

这种嵌套保证了国际化、主题、认证状态在所有页面共享。工作区 src/components/app/AuthenticatedWorkspace.tsx 再叠加WebSocketProvider、TaskMasterProvider并挂载路由,整个工作区组件本身也是懒加载的,配合 src/utils/lazyWithRetry.tsx 的失败重试机制,首次打开速度明显更快。

WebSocket 连接管理的关键设计

<src/contexts/WebSocketContext.tsx> 是前端实时通信的核心,有三个值得学习的设计:

  1. 带 Token 的握手:连接 URL 携带 JWT(/ws?token=...),HTTPS 环境下自动升级为wss:,见 buildWebSocketUrl;
  2. 消息队列防丢失:AI 流式输出时消息到达极快,React 状态更新可能跟不上。前端用一个messageQueueRef队列 +setTimeout逐条"排水"(drain),保证每条消息都能触发一次渲染,见 drainQueue;
  3. 断线重连与连接去重:维护retryCountRef指数退避重连,并在onopen中校验wsRef.current是否为最新 socket,避免半开连接泄漏。

会话历史加载则在 src/components/chat/hooks/useChatSessionState.ts 中实现了 LRU 消息缓存(最多缓存 10 个会话),切换会话标签时秒开,这是"多会话并行"体验的关键。

Express 后端层:路由、认证与本地存储

后端入口 server/index.js 在单进程内挂载了 20 多个 REST 路由,覆盖项目管理、Git、MCP、技能、模型、计算节点、新闻等模块:

app.use('/api/projects', authenticateToken, projectsRoutes); app.use('/api/git', authenticateToken, gitRoutes); app.use('/api/skills', authenticateToken, skillsRoutes); app.use('/api/models', authenticateToken, modelsRoutes); app.use('/api/agent', agentRoutes); // 对外 Agent API

所有/api/*路由先经过validateApiKey,再叠加 JWT 中间件authenticateToken,认证逻辑集中在 server/middleware/auth.js。

数据存储选用本地SQLite(better-sqlite3),数据库初始化与迁移逻辑在 server/database/db.js,支持通过DATABASE_PATH环境变量自定义位置,并内置旧库自动迁移。

另一个亮点是文件监听驱动的会话同步:后端用 chokidar 监听~/.claude/projects、~/.codex/sessions等各引擎的会话目录(见 PROVIDER_WATCH_PATHS),任何 AI 工具在外部产生的新会话文件都会触发防抖广播,让 Web 端侧边栏"无刷新"更新——这正是 Dr. Claw 能统一管理多家 AI 工具会话的基础。

WebSocket 层:一条通道服务三类流量

Dr. Claw 只创建了一个WebSocketServer(server/index.js),但通过消息类型(type字段)在同一连接上区分三类流量:

流量类别典型消息类型用途
AI 会话claude-command、codex-command、gemini-command、abort-session发起/中止各引擎对话
终端init、input、resizenode-pty 伪终端双向转发
状态同步check-session-status、get-active-sessions、telemetry-settings查询活跃会话、埋点开关

连接建立前会执行verifyClient校验 JWT,未认证的连接直接被拒绝(authenticateWebSocket)。所有在线客户端保存在connectedClients集合中,项目/会话变更时向全体客户端广播,实现多标签页、多设备实时同步。

多Agent流式调度:一套管道接入7种AI引擎

这是 Dr. Claw 架构中最值得拆解的部分。每种 AI 引擎对应一个独立的会话模块,但都遵循同一个接口契约——启动函数(command, options, ws):

AI 引擎调度模块接入方式
Claude Codeserver/claude-sdk.jsClaude Agent SDK(原生,无子进程)
Cursorserver/cursor-cli.jsCLI 子进程
Codexserver/openai-codex.jsCodex SDK
Geminiserver/gemini-cli.js / server/gemini-api.jsCLI 或 REST API 双通道
OpenRouterserver/openrouter.jsREST API
本地 GPUserver/local-gpu.js本地推理
Nano Claudeserver/nano-claude-code.js轻量内置引擎

流式输出的"三段式"处理

以 Claude 通道为例(server/claude-sdk.js),调度流程非常清晰:

  1. 捕获会话 ID:首条消息带回session_id,前端随即收到session-created事件,侧边栏立即出现新会话;
  2. 逐条转发:for await (const message of queryInstance)异步迭代器消费引擎输出,每条消息经transformMessage归一化后,以claude-response类型写入 WebSocket,前端逐字渲染;
  3. 收尾事件:回合结束时发送token-budget(Token 用量统计)和claude-complete(含退出码),后台清理任务用Promise.allSettled延后执行,不阻塞 UI 收尾。

这套"会话创建 → 流式转发 → 完成事件"的协议对 7 种引擎完全一致,前端因此无需为不同引擎写不同逻辑——换引擎就像换频道,UI 无感知。

双通道输出:WebSocket 之外还有 SSE

除了浏览器端的 WebSocket,Dr. Claw 还通过 server/routes/agent.js 暴露POST /api/agentREST 接口:外部脚本可以用 API Key 触发任意引擎,通过SSE(Server-Sent Events)接收流式结果,甚至自动创建 Git 分支和 Pull Request。SSEStreamWriter与 WebSocket 的send接口签名一致,因此同一套引擎代码可以无缝服务两种传输方式。

一条消息的完整旅程

把三层串起来,你发出一条消息后发生的事情是:

  1. 前端:聊天组件调用sendMessage({type: 'claude-command', command, options}),经WebSocketProvider发出;
  2. 鉴权:后端verifyClient在握手阶段已校验 JWT,消息直接进入分发器;
  3. 调度:分发器按type前缀路由到对应引擎模块(claude-command→queryClaudeSDK),并启动流式消费循环;
  4. 回流:引擎输出逐条转换为claude-response,经connectedClients精准回发给发起方,同时向其他在线客户端广播会话状态变更;
  5. 落盘:会话索引通过recordIndexedSession写入本地 SQLite(server/utils/sessionIndex.js),历史消息仍保留在引擎原生存储(如~/.claude/projects),由文件监听器兜底同步;
  6. 渲染:前端消息队列逐条排水,React 组件流式渲染文本、工具调用与 Token 预算。

架构要点速查

  • 单进程多通道:Express 与 WebSocketServer 共享一个 Node 进程,状态(活跃会话表、客户端集合)无需跨进程同步,架构简单且低延迟;
  • 传输无关的引擎接口:send()/end()/setSessionId()三个方法构成"writer 契约",WebSocket、SSE、响应收集器(ResponseCollector)都是它的适配器;
  • 前后端解耦的状态同步:REST 管 CRUD,WebSocket 管实时,文件监听管外部工具产生的会话,三管齐下保证任意入口的状态最终一致;
  • 桌面端零改造:Electron 主进程(electron/main.mjs)只是把这套 Node 服务作为子进程拉起并加载到 BrowserWindow,同一套代码同时服务于浏览器、PWA 与桌面应用。

对新手而言,Dr. Claw 的代码库是一个极佳的学习样本:想学 React Context 与懒加载,看 src/contexts/;想学 Express 路由与 JWT 鉴权,看 server/routes/;想学 WebSocket 流式协议设计,重点精读 server/index.js 的消息分发器和 server/claude-sdk.js 的调度循环即可。

【免费下载链接】dr-claw

A Super AI Lab with massive AI Doctors as Assistants. Best IDE for Research via AI Power.

项目地址:https://gitcode.com/gh_mirrors/dr/dr-claw
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进