Stephen 技术博客

AI和数据平台的工程实践

← 返回文章列表
META-HARNESS · 分布式 Agent 平台

Omnigent 架构总览

在 Claude Code / Codex / Pi / 自定义 agent 之上的统一层 —— 跨设备实时协作、混用多 agent、统一策略与沙箱

一句话定位:Omnigent 是一个"元 harness"。它不重新发明 agent,而是在各家 agent 框架(Claude Code、Codex、Pi) 之上抽象出统一层,让你能够 swap or combine harnesses(随意切换/组合)、跨设备接管同一个 live session、 并对所有 agent 统一加上策略(policies)和沙箱(sandbox)。核心思想是: Server 只做协调,真正的 agent 执行发生在你的机器或云沙箱上

Omnigent 架构总览 A meta-harness — 在 Claude Code / Codex / Pi / 自定义 agent 之上的统一层 ① 客户端 跨设备实时协作 · 会话跟随你走 浏览器 Web UI 手机 桌面 App CLI/终端 ap-web/ (React+Vite+xterm) REST · WS /sessions/updates · WS terminal ② Server 轻量协调器 · 不跑 agent 代码 · 可水平扩展 omnigent/server/ (FastAPI) 路由 routes/sessions · hosts*_tunnel · auth · policies 内存注册表HostRegistryTunnelRegistry(活连接) 策略引擎PolicyEngineALLOW / DENY / ASK 认证header / accountsOIDC · 4级权限 DBSQLite/PG跨副本真相 conversations · itemsagents · hosts · users WebSocket 隧道(host/runner 主动外连 server)穿 NAT/防火墙 · 无需开放入站端口 · 帧协议 = HTTP-over-WS ③ Host 你的笔记本 或 云沙箱(Modal/Daytona)— 真正执行的地方 omnigent/host/ · `omnigent host` 守护进程 daemon收 host.launch_runner 帧 → 派生 Runner 身份 host_<uuid>~/.omnigent/config.yaml 一台 host 可跑多个 Runner(每会话一个)云沙箱 = managed host(server 注入 token,用完即弃) subprocess(每个 session 派生一个) ④ Runner 每个 session 一个进程(FastAPI) omnigent/runner/ (+ WS 隧道传输) harness 生命周期spawn / 监控 / 回收 工具分发回传 server 执行 文件/终端/MCPtmux PTY · 资源 成本统计 · 审批中转token/费用 · ASK 流程 Unix socket(每个对话一个) ⑤ Harness + Executor "meta-harness" 的核心 · 跑 LLM 循环 omnigent/runtime/harnesses/ · inner/*_executor.py claude-sdk claude-native codex codex-native pi openai-agents 统一接口:Executor.run_turn() → AsyncIterator[ExecutorEvent] TextChunk · ToolCallRequest · TurnComplete — 上层只认这套接口,因此可以 swap / combine harness ⑥ 底层模型 / CLI API key · 订阅(Claude Pro/Max · ChatGPT/Codex)· 兼容网关 — 全部一等公民 Claude Code CLI codex CLI OpenAI/本地 横切关注点 ▸ 策略 Policies:session → agent → server 三级,工具调用边界评估 ▸ 沙箱 Sandbox:Linux bwrap / macOS seatbelt(os_env 配置) ▸ 多 agent 编排:sys_session_send / read_inbox / session_create Agent 配置(agent.yaml → AgentSpec) ▸ executor:harness + model + auth ▸ tools:MCP / 函数 / 子 agent ▸ prompt:系统提示 ▸ guardrails:策略 / 标签 ▸ os_env:沙箱 ▸ spawn:能否创建自定义子 agent

图 1 · Omnigent 六层架构:客户端 → Server → Host → Runner → Harness/Executor → 模型

客户端层

跨设备实时协作 —— 会话跟随你走:终端发起、浏览器继续、手机接管,消息/子 agent/终端/文件全程同步。

技术栈与通道

前端在 ap-web/:React 18 + TypeScript + Vite + Tailwind + xterm(终端模拟)。 vite build 的产物输出到 omnigent/server/static/web-ui/,由 server 在 / 直接 serve。

与 Server 三种通道:

REST:会话 CRUD / 发消息 WS /v1/sessions/updates:实时推快照+diff WS .../terminal:桥接 tmux PTY 到浏览器

Server 层 —— 轻量协调器

FastAPI,本身不跑 agent 代码。负责存储会话/用户/agent/策略、做路由与策略校验。内存注册表放活连接,DB 是跨副本真相,因此可水平扩展。代码在 omnigent/server/

路由模块职责
routes/sessions.py会话 CRUD、消息派发、SSE 事件流、文件上传(最大模块)
routes/host_tunnel.pyWS /v1/hosts/{id}/tunnel —— host 守护进程外连
routes/runner_tunnel.pyWS /v1/runners/{id}/tunnel —— runner 外连
routes/hosts.py列出 host、启动 runner、代理文件系统浏览
routes/auth.py / accounts_auth.pyheader / 账号密码 / OIDC 三种认证,4 级权限
routes/*_policies.pysession / server-wide 策略 CRUD

持久化(omnigent/db/ + omnigent/stores/):SQLAlchemy + Alembic,SQLite(本地)或 Postgres(部署)。核心表: conversations(会话)、conversation_items(消息/工具调用)、agentshostsuserssession_permissionsfiles。每表对应一个 Store 抽象。

Host 层 —— 真正执行的地方

omnigent host 守护进程,可以是你的笔记本,也可以是云沙箱(Modal/Daytona = managed host)。代码在 omnigent/host/

身份 host_<uuid> 存在 ~/.omnigent/config.yaml,首次 omnigent host 自动创建。 守护进程主动外连 Server 建 WebSocket 隧道,收到 host.launch_runner 帧后派生一个 Runner 子进程(每个 session 一个),并监控其退出、上报状态。

为什么是外连? Host/Runner 都主动拨向 Server,Server 被动接受 —— 这样穿 NAT/防火墙、无需开放任何入站端口,隧道用 JSON 帧把 HTTP 请求封装在 WebSocket 上(HTTP-over-WS)。

Runner 层 —— 每会话一个进程

每个 session 派生一个 FastAPI 子进程(omnigent/runner/),是 host 与 harness 之间的中间层。

职责说明
harness 生命周期按对话 spawn / 监控 / 回收 harness 子进程,空闲回收
工具分发把 harness 的工具调用回传 Server 执行(文件、shell、MCP)
资源管理文件、终端(tmux PTY)、MCP 池
成本 / 审批统计 token 与费用;中转策略 ASK 审批流

Harness + Executor —— meta-harness 核心

这是"统一层"真正落地的地方。每个 harness 被包成一个讲同一套 Omnigent REST 协议的 FastAPI 服务,内部用 Executor 适配各家 SDK/CLI。 核心 7 条设计单独成文 → Meta-Harness 核心 7 设计

Harness 注册表 omnigent/runtime/harnesses/__init__.py

_HARNESS_MODULES = {
  "claude-sdk":    "...claude_sdk_harness",
  "claude-native": "...claude_native_harness",   # 包真实 Claude Code CLI
  "codex":         "...codex_harness",
  "codex-native":  "...codex_native_harness",     # 包真实 codex CLI
  "pi":            "...pi_harness",
  "openai-agents": "...openai_agents_sdk_harness",
}

统一接口 —— 为什么能 swap / combine

所有 harness 最终都实现同一个抽象:

class Executor:
    async def run_turn(messages, tools, system_prompt, config)
        -> AsyncIterator[ExecutorEvent]
        # 事件:TextChunk · ToolCallRequest · TurnComplete · ReasoningChunk ...

上层(workflow / runner)只认 Executor 这套事件流,完全不关心底下是 Claude SDK 还是 codex CLI。 这就是 README 所说 "swap or combine harnesses without rewriting" 的实现根基。具体实现在 omnigent/inner/*_executor.py(例如 codex_executor.py)。

底层模型 / CLI

凭证全部一等公民:API key、订阅(Claude Pro/Max、ChatGPT/Codex)、兼容网关(OpenRouter/Ollama)。 native harness 直接包真实 CLI(Claude Code / codex),复用其订阅登录。

Agent 配置:agent.yaml → AgentSpec

一个 agent 由声明式 YAML 定义(docs/AGENT_YAML_SPEC.md),解析为 AgentSpec(omnigent/spec/types.py)。

字段含义
executorharness + model + auth —— 跑在什么上
prompt系统提示
toolsMCP 服务、Python 函数、子 agent
guardrails策略、标签、ASK 超时
os_env本地文件/shell 沙箱配置
spawn是否允许用 sys_session_create 创建自定义子 agent

多 agent 编排

编排器(如示例 examples/polly/)通过系统工具异步派发子 agent: sys_session_send 派活 sys_read_inbox 收结果 sys_session_create 创建子 agent

每个子 agent 各自跑自己的 harness —— 例如 polly 的大脑跑 Claude,把编码任务委派给 codex 子 agent, 这些 codex 子 agent 共享你的 Codex 订阅(凭证桥接见下文)。

策略与沙箱(横切)

三级策略(session → agent → server-wide)在工具调用边界由 PolicyEngine 评估,返回 ALLOW / DENY / ASK。 内置:成本预算、危险工具需审批、GitHub/Google 工作区限制、模型路由等。沙箱按 os_env 走 Linux bwrap / macOS seatbelt。

一次用户请求的完整数据流

  1. 浏览器创建会话 POST /v1/sessions,Server 建 conversations 行并选定 host
  2. Server 经 host 隧道发 host.launch_runner → Host 派生 Runner 子进程
  3. Runner 主动外连 WS /v1/runners/{id}/tunnel 注册
  4. 用户发消息 POST /v1/sessions/{id}/events → Server 过策略、存 DB、经隧道转给 Runner
  5. Runner 经 Unix socket 转给 harness 子进程 → harness 跑 LLM 循环
  6. harness 要调工具 → 回传 Server 执行(文件/shell/MCP)→ 结果回灌继续循环
  7. 事件流式回传 → Server 经 WS /v1/sessions/updates 推给前端实时渲染

Codex 订阅如何被多 agent 共用

每个 session 创建私有临时 CODEX_HOME,再把用户真实 ~/.codex/ 桥接进去 (omnigent/inner/codex_executor.py):

auth.json → 软链接(共享订阅 + token 自动刷新) config.toml → 复制(隔离模型/成本策略) 剥离 OPENAI_API_KEY(强制走订阅而非按量计费)

因此多个 agent/session 共享同一份订阅凭证,但各自的模型选择与会话历史互不干扰。

目录速查

目录是什么
omnigent/cli.pyCLI 总入口(omnigent/omni)
omnigent/server/FastAPI server、路由、认证
omnigent/host/host 守护进程
omnigent/runner/runner + WS 隧道传输
omnigent/runtime/harnesses/harness 注册与进程管理
omnigent/inner/*_executor.py各家 Executor 实现(含 codex_executor.py)
omnigent/spec/AgentSpec 类型定义
omnigent/policies/ · sandbox/策略与沙箱
omnigent/stores/ · db/持久化
ap-web/React 前端
deploy/Docker / Render / Railway / Fly / Modal 部署
examples/polly · debby示例 agent(多 agent 编排器 / 双头脑)
Omnigent 架构总览 · 基于代码仓库 main 分支梳理生成 · 配套图见 docs/architecture.svg