> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 自建开源 coding agent 平台：OpenHands vs Munder Difflin
- URL: https://www.hubwiz.com/blog/self-host-open-source-coding-agent-platforms/
- Published: 2026-10-15T14:39:57.000Z
- Updated: 2026-10-15T14:50:39.000Z
- Description: 买席位省事，但代码、模型和预算都不在自己手里。OpenHands 的自托管把模型生成的每一步关进 Docker 沙箱，代价是 Docker socket、动态端口、镜像固定与清理都得自己扛；Munder Difflin 走另一条路——复用已付费的 CLI 与小时额度，用 git 文件当消息总线，用审批队列和熔断器控制自治。两条路线的架构、成本与决策清单，外加自己实现时的五个最小层。
- Author: admin
- Tags: AI 编程, 开源, OpenHands, 多智能体, 自托管

**一句话结论**：自建 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 席位，解决不了工程团队面对的基础设施问题**。他们想回答的是四个所有权问题：

1. 执行层能不能**自己运营**，而不是向供应商租一个黑盒；
2. 能不能接**自己选的模型供应商**；
3. 能不能把**源码、运行时镜像、网络策略、用量核算**攥在自己手里；
4. 当多个 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 一起拉起来。

![Agent Canvas 的自动化面板：PR 摘要、夜间安全扫描、文档同步等以任务卡形式管理](https://www.hubwiz.com/blog/content/images/2026/10/img_c85b6e567dfc60c7bb91769e2f1ee7c7.png)

### 2.2 执行层：模型在沙箱外，动作在沙箱内

评测方认为，OpenHands 最值得看的**不是聊天界面**，而是那条把"模型生成的行动"变成 shell 命令、文件修改、Python 执行和 observation 的**运行时路径**：

- backend 启动一个**专用 runtime 容器**，在容器内启动 **action execution server**；
- backend 通过 **HTTP 接口**发送 action，收回**结构化 observation**；
- **模型留在执行边界之外**，容器里跑的只有可能造成破坏的操作。

这层分离是自建时最重要的控制点——镜像策略、工作区挂载、资源限制、进程清理、审计日志全挂在这里。也意味着 **Docker 不是"顺便用了"**：它是 OpenHands 安全与调度模型的一部分。

镜像工作流也比"每个任务 build 一次"讲究，评测方观察到**三层 tag**：

1. **versioned**：绑定 OpenHands 版本与 base 镜像；
2. **lock**：由 base 镜像 + 依赖文件推导；
3. **source**：包含 OpenHands 源码 hash。

命中 source 镜像可整体复用；只命中 lock 层时，可以**只拷变化的源码**而跳过缓慢的依赖安装。这能减少重复构建，但生产环境仍应**直接 pin 不可变 digest**，而不是依赖会移动的 tag。

最短启动路径（CLI 栈）：

```bash
uv tool install openhands --python 3.12
openhands serve --mount-cwd

```

`--mount-cwd` 会把当前仓库挂进工作区——**方便，也意味着有写权限的 Agent 能改这个挂载里的一切**。更可控的复现要走固定版本的容器，并且要挂 `/var/run/docker.sock`（直连部署里 Agent 需要用它创建和管理 sandbox 容器）：

```bash
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 成本模型：什么时候自建更划算

自建的月成本可以写成：

```text
自托管月成本 = worker 基础设施 + 工程维护 + 可观测性与存储
             + LLM / 本地推理 + 安全与事故开销

托管月成本   = 席位数 × 单席位月价 + 超量 + 集成开销

```

评测方给了一个**示例**（不是 Devin 报价，也不是真实 OpenHands 账单）：worker + 日志 $600/月；运行时维护 12 工程师·小时/月；全负担工程费率 $150/小时；自托管模型用量 $120/活跃用户/月；托管替代 $500/活跃用户/月。于是：

```text
固定成本 = $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 协作"从**运行时依赖**降级成了**文件约定**：进程可以崩、可以重启，状态留在磁盘上。

![Munder Difflin 的办公室界面：左侧是 Agent 工位与实时状态，右侧是 Command Center 与终端流](https://www.hubwiz.com/blog/content/images/2026/10/floor_r.png)

### 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 是其余一切。"** 他把"其余一切"拆成**五个层**，并逐层写代码验证——结论是：**五层全是承重墙，少任何一层，都会在真实使用约一天内以可预测的失败模式暴露**：

1. **执行边界**：模型"决定调用工具"与工具"真正执行"之间的代码。只在 system prompt 里写"不要做危险操作"没有用——作者前后换了 11 种措辞都失败，最后写了一个 pre-dispatch 闸门，用拒绝模式（如 `rm -rf /`、`git push --force`）在工具执行前拦下调用。
2. **沙箱**：容器隔离（Linux namespaces / cgroups）久经验证、启动在毫秒级；但**共享内核才是攻击面**——内核漏洞或容器逃逸配置错误会把宿主交出去，所以不可信或模型生成的代码不应裸跑在容器里、旁边还放着你在意的东西。再上一层是微虚拟机：Firecracker 给每个 VM 独立内核，约 **125ms 启动**、每 VM **<5MiB 内存开销**、单机可达约 **150 VM/s** 的启动密度（AWS 公开数据，已被独立复现）。
3. **记忆持久化**：真正出事的是跨会话持久化——条目**不会自己过期**。作者见过 Agent 自信引用一个三周前已被推翻的决定。最小实现用 **SQLite + 显式 TTL** 就够；在上向量库之前，先证明你需要它。
4. **验证循环**：evaluator-optimizer 必须配**硬性迭代上限**——作者有一个翻译任务在没有上限时被评测器越挑越细的毛病拖到 **41 轮**，最后手动杀掉。这也是成本失控最常见的来源。
5. **上下文管线**：三个动词——**select（选取）、compress（压缩）、isolate（隔离）**，按 token 预算组装上下文，而不是把历史无限 append 给模型。这一层最常被跳过，因为它"看起来不像 bug，直到 token 账单像 bug"。

所以自己实现的起点不是"选一个框架"，而是**先把这五层的失败模式定义出来**，再决定每层用现成组件还是自己写。想从上下文层切入的人，可以继续读我们之前编译的 [给 coding agent 一份自己的记忆](https://www.hubwiz.com/blog/give-your-coding-agents-a-memory-you-own/)；想从编排层切入，读 [多 Agent 团队到底值不值](https://www.hubwiz.com/blog/do-agent-teams-pay-off/)。

---

## 来源

- 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 完全指南](https://www.hubwiz.com/blog/vibe-coding-stack/)；也推荐继续读 [一台终端、多台机器、多个 Agent](https://www.hubwiz.com/blog/parallel-coding-agents-multi-machine/) 与 [为什么多智能体编程会失败](https://www.hubwiz.com/blog/why-multi-agent-coding-fails/)。

> **这是「AI 编程 / Vibe Coding」专题的一部分。**完整地图见：[AI 编程 / Vibe Coding 完全指南](https://www.hubwiz.com/blog/vibe-coding-stack/)