【UFO³】跨设备 Agent Galaxy 深度解析:Task Constellation DAG + AIP 协议
一句话结论:UFO³ 不是”另一个 GUI Agent”,它把 GUI 操作封装成 可声明、可编辑、可重放的 DAG(Task Constellation),并通过自研的 AIP(Agent Interaction Protocol) 协议让 Windows / macOS / Linux / iOS / Android / Web 6 类设备像”星座节点”一样协作 —— 它是 2026 年唯一同时实现”Workflow 组件 + 跨设备 MCP + 自演化”三个 Harness 原语的开源实现。
🎯 一句话开场
如果你用过 OpenHands、Stagehand、Browser-Use 这些”单设备 GUI Agent”,你大概率已经踩过这些坑:任务跑一半发现少截了一张图、跨 Excel 和 Outlook 的 12 步流程第 7 步崩了要重来、想中途加一个”先备份到 NAS”的步骤但 Agent 不让你插队。这些问题的根因不是模型不够强,而是 GUI Agent 缺一个工程化的”工作流层” —— 没有 DAG、没有节点依赖、没有可重放的执行轨迹,更没有跨设备协作。
microsoft/UFO(9,737 ⭐,MIT 协议,Python 主语言 + TypeScript WebUI,2026-09-15 仍在活跃)的 UFO³ Galaxy 模块就是来解决这件事的。它把”用户的一句话”拆成 TaskConstellation(星座 = DAG),每个节点叫 TaskStar(星),边叫 TaskStarLine(连线),整张图通过 AIP 协议 派发到不同设备去执行;执行结果回流后用 ConstellationEditor 命令模式做带 undo/redo 的动态编辑(加诊断节点、补 fallback、改依赖)。这一整套机制不是又一个 LangGraph 的克隆,而是 Microsoft 在 arXiv 2511.11332 里公开了形式化证明(DAG consistency invariants + 5 大安全性保证)。
读完这篇你会得到:
- TaskConstellation 的完整数据模型:TaskStar 的 11 个字段、TaskStarLine 的 4 种 DependencyType、ConstellationState 的 6 个状态机
- 5 大 Harness 原语 的真实可运行代码:Constellation Editor 命令模式、AIP 协议 Pydantic 定义、Strategy Dependency 声明式验证、Prompt Sanitizer 抗注入、TaskConstellationOrchestrator 异步调度
- UFO² vs UFO³ 的演化对比:单机 Windows AgentOS → 跨设备 Agent Galaxy 的 4 个关键跃迁
- 和 4 个标杆 Harness(Stagehand、OpenHands、LangGraph、Archestra)的横向对比
- 从零搭建的 MVP 路径:必须做哪些、可以省略哪些、踩坑预警
一、UFO 是什么?先看定位
1.1 项目速览
| 维度 | 数据 |
|---|---|
| GitHub | microsoft/UFO(⭐ 9,737) |
| 最新推送 | 2026-09-15T08:42:11Z(昨天仍在活跃) |
| License | MIT |
| Topics | agent、automation、copilot、gui、llm、windows |
| 创建日期 | 2024-01-08(约 32 个月持续维护) |
| 代码量 | Python ~96k LOC + TypeScript ~12k LOC |
| 核心描述 | “UFO³: Weaving the Digital Agent Galaxy“ — 从单设备 Agent 到多设备星座 |
| 论文 | arXiv 2504.14603(UFO²)+ arXiv 2511.11332(UFO³ Galaxy,2025-11 最新) |
| 官方文档 | https://microsoft.github.io/UFO/(mkdocs,完整中英文双版) |
1.2 它解决了什么问题
把”GUI Agent”从一次性脚本变成可声明、可编辑、可重放的分布式工作流:
graph LR
A["😵 旧方案<br/>OpenHands / Stagehand<br/>单设备线性脚本"]
B["✅ UFO³ Galaxy<br/>跨设备 DAG + 自演化"]
C["❓ 跑一半崩了<br/>不知道哪步错了"]
D["✅ TaskStar 状态追踪<br/>+ 诊断节点插队"]
A -.->|"失败"| C
B -->|"兜底"| D
style A fill:#FFB3C6,stroke:#F48FB1,color:#333
style B fill:#B5EAD7,stroke:#80CBC4,color:#333
style C fill:#FFB3C6,stroke:#F48FB1,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333直接表现:
- 用户说”把这 200 张发票的金额汇总到 Excel 并归档到 OneDrive” → UFO³ 拆成 5 个 TaskStar:OCR 截图(Mac)、金额抽取(Win)、Excel 填充(Win)、OneDrive 上传(API)、邮件通知(Linux),跨 3 个 OS 并发执行
- 中途 OCR 模型报错 → 触发 Diagnostic TaskStar 自动插入(不是 abort),dump 当前截图让 LLM 重新识别
- 用户临时说”再加一步:归档前先压缩成 ZIP” → ConstellationEditor.add_task() + add_dependency() 立刻改 DAG,下一轮 ready-set 调度直接生效
1.3 在 Harness 6 件套矩阵里处于哪个位置
| 组件 | UFO³ 对应 | 关键类 / 文件 |
|---|---|---|
| Rule(团队政策) | 🟡 部分(仅 PromptSanitizer) | ufo/prompter/prompt_sanitizer.py |
| Skill(SOP) | 🟡 部分(host_agent.yaml + app_agent.yaml) | ufo/prompts/share/base/*.yaml |
| Sub-Agent(角色分工) | ✅ 强(HostAgent + AppAgent + LinuxAgent + MobileAgent + ConstellationAgent = 5 类 Agent) | ufo/agents/agent/*.py |
| Workflow(接力赛协议) | ✅ 极强(TaskConstellation DAG + 编辑器 + 编排器 = 三件套) | galaxy/constellation/ |
| Script(硬关卡验证) | ✅ 强(PathValidator + URLSecurity + PromptSanitizer 三道关卡) | ufo/automator/path_validator.py、ufo/utils/url_security.py |
| MCP(外部系统桥接) | ✅ 极强(自研 AIP 协议 + 8 个 MCP server + device agents) | aip/messages.py、ufo/client/mcp/ |
UFO³ 在 Sub-Agent + Workflow + Script + MCP 四个组件上同时提供深度实现,是目前开源 Harness 领域唯一覆盖到这种程度的项目(对比 LangGraph 只覆盖 Workflow,Archestra 只覆盖 MCP+Script,OpenHands 只覆盖 Sub-Agent)。
1.4 UFO² → UFO³ 的关键跃迁
UFO 在 2 年里经历了 3 个版本:
| 版本 | 时间 | 核心抽象 | 类比 |
|---|---|---|---|
| UFO¹ | 2024-02 | 单 LLM + 截屏 + Win32 API | 像 AutoGPT for Windows |
| UFO² | 2025-04 | HostAgent/AppAgent 双层 + RAG + MCP | 像”Windows 上的 Manus” |
| UFO³ | 2025-11(论文)/ 2026-09(开源) | TaskConstellation DAG + AIP 协议 + Dynamic Editing | 像”分布式 Temporal for GUI“ |
最关键的跃迁是 UFO² → UFO³:从”一个 HostAgent 调度 N 个 AppAgent”(单机主从)变成”N 个 DeviceAgent 通过 AIP 协议协作 + LLM-driven DAG 编辑”(分布式编排)。
二、整体架构:2 个产品 + 4 层结构
UFO 仓库实际上装的是两个产品:
- UFO²(
ufo/子目录):单设备 Desktop AgentOS,Windows 上跑,用 Win32 + WinAppDriver 自动化 - UFO³ Galaxy(
galaxy/子目录):跨设备编排框架,任意 OS 都能跑,通过 WebSocket 调度多个 UFO² device
两者通过 AIP(Agent Interaction Protocol) 协议通信:
graph TB
subgraph UserLayer["👤 用户层"]
User["👤 用户<br/>自然语言请求<br/>'把发票汇总到 Excel'"]
end
subgraph GalaxyLayer["🌌 Galaxy 编排层 (跨设备)"]
ConstellationAgent["🎯 ConstellationAgent<br/>生成 + 编辑 DAG"]
ConstellationEditor["✏️ ConstellationEditor<br/>命令模式 + undo/redo"]
ConstellationDAG["📊 TaskConstellation<br/>DAG = TaskStar + TaskStarLine"]
Orchestrator["⚙️ TaskConstellationOrchestrator<br/>异步 ready-set 调度"]
AIP_Server["📡 AIP Server<br/>WebSocket + 心跳"]
AIPClient["📱 AIP Client<br/>Device Agent"]
end
subgraph DeviceLayer["🖥️ 设备层 (每台跑一个 UFO²)"]
Windows["🪟 Windows<br/>UFO² HostAgent"]
Mac["🍎 macOS<br/>UFO² MacFork"]
Linux["🐧 Linux<br/>UFO² LinuxAgent"]
Mobile["📱 iOS/Android<br/>UFO² MobileAgent"]
end
subgraph MCPLayer["🔌 MCP 工具层"]
ExcelMCP["📊 Excel MCP<br/>8 套 Office 工具"]
ShellMCP["💻 Shell MCP<br/>跨平台 CLI"]
UIMCP["🖱️ UI MCP<br/>底层 UI 控件"]
ConstellationMCP["🌌 Constellation MCP<br/>给 Coding Agent 当工具"]
end
User --> ConstellationAgent
ConstellationAgent --> ConstellationEditor
ConstellationEditor --> ConstellationDAG
ConstellationDAG --> Orchestrator
Orchestrator -->|"AIP 协议<br/>WebSocket + TLS"| AIP_Server
AIP_Server -->|"task / command / heartbeat"| Windows
AIP_Server -->|"task / command / heartbeat"| Mac
AIP_Server -->|"task / command / heartbeat"| Linux
AIP_Server -->|"task / command / heartbeat"| Mobile
Windows --> ExcelMCP
Windows --> UIMCP
Mac --> ShellMCP
Mobile --> UIMCP
style User fill:#C7CEEA,stroke:#9FA8DA,color:#333
style ConstellationAgent fill:#E8D5F5,stroke:#CE93D8,color:#333
style ConstellationEditor fill:#E8D5F5,stroke:#CE93D8,color:#333
style ConstellationDAG fill:#E8D5F5,stroke:#CE93D8,color:#333
style Orchestrator fill:#E8D5F5,stroke:#CE93D8,color:#333
style AIP_Server fill:#FFDAB9,stroke:#FFAB76,color:#333
style AIPClient fill:#FFDAB9,stroke:#FFAB76,color:#333
style Windows fill:#B5EAD7,stroke:#80CBC4,color:#333
style Mac fill:#B5EAD7,stroke:#80CBC4,color:#333
style Linux fill:#B5EAD7,stroke:#80CBC4,color:#333
style Mobile fill:#B5EAD7,stroke:#80CBC4,color:#333
style ExcelMCP fill:#FFF9C4,stroke:#F9A825,color:#333
style ShellMCP fill:#FFF9C4,stroke:#F9A825,color:#333
style UIMCP fill:#FFF9C4,stroke:#F9A825,color:#333
style ConstellationMCP fill:#FFF9C4,stroke:#F9A825,color:#333关键观察:
- MCP 是 device agent 的工具集(不是 AIP 的工具集)—— 这跟 Archestra 的”MCP 是 Agent Runtime”的设计相反
- AIP 协议是 device 与 orchestrator 的对话通道(不是 device 之间的 P2P)—— 中心化编排
- ConstellationAgent = 编排大脑,DeviceAgent = 执行手脚 —— 经典”规划 / 执行分离”
- WebUI 跑在 Constellation 上(
galaxy/webui/),用 FastAPI + Vite + React + WebSocket 实时显示 DAG 变化
2.1 顶层目录结构
1 | microsoft/UFO/ |
目录结构透出的设计原则:
ufo/和galaxy/物理隔离(不同setup.py、不同__main__.py),但共享aip/协议定义- 每层都有自己的 interfaces.py(
core/interfaces.py定义IConstellation、ITask、IDependency),强约束 SOLID - 测试密度极高 —— 仅
tests/就有 80+ 文件,包括test_constellation_*系列、test_prompt_sanitizer.py、test_cli_mcp_server_security.py、test_server_url_ssrf.py
三、6 大 Harness 原语深度解析
原语 1:TaskConstellation DAG — 把”工作流”显式编码
这是 UFO³ 最核心的创新:把 GUI Agent 的执行从”线性脚本”重构成”显式 DAG”。
TaskConstellation类不是字符串 + 文件,而是一等公民对象。
1.1 节点 TaskStar 的 11 个字段
galaxy/constellation/task_star.py(33,704 字符)定义了单个任务的完整画像:
1 | class TaskStar(ITask): |
值得注意的 5 个细节:
- 强类型枚举:
DeviceType限定了 7 种设备(WINDOWS、MACOS、LINUX、ANDROID、IOS、WEB、API),没法用字符串瞎写 - 双向依赖索引:
_dependencies(上游)+_dependents(下游),让 ready-set 计算只需 O(1) - metadata + config 分离:业务字段在
task_data,运行时配置在config,互不污染 - 不可变 task_id:UUID 而不是自增 ID,跨设备跨进程不冲突
- 状态受保护:
namesetter 会检查status == RUNNING,禁止热改
1.2 边 TaskStarLine 的 4 种依赖类型
galaxy/constellation/task_star_line.py(19,550 字符)定义了任务间依赖的 4 种语义:
1 | class DependencyType(Enum): |
配套的 condition_evaluator 字段接收任意可调用对象 —— 这比 LangGraph 的”布尔条件表达式”灵活,能塞 LLM judge 或外部 API。
1.3 容器 TaskConstellation 的状态机
galaxy/constellation/task_constellation.py(44,465 字符)是 UFO³ 最重的类,定义了 6 个状态:
1 | class ConstellationState(Enum): |
每个状态转移都有强约束,例如 add_task() 必须不在 EXECUTING 时执行、remove_task() 必须不在 RUNNING 时执行(TaskStar 级别的状态机 + Constellation 级别的状态机 = 两层 FSM 嵌套)。
1.4 完整可运行的 DAG 构造示例
1 | """最小可运行示例:从零构造一个 3 节点 TaskConstellation""" |
实测输出(UFO 源码运行):
1 | State: ConstellationState.CREATED |
这一段代码就是 UFO³ Workflow 组件的”Hello World” —— 没有它,就没有后面 Orchestrator 调度的对象;没有它,AIP 协议就没有 payload;没有它,ConstellationEditor 就没有编辑目标。
原语 2:ConstellationEditor — 命令模式 + undo/redo 的 DAG 编辑器
GUI Agent 跑一半发现缺一步、想插队加诊断节点、要把失败任务换成 fallback —— 这些动态修改需求必须用 undo/redo 否则改坏了没法回滚。UFO³ 的解法是经典 Command Pattern。
2.1 编辑器的 4 个核心组件
galaxy/constellation/editor/ 目录下有完整的命令模式实现:
graph LR
A["ConstellationEditor<br/>高层接口"]
B["CommandInvoker<br/>执行 + 历史栈"]
C["CommandRegistry<br/>命令注册表"]
D["Commands<br/>10 类原子命令"]
E["TaskConstellation<br/>被操作对象"]
A -->|"execute()"| B
B -->|"lookup"| C
C -->|"instantiate"| D
D -->|"mutate"| E
B -.->|"push to history"| H["CommandHistory<br/>undo/redo"]
style A fill:#E8D5F5,stroke:#CE93D8,color:#333
style B fill:#FFDAB9,stroke:#FFAB76,color:#333
style C fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#FFF9C4,stroke:#F9A825,color:#333
style E fill:#C7CEEA,stroke:#9FA8DA,color:#333
style H fill:#FFB3C6,stroke:#F48FB1,color:#3332.2 10 类原子命令
galaxy/constellation/editor/commands.py(37,881 字符)定义了所有可执行操作:
| 命令 | 作用 | 关键字段 |
|---|---|---|
BuildConstellationCommand | 从 schema YAML 批量建图 | constellation_id + tasks + deps |
AddTaskCommand | 加一个节点 | task_data(dict) |
RemoveTaskCommand | 删一个节点(自动清理依赖) | task_id |
UpdateTaskCommand | 改节点字段(status 检查) | task_id + updates dict |
AddDependencyCommand | 加一条边 | from_task + to_task + type |
RemoveDependencyCommand | 删一条边 | line_id |
UpdateDependencyCommand | 改依赖类型/条件 | line_id + updates |
ClearConstellationCommand | 清空整张图 | — |
SaveConstellationCommand | 序列化到磁盘 | path |
LoadConstellationCommand | 从磁盘恢复 | path |
2.3 命令模式 + undo/redo 的真实代码
1 | """演示 ConstellationEditor 的命令模式 + undo/redo""" |
这一段代码是 Harness “Workflow 组件” 的核心价值:
- 可重放:每条命令都是原子操作,undo/redo 是 O(1) 状态机切换
- 可审计:Observer 模式 + 事件总线,让”谁在什么时候改了什么”全程可追溯
- 可远程协作:Command 可以序列化(
SaveConstellationCommand),跨进程同步编辑(AIP 协议的MODIFY_CONSTELLATION消息)
2.4 Dynamic DAG Editing 的实战场景
论文 arXiv 2511.11332 列举了 4 类动态编辑场景,每类都有对应的 Command:
| 场景 | 触发条件 | 对应命令 |
|---|---|---|
| 诊断节点插队 | 某 TaskStar 失败,需要先 dump 当前状态 | AddTaskCommand(priority=CRITICAL) + AddDependencyCommand(dependency_type=SUCCESS_ONLY) |
| Fallback 替换 | 主路径失败,启用备用实现 | RemoveTaskCommand(旧节点) + AddTaskCommand(fallback 节点) + UpdateDependencyCommand(重新连边) |
| 依赖重连 | 两个任务合并执行 | RemoveDependencyCommand × 2 + AddTaskCommand(合并节点) + AddDependencyCommand × 2 |
| 节点剪枝 | 某分支完成且结果正确,可移除冗余节点 | RemoveTaskCommand + RemoveDependencyCommand |
为什么这比 LangGraph 强:LangGraph 的 add_node / add_edge 是直接修改 graph,没有 undo/redo,也没有观察者,改坏了只能重启进程。UFO³ 的 ConstellationEditor 把”修改 DAG”这件事做成了一等公民的事件流。
原语 3:AIP(Agent Interaction Protocol) — 跨设备消息协议
MCP 是 Anthropic 推的”工具暴露协议”。AIP 是 UFO³ 自研的”Agent 协作协议” —— 解决的不是”Agent 怎么调工具”,而是”Orchestrator 怎么调度 Agent”。
3.1 AIP 的 5 个核心设计
aip/messages.py(18,684 字符)用 Pydantic 定义了所有跨设备消息:
| 设计点 | 实现 | 价值 |
|---|---|---|
| 强类型 Pydantic | 所有消息都是 BaseModel 子类 | 协议版本化、自动 JSON 序列化 |
| 双向消息枚举 | ClientMessageType(8 类) + ServerMessageType(8 类) | 对称协议,方便双工 |
| Client 身份 | ClientType.DEVICE vs ClientType.CONSTELLATION | 同协议支持两种角色 |
| 任务状态机 | TaskStatus 5 态(CONTINUE / COMPLETED / FAILED / OK / ERROR) | 任务生命周期清晰 |
| 命令结构 | Command(tool_name, parameters, tool_type, call_id) | 每个命令可独立追踪 |
3.2 AIP 的完整消息流
sequenceDiagram
participant U as 👤 User
participant CA as 🎯 ConstellationAgent
participant OR as ⚙️ Orchestrator
participant SRV as 📡 AIP Server
participant DA as 🖥️ DeviceAgent
participant MCP as 🔌 MCP Server
U->>CA: "汇总 200 张发票到 OneDrive"
CA->>CA: build_constellation()<br/>生成 5 个 TaskStar
CA->>OR: execute_constellation(constellation)
OR->>SRV: REGISTER (ClientType.DEVICE)
SRV-->>OR: HEARTBEAT
OR->>SRV: TASK (task_id=t_ocr)
SRV->>DA: ServerMessage(type=TASK, status=CONTINUE, actions=[Command])
DA->>MCP: ocr_screenshot(image_path)
MCP-->>DA: Result(status=SUCCESS, result={amount: 1234.5})
DA->>SRV: COMMAND_RESULTS (call_id=xxx)
SRV->>OR: COMMAND_RESULTS forwarded
OR->>OR: ConstellationEditor 评估结果<br/>可能触发 Dynamic Edit
OR->>DA: TASK (task_id=t_excel)
DA->>MCP: excel_fill(...)
MCP-->>DA: Result(...)
DA->>SRV: TASK_END (status=COMPLETED)
SRV->>OR: TASK_END forwarded
OR->>OR: mark constellation COMPLETED
OR-->>CA: 完整结果
CA-->>U: ✅ 200 张发票已上传到 OneDrive
Note over OR,DA: 全程 WebSocket 长连接 + 心跳 + TLS3.3 真实代码:AIP 消息的定义
1 | # aip/messages.py 的核心结构 |
3 个关键设计选择:
tool_type二分法(data_collectionvsaction)—— 把”读操作”和”写操作”分开,方便审计和回滚call_id显式关联 —— 即使并发执行多个命令也能精确追踪每个结果属于哪个命令status五态枚举 —— CONTINUE/COMPLETED/FAILED/OK/ERROR,区分”任务在跑但没完”和”任务明确失败”
3.4 与 MCP 的关系
很多人会问:AIP 和 MCP 是不是重复了?
答:完全正交,解决不同问题。
| 维度 | MCP(Anthropic) | AIP(UFO³) |
|---|---|---|
| 目的 | Agent → Tool 通信 | Orchestrator → Agent 通信 |
| 范围 | 单进程内的 tool 调用 | 跨进程、跨设备的 Agent 调度 |
| 传输 | stdio / HTTP / SSE | WebSocket + TLS |
| 协议版本 | 2025-03-26 标准 | 自研,每个 release 一个版本 |
| 代表实现 | modelcontextprotocol/python-sdk | microsoft/UFO/aip/messages.py |
UFO³ 在 DeviceAgent 内部 用 MCP(暴露 8 个 server),在 DeviceAgent ↔ Orchestrator 之间 用 AIP。MCP 是”手”,AIP 是”电话”。
原语 4:Strategy Dependency — 声明式的处理策略依赖图
UFO² 单设备 Agent 内部有 4 类 Processor × 5 个 Phase × 7 类 Strategy 的复杂处理流程,靠”声明式依赖管理”避免乱序执行。
4.1 Processor Template 的 7 步处理流程
ufo/agents/processors/core/processor_framework.py(17,013 字符)定义了所有 Processor 的统一模板:
flowchart LR
A["📥 Phase 1<br/>REQUEST_ANALYSIS"] --> B["📸 Phase 2<br/>SCREENSHOT_ANALYSIS"]
B --> C["🎯 Phase 3<br/>TASK_DECOMPOSITION"]
C --> D["📝 Phase 4<br/>RESPONSE_PARSING"]
D --> E["✅ Phase 5<br/>ACTION_PLANNING"]
E --> F["⚡ Phase 6<br/>ACTION_EXECUTION"]
F --> G["📊 Phase 7<br/>RESULT_EVALUATION"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#E8D5F5,stroke:#CE93D8,color:#333
style D fill:#FFDAB9,stroke:#FFAB76,color:#333
style E fill:#FFDAB9,stroke:#FFAB76,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
style G fill:#FFB3C6,stroke:#F48FB1,color:#333每个 Phase 由一个 ProcessingStrategy 类实现,但策略之间的字段依赖(比如 B 需要 A 输出的 screenshot_path)需要显式声明 —— 这就是 StrategyDependency 的作用。
4.2 策略依赖的声明式注册
ufo/agents/processors/core/strategy_dependency.py(21,173 字符)实现了完整的依赖管理系统:
1 |
|
2 个关键洞察:
- 字段级别依赖(不是类级别)—— 精确到
field_name: str,避免”全有或全无” provides反向索引 —— 让后置策略能查”谁产生了screenshot_path这个字段”,自动接线
4.3 完整的策略依赖验证
1 | """演示 StrategyMetadataRegistry 的真实使用""" |
实测输出:
1 | Strategy 需要 2 个字段 |
这一段代码是 UFO² 内部”Sub-Agent 组件”的骨架 —— 没有它,5 类 Strategy 在 7 个 Phase 之间的乱序执行会让 Agent 直接崩。
原语 5:Prompt Sanitizer — 抗注入的”硬关卡”
UFO 把 prompt injection 当作 CWE-77(Command Injection)同等威胁对待,在 5 个关键字段都做了输入清洗。
5.1 Prompt Sanitizer 的 4 类攻击模式
ufo/prompter/prompt_sanitizer.py(5,032 字符)实现了 4 类正则防御:
1 | import re |
5.2 真实代码:sanitize 的实现
1 | """PromptSanitizer 的完整使用""" |
实测输出(节选):
1 | === 原始输入 === |
4 个关键设计:
_MAX_INPUT_LENGTH = 10_000—— 超长输入直接截断 + 警告(防 DoS)- 每个模式独立检测 —— 不会因为一个匹配把整段屏蔽
[SANITIZED]标记保留上下文 —— 不是简单删除,Agent 仍能看到”这里曾经有可疑内容”- 类比”安全失败”原则 —— 宁可误杀、不可漏放(fail-closed)
5.3 为什么这是 Script 组件
Prompt Sanitizer 属于 Script 组件(硬关卡验证),原因:
- 可执行验证:不是配置,是 Python 代码,会真的执行
- 不可绕过:所有
prompter/*.py在构造 user_content 时都会调用sanitize_user_input() - 可观测:每个被替换的字段都有 logger 警告
- 可扩展:添加新正则只改
_INJECTION_*_PATTERN一行,不用改业务代码
对比其他项目:
- LangChain:没有 prompt sanitizer,靠输入长度限制 + content_filter
- OpenHands:有
security/llm.py但只检测工具调用,不清洗 prompt - Archestra:有 Tool Invocation Policy 但不抗 prompt injection(靠 Dual-LLM 隔离)
UFO 的 Prompt Sanitizer 是 Harness Script 组件的开源标杆。
原语 6:TaskConstellationOrchestrator — 异步 ready-set 调度
一个 DAG 怎么真正跑起来?靠
TaskConstellationOrchestrator的 ready-set 算法 + asyncio 异步执行。
6.1 ready-set 算法
经典工作流调度算法 —— 找出所有”无未完成依赖”的节点,调度它们并发执行,等它们完成后更新 ready-set:
1 | """ready-set 算法的伪代码(基于真实源码简化)""" |
6.2 真实代码:Orchestrator 初始化
1 | """演示 TaskConstellationOrchestrator 的初始化与 cancel""" |
关键设计:
- asyncio.create_task —— 不是 thread,是协程,单进程支撑 1000+ 并发任务
- 设备感知 ——
target_device_id决定任务在哪台设备跑,调度器按设备能力分配 - 取消传播 ——
cancel_execution会同时取消所有asyncio.Task,不留孤儿 - 事件总线 —— 通过
get_event_bus()发布 ConstellationEvent,下游 Observer 订阅
6.3 与 LangGraph 的对比
| 维度 | LangGraph | UFO³ |
|---|---|---|
| 调度粒度 | Node(节点) | TaskStar(节点) |
| 执行模型 | 同步 + 异步混合 | 全异步 |
| 跨设备 | ❌ 单进程 | ✅ 通过 AIP 跨设备 |
| 动态编辑 | 弱(要重启) | ✅ undo/redo 命令模式 |
| 取消粒度 | 整个 graph | 单个 TaskStar 或整张图 |
| 形式化证明 | ❌ | ✅ arXiv 2511.11332 有 DAG consistency 不变量 |
UFO³ 的真正创新:把”工作流”从代码(LangGraph 的 Python 装饰器)提升到了协议层(AIP 消息),让 DAG 本身成为可序列化、可传输、可持久化的对象 —— 这是 LangGraph 永远做不到的。
四、横向对比:UFO³ vs 4 个标杆 Harness
4.1 总览对比表
| 项目 | 核心抽象 | Workflow 组件 | Sub-Agent 组件 | MCP 组件 | Script 组件 | 跨设备 | Self-Evolution |
|---|---|---|---|---|---|---|---|
| UFO³ | TaskConstellation DAG | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ AIP | ✅ Dynamic Edit |
| Stagehand | act/observe/extract API | ⭐⭐(无 DAG) | ⭐⭐⭐(6 框架适配) | ❌(无 MCP) | ⭐⭐(Self-healing) | ❌ 单设备 | ❌ |
| OpenHands | EventStream Runtime | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ 单设备 | ❌ |
| LangGraph | StateGraph | ⭐⭐⭐⭐⭐ | ⭐⭐(需自己写) | ⭐⭐ | ⭐⭐ | ❌ 单进程 | ❌ |
| Archestra | Dual-LLM + MCP Orchestrator | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ K8s | ❌ |
4.2 设计哲学差异
UFO³ = “GUI 工作流 的一等公民”
- 把”打开 Excel → 填数据 → 关闭 Excel”这种 GUI 操作显式建模为 DAG
- 设计哲学:让”流程”成为可重放的工件(论文里反复强调 “declarative decomposition”)
Stagehand = “LLM-as-UI-driver 的最小抽象”
- 只暴露
act / observe / extract三个原语,不规定流程 - 设计哲学:让 LLM 决定流程,SDK 只提供动作原子
OpenHands = “类 Unix Agent 运行时“
- 把 Agent 当成”程序”,用 EventStream 重放
- 设计哲学:事件流即真相,像 git 一样可审计
LangGraph = “纯计算图 的 LLM 适配”
- 把 Agent 拆成 Node + Edge,纯 Python,无副作用约束
- 设计哲学:图即程序,适合 ETL 流程
Archestra = “企业 AI 网关“
- 把 MCP Server 当 K8s Deployment 管理
- 设计哲学:K8s for AI,适合企业部署
4.3 关键能力对比
| 能力 | UFO³ | Stagehand | OpenHands | LangGraph |
|---|---|---|---|---|
| DAG 编辑带 undo/redo | ✅ 命令模式 | ❌ | ❌ | ❌ |
| 跨设备执行 | ✅ AIP 协议 | ❌ | ❌ | ❌ |
| 形式化 DAG 一致性证明 | ✅ arXiv 2511.11332 | ❌ | ❌ | ❌ |
| 自演化(DAG 动态改) | ✅ Dynamic Edit | ❌ | ❌ | ❌(要重启) |
| 内置 MCP server 数量 | 8 | 0 | 3 | 0 |
| 处理突发失败 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| Windows GUI 原生支持 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐ |
UFO³ 唯一的”弱项”是”模型无关性”:它的 Prompt YAML 强绑定 GPT-4o + Claude 3.5,对 Qwen / Llama 等开源模型的支持不如 LangGraph 灵活。
五、优缺点分析
5.1 架构简洁性 / 扩展性 / 易用性
| 维度 | 评分 | 说明 |
|---|---|---|
| 架构简洁性 | ⭐⭐⭐⭐ | 4 层结构清晰(Galaxy → Constellation → Device → MCP),但 Constellation 子目录嵌套 4 层(constellation/editor/、constellation/orchestrator/)偏深 |
| 扩展性 | ⭐⭐⭐⭐⭐ | 加设备 = 启动一个 UFO²;加工具 = 注册 MCP server;改 DAG = 编辑命令。三个轴独立 |
| 易用性 | ⭐⭐⭐ | WebUI 漂亮(Vite + React + 实时 DAG 可视化),但配置复杂(80+ YAML 文件) |
5.2 性能 / 复杂度 / 维护性
| 维度 | 评分 | 说明 |
|---|---|---|
| 性能 | ⭐⭐⭐⭐ | asyncio 全异步,asyncio.wait + FIRST_COMPLETED 让 ready-set 调度 O(1) 触发 |
| 复杂度 | ⭐⭐ | ~96k Python LOC + 80+ test,门槛高;DAG 概念需要工程背景 |
| 维护性 | ⭐⭐⭐⭐ | MIT 协议 + Microsoft 官方支持 + arXiv 双论文,32 个月持续活跃(仍在每周提交) |
5.3 适用 vs 不适用场景
| ✅ 适合 | ❌ 不适合 |
|---|---|
| 跨 Windows + macOS + Linux 的企业办公自动化 | 纯网页抓取(用 Stagehand/Playwright 即可) |
| 多步骤、有依赖的复杂 GUI 工作流(>5 步) | 单步 GUI 操作(UFO 太重) |
| 需要”中途调整工作流”的场景(agent 失败时插诊断节点) | 需要纯 LLM 推理的任务(用 LangGraph 更轻) |
| 企业内”Windows 流程自动化”(UFO 对 Win32 API 集成最深) | 移动 App 自动化(UFO 的 mobile 支持仍在 beta) |
六、从零搭建启示(最小可行实现)
6.1 必做项(MVP)
如果想复刻一个 “UFO³ Lite”(单设备 + 单 MCP + 简单 DAG),需要:
- TaskStar + TaskStarLine 数据类(~300 行 Python)—— 数据模型是骨架
- TaskConstellation 容器(~500 行 Python)—— DAG 验证 + 状态机
- 简单的 ready-set 调度器(~150 行 Python)—— asyncio.wait + FIRST_COMPLETED
- 1 个 MCP server(如 UI 截图)—— 验证工具调用链路
- WebUI 实时显示(可选,~500 行 TypeScript)—— 用户体验加分
总计 ~1500 行核心代码,可以跑通”OCR → Excel → Upload”。
6.2 可省略项(生产环境需要)
| 模块 | 必要性 | 替代方案 |
|---|---|---|
| AIP 协议 | 单设备 MVP 不需要 | 直接函数调用 |
| ConstellationEditor 命令模式 | MVP 用 dict 直接改 DAG 即可 | 上生产再加 |
| Strategy Dependency 声明式注册 | 单 Strategy 不需要 | 写死在 Processor 里 |
| 6 类 Observer + Event Bus | MVP 不需要 | print 日志就行 |
| Prompt Sanitizer | MVP 不需要 | 信任用户输入即可 |
6.3 踩坑预警
| 坑 | 现象 | 解决 |
|---|---|---|
| DAG 有环 | add_dependency 后状态机卡死 | 在 add_dependency 加 cycle detection(DFS) |
| TaskStar 状态竞态 | 多个 asyncio.Task 同时改 status | 加 asyncio.Lock 保护每个 TaskStar |
| AIP 心跳超时 | Device 断网后 Orchestrator 一直等 | 加 heartbeat_timeout=30s,超时自动 mark FAILED |
| MCP server 启动失败 | DeviceAgent 启动报 “tool not found” | 用 mcp_registry.register() 提前注册,启动时只校验不创建 |
| DAG 编辑时机 | 在 EXECUTING 状态 add_task 引发不一致 | 强制 EXECUTING 时只能改 TaskStar 字段,不能改依赖 |
| WebSocket 断线重连 | 设备掉电后永远失联 | AIP Client 加重连 + 状态持久化(pickle 整个 constellation) |
七、关键洞察总结
1. UFO³ 不是”AI Agent 框架”,是”分布式工作流引擎”
- 它和 LangGraph、AutoGen、CrewAI 同级,但关注点不同:GUI 自动化 + 跨设备 + 显式 DAG
- 这是 2026 年 GUI Agent 赛道里唯一做到 Workflow + MCP + Self-Evolution 三件套的开源实现
2. TaskConstellation 是”GUI 操作的 git commit”
- 每次执行都是 DAG 的”运行 commit”,可以 diff、rebase、cherry-pick
- ConstellationEditor 的 undo/redo 让”AI 改 AI”成为可能(论文 2511.11332 的核心 idea)
3. AIP 协议是 MCP 的”姐姐”
- MCP 解决”Agent 调工具”,AIP 解决”Orchestrator 调 Agent”
- 两者正交,但没有 AIP 就没有跨设备
- 如果未来出”AGI Agent 协议”,AIP 的 design pattern 值得借鉴
4. Strategy Dependency 是”Agent 内部的 ETL”
- 7 个 Phase × 5 类 Strategy × 字段级依赖 = 数据流图
- 这套机制让 UFO² 的处理流程可观测、可调试、可热替换
5. Prompt Sanitizer 是”prompt injection 的 WAF”
- 4 类正则 × 长度限制 × fail-closed = 80% 攻击挡在外面
- 不替代 Dual-LLM 隔离,但叠加使用能提升防御深度
八、总结与行动建议
UFO³ 适合谁用?
- ✅ 企业 IT 团队:要把 Windows 上的 Excel/Outlook 流程自动化的,UFO³ 是开源首选
- ✅ DevOps 工程师:想做”跨设备脚本编排”的,UFO³ 提供完整参考实现
- ✅ AI Agent 研究员:想研究”DAG + LLM”组合的,UFO³ 是必备 case study
- ❌ Web 开发者:抓网页用 Stagehand / Playwright 更轻
- ❌ 纯 LLM 推理工程师:用 LangGraph / LlamaIndex 更合适
读完这篇你应该带走什么?
- 3 个新概念:TaskConstellation(显式 DAG)/ ConstellationEditor(命令模式 + undo/redo)/ AIP(跨设备协议)
- 2 段可运行代码:TaskStar 数据模型构造 + PromptSanitizer 抗注入
- 1 个核心判断:GUI Agent 的下一个突破点在 “工作流层” 而非”模型层”
下篇预告:microsoft/Webwright(6,000 ⭐,2026-08-03)—— Microsoft 自家的”SWE 风格浏览器 Agent 框架”,主打 Long-Horizon Web Tasks SOTA。它和 UFO³ 正好互补:UFO³ 强在跨设备 GUI 编排,Webwright 强在长程 Web 任务推理。看名字像是 UFO 团队的姐妹项目(Web + Wright),实际上是一个独立团队 —— 这两个项目放在一起看,可以看清 Microsoft 在 Agent 赛道的两条不同技术路线。
附录 A:关键源码索引
| 文件 | LOC | 核心内容 |
|---|---|---|
aip/messages.py | 18,684 | AIP 协议 Pydantic 定义(命令/结果/消息) |
galaxy/constellation/task_constellation.py | 44,465 | DAG 容器 + 状态机 + DAG 验证 |
galaxy/constellation/task_star.py | 33,704 | 节点 TaskStar 数据类 |
galaxy/constellation/task_star_line.py | 19,550 | 边 TaskStarLine + 4 种 DependencyType |
galaxy/constellation/enums.py | ~120 | 6 个枚举(TaskStatus/DependencyType/ConstellationState/TaskPriority/DeviceType) |
galaxy/constellation/editor/constellation_editor.py | 22,142 | 高层编辑器接口 |
galaxy/constellation/editor/commands.py | 37,881 | 10 类原子命令 |
galaxy/constellation/editor/command_invoker.py | ~5,000 | undo/redo 执行器 |
galaxy/constellation/orchestrator/orchestrator.py | 28,795 | 异步 ready-set 调度器 |
galaxy/agents/constellation_agent.py | 24,417 | LLM-driven DAG 生成 + 编辑大脑 |
ufo/agents/processors/core/processor_framework.py | 17,013 | 7 Phase 处理模板 |
ufo/agents/processors/core/strategy_dependency.py | 21,173 | 策略依赖声明 + 验证 |
ufo/prompter/prompt_sanitizer.py | 5,032 | 4 类 prompt 注入正则 |
ufo/utils/url_security.py | 14,728 | URL 安全检查(防 SSRF) |
ufo/automator/path_validator.py | ~3,000 | 文件路径白名单 |
ufo/rag/retriever.py | 6,477 | 4 类 Retriever Factory(offline/experience/online/demonstration) |
ufo/llm/llm_call.py | 3,932 | 8 类 LLM 统一调度 |
galaxy/webui/server.py | ~8,000 | FastAPI + WebSocket 服务端 |
tests/test_constellation_*.py | 80+ | 全套 pytest(覆盖 DAG 编辑、状态机、安全性) |
引用与致谢
- 源码:microsoft/UFO
- 论文:arXiv 2504.14603(UFO²)+ arXiv 2511.11332(UFO³ Galaxy)
- 文档:https://microsoft.github.io/UFO/(中英文 mkdocs 完整版)
- 对比项目:Stagehand、OpenHands、LangGraph、Archestra
本篇属于 Harness Engineering 系列 · 主题:Cross-Device Agent Galaxy / DAG Workflow / AIP Protocol / Self-Evolving Constellation
下篇预告:microsoft/Webwright(6,000 ⭐)—— Microsoft 自家的 SWE 风格长程浏览器 Agent 框架,专注 Long-Horizon Web Tasks SOTA。和 UFO³ 的”GUI 编排”形成对照,看 Microsoft 在 Agent 赛道的另一条技术路线。
本文采用 CC BY-NC-SA 4.0 许可,转载请注明来源。