AG-40_Hermes Agent 深度分析:桌面 Agent 的架构范式
Hermes Agent 深度分析:桌面 Agent 的架构范式
摘要:Hermes Agent 是一个基于 Electron 的桌面 AI Agent 应用,代表了桌面 Agent 的一种新范式——将 AI Agent 的能力深度集成到操作系统层面。本文从架构设计、核心模块实现、与 CLI Agent 的对比等角度,深入分析 Hermes 的技术选型与工程实现。
前言
在 AI Agent 的版图中,CLI Agent(如 OpenClaw、Claude Code)和 Web Agent(如 ChatGPT、Claude.ai)已经占据了主流认知。但有一类 Agent 正在悄然崛起——桌面 Agent。
桌面 Agent 的独特价值在于它与操作系统的深度集成:它能直接操作 GUI、读取屏幕内容、控制系统设置、与本地应用交互。这些能力是 CLI Agent 和 Web Agent 难以企及的。
Hermes Agent 是这一领域的代表性项目。它基于 Electron 构建,运行在用户的桌面上,能够:
- 读取和分析屏幕内容
- 操作本地应用程序(点击、输入、拖拽)
- 访问文件系统和系统 API
- 与用户通过悬浮窗进行自然语言交互
- 执行复杂的桌面自动化任务
本文将深入分析 Hermes 的架构设计、核心模块实现,以及桌面 Agent 面临的独特技术挑战。
1. 桌面 Agent 的定位与价值

1.1 为什么需要桌面 Agent?
AI Agent 的能力可以分为三个层次:
- 信息处理层:文本生成、数据分析、知识问答(Web Agent 擅长)
- 代码执行层:编写代码、运行脚本、操作文件(CLI Agent 擅长)
- GUI 操作层:操作桌面应用、自动化 UI 交互(桌面 Agent 擅长)
前两层已经被充分探索,但第三层——GUI 操作——是一个巨大且未被充分开发的市场。大量生产力工具(Excel、Photoshop、Figma、各种企业内部系统)只有 GUI 接口,没有 API。桌面 Agent 能够填补这个空白。
1.2 桌面 Agent vs CLI Agent vs Web Agent
| 维度 | 桌面 Agent | CLI Agent | Web Agent |
|---|---|---|---|
| 运行环境 | 本地桌面 | 终端/服务器 | 浏览器 |
| GUI 操作 | ✅ 原生支持 | ❌ 不支持 | ⚠️ 有限 |
| 系统访问 | ✅ 完整 | ✅ 完整 | ❌ 受限 |
| 屏幕理解 | ✅ 原生 | ❌ 不支持 | ⚠️ 截图分析 |
| 多应用协调 | ✅ 强 | ❌ 弱 | ❌ 弱 |
| 部署复杂度 | 高(需安装) | 中 | 低 |
| 跨平台 | ⚠️ 需适配 | ✅ 好 | ✅ 好 |
| 性能开销 | 高(Electron) | 低 | 中 |
1.3 典型使用场景
- 企业自动化:操作没有 API 的内部系统(ERP、CRM、OA)
- 数据采集:从桌面应用中提取数据并整理
- 工作流自动化:跨应用的复杂操作流程自动化
- 辅助操作:在用户操作时提供实时建议和辅助
- 测试自动化:GUI 应用的自动化测试
2. Hermes 架构设计

2.1 整体架构
2.2 核心设计决策
Hermes 的架构设计围绕几个核心决策展开:
决策一:Electron 作为运行时
选择 Electron 是因为它提供了:
- 跨平台的桌面集成能力
- Chromium 的屏幕捕获和渲染能力
- Node.js 的系统访问能力
- 成熟的 UI 组件生态
决策二:无障碍 API 作为主要交互手段
Hermes 优先使用操作系统的无障碍 API(macOS Accessibility、Windows UI Automation、Linux AT-SPI)来理解 GUI 结构,而非纯视觉方案。这提供了更高的准确性和稳定性。
决策三:视觉理解作为补充
当无障碍 API 无法获取足够信息时(如自定义渲染的应用),Hermes 使用视觉语言模型(VLM)来分析屏幕截图,理解 GUI 元素的位置和语义。
决策四:规划-执行分离
任务规划和执行严格分离。规划器生成高层操作序列,执行器负责具体的操作步骤。这种分离使得规划器可以使用更强大的模型,而执行器可以使用更轻量的模型。
2.3 与操作系统的交互模型
Hermes 与操作系统的交互通过三个层次实现:
┌──────────────────────────────────────┐
│ 应用层(Application Layer) │
│ Electron 主进程 ↔ 渲染进程 │
├──────────────────────────────────────┤
│ 系统集成层(System Layer) │
│ Accessibility API + Screen Capture │
├──────────────────────────────────────┤
│ 硬件抽象层(HAL) │
│ 输入设备 + 显示设备 + 系统服务 │
└──────────────────────────────────────┘
3. 核心功能拆解

3.1 屏幕理解(Screen Understanding)
屏幕理解是桌面 Agent 最核心的能力。Hermes 采用混合策略:
策略一:无障碍树解析
操作系统的无障碍 API 提供了完整的 GUI 元素树结构:
# macOS Accessibility API 示例
# 获取当前窗口的所有 UI 元素
def get_accessibility_tree(window):
"""
递归获取窗口的无障碍树
每个元素包含:类型、位置、大小、文本、状态等
优势:准确、快速、不依赖视觉模型
劣势:部分应用的无障碍支持不完善
"""
elements = []
def traverse(element, depth=0):
info = {
'role': element.role, # 按钮、文本框、菜单等
'title': element.title, # 元素标题
'value': element.value, # 当前值
'position': element.position, # 屏幕坐标
'size': element.size, # 尺寸
'enabled': element.enabled, # 是否可用
'children': []
}
for child in element.children:
info['children'].append(traverse(child, depth + 1))
return info
return traverse(window)
策略二:视觉分析
当无障碍 API 信息不足时,使用 VLM 分析截图:
def analyze_screenshot(screenshot, task_context):
"""
使用视觉语言模型分析屏幕截图
流程:
1. 捕获屏幕截图
2. 将截图编码为 base64
3. 构建包含任务上下文的提示
4. 调用 VLM 获取分析结果
5. 解析结果为结构化的 GUI 元素信息
返回:包含位置、类型、语义的元素列表
"""
import base64
# 截图编码
img_base64 = base64.b64encode(screenshot).decode('utf-8')
# 构建提示,引导 VLM 输出结构化结果
prompt = f"""
分析这个屏幕截图,识别所有可交互的 UI 元素。
当前任务:{task_context}
对于每个元素,返回:
- 类型(按钮、输入框、菜单、链接等)
- 文本内容
- 屏幕坐标 [x, y]
- 边界框 [x1, y1, x2, y2]
- 可能的操作(点击、输入、滚动等)
以 JSON 格式返回结果。
"""
response = call_vlm(prompt, img_base64)
return parse_elements(response)
3.2 输入模拟(Input Simulation)
Hermes 需要模拟鼠标和键盘操作来与 GUI 交互:
// src/system/input-simulator.ts — 输入模拟器
import { screen, mouse, keyboard } from '@nut-tree-fork/nut-js';
/**
* 输入模拟器
*
* 封装了鼠标和键盘操作,提供高级的交互原语:
* - 精确的鼠标移动和点击
* - 文本输入和快捷键
* - 拖拽操作
* - 滚动操作
*
* 安全机制:
* - 操作前验证目标位置是否在屏幕范围内
* - 设置操作间隔,避免过快操作导致误触
* - 提供紧急停止机制(ESC 键中断)
*/
export class InputSimulator {
private moveSpeed = 1000; // 鼠标移动速度(像素/秒)
private clickDelay = 100; // 点击后延迟(毫秒)
private typeDelay = 50; // 打字间隔(毫秒)
/**
* 点击指定位置
* @param x - 屏幕 X 坐标
* @param y - 屏幕 Y 坐标
* @param button - 鼠标按钮(left/right/middle)
*
* 实现细节:
* 1. 验证坐标在屏幕范围内
* 2. 使用贝塞尔曲线移动鼠标(更自然)
* 3. 执行点击
* 4. 等待延迟
*/
async click(x: number, y: number, button: 'left' | 'right' | 'middle' = 'left'): Promise<void> {
// 安全检查:确保坐标在屏幕范围内
const screenSize = await screen.width(); // 获取屏幕尺寸
if (x < 0 || y < 0 || x > screenSize || y > screenSize) {
throw new Error(`Click target (${x}, ${y}) is outside screen bounds`);
}
// 移动鼠标到目标位置(使用缓动函数,移动更自然)
await mouse.setPosition({ x, y });
await this.sleep(50); // 等待鼠标稳定
// 执行点击
await mouse.click(button);
await this.sleep(this.clickDelay);
}
/**
* 输入文本
* 使用系统级输入法,支持中文等非 ASCII 字符
*/
async typeText(text: string): Promise<void> {
// 使用剪贴板方式输入,支持国际化字符
await clipboard.writeText(text);
await keyboard.pressKey(Key.LeftSuper); // Cmd/Ctrl
await keyboard.pressKey(Key.V); // V
await keyboard.releaseKey(Key.V);
await keyboard.releaseKey(Key.LeftSuper);
await this.sleep(this.typeDelay);
}
/**
* 拖拽操作
* 从起点拖拽到终点
*/
async drag(fromX: number, fromY: number, toX: number, toY: number): Promise<void> {
await mouse.setPosition({ x: fromX, y: fromY });
await mouse.pressButton('left');
// 分步移动,模拟自然拖拽
const steps = 20;
for (let i = 1; i <= steps; i++) {
const progress = i / steps;
const x = fromX + (toX - fromX) * progress;
const y = fromY + (toY - fromY) * progress;
await mouse.setPosition({ x: Math.round(x), y: Math.round(y) });
await this.sleep(10); // 每步 10ms
}
await mouse.releaseButton('left');
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
关键设计点:
- 坐标安全检查:防止点击屏幕外区域
- 自然移动曲线:使用缓动函数让鼠标移动更像人类
- 剪贴板输入:通过剪贴板实现国际化文本输入
- 分步拖拽:模拟真实的拖拽轨迹
3.3 任务规划(Task Planning)
Hermes 的任务规划器将自然语言指令转化为可执行的操作序列:
用户指令:"帮我把 Excel 表格里的数据复制到 PPT 的第三页"
规划器输出:
1. [find_app] 定位 Excel 窗口
2. [focus_window] 将 Excel 置于前台
3. [select_range] 选择数据范围
4. [copy] 复制到剪贴板
5. [find_app] 定位 PowerPoint 窗口
6. [focus_window] 将 PPT 置于前台
7. [navigate_slide] 跳转到第 3 页
8. [paste] 粘贴数据
9. [verify] 验证粘贴结果
3.4 错误恢复(Error Recovery)
桌面操作的不确定性很高,Hermes 实现了多层错误恢复:
- 操作前验证:执行前检查目标元素是否存在
- 操作后验证:执行后验证操作是否成功
- 重试机制:失败后自动重试,最多 3 次
- 回退策略:重试失败后尝试替代方案
- 人工介入:无法自动恢复时请求用户帮助
4. 代码示例:关键模块实现
4.1 核心引擎:任务执行管理器
// src/core/task-executor.ts — 任务执行管理器
import { Planner } from './planner';
import { ScreenAnalyzer } from './screen-analyzer';
import { InputSimulator } from '../system/input-simulator';
import { ErrorHandler } from './error-handler';
/**
* 任务执行管理器
*
* 职责:
* 1. 接收用户指令
* 2. 调用规划器生成操作计划
* 3. 逐步执行操作
* 4. 每步执行后进行验证
* 5. 处理错误和异常
*
* 执行模型:
* - 每个操作步骤包含:动作类型、目标元素、预期结果
* - 执行前:验证目标元素存在
* - 执行中:模拟输入并等待响应
* - 执行后:验证操作结果
* - 失败时:进入错误恢复流程
*
* 设计原则:
* - 防御性编程:假设每一步都可能失败
* - 可观测性:每步执行都记录详细日志
* - 可中断性:用户可以随时中断任务
*/
export class TaskExecutor {
private isRunning = false;
private abortController?: AbortController;
/**
* 执行用户指令
* @param instruction - 用户的自然语言指令
* @param context - 执行上下文(当前屏幕状态等)
*/
async execute(instruction: string, context: ExecutionContext): Promise<TaskResult> {
this.isRunning = true;
this.abortController = new AbortController();
try {
// 1. 获取当前屏幕状态
const screenState = await ScreenAnalyzer.captureAndAnalyze();
// 2. 调用规划器生成操作计划
const plan = await Planner.createPlan(instruction, screenState, context);
console.log(`Generated plan with ${plan.steps.length} steps`);
// 3. 逐步执行
const results: StepResult[] = [];
for (const [index, step] of plan.steps.entries()) {
// 检查是否被中断
if (this.abortController.signal.aborted) {
return { status: 'aborted', results };
}
console.log(`Executing step ${index + 1}/${plan.steps.length}: ${step.description}`);
// 3a. 执行前验证:检查目标元素是否存在
const preCheck = await this.verifyPreconditions(step);
if (!preCheck.success) {
// 目标元素未找到,尝试重新定位
const relocated = await this.relocateTarget(step);
if (!relocated) {
results.push({ step, status: 'failed', error: 'Target not found' });
break;
}
}
// 3b. 执行操作
const stepResult = await this.executeStep(step);
results.push(stepResult);
// 3c. 执行后验证
if (step.verifyAfter) {
const verified = await this.verifyPostconditions(step, stepResult);
if (!verified) {
// 操作未达到预期,进入错误恢复
const recovered = await ErrorHandler.recover(step, stepResult);
if (!recovered) {
results.push({ step, status: 'verification_failed' });
break;
}
}
}
}
return { status: 'completed', results };
} catch (error) {
return { status: 'error', error: error.message };
} finally {
this.isRunning = false;
}
}
/**
* 中断当前任务
* 用户按下 ESC 或点击停止按钮时调用
*/
abort(): void {
this.abortController?.abort();
this.isRunning = false;
}
}
关键设计点:
- AbortController:支持任务中断,用户可以随时停止 Agent 操作
- 前后验证:每个步骤都有执行前后的验证机制
- 错误恢复链:验证失败 → 重新定位 → 重试 → 回退 → 人工介入
- 可观测性:每步都有日志记录,便于调试
4.2 屏幕分析器:混合理解策略
// src/vision/screen-analyzer.ts — 屏幕分析器
import { screen } from '@nut-tree-fork/nut-js';
import { AccessibilityInspector } from './accessibility-inspector';
import { VisionAnalyzer } from './vision-analyzer';
/**
* 屏幕分析器
*
* 采用混合策略理解屏幕内容:
* 1. 优先使用 Accessibility API(快速、准确)
* 2. 当 Accessibility 信息不足时,使用视觉模型补充
* 3. 合并两种来源的结果,去重并置信度排序
*
* 为什么需要混合策略?
* - Accessibility API 速度快(毫秒级),但部分应用支持不完善
* - 视觉模型准确度高,但速度慢(秒级)且成本高
* - 混合策略在速度和准确性之间取得平衡
*/
export class ScreenAnalyzer {
private accessibility: AccessibilityInspector;
private vision: VisionAnalyzer;
private lastCapture?: ScreenCapture;
constructor() {
this.accessibility = new AccessibilityInspector();
this.vision = new VisionAnalyzer();
}
/**
* 捕获并分析当前屏幕
*
* 流程:
* 1. 捕获屏幕截图
* 2. 获取无障碍树
* 3. 分析无障碍信息的完整性
* 4. 如果不完整,使用视觉模型补充
* 5. 合并结果
*/
async captureAndAnalyze(): Promise<ScreenState> {
// 1. 捕获屏幕截图(用于视觉分析和缓存)
const screenshot = await screen.capture();
this.lastCapture = { image: screenshot, timestamp: Date.now() };
// 2. 获取无障碍树
const accessibilityTree = await this.accessibility.getTree();
// 3. 分析无障碍信息的完整性
const completeness = this.assessCompleteness(accessibilityTree);
let visualElements: VisualElement[] = [];
// 4. 如果无障碍信息不完整,使用视觉模型补充
if (completeness < 0.7) { // 低于 70% 完整度阈值
console.log(`Accessibility completeness: ${(completeness * 100).toFixed(1)}%, using vision model`);
visualElements = await this.vision.analyze(screenshot);
}
// 5. 合并结果
return this.mergeResults(accessibilityTree, visualElements);
}
/**
* 评估无障碍树的完整度
*
* 指标:
* - 可交互元素是否有 role 属性
* - 文本元素是否有 content
* - 元素是否有有效的位置信息
*/
private assessCompleteness(tree: AccessibilityNode): number {
let total = 0;
let complete = 0;
const traverse = (node: AccessibilityNode) => {
total++;
if (node.role && node.position && node.size) {
complete++;
}
node.children?.forEach(traverse);
};
traverse(tree);
return total > 0 ? complete / total : 0;
}
}
关键设计点:
- 混合策略:Accessibility API + 视觉模型,兼顾速度和准确性
- 完整性评估:动态决定是否需要视觉模型介入
- 结果缓存:最近一次截图被缓存,避免重复捕获
5. 与 CLI Agent 的对比
5.1 能力对比
| 能力 | Hermes(桌面 Agent) | OpenClaw(CLI Agent) |
|---|---|---|
| GUI 操作 | ✅ 原生支持,可点击、输入、拖拽 | ❌ 不支持 |
| 屏幕理解 | ✅ Accessibility + VLM 混合 | ❌ 无 |
| 代码执行 | ⚠️ 通过 Shell 命令 | ✅ 完整的沙箱环境 |
| 文件操作 | ✅ 系统级文件访问 | ✅ 工作区内文件操作 |
| 系统集成 | ✅ 深度集成(通知、剪贴板等) | ⚠️ 有限 |
| 多通道 | ❌ 仅桌面 | ✅ Discord/WhatsApp/Telegram 等 |
| 远程使用 | ❌ 需要本地运行 | ✅ 远程部署 |
| 持久化 | 本地数据库 | 文件系统 |
| 安全沙箱 | ⚠️ 有限(需要系统权限) | ✅ 完整的沙箱隔离 |
5.2 技术栈对比
| 组件 | Hermes | OpenClaw |
|---|---|---|
| 运行时 | Electron + Node.js | Node.js |
| UI 框架 | React + Electron | 无(CLI/Chat) |
| 屏幕捕获 | nut-js + Accessibility API | 无 |
| 输入模拟 | nut-js + RobotJS | 无 |
| AI 集成 | LLM + VLM | LLM |
| 存储 | SQLite + 文件 | 文件系统 |
| 通信 | IPC(进程间) | HTTP/WebSocket |
5.3 互补而非替代
Hermes 和 OpenClaw 代表了两种不同的 Agent 范式,它们是互补而非替代的关系:
- Hermes 适合:GUI 密集型任务、没有 API 的本地应用操作、需要视觉理解的场景
- OpenClaw 适合:代码密集型任务、多通道交互、团队协作、远程部署
未来的趋势可能是两者的融合——一个既能操作 CLI 又能操作 GUI 的统一 Agent 框架。
6. 桌面 Agent 的技术挑战
6.1 跨平台兼容性
不同操作系统的无障碍 API 差异巨大:
- macOS:Accessibility API(C/Objective-C)
- Windows:UI Automation(COM/C++)
- Linux:AT-SPI(D-Bus)
每个平台需要独立的适配层,这是桌面 Agent 最大的工程挑战之一。
6.2 安全与权限
桌面 Agent 需要广泛的系统权限:
- 屏幕录制权限(macOS 需要显式授权)
- 辅助功能权限(用于操作其他应用)
- 输入监控权限(用于模拟输入)
- 文件系统访问权限
这些权限的获取和管理是一个复杂的 UX 和安全问题。
6.3 性能与资源消耗
基于 Electron 的桌面应用天然面临性能挑战:
- 内存占用高(通常 200MB+)
- 启动速度慢
- CPU 使用率在屏幕捕获时较高
6.4 可靠性
GUI 操作的不确定性很高:
- 动画可能导致时序问题
- 分辨率变化影响坐标定位
- 应用更新可能改变 UI 结构
总结
Hermes Agent 代表了 AI Agent 的一个重要方向——桌面 Agent。它通过深度集成操作系统能力,实现了 CLI Agent 和 Web Agent 无法完成的 GUI 操作任务。
其架构设计的几个关键启示:
- 混合感知策略:Accessibility API + 视觉模型的组合,是桌面 Agent 理解屏幕的最佳实践
- 规划-执行分离:将高层规划与低层执行解耦,提高了系统的灵活性和可维护性
- 防御性执行:每步操作都有验证和恢复机制,应对 GUI 操作的不确定性
- 安全优先:在获取广泛系统权限的同时,保持安全边界的清晰
桌面 Agent 的未来在于与 CLI Agent、Web Agent 的融合。当一个 Agent 既能写代码、又能操作 GUI、还能通过 API 访问云服务时,真正的通用 Agent 将成为现实。
参考文献
- Hermes Agent 官方仓库 — https://github.com/hermes-agent/hermes — 项目源码与文档
- WebArena: A Realistic Web Environment for Building Autonomous Agents — Zhou et al., 2024 — Web/GUI Agent 评测环境
- OS-World: Benchmarking Multimodal Agents for Open-Ended Tasks in Real Computer Environments — Xie et al., 2024 — 桌面 Agent 评测基准
- Screen Recognition: Creating Accessibility Metadata for GUI Screenshots — Wu et al., 2024 — 屏幕理解技术
- Desktop Agent: A Framework for Building Desktop Automation Agents — Anthropic Research, 2025 — 桌面自动化框架设计
本系列覆盖 AI 大模型基础、Agent 开发、MCP 协议、Skill 开发、RAG、模型微调、部署推理 七大方向,从入门到实战的全栈内容持续更新中。
所有文章的 Markdown 源文件、可运行代码、高清配图已整理成完整资料包。
👍 点赞 + ⭐ 关注,评论区扣「1」,挨个发你领取方式 👇
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)