OpenHands:让 agent 自主规划并提交可审查改动的编码平台
OpenHands 把 issue 交给 AI agent,由它规划、写代码、跑命令并提交可审查改动。MIT 许可,9.1 万星,支持 CLI 与 Web 界面,可接任意模型。
大多数人第一次用 AI 写代码,卡住的地方不是模型不够强,而是它没有一台自己的机器。
你在聊天框里贴一段代码,它给你一段补丁;你想让它跑一遍测试、看一眼报错、再改一版,就得自己复制粘贴、自己开终端、自己判断哪一步错了。所谓「AI 编程」,本质上还是人在当执行器。
OpenHands 要拆掉的就是这个人肉环节。它给 agent 一台能跑命令的机器、一个能读写的文件系统、一套能持续多轮的执行循环,然后把 issue 丢进去,等它自己规划、自己改、自己验证。README 里对它的定位写得很直白:self-hosted developer control center for coding agents and automations——不是聊天工具,是一个控制中心。
下面按「它凭什么能让 agent 自主干活」这条线拆开讲。
一、先看它到底由什么组成
OpenHands 的 README 里,产品名其实叫 Agent Canvas。这个名字容易让人以为是画布式的 UI 玩具,但它的架构说明指向一个更工程化的结构:一个前端控制中心 + 若干个可插拔的 Agent Server + 一个自动化服务。
README 的 Architecture 段给了一句关键定义:
Agent Canvas is powered by the OpenHands Agent Server, a REST API for running multiple agents on a single machine. Each Agent Server runs on a single host/port; the Agent Canvas can connect to multiple Agent Servers and easily flip between them.
这句话把整个系统的分层说清楚了。把它展开成层:
| 层 | 组件 | 职责 |
|---|---|---|
| 控制层 | Agent Canvas 前端(本仓库 OpenHands/OpenHands) | 用户界面、会话发起、后端选择与切换、本地栈编排 |
| 执行层 | OpenHands Agent Server(REST API) | 在单机单端口上跑多个 agent,管理会话、工具、工作区、事件 |
| 自动化层 | Automation Server | 让 agent 按定时或事件/webhook触发运行 |
| 集成层 | Slack / GitHub / Linear / Notion 等 | 作为自动化的输入源与输出目标 |
| 模型层 | 任意 LLM(LLM Profiles) | 由用户自带,不绑定厂商 |
再往下是仓库边界。README 专门列了一张表,说明这套系统是多仓库的,改行为要去对的仓库改:
| 仓库 | 负责什么 |
|---|---|
OpenHands/OpenHands | Agent Canvas 前端、面向用户的控制中心、后端选择、本地栈编排 |
OpenHands/software-agent-sdk | Python SDK、Agent Server、agents、tools、conversations、workspaces、events,以及规范的 server API |
OpenHands/typescript-client | TypeScript 客户端(README 在此截断) |
这张表本身就是一条重要信息:OpenHands 不是一个单体应用。你在这个仓库里看到的是「壳」和「编排」,真正让 agent 跑起来的运行时(会话、工具、工作区、事件流)在 software-agent-sdk 里。所以评价它时,说「前端仓库」是准确的——它的价值在于把多个后端收敛成一个可操作的面板,而不是自己实现 agent 循环。
请求怎么流转
按 README 的描述,一次典型交互的路径是:
- 用户在 Canvas 里发起一个会话,选定一个后端(本地 / Docker / VM / 云)。
- Canvas 把请求路由到对应的 Agent Server(
host:port)。 - Agent Server 在该环境里创建会话、挂载工作区、暴露工具,让 agent 开始多轮执行。
- 如果这个会话属于某个自动化,Automation Server 负责触发时机(cron 或 webhook)和结果投递(比如发到 Slack)。
关键设计点在第 1 步和第 2 步之间:Canvas 可以同时连着多个 Agent Server,并在 UI 里切换。README 举的例子很具体——团队共享一台 Agent Server 跑 code review 和依赖升级,个人的 agent 跑在自己笔记本上,同一个前端里来回切,不用换工具。
这个设计的直接后果是:agent 的执行环境与用户界面解耦。你把笔记本合上,跑在云上服务器里的 agent 不会停。README 明确说这是「最强大的运行方式」的原因:agent 能持续跑,也更容易被 Slack、GitHub、Datadog 这类外部服务触发。
它不绑定自己的 agent
这一点容易被忽略,但是架构上最值得写的一处。README 反复强调:
Agent Canvas runs the open source OpenHands agent out-of-the-box, but can use third-party agents such as Claude Code, Codex, Gemini, Pi, and OpenCode.
并且给出了协议名:ACP(Agent-Client Protocol)。任何兼容 ACP 的 agent 都能接进来。这意味着 Canvas 的定位不是「OpenHands 模型的专属前端」,而是一个 agent 的通用驾驶舱——它管的是会话、后端、自动化、集成,至于里面跑的是谁的 agent,是可换的。
同理,模型层也是可换的,README 的卖点表里写的是「Use with any LLM」,配置入口在 LLM Profiles。
二、四种装法,对应四种信任级别
README 的 Quickstart 给了四条路径。它们不是简单的「安装方式不同」,而是隔离程度不同,这个差别 README 用 WARNING 标得很清楚。
方式一:直接跑,没有沙箱
前置条件:Node.js 24 或更高、uv。
shnpm install -g @openhands/agent-canvas agent-canvas
agent-canvas 默认拉起完整的本地栈。也可以拆开跑:
shagent-canvas --frontend-only # static frontend + ingress only agent-canvas --backend-only # agent server + automation backend + ingress only
README 在这条路径上放了警告:agent-server 直接跑在你安装的那台机器上,agent 对你的文件系统有完全访问权限。这不是客套话,是这套架构的必然结果——agent 要能改代码、跑命令,就得有真实的文件和 shell 权限。
方式二:Docker 沙箱
前置条件是 Docker,外加一个宿主机目录 PROJECTS_PATH,里面放你想让 agent 访问的项目文件夹,启动容器前先建好。
shexport PROJECTS_PATH="$HOME/projects" # directory containing your project folders mkdir -p "$PROJECTS_PATH" "$HOME/.openhands" docker run -it --rm \ -p 127.0.0.1:8000:8000 \ -e AGENT_CANVAS_ALLOW_LAN_SESSION_KEY=true \ -v "$HOME/.openhands:/home/openhands/.openhands" \ -v "${PROJECTS_PATH}:/projects" \ ghcr.io/openhands/agent-canvas:1.27.1 # x-release-please-version
注意端口绑定写的是 127.0.0.1:8000:8000,只发布到回环地址。agent 只能访问 PROJECTS_PATH 下的项目。
方式三:每个会话一个 Docker 容器
这条路径是为并发准备的:每个新会话跑在自己的容器里,有自己的 Agent Server 和工具。Canvas 和外层 Agent Server 跑在宿主机上,把会话请求路由进各个容器。
shnpm install -g @openhands/agent-canvas OH_CONVERSATION_RUNTIME=docker agent-canvas
README 在这里补了两个容易被踩的细节:
- 已有的本地会话不会被转换。
- 每个容器挂载自己会话的工作区和持久化状态,所以文件和历史能扛住容器替换;但共用同一个宿主机工作区的会话仍然共享文件,要避免冲突编辑,得选不同目录或 worktree。
还有一句边界说明很重要:这个设置隔离的是会话执行,不是把整个 Canvas 和自动化服务也塞进沙箱。
方式四:从源码跑
前置条件多了 npm,uv 用来通过 uvx 跑 agent server。
shgit clone https://github.com/OpenHands/OpenHands.git cd OpenHands npm install npm run dev
访问地址有两套:npm / 源码启动的走 http://localhost:8000,Docker 镜像的走 http://localhost:8000/canvas。额外后端可以直接在 UI 里加。
安全模型:会话密钥怎么注入
这段是 README 里技术含量最高、也最容易被跳过的部分,值得单独拎出来。
- 本地(
npx/npm run dev)监听器只绑回环地址(127.0.0.1),这样自动注入的 session key 不会被同网段其他机器拿到。 - 要监听所有网卡,得传
--host 0.0.0.0或设OH_BIND_HOST;此时 session key 不会被注入,UI 走和--public一样的 API key 输入页。 - Docker 监听所有容器网卡(否则端口发布不出去),但默认不把 session key 注入 HTML。上面的 quickstart 显式开了注入,同时把宿主机端口只发布在
127.0.0.1上——两个条件必须同时成立才安全。 - 如果要把 Docker 发布到 LAN 或公网,就去掉
AGENT_CANVAS_ALLOW_LAN_SESSION_KEY,在 UI 里手输 API key;LOCAL_BACKEND_API_KEY设一个强值,或者用docker exec <container> sh -c 'cat "$STATE_DIR/api-key.txt"'取出自动生成的那个。 - 面向公网的部署,README 指向
docs/SELF_HOSTING.md。
这套设计的逻辑是一致的:便利性和暴露面成反比。默认配置尽量只对本机开放,一旦你扩大监听范围,鉴权就从「自动注入」退回到「手动输入」。
三、能力清单:它到底能替你做什么
README 的卖点表列了六项,逐条对应到具体机制:
| 能力 | 具体含义 |
|---|---|
| Self-host your way | 本地、Docker、VM,或任何能跑 agent server 后端的地方 |
| Switch between different backends | 本地 / 远程 / 云端 agent 之间切换,不打断当前工作 |
| Create automations | 建自动化和 workflow,接 Slack、GitHub、Linear 等;按计划或 webhook 事件触发 |
| Integrate with the tools you use | 自动化可连 Slack、GitHub、Notion 等第三方服务 |
| Bring your own model | 配 LLM Profiles,任意 LLM |
| Use with any agent | OpenHands、Claude Code、Codex、Gemini、Pi、OpenCode,或任何支持 ACP 的 agent |
README 开头给的两个自动化例子很能说明产品意图:生成报告并发布到 Slack、自动把 GitHub issue 拆解成任务。这两个都不是「帮我写个函数」,而是「把一件周期性、有明确输入输出的工程事务交给 agent 常驻处理」。
这也解释了为什么它要把 agent 放在服务器上跑:自动化的前提是常驻。笔记本合上就停的 agent,做不了 webhook 触发的活。
四、和同主题项目比,它站在哪
用素材里的对照项目做一个横向定位。需要说明的是,这几个项目解决的问题并不完全重叠,放在一起看的是「它们各自把 AI 放在了工程流程的哪个位置」。
| 项目 | 语言 | 星标(快照) | 它占据的位置 |
|---|---|---|---|
| OpenHands | TypeScript | 约 9.1 万 | 自托管的 agent 控制中心:多后端、多 agent、自动化编排 |
| claude-mem | TypeScript | 约 10.0 万 | agent 的跨会话记忆:记录操作、AI 压缩、后续会话注入上下文 |
| strix | Python | 约 6.8 万 | 安全测试专用 agent:攻击模拟 + 修复建议,可进 CLI / CI |
| kong | Lua | 约 4.4 万 | API / AI Gateway:把多家模型 API 收敛到一个入口,管 key、转发、配额 |
| AI-For-Beginners | Jupyter Notebook | 约 7.0 万 | 教学课程,不是工具 |
| Deep-Live-Cam | Python | 约 9.7 万 | 实时换脸,与编码 agent 不在同一赛道 |
从这张表能读出两件事。
第一,OpenHands 和 claude-mem 是互补而非竞争。 claude-mem 解决的是「每次重开对话都要重新交代背景」——它管的是上下文连续性。OpenHands 解决的是「agent 没有执行环境」——它管的是执行与编排。一个 agent 可以在 OpenHands 提供的后端里跑,同时用 claude-mem 保住跨会话记忆。两者都在 TypeScript 生态里,星标量级接近,但切入的痛点完全不同。
第二,OpenHands 和 kong 是不同层的收敛。 kong 收敛的是模型 API 的入口(key、转发、配额);OpenHands 收敛的是agent 后端的入口(本地/远程/云、不同 agent 实现)。如果你的团队既要用多家模型、又要跑多种 agent,这两个东西会同时出现在架构图里,一个在模型侧,一个在执行侧。
第三,strix 展示了另一条路:垂直化。 strix 只做渗透测试,把安全测试做成可编排的 workflow。OpenHands 走的是通用化——不限定 agent 干什么,只提供跑 agent 的基础设施和自动化框架。通用平台的代价是你要自己想清楚自动化做什么;垂直工具的代价是它只能干那一件事。
五、谁该用它,以及用之前要想清楚什么
从 README 的描述倒推,它最适合的场景有三类:
- 想让 agent 常驻的团队。把 Canvas 装在一台服务器或 Mac Mini 上,agent 24 小时在线,Slack 里 @ 一下或者 GitHub 上开个 issue 就能触发。
- 同时用多种 agent 的人。手上既有 OpenHands,也用 Claude Code、Codex、Gemini CLI,不想为每个工具开一个窗口、记一套用法。ACP 让它们进同一个面板。
- 要把工程事务自动化的团队。issue 拆解、依赖升级、code review、报告生成——这些有明确触发条件和输出目标的事,适合挂到 Automation Server 上。
用之前要想清楚的是权限边界。README 在两条安装路径上都放了同一句警告:agent 会对你安装所在的机器有完全的文件系统访问权。方式二、方式三用 Docker 和目录挂载把范围收窄到 PROJECTS_PATH,方式一和方式四没有这层保护。这不是配置疏忽,而是「让 agent 真能干活」和「让它什么都碰不到」之间的取舍。
另一个要想清楚的是项目状态。README 顶部的徽章标的是 beta,并且挂在 OpenHands/incubator-program 下。同时它是 MIT 许可、9.1 万星、1.2 万 fork、仓库创建于 2024 年 3 月、最近一次推送在 2026 年 10 月——活跃度不缺,但 beta 标签意味着接口和行为还可能变。把它放进关键流程之前,值得先在自己的环境里跑通一遍。
拿到手的第一步
如果只是想看看它长什么样,最短路径是方式一,两条命令:
shnpm install -g @openhands/agent-canvas agent-canvas
然后开 http://localhost:8000。但如果你打算让它碰真实项目,建议直接上方式二——多写几行 docker run,换来的是 agent 只能看见 PROJECTS_PATH 下面那些目录。这个交换在第一次让 agent 自主跑命令之前,值得做。