Featured image of post OpenHands 变成了 Agent Canvas!一个自托管的编码 Agent 控制中心,深入源码拆解

OpenHands 变成了 Agent Canvas!一个自托管的编码 Agent 控制中心,深入源码拆解

如果你关注 AI 编码 Agent 的生态,一定听过 OpenHands(原名 OpenDevin)——那个曾经和 Devin 打对台的开源编码 Agent,Star 数一度冲到 30k+。但如果你现在去 github.com/OpenHands/OpenHands 看看,你会发现它已经完全变了

它不再是「一个编码 Agent」,而是一个 Agent 的控制中心——一个叫 Agent Canvas 的自托管 Web 界面,让你在同一套 UI 里运行 OpenHands、Claude Code、Codex、Gemini CLI 等任意 ACP 兼容 Agent,还能切换本地、Docker、云端等多个后端。

这不是一个简单的改名,而是整个产品定位的根本性转型——从「做一个更好的 Devin」变成了「做所有编码 Agent 的指挥中心」。这篇文章从源码出发,拆解 Agent Canvas 的架构设计,并与之前写过的 OpenTagOpenCodeGrok Build 横向对比。

从 OpenDevin 到 Agent Canvas:一个产品的进化

先回顾一下历史。OpenDevin 在 2024 年横空出世,作为 Devin 的开源替代吸引了大量关注。但到了 2026 年,编码 Agent 的赛道已经完全变了——Claude Code 和 Codex 成了主流选择,OpenHands 团队做了一个大胆的决定:不再试图和它们竞争,而是成为它们的统一控制界面

这个决策直接体现在项目的 README 里:

“Agent Canvas turns your coding agents into a self-hosted, always-on engineering team.”

它不再是一个 agent,而是一个 agent 的平台。这个转型和我之前分析的 OpenTag 异曲同工——OpenTag 是 CopilotKit 的聊天 Agent 平台,OpenHands 是编码 Agent 的平台。两个项目在 2026 年 7 月同时走在了「Agent 平台化」的路上。

架构全景:前端 + 后端 + ACP 的三角关系

Agent Canvas 的架构可以拆成三个核心组件:

┌─────────────────────────────────────────────────┐
│  Agent Canvas 前端 (React + TypeScript)          │
│  npm install -g @openhands/agent-canvas          │
│  agent-canvas 命令启动全栈                       │
│                                                   │
│  ┌──────────────┐  ┌──────────────┐              │
│  │  Conversation │  │  Settings    │              │
│  │  · 聊天界面   │  │  · 后端切换  │              │
│  │  · 终端       │  │  · Agent选择 │              │
│  │  · 浏览器渲染 │  │  · 密钥管理  │              │
│  │  · 文件浏览   │  │  · 模型配置  │              │
│  └──────────────┘  └──────────────┘              │
│  ┌──────────────┐  ┌──────────────┐              │
│  │  Automations  │  │  Backends    │              │
│  │  · 定时任务   │  │  · 本地后端  │              │
│  │  · 事件触发   │  │  · Docker    │              │
│  │  · Slack集成  │  │  · VM/云端   │              │
│  └──────────────┘  └──────────────┘              │
└──────────────────┬──────────────────────────────┘
                   │ REST API / WebSocket
                   ▼
┌─────────────────────────────────────────────────┐
│  OpenHands Agent Server (Python)                  │
│                                                   │
│  收到请求 → 根据 agent_kind 选择运行时            │
│                                                   │
│  ┌──────────────┐  ┌──────────────────────┐      │
│  │ OpenHands    │  │ ACP 子进程            │      │
│  │ 原生 Agent   │  │ · npx claude-agent-acp│      │
│  │ Python       │  │ · npx codex-acp       │      │
│  │ LangGraph    │  │ · npx gemini-cli --acp│      │
│  └──────────────┘  └──────────────────────┘      │
│                           │                       │
│                           │ JSON-RPC over stdio   │
│                           ▼                       │
│                    ┌──────────────┐               │
│                    │ LLM Provider  │               │
│                    │ (各自管理)    │               │
│                    └──────────────┘               │
└─────────────────────────────────────────────────┘

这个架构和 Grok Build 的 ACP 集成思路一致——都通过 Agent Client Protocol 来对接外部 Agent。但 Grok Build 是 ACP 的服务端(它实现 ACP 协议让外部客户端连接),而 Agent Canvas 是 ACP 的客户端(它启动 ACP 子进程并消费其服务)。

前端:一个可嵌入的 React 组件库

Agent Canvas 的前端不只是简单的 Web UI,它被设计成一个可嵌入的组件库@openhands/agent-canvas 的 npm 包暴露了:

  • agent-canvas 命令行:启动全栈本地服务
  • 独立应用:完整的 SPA 构建
  • 库入口browserconversationfilessettingssidebarterminali18n 等模块可以直接嵌入到其他应用中

这个设计让我想起 OpenCode 的 Effect TS 多包架构——两者都采用了「核心功能模块化、可独立消费」的设计哲学。但 OpenCode 的模块化是为了运行时扩展(Provider、Auth、Framing 四轴),而 Agent Canvas 的模块化是为了UI 复用(嵌入到不同的宿主应用)。

技术栈方面,Agent Canvas 使用:

  • React 19 + React Router 7 + Vite
  • HeroUI (原 NextUI) 组件库
  • Monaco Editor(代码编辑器)
  • xterm(终端模拟器)
  • Framer Motion(动画)
  • i18next(国际化)
  • Zustand(状态管理)

标准的大型 SPA 技术栈,没有特别激进的技术选择——这和 Nanobot 的 Python asyncio 路线完全不同,Nanobot 在技术栈上更激进(8 状态机、两阶段记忆合并)。

ACP 集成:让 Agent 可插拔

Agent Canvas 最核心的架构决策是通过 ACP 协议支持外部 Agent。在 docs/ACP_AGENTS.md 中,它详细定义了三种 ACP Agent 的接入方式:

提供方 默认命令 认证方式
Claude Code npx -y @agentclientprotocol/claude-agent-acp macOS Keychain / OAuth Token
Codex npx -y @agentclientprotocol/codex-acp codex login / API Key
Gemini CLI npx -y @google/gemini-cli --acp Google OAuth / API Key

每个 ACP Agent 被 Agent Server 以子进程方式启动,通过 JSON-RPC over stdio 通信。Agent Server 管理子进程的生命周期和凭证,Agent Canvas 前端只负责记录「用哪个 Agent」和「需要什么密钥」。

这个设计的关键在于凭证的传递方式——Agent Canvas 把凭证保存为 Agent Server 的全局密钥(LookupSecret),在启动子进程时注入。对于容器化部署,它还支持将 CODEX_AUTH_JSON 等文件型凭证反序列化回文件系统。

对比来看,OpenTag 的「双运行时」设计(TS BuiltInAgent vs Python Deep Agent)也是可替换的 Agent 后端,但 OpenTag 通过 AG-UI 协议来切换,Agent Canvas 通过 ACP 协议来切换。AG-UI 是 Agent-to-UI 协议(关注前端渲染流),ACP 是 Agent-to-Agent 协议(关注工具调用和会话管理),两者定位不同。

多后端架构:打破单机限制

Agent Canvas 的另一个关键设计是多后端架构。一个前端可以连接多个 Agent Server 后端,并在 UI 中一键切换:

┌─────────────────────────────────────────────────┐
│  Agent Canvas 前端                                │
│                                                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐       │
│  │ 本地后端  │  │ Docker   │  │ 云端后端  │       │
│  │ localhost │  │ 容器     │  │ OpenHands │       │
│  │           │  │          │  │ Cloud     │       │
│  └──────────┘  └──────────┘  └──────────┘       │
└─────────────────────────────────────────────────┘

这个设计解决了编码 Agent 的一个核心痛点:隔离性。你可以在本地后端跑日常开发任务(快速、方便),在 Docker 后端跑不确定的代码(安全、隔离),在云端后端跑长时间运行的任务(持久、可靠)。通过同一个 UI 管理所有后端,不需要切换工具。

Automations 系统:让 Agent 跑在事件和定时器上

Agent Canvas 还内置了一个 Automation Server(来自独立的 OpenHands/automation 仓库),支持:

  • 定时执行:每天固定时间运行 Agent 任务
  • 事件触发:GitHub Issue 创建时自动分配、Slack 消息触发
  • 集成:Slack、GitHub、Linear、Notion、Datadog

这个功能和 OpenTag 的 «Intelligence Gateway» 模式类似——两者都试图让 Agent 从「手动启动」变成「自动运行」。但 OpenTag 的自动化依赖 CopilotKit Intelligence 托管服务,而 Agent Canvas 的 Automation Server 是自托管的开源组件。

安全模型

Agent Canvas 在安全方面做了几个设计选择:

  1. Docker Sandbox 模式:默认推荐。Agent 在容器内运行,无法访问宿主文件系统
  2. 无沙箱模式有明确警告npm install -g @openhands/agent-canvas 直接运行的模式会给予 Agent 完全的文件系统访问权限,README 用红色警告标出
  3. ACP 凭证隔离:每个 Agent 的凭证通过 Agent Server 的密钥管理,不在前端持久化(除了 LookupSecret 引用)
  4. 多后端隔离:不同后端之间完全隔离,一个后端的漏洞不会影响其他后端

但和 OpenTag 的安全性分析 类似,ACP 子进程的 stdout/stderr 可能泄露凭证信息——如果 ACP 子进程在日志中打印了 ANTHROPIC_API_KEY,这些日志可能会被 Agent Server 捕获。

三方横向对比

Agent Canvas 在「编码 Agent 平台」这个赛道上,和之前分析过的几个项目既有重叠又有差异:

维度 Agent Canvas OpenTag OpenCode Grok Build
定位 编码 Agent 控制中心 聊天 Agent 平台 编码 Agent 运行时 编码 Agent 运行时
语言 TypeScript (前端) + Python (后端) TypeScript (+ Python 可选) TypeScript (Effect TS) Rust
核心协议 ACP (JSON-RPC stdio) AG-UI (HTTP SSE) HTTP API ACP (服务端)
Agent 运行时 OpenHands / Claude Code / Codex / Gemini CopilotKit BuiltInAgent / Deep Agent 双 Agent (build/plan) MvpAgent + 60+ Tools
UI Web SPA (React) Chat (Slack/Discord/Telegram) CLI CLI
多后端 ✅ 本地/Docker/VM/云端 ❌ 单 Agent URL ❌ 单进程 ❌ 单进程
ACP 支持 ✅ 客户端(消费方) ✅ 服务端(提供方)
自动化 ✅ 定时 + 事件触发 ✅ (Intelligence Gateway)
开源协议 MIT MIT MIT Apache 2.0
部署方式 npm install / Docker / 源码 npm install / Railway bun run Cargo build

核心差异点:Agent Canvas 不写代码,它管理写代码的 Agent。 它更像是一个 IDE 的替代品——不是帮你写代码,而是帮你管理那些帮你写代码的 Agent。

值得关注的设计教训

  1. 产品转型的勇气:从「做一个 Agent」到「管理所有 Agent」,OpenHands 团队在 Claude Code 和 Codex 的夹击下选择了一条更难但更差异化的路。

  2. ACP 生态的成熟:Agent Canvas 支持三种 ACP Agent,每种都有完整的凭证管理和容器化部署方案。这标志着 ACP 协议已经从概念验证进入了生产可用阶段。

  3. 前端即平台@openhands/agent-canvas 的 npm 包同时提供 CLI 工具、独立应用和可嵌入组件库,这种「同源多分发」策略值得借鉴。

写在最后

Agent Canvas 的转型让我看到了编码 Agent 赛道的一个新方向——不是做出更好的 Agent,而是做出更好的 Agent 管理平台。当 Claude Code 和 Codex 已经足够好时,市场需要的不是另一个 Agent,而是一个能把它们整合到一起的「指挥中心」。

Agent Canvas 的架构设计有几个值得参考的点:多后端切换、ACP 凭证管理、Automation 事件驱动——这些都是在构建 Agent 基础设施时迟早会遇到的问题。

GitHub: https://github.com/OpenHands/OpenHands

延伸阅读:

By AI博士 万戈