UFO AppAgent 深度解析:面向单一 Windows 应用的任务执行代理
【免费下载链接】UFOUFO³: Weaving the Digital Agent Galaxy项目地址: https://gitcode.com/GitHub_Trending/uf/UFO
AppAgent(Application Execution Agent)是 UFO 多代理体系中的核心执行运行时,专门负责在某个特定 Windows 应用内完成由 HostAgent 委派的子任务。本文以documents/docs/ufo2/app_agent/overview.md为骨架,结合仓库源码(ufo/agents/agent/app_agent.py、ufo/agents/states/app_agent_state.py、ufo/agents/processors/app_agent_processor.py等)与配套文档(state.md / strategy.md / commands.md),系统讲解 AppAgent 的架构定位、ReAct 控制循环、7 状态有限状态机、4 阶段处理管线、混合 GUI-API 执行、控制检测后端与 RAG 知识增强。读完本文,你将掌握 UFO 中 AppAgent 的完整工作原理、关键配置项与源码调用链,并能据此进行二次开发与调试。
AppAgent 是什么:应用专属的执行型子代理
在 UFO 的分层架构中,HostAgent 负责理解用户请求、分解任务并统筹调度,而AppAgent 则是被 HostAgent 启动并编排的“应用专属工作者进程”。原文档(AppAgent Overview)将其定义为:
- 隔离运行时(Isolated Runtime):每个 AppAgent 只服务于一个 Windows 应用(如 Word、Excel、PowerPoint、资源管理器)。
- 子任务执行器(Subtask Executor):执行 HostAgent 委派的具体子任务。
- 应用专家(Application Expert):内置目标应用的 API 表面、控件语义与领域逻辑知识。
- 混合执行(Hybrid Execution):同时借助 GUI 自动化与基于 MCP 命令的 API 操作。
这与把一切 GUI 上下文一视同仁的 monolithic Computer-Using Agents(CUA)形成鲜明对比:AppAgent 面向单一应用定制,掌握该应用的界面与能力细节。
从源码结构看,AppAgent继承自BasicAgent,并通过装饰器@AgentRegistry.register(agent_name="appagent", processor_cls=AppAgentProcessor)注册到代理注册表(见 app_agent.py),构造时接收name、process_name、app_root_name、is_visual、main_prompt、example_prompt等参数,其中process_name对应目标应用进程名(如WINWORD.EXE),app_root_name用于后续 RAG 检索的应用过滤。同一个文件中还定义了继承自AppAgent的OpenAIOperatorAgent(注册名operator),表明 AppAgent 的设计可扩展到不同底层驱动。
核心职责:感知 → 推理 → 执行 → 汇报
AppAgent 的每一轮工作围绕四项核心职责展开,原文档给出了如下循环模型:
Sense(捕获应用状态) → Reason(分析下一步动作) → Execute(执行GUI/API动作) → Report(写入Blackboard)| 职责 | 描述 | 示例 |
|---|---|---|
| 状态感知(State Sensing) | 捕获应用 UI、检测控件、理解当前状态 | 截取 Word 窗口 → 检测 50 个控件 → 为 UI 元素添加标注 |
| 推理(Reasoning) | 借助 LLM 分析状态并决定下一步动作 | "表格可见且存在 Export 按钮 [12] → 点击以导出数据" |
| 动作执行(Action Execution) | 通过 MCP 命令执行 GUI 点击或 API 调用 | click_input(control_id=12)或execute_word_command("export_table") |
| 结果汇报(Result Reporting) | 将执行结果写入共享 Blackboard | 将提取的数据写入subtask_result_1供 HostAgent 使用 |
其中Blackboard是 UFO 中所有代理共享的"黑板"内存,其实现见 blackboard.py:内部维护questions、requests、trajectories、screenshots四类 Memory,通过blackboard_to_prompt()将共享内容拼接进 LLM 上下文,从而实现代理间的信息传递(例如 AppAgent 的轨迹与截图可供 HostAgent 及后续子任务引用)。
ReAct 控制循环:观察 → 思考 → 行动
收到 HostAgent 委派的子任务与执行上下文后,AppAgent 初始化一个ReAct 风格的控制循环,迭代执行:
- Observe(观察):采集当前应用状态(截图 + 控件检测)
- Think(思考):LLM 推理下一步动作
- Act(行动):执行 GUI 或基于 API 的动作(MCP 命令)
MCP 命令系统是这一循环可靠运转的关键:只要可能就优先采用结构化 API 命令控制动态、复杂的 UI,必要时回退到基于 GUI 的交互命令。这是 UFO 中"混合执行"思想的落地点,后续章节会展开。
执行架构(一):7 状态有限状态机
AppAgent 使用一个包含7 个状态的有限状态机(FSM)控制执行流,状态枚举定义于 app_agent_state.py:
- CONTINUE:继续处理当前子任务(主执行状态)
- FINISH:成功完成子任务
- ERROR:遭遇不可恢复错误
- FAIL:子任务失败但可恢复
- PENDING:等待用户输入或澄清
- CONFIRM:敏感动作需用户确认
- SCREENSHOT:重新捕获并标注应用截图
各状态的行为差异可从源码与 state.md 归纳为下表:
| 状态 | 类型 | 是否执行 Processor | 子任务是否结束 | 是否交还 HostAgent |
|---|---|---|---|---|
| CONTINUE | 执行 | ✅ 是(4 阶段) | ❌ | ❌ |
| SCREENSHOT | 执行 | ✅ 是(同 CONTINUE) | ❌ | ❌ |
| FINISH | 终止 | ❌ | ✅ | ✅ |
| FAIL | 终止 | ❌ | ✅ | ✅ |
| PENDING | 交互 | ✅(询问用户) | ❌ | ❌ |
| CONFIRM | 交互 | ✅(展示确认) | ❌ | ❌ |
| ERROR | 终止 | ❌ | ✅ | ✅ |
几个关键状态的行为细节:
- SCREENSHOT继承自
ContinueAppAgentState,同样执行 4 阶段管线;它在执行后检查处理器中的control_reannotate集合:若仍需重新标注则停留在 SCREENSHOT,否则回到 CONTINUE。典型场景是点击会弹出对话框/展开下拉菜单的按钮之后,UI 发生显著变化。 - PENDING通过
agent.process_asker(ask_user=ufo_config.system.ask_question)向用户提问(需配置system.ask_question = true),用户应答后无条件回到 CONTINUE。 - CONFIRM先判断
ufo_config.system.safe_guard:若安全护栏关闭则直接process_resume()并视为已确认;否则调用agent.process_confirmation()展示动作征求用户批准,批准则继续(CONTINUE),拒绝则归档子任务并转入 FINISH。 - FINISH / FAIL / ERROR三个终态都会调用
archive_subtask(context, result)把子任务及结果写入previous_subtasks,并通过next_agent()返回 HostAgent。区别在于:FINISH 成功后 HostAgent 进入ContinueHostAgentState(follower 模式下为FinishHostAgentState)继续编排;ERROR 会终止当前 round(is_round_end() = True);FAIL 则保留 round,HostAgent 可以重试或换方案。
LLM 驱动的转移是这套状态机的核心特征:大多数转移由 LLM 响应中的Status字段决定,CONTINUE/SCREENSHOT/FINISH/FAIL/PENDING/CONFIRM一一映射到对应状态;系统异常则驱动 ERROR。所有状态类通过@AppAgentStateManager.register装饰器注册到状态管理器(AppAgentStateManager,内部维护_state_mapping),实现了按名称集中查找与类型安全的检索,也方便后续扩展新状态。
执行架构(二):4 阶段处理管线
在 CONTINUE 与 SCREENSHOT 状态下,每一轮执行遵循4 阶段处理管线:
Phase 1: DATA_COLLECTION(截图 + 控件) → Phase 2: LLM_INTERACTION(推理) → Phase 3: ACTION_EXECUTION(GUI/API 动作) → Phase 4: MEMORY_UPDATE(记录动作)这条管线的"总协调者"是AppAgentProcessor(app_agent_processor.py),它继承自ProcessorTemplate,在_setup_strategies()中注册四个阶段的策略,并配置专属的AppAgentProcessorContext上下文与AppAgentLoggingMiddleware日志中间件。各阶段策略类定义于 app_agent_processing_strategy.py,其 fail_fast 语义与组成方式如下:
| 阶段 | 策略类 | fail_fast | 组成 | 理由 |
|---|---|---|---|---|
| DATA_COLLECTION | ComposedStrategy(截图 + 控件信息) | ✅ True | 组合 | 截图与控件检测是 LLM 上下文的前提 |
| LLM_INTERACTION | AppLLMInteractionStrategy | ✅ True | 单一 | LLM 响应失败需立即恢复 |
| ACTION_EXECUTION | AppActionExecutionStrategy | ❌ False | 单一 | 动作失败可优雅处理并重试 |
| MEMORY_UPDATE | AppMemoryUpdateStrategy | ❌ False | 单一 | 记忆更新失败不应阻塞主流程 |
各阶段要点(详见 strategy.md):
Phase 1 — 数据收集(组合策略)
AppScreenshotCaptureStrategy:调用capture_window_screenshot捕获应用窗口截图并保存至日志路径;若配置system.save_full_screen = true还捕获桌面全屏;若system.save_ui_tree = true则保存 UI 树 JSON;同时获取应用窗口信息(application_window_info)。AppControlInfoStrategy:调用get_app_window_controls_target_info获取 UIA 控件列表,或在启用omniparser后端时调用视觉接地服务的screen_parsing获取视觉元素,最后按iou_threshold_for_merge合并去重,生成annotation_dict(id → TargetInfo),并用 Photographer 在截图上绘制[1]、[2]…标注框。
Phase 2 — LLM 交互收集图片字符串(上一步截图、干净截图、标注截图、拼接图),从 RAG 系统检索知识(经验示例、人工演示、离线文档、在线搜索结果),通过agent.message_constructor(...)构建包含 Blackboard 上下文与最近成功动作的完整提示,再调用 LLM(json_parsing_retry次重试,默认 3 次)并解析为结构化的AppAgentResponse。
Phase 3 — 动作执行将解析结果中的ControlLabel / Function / Args转换为Command(tool_name即函数名,parameters即参数),经command_dispatcher.execute_commands([...])下发执行,随后创建包含目标控件与执行结果的ActionCommandInfo用于记忆追踪,并保存高亮所选控件的截图。
Phase 4 — 记忆更新创建MemoryItem(合并 LLM 响应与附加上下文:轮次/步数/成本/动作/结果等),写入agent.add_memory(memory_item);再依据system.history_keys配置(默认["step", "subtask", "action_representation", "user_confirm"])筛选字段写入 Blackboard 的trajectories;若 LLM 请求保存截图则调用blackboard.add_image(...)。这保证了跨代理通信的"选择性记忆",避免信息过载。
混合 GUI–API 执行:MCP 命令系统
AppAgent 通过MCP(Model-Context Protocol)命令系统执行动作,为 GUI 自动化与原生 API 调用提供统一接口。原文档给出两种命令构造方式:
# GUI-based command (fallback) command = Command( tool_name="click_input", parameters={"control_id": "12", "button": "left"} ) await command_dispatcher.execute_commands([command]) # API-based command (preferred when available) command = Command( tool_name="word_export_table", parameters={"format": "csv", "path": "output.csv"} ) await command_dispatcher.execute_commands([command])命令不是硬编码的:AppAgent 在_load_mcp_context()(app_agent.py)中通过list_tools动态发现 MCP 服务器提供的全部工具,把结果包装为MCPToolInfo存入上下文,并据此为提示词生成 API 模板。可用命令取决于 config/ufo/mcp.yaml 中的服务器配置与应用上下文:
- 默认所有应用加载
UICollector(数据收集)、AppUIExecutor(UI 自动化)、CommandLineExecutor(Shell 执行); - 处理
WINWORD.EXE、EXCEL.EXE、POWERPNT.EXE时自动追加对应的WordCOMExecutor、ExcelCOMExecutor、PowerPointCOMExecutor(COM 原生 API 服务器),并设置reset: true防止文档切换时状态泄漏。
原文档列出的应用级命令包括:
capture_window_screenshot— 捕获应用窗口get_control_info— 通过 UIA/OmniParser 检测 UI 控件click_input— 点击 UI 控件set_edit_text— 向输入框键入文本annotation— 为截图添加控件标注
完整的命令类别与参数说明可参考 commands.md(鼠标/键盘动作、数据检索、各办公应用的 COM API 命令等)。由于命令随 MCP 服务器演进,具体参数与名称应以各服务器文档为准。
控制检测后端:UIA、OmniParser 与混合模式
为了全面理解 UI,AppAgent 支持多种控件检测后端,配置项为system.control_backend(见 config/ufo/system.yaml,默认["uia"],可扩展omniparser):
UIA(UI Automation)— 原生 Windows UI Automation API,适用于标准控件。
- ✅ 快速、准确
- ✅ 兼容大多数 Windows 应用
- ❌ 可能遗漏自定义控件(图标、Web 内容等)
OmniParser(视觉检测)— 基于视觉的接地模型,识别视觉元素。
- ✅ 可检测图标、图片、自定义控件
- ✅ 支持 Web 内容
- ❌ 需要外部服务支持
Hybrid(UIA + OmniParser)— 两者合并,覆盖面最大。
- ✅ 原生控件 + 视觉元素
- ✅ 综合的 UI 理解能力
混合模式的合并逻辑在AppControlInfoStrategy中实现:先分别收集 UIA 控件列表与 OmniParser 接地控件列表,再通过photographer.merge_target_info_list(...)依据 IoU 重叠阈值(iou_threshold_for_merge,默认 0.1)去重,最终得到标注列表。这一机制详见 control_detection/overview.md。
知识增强:RAG 驱动的四种知识来源
AppAgent 通过检索增强生成(RAG)从异构来源获得知识增强,原文档归纳为四种来源:
| 知识来源 | 用途 | 相关文档 |
|---|---|---|
| 帮助文档(Help Documents) | 应用专属文档(离线检索) | Learning from Help Documents |
| Bing 搜索(Bing Search) | 最新信息与更新(在线检索) | Learning from Bing Search |
| 自我演示(Self-Demonstrations) | 成功动作轨迹(经验学习) | Experience Learning |
| 人工演示(Human Demonstrations) | 专家提供的工作流 | Learning from Demonstrations |
从源码看,AppAgent在context_provision()(app_agent.py)中根据ufo_config.rag下的开关(offline_docs、online_search、experience、demonstration)分别构建四类检索器:build_offline_docs_retriever()使用app_root_name过滤离线文档;build_online_search_retriever()创建 Bing 搜索检索器;build_experience_retriever()从experience_saved_path/experience_db加载经验库;build_human_demonstration_retriever()从demonstration_saved_path/demonstration_db加载演示库。经验检索还会用过滤器确保只返回与当前应用(app_root_name)相关的示例。
检索结果最终进入 LLM_INTERACTION 阶段:经验示例与演示示例作为dynamic_examples,离线文档与在线搜索结果作为dynamic_knowledge,一并拼入提示词。完整的 RAG 架构参见 knowledge_substrate/overview.md。
输入与输出协议
AppAgent 输入
| 输入 | 描述 | 来源 |
|---|---|---|
| 用户请求(User Request) | 自然语言描述的原始用户请求 | HostAgent |
| 子任务(Sub-Task) | 待执行的具体子任务 | HostAgent 委派 |
| 应用上下文(Application Context) | 目标应用名、窗口信息 | HostAgent |
| 控件信息(Control Information) | 带标注的已检测 UI 控件 | 数据收集阶段 |
| 截图(Screenshots) | 干净截图、标注截图、上一步截图 | 数据收集阶段 |
| 黑板(Blackboard) | 代理间通信的共享内存 | 全局上下文 |
| 检索知识(Retrieved Knowledge) | 帮助文档、演示、搜索结果 | RAG 系统 |
AppAgent 输出
| 输出 | 描述 | 消费方 |
|---|---|---|
| 观察(Observation) | 当前 UI 状态描述 | LLM 上下文 |
| 思考(Thought) | 关于下一步动作的推理 | 执行日志 |
| 控件标签(ControlLabel) | 选中的交互控件 | 动作执行器 |
| 函数(Function) | 要执行的 MCP 命令(click_input、set_edit_text 等) | 命令调度器 |
| 参数(Args) | 命令参数 | 命令调度器 |
| 状态(Status) | 代理状态(CONTINUE、FINISH 等) | 状态机 |
| 黑板更新(Blackboard Update) | 执行结果 | HostAgent |
示例输出(JSON):
{ "Observation": "Word document with table, Export button at [12]", "Thought": "Click Export to extract table data", "ControlLabel": "12", "Function": "click_input", "Args": {"button": "left"}, "Status": "CONTINUE" }完整的响应 Schema(含ControlText、Plan、Comment、SaveScreenshot等字段)与解析逻辑见 strategy.md 与ufo/agents/processors/schemas/response_schema.py。
关键配置项速览
AppAgent 的运行行为大量受 config/ufo/system.yaml 控制,以下是与上文直接相关的核心配置:
# 控件检测后端 CONTROL_BACKEND: ["uia"] # 可选: uia, omniparser, 或两者混合 IOU_THRESHOLD_FOR_MERGE: 0.1 # 混合模式控件合并的 IoU 阈值 # 执行限制 MAX_STEP: 50 # 完成用户请求的最大步数 MAX_ROUND: 1 # 最大轮次 SLEEP_TIME: 1 # 步骤间等待窗口就绪的秒数 # 截图与日志 SAVE_FULL_SCREEN: False # 是否同时保存桌面全屏 SAVE_UI_TREE: False # 是否每步保存 UI 树 INCLUDE_LAST_SCREENSHOT: True # 观察中是否包含上一步截图 CONCAT_SCREENSHOT: False # 是否拼接干净/标注截图 SHOW_VISUAL_OUTLINE_ON_SCREEN: False# 是否在屏幕上绘制红色轮廓 # 安全 SAFE_GUARD: True # 敏感操作前是否需要用户确认 ASK_QUESTION: ... # 是否允许 PENDING 状态向用户提问 # 记忆 HISTORY_KEYS: ["step", "subtask", "action_representation", "user_confirm"] # LLM 重试 JSON_PARSING_RETRY: 3 # LLM 响应 JSON 解析重试次数MCP 服务器配置则位于 config/ufo/mcp.yaml(默认服务器、各办公应用的 COM 执行器、reset语义等),RAG 开关与路径配置位于config/ufo/rag.yaml。需要说明的是,以上参数为当前仓库的实际默认值,实际使用时请以仓库内配置为准。
深入路径与相关文档
详细文档(AppAgent 专题):
- State Machine:完整 FSM 定义、状态转移图与各状态行为
- Processing Strategy:4 阶段管线的实现细节与序列图
- Command System:应用级 MCP 命令参考
核心功能:
- Hybrid Actions:GUI-API 混合执行的 MCP 命令系统
- Control Detection:UIA 与视觉检测
- Knowledge Substrate:RAG 系统总览
教程:
- Creating AppAgent:分步创建指南
- Help Document Provision:配置帮助文档
- Demonstration Provision:配置演示样本
- Wrapping App-Native API:接入应用原生 API
源码入口:
- 代理主体:
ufo/agents/agent/app_agent.py - 状态机:
ufo/agents/states/app_agent_state.py - 处理管线:
ufo/agents/processors/app_agent_processor.py与ufo/agents/processors/strategies/app_agent_processing_strategy.py - 共享黑板:
ufo/agents/memory/blackboard.py
总结
AppAgent 的关键特征:
- ✅应用专属工作者:每个 AppAgent 只服务单一 Windows 应用,具备该应用的接口与控件语义知识
- ✅ReAct 控制循环:观察 → 思考 → 行动 的迭代执行模型
- ✅混合执行:通过 MCP 命令统一 GUI 自动化与原生 API 调用,API 优先、GUI 兜底
- ✅7 状态 FSM:CONTINUE/SCREENSHOT/FINISH/FAIL/PENDING/CONFIRM/ERROR,支持 UI 重标注、用户交互、安全确认与优雅降级
- ✅4 阶段管线:数据收集 → LLM 推理 → 动作执行 → 记忆更新,各阶段可独立配置 fail_fast 语义
- ✅知识增强:从帮助文档、Bing 搜索、自我演示与人工演示四条路径进行 RAG
- ✅HostAgent 编排:作为分层架构中的子代理,通过 Blackboard 与 HostAgent 完成结果交接
建议的下一步学习路径:先通读 state.md 与 strategy.md 掌握实现细节,再通过 commands.md 了解可用动作,最后按 Creating AppAgent 教程动手实践,将本文的理论映射到真实的自动化流程中。
【免费下载链接】UFOUFO³: Weaving the Digital Agent Galaxy项目地址: https://gitcode.com/GitHub_Trending/uf/UFO
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考