自建开源 coding agent 平台:OpenHands vs Munder Difflin
买席位省事,但代码、模型和预算都不在自己手里。OpenHands 的自托管把模型生成的每一步关进 Docker 沙箱,代价是 Docker socket、动态端口、镜像固定与清理都得自己扛;Munder Difflin 走另一条路——复用已付费的 CLI 与小时额度,用 git 文件当消息总线,用审批队列和熔断器控制自治。两条路线的架构、成本与决策清单,外加自己实现时的五个最小层。
一句话结论:自建 coding agent 平台不是"再装一个软件",而是把执行层的所有权拿回来。OpenHands 走重型路线——把模型发出的每个动作关进 Docker 沙箱,模型留在边界外;Munder Difflin 走轻型路线——把你已经付费的终端 CLI变成员工,用文件当消息总线。两条路都是 MIT、都能自托管,但代价结构完全不同:前者把 Docker socket、动态端口、镜像固定与清理的责任交给你,后者把订阅的小时额度、自治边界与失控停止条件交给你。如果两条都不想选,最小可行的第三条路是自己实现 harness 的五层:执行边界、沙箱、记忆持久化、验证循环、上下文管线。
本文完整编译 OpenHands 自托管评测(Effloow / Jangwook Kim,2026-10-12)与 Munder Difflin 架构说明(dev.to,2026-09-28),并综合 OpenHands 官方 Agent Canvas 文档(2026)、Ali Suleyman TOPUZ《Seven Ways to Wire an Agent Harness...》(2026-10-04)做中文整理。
一、为什么要自建:它解决的不是"再买一个席位"
评测方(Effloow)的出发点很直接:再买一个 coding-agent 席位,解决不了工程团队面对的基础设施问题。他们想回答的是四个所有权问题:
- 执行层能不能自己运营,而不是向供应商租一个黑盒;
- 能不能接自己选的模型供应商;
- 能不能把源码、运行时镜像、网络策略、用量核算攥在自己手里;
- 当多个 sandbox 同时要端口、存储和清理时,会发生什么。
这也解释了他们评测里最值得学的一点:他们明确区分"能验证的"和"需要 Docker daemon + 付费凭据才能验证的"——因为评测环境没有 Docker,启动延迟、吞吐、内存、清理行为一律不测,也不用 mock 结果冒充生产证据。
先把期望摆正:自建不是省钱,而是把风险从供应商转移给你的基础设施团队。OpenHands 砍掉的是"按席位收的运行时授权费",但它不会让 Agent 执行变成免费。
二、路线一:OpenHands —— 把每一步关进沙箱的自托管控制台
2.1 它现在是什么:一个 9 万星项目的两层结构
OpenHands 是 MIT 许可、9 万+ 星(2026-10-15 为 90,969 星)的开源项目。今天它要分成两层看:
- Agent Canvas:当前主打的开源控制面(2026-06 发布,官方标注 beta)。浏览器 UI 连接一个或多个 backend,集中管理会话、文件、终端、模型、后端与自动化;
- OpenHands CLI / agent-server:真正执行动作的 Agent 层,也是这篇评测解剖的对象;
- 外加托管形态 OpenHands Cloud / Enterprise。
Agent Canvas 的 backend 可以放在本机、Docker、VM、Modal 或 OpenHands Cloud。这不是纯粹的部署选项,而是信任边界的选择:
| 安装方式 | 信任边界 | 适合 |
|---|---|---|
| npm 本地直装 | Agent server 直接操作本机文件系统 | 本机可信、图快 |
| Docker | 容器内运行,只能看到你挂载的目录 | 本地沙箱化、文件边界清晰 |
| VM / 独享机 | 跑在你控制的远端主机上 | 常驻 Agent、团队共享、工作与个人分离 |
| Cloud | 托管 sandbox | 不想自己维护 VM |
模型接入有四种:供应商 API key、OpenHands LLM API key、ACP 订阅登录(Claude Code / Codex / Gemini 等已登录的同机 CLI)、本地或 OpenAI 兼容服务(Ollama / LM Studio / LiteLLM)。本地启动只需要 Node.js 24+,一条 npx @openhands/agent-canvas 就能把 UI 和 backend 一起拉起来。

2.2 执行层:模型在沙箱外,动作在沙箱内
评测方认为,OpenHands 最值得看的不是聊天界面,而是那条把"模型生成的行动"变成 shell 命令、文件修改、Python 执行和 observation 的运行时路径:
- backend 启动一个专用 runtime 容器,在容器内启动 action execution server;
- backend 通过 HTTP 接口发送 action,收回结构化 observation;
- 模型留在执行边界之外,容器里跑的只有可能造成破坏的操作。
这层分离是自建时最重要的控制点——镜像策略、工作区挂载、资源限制、进程清理、审计日志全挂在这里。也意味着 Docker 不是"顺便用了":它是 OpenHands 安全与调度模型的一部分。
镜像工作流也比"每个任务 build 一次"讲究,评测方观察到三层 tag:
- versioned:绑定 OpenHands 版本与 base 镜像;
- lock:由 base 镜像 + 依赖文件推导;
- source:包含 OpenHands 源码 hash。
命中 source 镜像可整体复用;只命中 lock 层时,可以只拷变化的源码而跳过缓慢的依赖安装。这能减少重复构建,但生产环境仍应直接 pin 不可变 digest,而不是依赖会移动的 tag。
最短启动路径(CLI 栈):
uv tool install openhands --python 3.12
openhands serve --mount-cwd
--mount-cwd 会把当前仓库挂进工作区——方便,也意味着有写权限的 Agent 能改这个挂载里的一切。更可控的复现要走固定版本的容器,并且要挂 /var/run/docker.sock(直连部署里 Agent 需要用它创建和管理 sandbox 容器):
docker run -it --rm --pull=always \
-e AGENT_SERVER_IMAGE_REPOSITORY=ghcr.io/openhands/agent-server \
-e AGENT_SERVER_IMAGE_TAG=1.26.0-python \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME/.openhands:/.openhands" \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.openhands.dev/openhands/openhands:1.8
SDK 路径则可以直接拿到一个受控的沙箱:用 DockerWorkspace(server_image=..., host_port=..., platform=...) 调 execute_command(),拿到 exit_code / stdout / stderr 的结构化结果;需要额外编译器或内部工具链时用 DockerDevWorkspace 从指定 base 构建,但不要把它放在延迟敏感路径上——镜像构建会多一截启动时间。
成本核算有一个暴露出来的接口:conversation.conversation_stats.get_combined_metrics().accumulated_cost。评测方的建议是:按会话、仓库、模型、租户、完成状态记账,但在和供应商账单对账(重试、失败请求、缓存行为、会话对象之外的模型调用)之前,别把它当成完整账单。
2.3 VM 自托管:端口、密钥,和一个容易忽略的坑
Agent Canvas 官方自托管指南给了单机 VM 的完整拓扑:npx @openhands/agent-canvas --public 一次拉起静态前端(:3001)、agent server(:18000)、automation backend(:18001)和一个 ingress 代理(127.0.0.1:8000),nginx 只需要反代 8000 这一个端口。
--public 的关键变化是:API key 不再打进前端,用户首次打开 UI 要粘贴 LOCAL_BACKEND_API_KEY,且所有 /api/* 请求必须带 X-Session-API-Key。部署顺序是先收紧防火墙——除你自己的 IP 外,22 之外一律 drop——再启动服务。单用户 2 vCPU / 4GB 就够。
但记住这台 VM 的定位:它是一台"持有生产凭据的机器"。官方警告写得很直白:agent server 会读写文件系统、执行 shell、访问网络,任何能跟它通信的人都能让它做同样的事。
一个容易忽略的坑:内置 OpenVSCode 与 Canvas 共用同一个浏览器 origin(通过 /vscode 路径前缀提供)——路径前缀只负责路由,不负责隔离。另外,本地 npm/npx 安装的 Agent Canvas 会随终端关闭而停止;Docker / VM / 云端 backend 会继续跑。
2.4 评测测到的硬问题:Docker socket,与端口
评测方承认没测到的部分(启动延迟、吞吐、内存、清理)之后,给出了它测到的结构性风险:
- Docker socket 是最大的边界弱点。架构把 Agent 命令隔离进子容器,但父应用在直连部署里需要控制宿主 Docker daemon——在常规 Linux 上,这基本等同于特权宿主权限。应用容器一旦被攻破,沙箱边界保护不了 Docker 宿主。
- 缓解方案是架构性的,不是装饰性的:worker 放到专用节点或一次性 VM;不与数据库、CI 密钥、对外服务同机;controller 与 sandbox 都限制出网;只挂任务所需的仓库;优先只读挂载 + 显式可写 worktree;限制 CPU、内存、进程数与执行时长;把 Docker 宿主当作"用完可弃"。
- 反向代理下的端口问题:每个 sandbox 默认拿随机宿主端口,而生成的浏览器 URL 默认走 localhost 模式;
OH_WEB_URL只影响允许的 origin,不会重写 sandbox URL 的 host 与 port。两个次优选项:OH_SANDBOX_CONTAINER_URL_PATTERN(保留随机端口,要求边缘层转发一个动态端口段),或AGENT_SERVER_USE_HOST_NETWORK=true(固定端口 8000/8001,但每个 sandbox 抢同一批端口,单机只能跑一个,不能用于多租户 worker)。 - 镜像能力不一致:不要假设便携 SDK 镜像里带 VS Code、VNC、固定 editor 端口或
/api/vscode/url——那些属于特定的旧版 editor 镜像,应当特性探测而不是无条件拼 URL。 - 移动 tag 是复现性风险:
latest-python适合探索,生产要 pin 版本、最好是 digest;把应用镜像、agent-server 镜像、base 镜像、SDK 与模型配置当成一个发布单元一起测。
2.5 成本模型:什么时候自建更划算
自建的月成本可以写成:
自托管月成本 = worker 基础设施 + 工程维护 + 可观测性与存储
+ LLM / 本地推理 + 安全与事故开销
托管月成本 = 席位数 × 单席位月价 + 超量 + 集成开销
评测方给了一个示例(不是 Devin 报价,也不是真实 OpenHands 账单):worker + 日志 $600/月;运行时维护 12 工程师·小时/月;全负担工程费率 $150/小时;自托管模型用量 $120/活跃用户/月;托管替代 $500/活跃用户/月。于是:
固定成本 = $600 + 12 × $150 = $2,400/月
每用户优势 = $500 − $120 = $380
盈亏平衡 = $2,400 / $380 ≈ 6.32 → 约 7 个活跃用户
维护涨到 30 小时,或 Agent 在工具循环里反复烧 token,平衡点会明显上移。注意"一个任务不等于一次模型调用":Agent 会读文件、调工具、吃 observation、改计划、跑测试、报错再问模型,长命令输出还会回到上下文里推高后续请求成本。
开闸之前,他们要求四道控制:单会话模型花费上限、最大循环迭代数与墙钟时长、输出截断与工件外置、按团队/仓库的预算硬拒绝。
2.6 部署还是劝退:一张清单
| 该部署,如果…… | 该劝退,如果…… |
|---|---|
| 需要控制模型供应商、运行时镜像与源码位置 | 需要交钥匙服务、合同支持与可预测席位 |
| 能拿出隔离的 worker 主机跑不可信 Agent 执行 | 打算在共享基础设施上暴露宿主 Docker socket |
| 活跃用量足够摊薄平台维护成本 | 边缘架构无法承载动态 sandbox 端口 |
| 能 pin 并测试整套应用 + agent-server 镜像 | 以为每个 SDK 镜像都自带 VS Code / VNC |
| 会强制 token、迭代、时长、内存、网络限额 | 没有按会话的模型预算与供应商账单对账 |
| 接受"自建转移运营风险,而不是消除成本" | 需要强于普通 Docker 容器的多租户隔离审计 |
评测方的最终建议是受控试点,而不是一步上生产:先一台专用 worker、一套 pinned 镜像、默认拒绝出网、一次性仓库副本、一小群工程师;分别测冷/热启动,记录累计模型成本,测强制终止后的清理行为,并在扩容前主动尝试工作区逃逸。
三、路线二:Munder Difflin —— 把已付费的 CLI 变成"Agent 办公室"
3.1 定位:不替换 CLI,而是把它们组织起来
Munder Difflin(仓库 HarnessMD/munder-difflin,MIT,v0.5.3 pre-release,2026-10-15 为 8,773 星)的设计出发点完全不同:终端 CLI 留在中心。它把你已经安装的 claude、agy、codex、grok、kimi、gemini、qwen、opencode、crush、pi、copilot、cursor-agent 或任意自定义命令,作为真实进程启动,再围绕它们搭一个"办公室"。
它的经济学写在 README 第一屏:"与你已经付费的订阅一起工作,在它们的小时额度内。" 每个 Agent 就是一个终端,跑着你已有的订阅和小时额度——它明确不承诺让你绕过额度。
每个 Agent 是一个真正的伪终端进程(node-pty),用 xterm.js 渲染,README 称之为 "byte-for-byte authentic":你看到的就是 CLI 自己的会话。每个 Agent 有独立工作目录、身份和供应商生命周期;点一下工位就能读到那个终端并直接输入。订阅之外,也支持自带 API key 与本地模型(Ollama / LM Studio / vLLM);v0.5.3 起,缺失的 CLI 可以直接在应用内安装和登录,界面提供简体中文。
3.2 架构:终端是工作单元,文件是消息总线
十几个独立进程跑起来之后,协调才是问题。Munder 的答案故意无聊:一个本地 git 仓库 + 纯文本文件。
- 每个 Agent 只写自己的
outbox/,harness 的 router 把消息投递到收件人的inbox/; - Agent 读自己的记忆、清空邮箱;
- 没有任何 Agent 直接操作 git——harness 是唯一 committer,规避
index.lock冲突; - 记忆同样是文件优先:每个 Agent 维护 markdown 记忆,被挖掘进一个共享、可搜索的存储(README 称为 palace),背后是语义召回索引——关掉应用、第二天回来,Agent 还记得学过什么。
这套结构把"多 Agent 协作"从运行时依赖降级成了文件约定:进程可以崩、可以重启,状态留在磁盘上。

3.3 编排与治理:Michael、审批队列与熔断器
你不需要跟 12 个终端说话。你只 brief 一个叫 Michael 的"你的克隆":上层是 GOD agent,负责 roster(花名册)、路由、blackboard(公共黑板)和任务台账。它自己解决常规请求,只把关键事项升级到审批队列——README 明确列为三类:花钱、破坏性操作、范围变更。
围绕自治,还有三层控制:
- per-agent 自治级别:每个 Agent 能自己走多远,独立设置;
- 熔断器:对陷入循环或失控的 Agent,先引导、再约束、最后停掉;
- 成本账簿:花的钱进台账,v0.5.3 已有成本报告。
对一个"用你小时额度跑一堆进程"的办公室来说,循环的停止条件是最该先看的功能。
可视层是 Pixi.js 的办公室地板:每个会话是一个角色,工作时走向工位,互相发消息时信封在桌子之间飞——哪个 Agent 在干活、谁在跟谁说话,一眼就能看出来。默认皮肤之外还有 Pro 侧栏(Tasks / Inbox / Automations / Memory / Capabilities)、内置 Monaco IDE 与 git 轨道、看板、Slack 生成 worker、可分享的 Agent Gallery 等(v0.5.3 迭代记录)。
3.4 适合谁、注意什么
- 适合:团队已经为 1–2 个 CLI 付了订阅,想让多个会话同时跑在不同任务上、又不愿意逐个盯着;
- 注意:项目仍是 pre-release;订阅条款与小时额度是硬约束;多 Agent 自治要从保守开始——审批队列 + 自治级别 + 熔断器 + 预算一起设,再观察它们如何协调。
四、两条路线怎么选
| 维度 | OpenHands(沙箱控制台) | Munder Difflin(Agent 办公室) |
|---|---|---|
| 执行模型 | 每个动作进 Docker 沙箱(runtime 容器 + action execution server) | 每个 Agent 是你已装的 CLI 进程(伪终端) |
| 你复用什么 | 自己的模型 key / 本地推理、自己的镜像与网络策略 | 已付费的 CLI 订阅与小时额度 |
| 隔离强度 | 容器级,可换成独享 VM;共享 Docker socket 是边界弱点 | 进程级;工作目录隔离,不是安全边界 |
| 部署形态 | 本机 / Docker / VM / Modal / Cloud;npx @openhands/agent-canvas --public |
Electron 桌面应用,macOS / Windows / Linux |
| 协调方式 | 会话与 workspace 隔离 + automations(Slack / GitHub / Linear) | 本地 git 文件 hive + Michael/GOD 编排 |
| 治理 | token、迭代、时长、网络限额要自己搭 | 内置审批队列、自治级别、熔断器、成本台账 |
| 成本结构 | 基础设施 + 维护 + 模型;示例模型约 7 个活跃用户与托管打平 | 订阅复用;多开受小时额度约束 |
| 适合 | 要模型/镜像/源码位置的完全控制、能投入运维的团队 | 想低成本复用现有订阅、接受 pre-release 的团队或个人 |
选择的判断线:如果核心诉求是"代码与数据不出内网、模型自选、执行可审计",选 OpenHands 式沙箱路线,但准备好运维投入;如果核心诉求是"我已经付了 Claude Code/Codex,只想让它们在同一张工作台上协作",选 Munder 式路线,但把自治与额度设保守。两条路的共同红线:自建 ≠ 免费,自治必须配停止条件。
五、路线三:自己实现——一个 harness 的五个最小层
如果你不想被任何平台的取舍绑住,第三条路是自己实现。Ali Suleyman TOPUZ 在完整拆解了七种 harness 接法后引用了一句话:"你的 Agent 是六行 Python,harness 是其余一切。" 他把"其余一切"拆成五个层,并逐层写代码验证——结论是:五层全是承重墙,少任何一层,都会在真实使用约一天内以可预测的失败模式暴露:
- 执行边界:模型"决定调用工具"与工具"真正执行"之间的代码。只在 system prompt 里写"不要做危险操作"没有用——作者前后换了 11 种措辞都失败,最后写了一个 pre-dispatch 闸门,用拒绝模式(如
rm -rf /、git push --force)在工具执行前拦下调用。 - 沙箱:容器隔离(Linux namespaces / cgroups)久经验证、启动在毫秒级;但共享内核才是攻击面——内核漏洞或容器逃逸配置错误会把宿主交出去,所以不可信或模型生成的代码不应裸跑在容器里、旁边还放着你在意的东西。再上一层是微虚拟机:Firecracker 给每个 VM 独立内核,约 125ms 启动、每 VM <5MiB 内存开销、单机可达约 150 VM/s 的启动密度(AWS 公开数据,已被独立复现)。
- 记忆持久化:真正出事的是跨会话持久化——条目不会自己过期。作者见过 Agent 自信引用一个三周前已被推翻的决定。最小实现用 SQLite + 显式 TTL 就够;在上向量库之前,先证明你需要它。
- 验证循环:evaluator-optimizer 必须配硬性迭代上限——作者有一个翻译任务在没有上限时被评测器越挑越细的毛病拖到 41 轮,最后手动杀掉。这也是成本失控最常见的来源。
- 上下文管线:三个动词——select(选取)、compress(压缩)、isolate(隔离),按 token 预算组装上下文,而不是把历史无限 append 给模型。这一层最常被跳过,因为它"看起来不像 bug,直到 token 账单像 bug"。
所以自己实现的起点不是"选一个框架",而是先把这五层的失败模式定义出来,再决定每层用现成组件还是自己写。想从上下文层切入的人,可以继续读我们之前编译的 给 coding agent 一份自己的记忆;想从编排层切入,读 多 Agent 团队到底值不值。
来源
- Effloow / Jangwook Kim, OpenHands Self-Hosted Runtime Review: Docker Isolation, Agent Cost, and the Production Reality(2026-10-12):https://dev.to/jangwook_kim_e31e7291ad98/openhands-self-hosted-runtime-review-docker-isolation-agent-cost-and-the-production-reality-3eh4
- OpenHands Agent Canvas 仓库与官方文档:https://github.com/OpenHands/OpenHands 、https://docs.openhands.dev/openhands/usage/agent-canvas/overview 、VM 自托管指南(
docs/SELF_HOSTING.md) - Introducing Agent Canvas: From Coding Agents to Org-wide Automation(官方公告,2026-06-16):https://www.openhands.dev/blog/introducing-agent-canvas
- munder-difflin runs an office of agents on the coding CLIs you already pay for(dev.to,2026-09-28):https://dev.to/renolu/munder-difflin-runs-an-office-of-agents-on-the-coding-clis-you-already-pay-for-2jnc
- Munder Difflin README / 仓库(MIT,v0.5.3):https://github.com/HarnessMD/munder-difflin
- Ali Suleyman TOPUZ, Seven Ways to Wire an Agent Harness, and What Actually Changes Between Them(2026-10-04):https://dev.to/topuzas/seven-ways-to-wire-an-agent-harness-and-what-actually-changes-between-them-mk7
本文由 汇智网 · Software 2.0 编译整理,转载请注明出处。 想系统了解 AI 编程的选型、上下文工程与成本控制,见 AI 编程 / Vibe Coding 完全指南;也推荐继续读 一台终端、多台机器、多个 Agent 与 为什么多智能体编程会失败。
这是「AI 编程 / Vibe Coding」专题的一部分。完整地图见:AI 编程 / Vibe Coding 完全指南