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" # 拒绝
这个设计的巧妙之处在于,审批结果可以「升级」——用户从「这次允许」升级到「以后这个工具都允许」,减少重复审批。对比 OpenTag 的 confirm_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_message、list_channels、read_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 的另一开源项目 aisuite。coworker/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」,但有几个风险点:
-
OAuth 代理服务:README 提到 “a small service that brokers OAuth handshakes for connectors”——这个代理服务如果是云端托管的,它理论上可以看到哪些连接器被授权了(但看不到 Token 本身)。
-
连接器权限放大:一个连接器的 Token 通常有全部读写权限。比如 Gmail 连接器可以读所有邮件、Google Calendar 可以改所有事件。Agent 只要调用了对应的工具,就可以做连接器 Token 允许的任何事——审批门是唯一的防线。
-
审批疲劳:虽然审批门可以升级到
ALWAYS_TOOL,但如果用户不小心点了「以后都允许」,一个有恶意 prompt 的任务就可以绕过审批执行任意写操作。 -
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
延伸阅读: