Featured image of post Andrew Ng 开源了 OpenWorker!一个交付「成品」的桌面 AI 同事,深入源码拆解

Andrew Ng 开源了 OpenWorker!一个交付「成品」的桌面 AI 同事,深入源码拆解

Andrew Ng 最近又搞了个大事情——他开源了一个叫 OpenWorker 的项目,短短时间就冲到 9.8k Star。但这不是又一个「Agent 框架」或「编码 Agent」,而是一个直接交付成品的桌面 AI 同事

什么叫「交付成品」?你说「帮我准备一份客户简报」,它不会回你一段 Markdown 让你自己去整理,而是真的生成一个 .docx 文件、一封邮件草稿、一条已排好版的 Slack 消息。你说「理一下我的日历」,它真的去改 Google Calendar。你说「查一下发版进度」,它去 Jira 和 GitHub 拉数据,回来给你一条完整的回复。

这个定位和我之前分析过的几个项目很不一样。OpenHands 是编码 Agent 的控制中心,OpenTag 是聊天平台的 Agent 机器人,Nanobot 是轻量级 Agent 框架——而 OpenWorker 是一个 桌面 App,一个真正坐在你电脑上替你干活的「同事」。

这篇文章从源码出发,拆解 OpenWorker 的架构设计。它的代码质量很高——毕竟是 Andrew Ng 团队的作品——很多设计思路值得做 Agent 基础设施的人认真看。

TurnEngine:一个精心设计的异步 Agent 循环

OpenWorker 的核心是 coworker/engine.py 里的 TurnEngine。它不是普通的「LLM 循环」,而是从实际桌面 Agent 的需求出发设计的一个异步循环引擎。

核心设计决策有几个:

1. 并发工具执行

当模型在一次 turn 里请求多个工具调用时,低风险的(读文件、搜索)并发执行,高风险的(写文件、Shell 命令)严格串行

# 低风险工具:并发
asyncio.gather(*[safe_tool(t) for t in tool_calls])

# 高风险工具:串行
for t in write_tool_calls:
    await execute_with_approval(t)

这和 OpenTag 的 MCP 容错设计(独立连接 + 超时泄漏防护)思路一致——都认识到 Agent 不是「调用一次」就完事的,而是需要精细的并发控制。

2. 审批门(Approval Gate)

每次写操作前,PermissionEngine 检查是否需要用户批准。需要时,引擎发射 PERMISSION_REQUIRED 事件并等待 approver 的结果:

class ApprovalOutcome(str, Enum):
    ONCE = "once"        # 只允许这一次
    ALWAYS_TOOL = "always_tool"    # 以后这个工具自动允许
    ALWAYS_COMMAND = "always_command"  # 以后这个命令自动允许
    DENY = "deny"        # 拒绝

这个设计的巧妙之处在于,审批结果可以「升级」——用户从「这次允许」升级到「以后这个工具都允许」,减少重复审批。对比 OpenTagconfirm_write(只有一次/取消),OpenWorker 的 approver 更灵活。

3. Steering(方向盘)机制

TurnEngine 支持用户在执行过程中「插话」干预——通过 _steering 列表:

# 用户可以在 Agent 执行中间发来新的指令
self._steering: list[tuple[str, Optional[dict[str, Any]]]] = []

这意味着你不需要等 Agent 执行完一轮才能纠正它——你可以随时说「等等,换这个方向」。这和 Pi Agent 的「Steering + Follow-up 双队列」设计理念一致,但 Pi Agent 的 steering 是架构层面的队列,OpenWorker 的是用户交互层面的插话。

25+ 连接器:从工具到 Connector 的抽象

OpenWorker 最亮眼的功能是 25+ 连接器(connectors)——Slack、GitHub、Jira、Notion、Linear、HubSpot、Outlook、Gmail、Google Calendar……几乎覆盖了日常工作需要的所有工具。

coworker/connectors/ 下,每个连接器是一个独立的模块。架构很有意思:

┌────────────────────────────────────────────────────────┐
│                    TurnEngine                           │
├────────────────────────────────────────────────────────┤
│  ToolRegistry                                           │
│   ├── 内置工具 (shell, files, web_search, ...)          │
│   └── Connector 工具 (动态注册)                          │
│        ├── slack_send_message                           │
│        ├── github_list_issues                           │
│        ├── jira_get_ticket                              │
│        ├── notion_search_pages                          │
│        ├── linear_create_issue                          │
│        ├── gmail_search_threads                         │
│        ├── google_calendar_list_events                  │
│        └── ...                                          │
├────────────────────────────────────────────────────────┤
│  PermissionEngine                                       │
│  所有写操作 → Approval Gate                             │
└────────────────────────────────────────────────────────┘

连接器通过 connector_list() + load_settings() 发现哪些连接器已配置,然后 make_integration_tools() 动态生成工具。每个连接器可以声明多个工具(比如 Slack 连接器有 send_messagelist_channelsread_thread),但只有 enabled=True 的才被注册到 ToolRegistry。

这和 Nanobot 的多平台 Channel 抽象类似——Nanobot 有 15+ 聊天平台适配器,OpenWorker 有 25+ 工具连接器。但 Nanobot 的 Channel 是「把 Agent 放进聊天平台」,OpenWorker 的 Connector 是「让 Agent 操作你的工具」。

桌面 App 三层架构

OpenWorker 的部署架构是三层分离的:

┌────────────────────────────────────────────┐
│  GUI (surfaces/gui/)                       │
│  React UI + Tauri 桌面 Shell               │
│  · 会话管理                                 │
│  · 审批面板                                 │
│  · 文件浏览                                 │
│  · 自动更新                                 │
├────────────────────────────────────────────┤
│  Agent 服务器 (Python)                     │
│  · TurnEngine                              │
│  · ProviderRouter                          │
│  · ToolRegistry                            │
│  · PermissionEngine                        │
│  · MemoryStore                             │
│  · Automation                              │
├────────────────────────────────────────────┤
│  STT 侧车 (Rust)                          │
│  · 语音输入处理                             │
└────────────────────────────────────────────┘

这个三层分离和 OpenHands Agent Canvas 的架构如出一辙——前端 (React) + Agent Server (Python) + 辅助服务。但 OpenHands 用 Tauri 打包成桌面 App 还是最近的事,OpenWorker 从一开始就是桌面 App 设计。

技术栈对比:

组件 OpenWorker OpenHands
前端 React + Tauri React + Vite
Agent 运行时 Python (aisuite) Python (Agent Server)
桌面壳 Tauri (Rust) Electron (可选)
外部 Agent ❌ (自带引擎) ✅ ACP (Claude Code/Codex)
模型提供 14+ Provider OpenHands / ACP 自带
安装方式 DMG 下载 npm install / Docker

OpenWorker 走的是「自己做 Agent 引擎」的路线,不依赖 ACP 协议。这有利有弊——好处是完全掌控体验,坏处是不能直接用生态里的其他 Agent(比如用 Claude Code 写代码、用 OpenWorker 做文档)。

基于 aisuite 的 Provider 抽象

OpenWorker 的 Provider 层基于 Andrew Ng 的另一开源项目 aisuitecoworker/providers/ 下的 ProviderClient 用 aisuite 作为统一接口:

# 支持 14 个 Provider,统一接口
provider = ProviderClient(model="gpt-5.6-sol")
# 或
provider = ProviderClient(model="claude-sonnet-4-20260514")
# 或本地
provider = ProviderClient(model="ollama/llama-4")

配置通过 config.toml 管理:

model = "gpt-5.5"
mode = "interactive"
max_iterations = 12
allowed_commands = ["ls", "cat", "grep", "git status", ...]
host = "127.0.0.1"
port = 8765

特别值得注意 allowed_commands 配置——用户可以精确控制 Agent 能执行哪些 Shell 命令,不在列表里的命令需要审批。这和 OpenTag 的 Intelligence Gateway 模式(不持有平台 Token)都是「最小权限」原则的具体实现,但 OpenWorker 的粒度更细——命令级别的白名单。

三方横向对比

OpenWorker 的定位——桌面 AI 同事——在之前的项目中还没有完全对标的:

维度 OpenWorker OpenHands (Agent Canvas) OpenTag Nanobot
定位 桌面 AI 同事 编码 Agent 控制中心 聊天 Agent 平台 轻量 Agent 框架
安装方式 Desktop App (DMG) Web UI (npm/Docker) CLI + Chat 集成 CLI
核心引擎 TurnEngine (asyncio) Agent Server (Python) BuiltInAgent (TS) AgentLoop (asyncio)
工具系统 25+ Connectors + MCP ACP 子进程 MCP (Streamable HTTP) Python Tool 类
审批模型 4 级 (Once/Always/Deny) confirm_write (阻塞) confirm_write (阻塞) 无内置 HITL
模型支持 14+ Provider (aisuite) ACP Agent 自带 OpenAI-only 30+ Provider
桌面 UI ✅ Tauri (Rust) ⚠️ Electron (可选) ❌ 纯 Chat ❌ 纯 Chat
Slack 集成 ✅ @OpenWorker ✅ Automations ✅ 原生 ✅ 原生
MCP ✅ MCP client ✅ MCP (Linear/Notion) ✅ MCP client
记忆系统 ✅ MemoryStore ❌ 对话级 ❌ 对话级 ✅ Dream 记忆
自动化 ✅ 定时任务 ✅ 定时+事件 ✅ Intelligence Gateway

核心差异点:OpenWorker 的定位是「取代桌面工作流」,而其他几个项目都是「给开发者用的工具」。OpenWorker 的目标用户是「任何需要日常办公的人」——做简报、理日历、回邮件、查 Jira——而不仅是写代码的开发者。

安全隐患

OpenWorker 的 25+ 连接器意味着它持有大量第三方的 OAuth Token 和 API Key。虽然 README 强调「local-first,everything on your machine」,但有几个风险点:

  1. OAuth 代理服务:README 提到 “a small service that brokers OAuth handshakes for connectors”——这个代理服务如果是云端托管的,它理论上可以看到哪些连接器被授权了(但看不到 Token 本身)。

  2. 连接器权限放大:一个连接器的 Token 通常有全部读写权限。比如 Gmail 连接器可以读所有邮件、Google Calendar 可以改所有事件。Agent 只要调用了对应的工具,就可以做连接器 Token 允许的任何事——审批门是唯一的防线。

  3. 审批疲劳:虽然审批门可以升级到 ALWAYS_TOOL,但如果用户不小心点了「以后都允许」,一个有恶意 prompt 的任务就可以绕过审批执行任意写操作。

  4. Shell 访问allowed_commands 白名单可以限制 Shell 命令,但白名单中的命令如果被参数注入(比如 git 命令后跟恶意参数),仍然有风险。

相比之下,OpenHands 的 ACP 模式更安全——ACP Agent 运行在独立的子进程中,凭证不暴露给前端。OpenWorker 的把所有连接器 Token 放在本地密钥存储中,虽然「本地」减少了泄露面,但一旦进程被攻破,所有 Token 都可能被盗。

写在最后

OpenWorker 是 Andrew Ng 团队在 Agent 领域的最新尝试。和之前的 aisuite(统一 Provider 接口)不同,OpenWorker 是一个完整的端到端产品——从桌面 App 到 25+ 连接器到自动化调度,覆盖了日常办公的完整工作流。

它的架构设计——TurnEngine 的并发执行 + 审批升级 + Steering 插话——代表了「Agent 作为真正的同事」这一理念的工程实践。不再是把 Agent 当成聊天机器人,而是当成一个坐在你旁边的、能替你干活的人。

对于做 Agent 基础设施的人来说,OpenWorker 有几点值得参考:

  • TurnEngine 的并发控制:低风险工具并发、高风险串行,比「全串行」和「全并发」都更合理
  • 连接器动态注册make_integration_tools() 模式比硬编码工具列表更优雅
  • 审批升级:从「一次允许」到「永久允许」的递进式授权

当然,OpenWorker 还很新(72 个 commit),很多功能还在快速迭代中。但它的方向和定位非常清晰——不是又一个 Agent 框架,而是一个你真正可以交给他干活的「同事」。

GitHub: https://github.com/andrewyng/openworker

延伸阅读:

By AI博士 万戈