多智能体协作编程的桌面工作台搭建

文章内容

一、项目概述

AgentPlanFlow 是一个面向多智能体协作编程的桌面工作台。它把 Codex(OpenAI)、Claude Code(Anthropic)和 Hermes(Nous Research)组织在同一个原生桌面窗口里,让不同智能体可以围绕同一工作目录运行、协作、委托任务,并共享执行上下文。

它并不是简单地把几个终端拼在一起。AgentPlanFlow 在桌面侧负责窗口、终端、进程和跨面板控制,在服务侧提供模型 API 代理、请求记录、控制台输出和 Trace 事件管理。这样一来,用户既可以直接操作每个智能体,也可以让 Hermes 拆解任务后,把子任务委托给 Codex 或 Claude,再把结果带回编排流程。

AgentPlanFlow 还集成了 Codex App / Codex Desktop。桌面层会启动 codex-desktop,再通过 X11 窗口定位与同步方案,把 Codex App 视觉嵌入到 GTK 工作台左侧区域。用户可以在 Codex App 中保留完整的图形化交互体验,同时继续使用 Codex CLI 面板参与 Hermes 的自动委托链路。

各面板的职责如下:

面板 运行对象 主要职责
Codex App OpenAI Codex Desktop 图形化 Codex 交互入口,视觉嵌入 GTK 工作台
Codex OpenAI Codex CLI 代码生成、修复和局部实现,可被 Hermes 委托
Claude Code Anthropic Claude CLI 代码审查、重构建议和复杂推理
Hermes Nous Research Hermes CLI 任务拆解与编排,可通过 ask_codex / ask_claude 委托子任务
Trace 内置 Trace / Console 面板 展示代理请求、控制台输出和任务事件

这个设计的核心目标,是把不同智能体的优势放进同一个开发工作流:Codex 偏向出图,Claude 偏向审查和解释,Hermes 则负责拆解、调度和串联任务。

AgentPlanFlow 桌面面板

二、技术栈

层次 技术选型 工程结构
桌面 GUI Python 3 + GTK3 + VTE index.py、app/
Codex 桌面嵌入 X11 窗口嵌入与同步 app/embed/
跨面板控制 PTY + Unix Domain Socket + JSON app/control_server.py、service/hermes/bridge/
API 代理服务 Rust + Tokio + Axum service/proxy/
Web 仪表盘 Rust + Axum + SSE service/proxy/crates/web_app/
终端仪表盘 Rust + Ratatui service/proxy/crates/tui_app/
Python 绑定 PyO3 service/proxy/crates/python_api/
容器化 Docker + Compose docker/

核心依赖关系可以概括为:

  • index.py 是 GTK3 桌面应用入口,负责创建窗口、读取配置、启动 Codex、Claude、Hermes 和 Trace 面板。
  • CodexEmbedder 负责启动并管理 Codex App,把 codex-desktop 作为独立 X11 顶层窗口固定到 GTK 嵌入区。
  • Codex、Claude、Hermes 分别运行在独立 PTY 中,保留各自原生 CLI 的认证、会话和交互体验。
  • Hermes 通过 Bridge Plugin(agentplanflow-bridge)访问本机 Unix Socket,把任务发送到 Codex 或 Claude 面板。
  • Rust Proxy Service 提供 OpenAI / Anthropic 风格的兼容路由,并把请求、响应和控制台输出推送到观测层。

三、系统架构

3.1 整体架构图

下图展示了 AgentPlanFlow 从桌面窗口到上游模型服务的整体链路。

AgentPlanFlow 整体架构

架构可以分为四层:

  1. 桌面窗口层 Desktop:GTK3 + VTE 承载 Codex App、Codex CLI、Claude Code、Hermes 和 Trace。Codex App 通过 X11 视觉嵌入固定在桌面工作台中,其他智能体则以 PTY 终端面板运行。
  2. 服务应用层 Service App(Python):负责 PTY 进程管理、Unix Socket 控制服务和面板输出采集,是桌面窗口和智能体 CLI 之间的协调层。
  3. 代理服务层 Proxy Service(Rust):负责 API 代理、请求记录、Trace 事件、Web / TUI 仪表盘,以及 Python API 绑定。
  4. 上游 LLM 服务:真正处理模型请求的服务端,可以是不同模型提供方或兼容 OpenAI / Anthropic 协议的服务。

主要数据流有两条:

  • 任务委托流:用户把任务交给 Hermes,Hermes 通过 ask_codex 或 ask_claude 发起委托;请求经 Unix Socket 到达 Control Server,再写入对应 PTY 面板,最终把终端输出作为结果返回。
  • 模型代理流:Codex CLI、Claude Code 或其他客户端发起模型请求;Proxy API Server 接收后路由到上游 LLM 服务,并把请求摘要、响应预览和 Trace 事件交给 Manager Service。

Codex App 是一个独立的图形化入口。它由 AgentPlanFlow 统一启动、定位、隐藏和恢复,但不直接参与 Hermes 的 PTY 委托返回链路。

3.2 Rust Proxy Service 内部模块结构

Proxy Service 内部模块

Cargo.toml :

toml
# service/proxy/Cargo.toml[workspace]members = [    ".",    "crates/trace/lib",    "crates/clients",    "crates/clients/common",    "crates/clients/deepseek",    "crates/clients/minmax",    "crates/plan",    "crates/http-proxy",    "crates/api_server",    "crates/manager",    "crates/python_api",    "crates/tui_app",    "crates/web_app",]

Proxy Service 由两类模块组成:

  • 核心服务:main 是程序入口;api_server 负责 API 代理,默认监听 127.0.0.1:3001;manager 负责 Console / Trace 管理,默认监听 127.0.0.1:3002;web_app 提供 Web 仪表盘,默认监听 127.0.0.1:3000。
  • 支撑模块:plan 承担任务拆解和协作相关能力;clients 封装上游模型客户端;trace 提供追踪基础设施;python_api 通过 PyO3 暴露 Python 扩展;tui_app 提供终端仪表盘;vendor 放置外部协议和执行策略相关依赖。

api_server、manager 和 web_app 构成了运行时的服务闭环:API Server 处理模型请求,Manager 聚合可观测数据,Web / TUI / Trace 面板再把这些数据展示出来。

四、核心工作流程

4.1 应用启动流程

下图展示从执行入口到桌面面板可用的启动过程。

AgentPlanFlow 启动流程

python
# index.py:4629-4672(精简)def main() -> int:    args = parse_args()    app_config = load_app_config()    # ... 加载配置、解析 CWD    maybe_reexec_with_system_python()   # ① 检查 GTK 环境    gtk = load_gtk()                    # ② 加载 GTK/VTE 绑定    builder = AppBuilder(gtk)    terminal_pane_cls = build_terminal_pane_class(...)    main_window_cls = builder.main_window_class(terminal_pane_cls)    terminal_app_cls = builder.terminal_app_class(main_window_cls)    app = terminal_app_cls(             # ③ 构建 GTK Application        codex_runtime.resolve_cli_command(args.codex_cmd),        claude_runtime.resolve_cli_command(args.claude_cmd),        hermes_runtime.resolve_cli_command(args.hermes_cmd),        args.proxy_cmd,        cwd, ...    )    return app.run(sys.argv)            # ④ 进入 GTK 主循环

启动流程分为 6 步:

  1. 检查 GTK 环境:maybe_reexec_with_system_python() 检查 PyGObject、GTK3 和 VTE 是否可用,必要时切换到系统 Python 重新执行。
  2. 加载配置文件:读取 config.yaml、model_config.yaml、api_key_config.yaml 等配置,准备工作目录、模型和代理参数。
  3. 构建桌面窗口:创建 GTK3 主窗口,并组织 Codex App 嵌入区、Codex、Claude、Hermes、Trace 和状态栏布局。
  4. 启动面板进程:在独立 PTY 中启动 Codex、Claude、Hermes 等 CLI;同时启动 codex-desktop,等待其 X11 窗口被捕获后同步到嵌入区。
python
# app/embed/codex_embed.py:1-14"""Visually-embedded codex-desktop window via X11 position synchronisation.We tried real XReparentWindow into a host widget, but Chromium's top-levelwindows can't survive being reparented to a non-root parent — Electron detectsit and quits. Instead we keep codex-desktop as its own top-level X window and:* strip its decorations (_MOTIF_WM_HINTS)* mark it as _NET_WM_STATE_SKIP_TASKBAR / SKIP_PAGER / ABOVE* set WM_TRANSIENT_FOR to our main window so the WM treats it as a child* keep it positioned over the EventBox host area in screen coordinates"""

实际做法是去掉窗口装饰、标记跳过任务栏、设置 WM_TRANSIENT_FOR 让它跟随主窗口,然后用屏幕坐标持续同步位置。

  1. 启动控制服务:创建 cache/control.sock,监听来自 Hermes Bridge Plugin 的跨面板请求。
  2. 进入交互状态:窗口恢复布局,Hermes 面板获得焦点,用户可以开始输入任务。

这条启动链路的关键点是先准备桌面运行环境,再启动智能体面板,最后开放跨面板控制。这样可以保证 Hermes 开始编排任务时,Codex / Claude 面板和本地 Socket 服务都已经就绪。

4.2 跨智能体协作流程

Hermes 将子任务委托给 Codex 或 Claude 的链路。

Hermes 委托子任务流程

以"先让 Codex 生成代码,再让 Claude 审查"为例,协作过程如下:

  1. Hermes 理解用户任务,决定调用 ask_codex 或 ask_claude。
  2. Bridge Plugin(agentplanflow-bridge)把委托内容封装成本地 JSON 请求。
  3. 请求通过 Unix Domain Socket 发送给 Control Server。
  4. Control Server 执行 run_prompt 动作,把 prompt 写入目标面板的 PTY stdin。

Control Server 的 _run_prompt 方法实现如下:

python
# app/control_server.py:132-167(精简)def _run_prompt(self, request: dict[str, Any]) -> dict[str, Any]:    pane_label = str(request.get("pane") or "Codex")    prompt = str(request.get("prompt") or "")    idle_timeout = max(0.5, float(request.get("idle_timeout") or 2.0))    timeout = max(idle_timeout, float(request.get("timeout") or 90.0))     pane = self._invoke_main(self._owner.get_pane_by_label, pane_label)    # ... 检查 pane 是否存在、进程是否在运行     # 用 bracketed-paste 包装 prompt,防止多行内容被 TUI 拆散    wrapped = "\x1b[200~" + prompt + "\x1b[201~"    self._invoke_main(pane.send_text, wrapped, submit=False, focus=True)    if submit:        time.sleep(0.1)           # 等 paste end marker 生效        self._invoke_main(pane.submit_enter)
  1. Codex 或 Claude 在原 CLI 会话中执行任务,并持续向 PTY stdout 输出结果。
  2. Control Server 读取终端输出,并通过输出变化和 idle timeout 判断任务是否完成:
python
# app/control_server.py:187-202(精简)started_at = time.monotonic()saw_change = Falsewhile time.monotonic() - started_at < timeout:    latest_state = self._invoke_main(pane.activity_state)    revision = int(latest_state.get("revision") or 0)    if revision > effective_baseline:        saw_change = True    if saw_change:        last_activity = float(latest_state.get("last_activity_monotonic") or started_at)        if time.monotonic() - last_activity >= idle_timeout:            break              # 终端输出停止 idle_timeout 秒,判定任务完成    time.sleep(0.2)
  1. 任务结果沿 Socket 返回给 Bridge Plugin,再回到 Hermes 的上下文中。
  2. Hermes 根据返回结果继续拆解任务、调用另一个智能体,或把最终结论交还给用户。

这条链路的特点是低侵入。AgentPlanFlow 不要求 Codex 或 Claude 暴露额外 API,而是复用已有 CLI 的认证、会话、模型配置和交互界面。代价是任务完成判断依赖终端输出和 idle timeout,因此长时间流式输出、强交互确认或输出格式变化,都需要更谨慎地配置超时和结果抓取策略。

4.3 API 请求代理流程

下图展示模型请求经过 Proxy Service 的转发过程。

API 请求代理流程

代理链路如下:

  1. Codex CLI、Claude Code 或其他客户端发起 HTTP 模型请求。
  2. Proxy API Server(Rust Axum,默认端口 3001)接收请求。

Proxy Service 的入口在 service/proxy/src/main.rs:

rust
// service/proxy/src/main.rs:55-84(精简)#[tokio::main]async fn main() -> Result<()> {    let cli = Cli::parse();    let file_config = FileConfig::load_from(&app_root().join("config.yaml"))?;    trace::set_enabled(file_config.resolve_trace_enabled());     match cli.command {        Some(Command::Serve { api_bind, web_bind, workspace, .. }) => {            let runtime = build_runtime(&file_config, api_bind, web_bind,                                        workspace, base_url, model, api_key)?;            ensure_runtime_ports_free(&runtime)?;  // 端口占用检测            if tui {                run_runtime_with_tui(runtime).await            } else {                run_runtime_servers(runtime).await  // 启动 API + Manager + Web            }        }        // ...    }}
  1. API Server 根据路径进入 OpenAI 风格或 Anthropic 风格的兼容处理逻辑,例如 /v2/chat/completions、/v1/* 和 /anthropic/v1/messages。
  2. Proxy Service 根据模型配置选择对应的上游客户端,并转发请求。
  3. 上游 LLM 服务返回普通响应或 SSE 流式响应。
  4. 响应沿原请求路径返回给调用方。
  5. Manager Service 同步记录请求摘要、响应预览、Trace 事件和 Console 输出,供 Web 仪表盘、TUI 仪表盘和 Trace 面板查看。

这层代理的职责不只是"转发请求",而且将模型适配、协议兼容和运行观测集中聚合到一个 Rust 服务。

五、Q&A

5.1 为什么选择桌面应用,而不是纯 Web 应用?

  • 保留原生 CLI 体验:Codex、Claude 和 Hermes 仍以各自熟悉的终端形态运行,用户可以随时查看、输入和干预。
  • 复用本地开发环境:工作目录、认证状态、终端配置和模型选择都可以跟随本机环境,不需要重新搬到浏览器沙箱中。
  • 支持 Codex App 嵌入:在 X11 环境下,Codex Desktop 可以被嵌入到 GTK 工作台中,形成更统一的桌面体验。
  • 本地控制链路更短:跨面板委托通过 Unix Socket 和 PTY 完成,适合单机桌面场景。

5.2 为什么同时保留 Codex App 和 Codex CLI?

Codex App 和 Codex CLI 在 AgentPlanFlow 中承担的是两种互补入口。

  • Codex App 更适合用户主动探索、调整和继续对话,保留 Codex Desktop 自身的产品化体验。
  • Codex CLI 面板 更适合被 Hermes 自动委托,因为它运行在可控 PTY 中,Control Server 可以写入 prompt、读取 stdout,并捕获任务结果。
  • 嵌入方式低侵入:AgentPlanFlow 不改造 Codex App 内部实现,只负责启动、定位、隐藏和尺寸同步,因此 Codex App 可以继续按原应用方式升级和运行。
  • 工作流边界清晰:人工探索走 Codex App,自动化子任务和跨面板结果回传走 Codex CLI PTY。

因此,两者并不是重复建设。Codex App 提供更完整的人工交互体验,Codex CLI 提供更适合编排的机器可控通道。

六、总结

整体来看,AgentPlanFlow 更像是一个本地多 Agent 编程实验平台。将智能体协作从"多个终端之间手动切换"推进到"统一桌面中的可编排工作流":

  • 多智能体协作:Codex 负责实现,Claude 负责审查,Hermes 负责任务拆解和编排。
  • Codex App 嵌入:在 GTK 工作台内提供图形化 Codex 入口,同时保留 Codex CLI 作为可委托的自动化通道。
  • 低侵入集成:通过 PTY 和 Unix Socket 复用已有 CLI 会话,而不是强制接入专用 API。
  • 可观测工作流:通过 Manager、Trace、Console、Web 和 TUI 视图观察请求与任务执行过程。
  • 本地桌面体验:GTK3、VTE 和 Codex 桌面嵌入让多个智能体集中在一个窗口中工作。
  • 可扩展代理层:Rust Proxy Service 为模型兼容、请求记录和后续多模型适配提供基础。

本文由 AgentPlanFlow 生成

觉得不错?给作者点个赞吧

分类:Agent

评论 (0)

无需注册,留言经站长审核后公开。

加载评论中…

多智能体协作编程的桌面工作台搭建 · Yinchen 的博客