OpenHands Agent Canvas:自托管编码 Agent 控制中心的安装、运行与架构解析
OpenHands Agent Canvas 是一个自托管的开发者控制中心,用于在同一界面上启动、切换和自动化多个编码 Agent(OpenHands、Claude Code、Codex、Gemini 等),支持本地、Docker 沙箱与云端后端的灵活部署。本文基于仓库根目录 README.md 展开,覆盖三种安装方式的完整命令、CLI 参数与环境变量、Docker 镜像的内部服务路由,并结合源码给出端口、版本与调用链的实现证据。读完后可独立完成从笔记本快速试用到 VM 上长期运行的完整部署。
定位:把编码 Agent 变成常驻工程团队
Agent Canvas 的核心价值在于把分散的编码 Agent 收敛到一个自托管的控制中心:
- 开箱即运行开源的 OpenHands Agent,也可驱动任意第三方 Agent(Claude Code、Codex、Gemini CLI 等任何兼容 ACP 协议的 Agent);
- 默认在本地机器上运行,但可连接多个「Agent 后端」(agent backend),例如把 Agent 放进 Docker 容器、虚拟机或公司自有基础设施中执行;
- 支持创建自动化(automations),例如定时生成报告并发布到 Slack,或把 GitHub Issue 自动拆解为任务;
- 支持「自带模型」(bring your own model)与跨后端切换,本地、远程、云后端可在同一前端间无缝切换。
这一能力在 package.json 中也有体现:npm 包名为 @openhands/agent-canvas(当前版本 1.16.0),同时暴露了 agent-canvas 可执行入口(bin/agent-canvas.mjs)、独立应用构建产物,以及 browser、conversation、files、settings、sidebar、terminal、i18n 等库式入口,说明它既可作为独立应用自托管,也可作为组件嵌入其他宿主应用(对应 docs/architecture.md 中的「Runtime modes / Packaging」部分)。
快速开始:三种安装方式
README 给出三种等价的部署路径,分别对应不同安全边界。选择的核心判据是:是否允许 Agent 直接访问宿主机文件系统。
方式一:无沙箱直跑(npm 全局安装)
注意:该模式让 agent-server 直接运行在安装目标机器上,Agent 将获得对文件系统的完全访问权限,仅在可信环境使用。
前置条件:Node.js 22.12.x 或更高版本(package.json 中 engines.node 要求 >=22.12.0),以及 uv(用于通过 uvx 拉取 Python 侧的 agent-server)。
npm install -g @openhands/agent-canvas
agent-canvas
agent-canvas 命令默认启动完整本地栈。如果希望把各部分拆开单独运行:
agent-canvas --frontend-only # 仅静态前端 + ingress 代理
agent-canvas --backend-only # 仅 agent server + automation backend + ingress 代理
方式二:Docker 沙箱(推荐用于个人机器)
前置条件:
- Docker:macOS/Windows 用 Docker Desktop,Linux 用 Docker Engine/Docker Desktop;
- 一个作为
PROJECTS_PATH的宿主机目录,存放希望 Agent 访问的项目文件夹,需在启动容器前创建。
macOS / Linux:
export PROJECTS_PATH="$HOME/projects" # 存放项目文件夹的目录
mkdir -p "$PROJECTS_PATH" "$HOME/.openhands"
docker run -it --rm \
-p 8000:8000 \
-v "$HOME/.openhands:/home/openhands/.openhands" \
-v "${PROJECTS_PATH}:/projects" \
ghcr.io/openhands/agent-canvas:1.16.0
Windows(PowerShell)等价命令见 README.windows.md,要点是 docker pull 后使用 Join-Path 构造路径,并以反引号续行执行同样的 docker run。
启动后 Agent 可访问 PROJECTS_PATH 下的任意项目。这里的两个卷挂载与 Dockerfile 完全对应:docker/Dockerfile 声明了 VOLUME ["/home/openhands/.openhands", "/projects"],并注释说明前者持久化「设置、密钥、会话、自动化数据库」,后者是「Agent 可读写用户代码」;镜像预创建了 /home/openhands/.openhands/agent-canvas/conversations、bash_events、automation 等子目录并 chown 给 openhands 用户,因此宿主机挂载点建议是空目录或已存在的用户目录。
方式三:从源码运行
同样是「agent-server 直跑」模式,Agent 对宿主机文件系统有完全访问权限。
前置条件:Node.js 22.12.x+、npm、uv(用于通过 uvx 运行 agent server)。
git clone https://github.com/OpenHands/OpenHands.git
cd OpenHands
npm install
npm run dev
访问入口与后端管理
启动完成后:
- npm / 源码启动方式访问
http://localhost:8000; - Docker 镜像访问
http://localhost:8000/canvas(镜像构建时通过VITE_BASE_PATH=/canvas把前端烘到子路径下,见 docker/Dockerfile)。
额外后端可以直接在 UI 中添加。README 强调的一点是「多后端」:可以把同一个 Agent Server 共享给团队做代码评审和依赖更新,同时保留笔记本上的个人 Agent,在同一 Agent Canvas 前端之间切换而不中断上下文。
CLI 参数与环境变量:来自源码的完整说明
上面只列了 README 出现的两个拆分参数。完整的参数面可从 CLI 入口 bin/agent-canvas.mjs 的 --help 输出处确认,该文件是 agent-canvas 命令的入口,默认以「生产等价模式」运行:通过 uvx 拉起 agent-server 与 automation backend,并服务预构建的静态前端(即 npm run dev 的产物化等价物)。
参数
| 参数 | 作用 |
|---|---|
-p, --port <port> |
ingress 代理端口,默认 8000 |
--public |
启用 public 模式:API key 不再注入前端,用户首次打开 UI 需手动粘贴 LOCAL_BACKEND_API_KEY;要求设置该环境变量 |
--frontend-only |
仅启动 ingress 后的静态前端 |
--backend-only |
仅启动 agent-server + automation backend(与 --frontend-only、--public 互斥,入口代码中有显式校验并报错退出) |
-v, --version |
输出版本号 |
--info |
输出默认栈版本、兼容下限与各服务端口 |
-h, --help |
帮助信息 |
环境变量
| 变量 | 说明 |
|---|---|
LOCAL_BACKEND_API_KEY |
服务端 API key。非 public 模式下可省略(自动生成并在重启间持久化);public 模式下必填 |
OH_SECRET_KEY |
用于加密设置的密钥 |
OH_AGENT_SERVER_GIT_REF |
agent-server 的 Git 引用 |
OH_AGENT_SERVER_LOCAL_PATH |
本地 software-agent-sdk checkout 路径,用于开发(优先级最高:会从本地源码重建 agent-server 并以 editable 方式安装 SDK 组件) |
OH_AGENT_SERVER_VERSION |
指定 agent-server 的 PyPI 版本 |
帮助文本还明确了一点常被问到的问题:LLM 配置通过 Web UI 的设置页完成,而不是环境变量。
从入口实现看,agent-canvas 最终调用 scripts/dev-with-automation.mjs 的 main(),传入 staticMode: true 与构建目录 build/;该脚本头部的注释也完整画出了 ingress 的路由拓扑:/api/automation/* 路由到 Automation Backend(:18001),/api/* 与 /sockets 路由到 Agent Server(:18000),其余路径路由到 Vite 开发服务器或静态服务。
默认版本与端口
所有 npm 与 Docker 安装路径共享的「单一事实来源」是 config/defaults.json,agent-canvas --info 读取的就是它:
- 版本钉定:agent-server
1.44.0、agent-canvas1.16.0、automation1.9.0;agent-server 兼容下限1.28.0; - 端口:ingress
8000、agent-server18000、automation18001、内置编辑器(vscode)8001; - 路径:状态子目录
agent-canvas/、会话目录、bash 事件目录、automation 数据库automation/automations.db、Canvas 基路径/canvas、编辑器基路径/vscode。
此外,该文件还包含一个值得注意的约束:agent-client-protocol 被临时钉在 <0.11(acp 0.11.0 重排了 prompt() 参数,会破坏 SDK 的 ACP 客户端),这解释了本地启动脚本为什么需要对 uvx 安装命令做约束处理(从源码结构看,约束由 scripts/dev-safe.mjs 消费)。
架构:Agent Canvas、Agent Server 与 Automation Server
README 的 Architecture 部分给出了三层结构,docs/architecture.md 进一步明确了系统边界:
- Agent Canvas(本仓库):React + TypeScript 前端,直接对接 OpenHands Agent Server。它负责渲染会话、终端、浏览器、文件、设置与自动化 UI,管理前端状态,并把 UI 操作翻译成 Agent Server API 调用;它不负责执行 Agent 动作、提供沙箱隔离、托管 LLM 凭证,也不在没有 automation 后端时运行定时/事件触发的自动化。
- OpenHands Agent Server:一个「在单机上运行多个 Agent」的 REST API。每个 Agent Server 监听单一 host/port;Agent Canvas 可同时连接多个 Agent Server 并在 UI 中切换。Agent Server 可以跑在任何地方:笔记本(谨慎)、专用机器(Mac Mini 等)、云上虚拟机、OpenHands Cloud。
- Automation Server(可选配套):负责「什么时候跑」——按调度或事件(webhook)把会话派发给 Agent Server/SDK 执行;Agent Canvas 前端中的自动化功能即对接它。
关于仓库分工,README 的「Repository boundaries」表格明确了多仓库边界,变更应提交到拥有该行为的仓库:
| 仓库 | 职责 |
|---|---|
OpenHands/OpenHands(本仓库) |
Agent Canvas 前端、用户控制中心、后端选择、本地栈编排 |
OpenHands/software-agent-sdk |
Python SDK、Agent Server、Agent、工具、会话、工作区、事件与规范服务端 API |
OpenHands/typescript-client |
浏览器可用的 Agent Server API TypeScript 客户端 |
OpenHands/automation |
自动化定义、调度、webhook、运行历史与派发 |
本仓库前端最重要的源码区域(见 docs/architecture.md):src/api/(Agent Server、云、设置、git、skills、automations、backend registry 的服务适配器)、src/components/(会话、聊天、浏览器、文件、设置、后端、自动化等路由与功能 UI)、src/hooks/(React Query 与状态 hooks)、src/stores/(Zustand 状态)、src/mocks/(MSW 处理器)、以及 bin/ 与 scripts/(CLI 与开发栈启动器)。
单端口 ingress:Docker 镜像内部路由
Docker 镜像把三个服务合并进一个镜像(docker/Dockerfile 头部注释):
- Agent Server 基于上游 SDK 镜像
ghcr.io/openhands/agent-server; - Automation 通过 pip 安装
openhands-automation(钉定版本); - 前端为预构建静态产物,由 Node 静态服务器提供。
入口 docker/entrypoint.sh 启动全部服务与一个 ingress 代理,统一在 8000 端口暴露,路由规则为:
/api/automation/* → automation backend (:18001)
/api/*, /sockets → agent server (:18000)
/* (default) → 静态前端 + SPA fallback
这也是为什么容器只 EXPOSE 8000 一个端口,而 README 中的 docker run 只需 -p 8000:8000。
ACP Agent:接入 Claude Code、Codex、Gemini
README 能力表中「Use with any agent」对应的实现细节在 docs/ACP_AGENTS.md:Agent Canvas 并不直接调用 LLM,而是由 Agent Server 以子进程方式拉起 ACP Agent 的 CLI(stdio 上的 JSON-RPC),逐轮转发消息。外部 Agent 自管 LLM、工具与执行,Agent Canvas 只记录「跑哪个 Agent」并渲染返回内容。
内置支持的提供方与默认命令:
| 提供方 | 默认命令 |
|---|---|
| Claude Code | npx -y @agentclientprotocol/claude-agent-acp |
| Codex | npx -y @agentclientprotocol/codex-acp |
| Gemini CLI | npx -y @google/gemini-cli --acp |
认证上有两类方式:订阅登录(provider 自有 CLI 在本地存的登录态,如 macOS Keychain、~/.codex/auth.json、~/.gemini/oauth_creds.json)或 API key(ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY)。关键点:登录态优先于 API key——在 Agent Server 与用户同一台机器(本地/自托管后端)时,通常无需配置任何 key;而在干净的云端沙箱中则必须提供 API key。Agent 选择按后端(backend)维度存储,切换后端即可能切换 Agent。提供方清单来自 SDK 注册表并镜像进 @openhands/typescript-client,Canvas 侧仅在 src/constants/acp-providers.ts 补充 UI 元数据。
自托管与安全加固
README 指出「最强大的运行方式是部署在云服务器上」——Agent 可以持续运行,并方便地被 Slack、GitHub、Datadog 等第三方服务触发。完整操作与加固细节在 docs/SELF_HOSTING.md,要点:
- 准备一台常开的 Linux/macOS 主机(云 VM 或 Mac Mini、NUC 等专用硬件);
- 先加固再启动:默认只允许 SSH(且限源 IP),ingress(:8000)、agent-server(:18000)、automation(:18001)、静态服务(:3001)全部绑定
127.0.0.1,禁止对外可达; - 生成密钥并 public 模式启动:
openssl rand -base64 32生成 key,export LOCAL_BACKEND_API_KEY=<key>后npx @openhands/agent-canvas --public。public 模式下 API key 不注入前端,用户需在 UI 首次加载时粘贴;每个/api/*调用都必须携带匹配的X-Session-API-Key头; - 可选:nginx + Let's Encrypt 提供 TLS,只开放 80/443;
- 可选:在本地 Agent Canvas 中把该远程添加为后端,实现「本地前端 + 云端 Agent」组合。
SELF_HOSTING 文档还记录了一个值得注意的安全边界:内置编辑器(OpenVSCode)通过路径前缀(默认 /vscode)复用 Canvas 的浏览器源,路径前缀只做路由不做隔离,编辑器侧的脚本可读 Canvas 的 localStorage(其中保存了该浏览器内所有已注册后端的 SESSION API key)——这正是「单一端口部署」的代价,公网暴露前应知悉。docs/architecture.md 的 Security posture 一节亦呼应此点:本地运行会让 Agent 访问用户工作区,因此推荐笔记本场景使用 Docker 沙箱模式;自托管部署应叠加常规服务器加固、认证、HTTPS、防火墙与谨慎的工作区限定。
运行时模式与开发命令
docs/architecture.md 以表格形式列出了 package.json scripts 对应的运行模式,与 package.json 中的定义一致:
| 模式 | 用途 |
|---|---|
npm run dev |
在宿主机直接启动完整本地栈:uvx 拉起 agent-server 与 automation backend、Vite 开发服务器、ingress 代理。Agent 拥有宿主机文件系统访问权,仅用于可信环境 |
npm run dev:minimal |
仅 agent-server + Vite 开发服务器,不含 automation backend |
npm run dev:static |
同 dev,但服务前端生产构建而非 Vite 开发服务器 |
npm run dev:mock |
前端对接 MSW mock,用于 UI 开发与测试 |
npm run build |
构建独立应用 |
npm run build:lib |
构建用于嵌入的库式入口 |
配套的质量门(CI):npm run lint(typecheck + ESLint + Prettier)、npm test(单元/组件测试)、npm run build 与 npm run build:lib(双构建验证)、npm pack --dry-run(打包校验)。npm 包通过 GitHub Actions 的 trusted publishing 与 provenance 发布,postinstall 脚本还会在全局安装后打印启动提示(agent-canvas,默认 http://localhost:8000)。
延伸阅读
围绕 README 的更多文档均可在当前仓库内查阅:
- docs/README.md:文档索引;
- docs/architecture.md:系统边界、运行时模式与质量门;
- docs/DEVELOPMENT.md:开发指南;
- docs/SELF_HOSTING.md:VM 自托管与安全加固;
- docs/ACP_AGENTS.md:接入外部 ACP Agent;
- docs/TESTING_MATRIX.md:跨安装器、操作系统与 Agent 的发布冒烟测试矩阵;
- AGENTS.md:贡献者视角的仓库边界与评审规范。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00