Skip to content

Commit f1b1dce

Browse files
author
Hongzhi Wen
committed
Update health check workflow to use more descriptive user messages and add new documentation for OpenFang integration and Windows MCP UIAutomation design.
1 parent 780122c commit f1b1dce

4 files changed

Lines changed: 1575 additions & 2 deletions

File tree

.github/workflows/health-check.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
-X POST "https://lanlan.app/text/v1/chat/completions" \
2020
-H "Content-Type: application/json" \
2121
-H "Authorization: Bearer free-access" \
22-
-d '{"model":"free-model","messages":[{"role":"user","content":"ok"}],"max_completion_tokens":5}' \
22+
-d '{"model":"free-model","messages":[{"role":"user","content":"sends some useful information"}],"max_completion_tokens":5}' \
2323
2>/dev/null || echo "000")
2424
BODY=$(cat /tmp/resp_app.json 2>/dev/null || echo "{}")
2525
echo "http_code=$HTTP_CODE" >> "$GITHUB_OUTPUT"
@@ -45,7 +45,7 @@ jobs:
4545
-X POST "https://lanlan.tech/text/v1/chat/completions" \
4646
-H "Content-Type: application/json" \
4747
-H "Authorization: Bearer free-access" \
48-
-d '{"model":"free-model","messages":[{"role":"user","content":"ok"}],"max_completion_tokens":5}' \
48+
-d '{"model":"free-model","messages":[{"role":"user","content":"sends some useful information"}],"max_completion_tokens":5}' \
4949
2>/dev/null || echo "000")
5050
BODY=$(cat /tmp/resp_tech.json 2>/dev/null || echo "{}")
5151
echo "http_code=$HTTP_CODE" >> "$GITHUB_OUTPUT"
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
# Windows MCP + UIAutomation 集成设计方案
2+
3+
## 1. 现状分析
4+
5+
### 1.1 当前 Agent 执行链
6+
7+
```
8+
用户消息 → main_server (ZMQ) → agent_server
9+
→ DirectTaskExecutor.analyze_and_execute()
10+
→ 并行评估:
11+
├─ _assess_computer_use() → ComputerUseDecision
12+
├─ _assess_browser_use() → BrowserUseDecision
13+
└─ _assess_user_plugin() → UserPluginDecision
14+
→ 决策优先级: UserPlugin > BrowserUse > ComputerUse
15+
→ agent_server dispatch (队列调度 / 直接执行)
16+
```
17+
18+
### 1.2 当前 ComputerUse 的工作方式
19+
20+
`brain/computer_use.py` 中的 `ComputerUseAdapter.run_instruction()`:
21+
22+
```
23+
循环 (最多 50 步):
24+
1. pyautogui.screenshot() ← 硬编码,前台截图
25+
2. compress_screenshot() → jpg
26+
3. VLM predict() → thought + action + code
27+
4. exec(code) with _ScaledPyAutoGUI ← 硬编码,前台操作
28+
```
29+
30+
**问题:**
31+
- 每步都需要 VLM 推理(慢、费 token)
32+
- 只能操作前台(抢占用户桌面)
33+
- 通过坐标操作(受 DPI/分辨率影响)
34+
- 没有语义理解(不知道控件是什么,只看像素)
35+
36+
### 1.3 已有的 MCP 基础设施
37+
38+
`plugin/plugins/mcp_adapter/` 已实现完整的 MCP Client:
39+
- 支持 stdio / SSE / streamable-http 三种 transport
40+
- 自动发现 MCP server 的 tools 并注册为 NEKO entries
41+
- 通过 UserPlugin 执行路径调用 MCP tools
42+
- 有 reconnect、error handling、payload normalization
43+
44+
---
45+
46+
## 2. 设计目标
47+
48+
1. **引入 UIAutomation 快车道**:标准 Windows 控件操作直接走 UIAutomation(毫秒级,零 VLM token)
49+
2. **保留 VLM 兜底**:UIAutomation 搞不定的场景(自绘 UI、游戏等)回退到现有 ComputerUse
50+
3. **复用已有 MCP adapter**:不重新造轮子,通过 mcp_adapter 桥接 Windows MCP 服务器
51+
4. **支持后台窗口操作**:UIAutomation 天然支持后台控件交互,为未来虚拟桌面方案铺路
52+
5. **对现有代码侵入最小**:不改 ComputerUse 核心逻辑,新增平行路径
53+
54+
---
55+
56+
## 3. 架构设计
57+
58+
### 3.1 整体架构
59+
60+
```
61+
DirectTaskExecutor.analyze_and_execute()
62+
63+
┌───────────────────┼───────────────────┐
64+
│ │ │
65+
_assess_uia() _assess_computer_use() _assess_browser_use()
66+
(NEW - 新增) (现有) (现有)
67+
│ │ │
68+
UIADecision CUDecision BUDecision
69+
│ │ │
70+
▼ ▼ ▼
71+
72+
决策优先级: UserPlugin > UIA > BrowserUse > ComputerUse
73+
^^^
74+
(新增,高于 BU/CU)
75+
76+
执行路径:
77+
┌─────────────────────────────────────────────────────┐
78+
│ execution_method == "uia" │
79+
│ → 通过 mcp_adapter 调用 Windows MCP Server │
80+
│ → MCP Server 内部走 UIAutomation / pywinauto │
81+
│ → 返回操作结果(文本/截图/状态) │
82+
└─────────────────────────────────────────────────────┘
83+
┌─────────────────────────────────────────────────────┐
84+
│ execution_method == "computer_use" │
85+
│ → 现有 VLM + pyautogui 流程(完全不变) │
86+
└─────────────────────────────────────────────────────┘
87+
```
88+
89+
### 3.2 Windows MCP Server 选型
90+
91+
推荐 **pywinauto-mcp****Windows-MCP.Net** 作为外部 MCP Server,理由:
92+
93+
| 特性 | pywinauto-mcp | Windows-MCP.Net |
94+
|------|--------------|-----------------|
95+
| UIAutomation 支持 | ✓ (pywinauto 底层) | ✓ (.NET UIA) |
96+
| 后台窗口操作 | 部分支持 | 部分支持 |
97+
| OCR | 需额外配置 | 内置 |
98+
| MCP 协议版本 | 3.1 (stdio) | stdio |
99+
| 语言 | Python | C# (.NET 8) |
100+
| 与 NEKO 技术栈 | 同栈(Python) | 异栈 |
101+
102+
**建议优先用 pywinauto-mcp**(Python 同栈,如需定制可以直接改源码)。
103+
104+
### 3.3 MCP Server 配置
105+
106+
在 NEKO 的 MCP adapter 配置中添加 Windows 桌面自动化 server:
107+
108+
```json
109+
{
110+
"name": "windows-desktop",
111+
"transport": "stdio",
112+
"command": "python",
113+
"args": ["-m", "pywinauto_mcp"],
114+
"enabled": true
115+
}
116+
```
117+
118+
mcp_adapter 会自动发现该 server 暴露的 tools(如 `automation_windows`, `automation_elements`, `automation_mouse`, `automation_keyboard`, `automation_visual`)并注册为 NEKO entries。
119+
120+
---
121+
122+
## 4. 代码改动详细设计
123+
124+
### 4.1 新增 `UIADecision` 数据类
125+
126+
**文件**: `brain/task_executor.py`
127+
128+
```python
129+
@dataclass
130+
class UIADecision:
131+
"""UIAutomation (via Windows MCP) 可行性评估结果"""
132+
has_task: bool = False
133+
can_execute: bool = False
134+
task_description: str = ""
135+
tool_name: str = "" # MCP tool 名称,如 "automation_elements"
136+
tool_args: Dict = None # MCP tool 参数
137+
reason: str = ""
138+
```
139+
140+
### 4.2 新增 `_assess_uia()` 方法
141+
142+
**文件**: `brain/task_executor.py`
143+
144+
核心思路:判断任务是否可以通过 UIAutomation 的语义操作完成(而非截图+坐标)。
145+
146+
```python
147+
async def _assess_uia(
148+
self,
149+
conversation: str,
150+
uia_tools: List[Dict[str, Any]], # 从 mcp_adapter 获取的 windows-desktop tools
151+
) -> UIADecision:
152+
"""
153+
评估任务是否适合 UIAutomation(精确控件操作)而非 VLM+坐标。
154+
155+
适合 UIA 的场景:
156+
- 打开/关闭/切换已知应用
157+
- 点击已知名称的按钮/菜单
158+
- 在文本框中输入内容
159+
- 读取窗口/控件中的文本
160+
- 操作标准 Windows 控件(列表、树形、选项卡等)
161+
162+
不适合 UIA 的场景:
163+
- 操作目标是屏幕上某个视觉位置("点击左上角的图标")
164+
- 目标应用使用自绘 UI(游戏、某些 Electron 应用)
165+
- 需要视觉理解("看看屏幕上显示了什么")
166+
"""
167+
if not uia_tools:
168+
return UIADecision(has_task=False, can_execute=False, reason="No UIA tools available")
169+
170+
# ... LLM 评估逻辑,与 _assess_computer_use 结构类似
171+
# 但 system_prompt 专注于判断"这个任务能否通过控件名/控件类型精确操作完成"
172+
```
173+
174+
**评估 prompt 的关键区分点**
175+
176+
```
177+
你是一个 Windows 桌面自动化评估 agent。判断用户的任务是否可以通过
178+
UIAutomation(按控件名称/类型精确操作)完成,还是必须通过截图+坐标操作。
179+
180+
可以用 UIAutomation 的例子:
181+
- "打开记事本" → 可以,通过 shell 或 automation_system 启动
182+
- "在搜索框里输入xxx" → 可以,定位 Edit 控件并输入
183+
- "点击'保存'按钮" → 可以,按名称定位 Button 控件并 Invoke
184+
- "把音量调到50%" → 可以,通过 automation_system
185+
186+
必须用截图+坐标的例子:
187+
- "点击屏幕中间那个红色图标" → 不行,需要视觉定位
188+
- "看看网页上显示了什么" → 不行,需要截图理解
189+
- "在游戏里移动角色" → 不行,游戏 UI 没有 UIA 控件树
190+
```
191+
192+
### 4.3 修改 `analyze_and_execute()` 决策逻辑
193+
194+
**文件**: `brain/task_executor.py`
195+
196+
在现有的并行评估中增加 UIA 分支:
197+
198+
```python
199+
# === 新增:获取 UIA (Windows MCP) 工具列表 ===
200+
uia_tools = []
201+
uia_enabled = agent_flags.get("uia_enabled", False)
202+
if uia_enabled:
203+
# 从 mcp_adapter 获取 windows-desktop server 的 tools
204+
uia_tools = await self._get_uia_tools()
205+
206+
# 并行评估
207+
if uia_enabled and uia_tools:
208+
assessment_tasks.append(('uia', self._assess_uia(conversation, uia_tools)))
209+
210+
# ... 现有的 cu / bu / up 评估 ...
211+
212+
# 决策优先级调整:
213+
# 1. UserPlugin (精确匹配用户插件)
214+
# 2. UIA (精确控件操作,零 VLM 开销) ← 新增
215+
# 3. BrowserUse (网页自动化)
216+
# 4. ComputerUse (VLM + 坐标,兜底)
217+
```
218+
219+
### 4.4 新增 UIA 执行路径
220+
221+
**文件**: `agent_server.py`
222+
223+
`_do_analyze_and_plan()` 的 dispatch 逻辑中新增:
224+
225+
```python
226+
elif result.execution_method == 'uia':
227+
# UIA 任务通过 mcp_adapter plugin 执行
228+
# 复用 user_plugin 的执行路径,因为 MCP tools 已经注册为 NEKO entries
229+
if Modules.agent_flags.get("uia_enabled", False) and Modules.task_executor:
230+
# ... 与 user_plugin dispatch 类似的逻辑
231+
# 通过 _execute_user_plugin() 调用 mcp_adapter 暴露的 entry
232+
```
233+
234+
### 4.5 agent_flags 新增开关
235+
236+
**文件**: `agent_server.py` (Modules 类)
237+
238+
```python
239+
agent_flags: Dict[str, Any] = {
240+
"computer_use_enabled": False,
241+
"browser_use_enabled": False,
242+
"user_plugin_enabled": False,
243+
"uia_enabled": False, # ← 新增
244+
}
245+
```
246+
247+
前端设置界面对应新增一个"Windows 智能操作 (UIAutomation)"开关。
248+
249+
### 4.6 UIA 工具发现
250+
251+
**文件**: `brain/task_executor.py`
252+
253+
```python
254+
async def _get_uia_tools(self) -> List[Dict[str, Any]]:
255+
"""从 mcp_adapter 获取 windows-desktop MCP server 的工具列表"""
256+
plugins = await self.plugin_list_provider(force_refresh=False)
257+
uia_tools = []
258+
for p in plugins:
259+
if not isinstance(p, dict):
260+
continue
261+
pid = p.get("id", "")
262+
# mcp_adapter 注册的 entries 的 id 格式为 "mcp_{server_name}_{tool_name}"
263+
# 匹配 windows-desktop server 的 tools
264+
entries = p.get("entries", [])
265+
for entry in entries:
266+
eid = entry.get("id", "") if isinstance(entry, dict) else ""
267+
if "automation_" in eid or "windows" in pid.lower():
268+
uia_tools.append(entry)
269+
return uia_tools
270+
```
271+
272+
---
273+
274+
## 5. 执行流程对比
275+
276+
### 场景 A: "打开计算器"
277+
278+
**现有流程 (ComputerUse):**
279+
```
280+
1. pyautogui.screenshot() → 300ms
281+
2. VLM: "看到桌面,需要打开计算器" → 2-5s, ~500 tokens
282+
3. exec: pyautogui.hotkey('win') → 100ms
283+
4. pyautogui.screenshot() → 300ms
284+
5. VLM: "看到开始菜单搜索框" → 2-5s, ~500 tokens
285+
6. exec: pyautogui.write('calculator') → 200ms
286+
7. pyautogui.screenshot() → 300ms
287+
8. VLM: "看到搜索结果" → 2-5s, ~500 tokens
288+
9. exec: pyautogui.press('enter') → 100ms
289+
总计: ~10-18s, ~1500 tokens, 3次 VLM 调用
290+
```
291+
292+
**新流程 (UIA via MCP):**
293+
```
294+
1. LLM assess: "打开计算器 → UIA 可处理" → 1-2s, ~200 tokens (一次性)
295+
2. MCP call: automation_system.launch("calc.exe") → 200ms
296+
总计: ~1-2s, ~200 tokens, 1次 LLM 调用 (仅评估)
297+
```
298+
299+
### 场景 B: "点击屏幕上那个蓝色按钮"
300+
301+
**新流程:**
302+
```
303+
1. LLM assess: "蓝色按钮 → 需要视觉定位 → UIA 不适合"
304+
2. Fallback to ComputerUse (现有流程,不变)
305+
```
306+
307+
---
308+
309+
## 6. 未来扩展:虚拟桌面集成点
310+
311+
当前设计中,UIA 路径与 ComputerUse 路径完全解耦。未来接入虚拟桌面时:
312+
313+
```
314+
ScreenBackend (抽象层)
315+
├─ ForegroundBackend → pyautogui (现有)
316+
└─ VirtualDesktopBackend → CreateDesktop / RDP / Agent Workspace
317+
318+
UIA 路径天然支持后台窗口
319+
只需要将 MCP Server 启动在
320+
虚拟桌面的会话中即可
321+
```
322+
323+
UIA 路径(通过 MCP Server)只需要把 MCP Server 进程启动在虚拟桌面/RDP 会话里,NEKO 侧代码零改动。
324+
325+
---
326+
327+
## 7. 改动文件清单
328+
329+
| 文件 | 改动 | 工作量 |
330+
|------|------|--------|
331+
| `brain/task_executor.py` | 新增 UIADecision, _assess_uia(), _get_uia_tools(), 修改 analyze_and_execute() 决策逻辑 ||
332+
| `agent_server.py` | 新增 uia dispatch 分支, agent_flags 新增 uia_enabled ||
333+
| `config/` | MCP server 配置新增 windows-desktop ||
334+
| `static/` + `templates/` | 前端设置新增 UIA 开关 ||
335+
| `brain/result_parser.py` | 新增 parse_uia_result() ||
336+
| (外部) pywinauto-mcp | 安装 + 配置为 MCP Server | 配置 |
337+
338+
**总工作量估算:2-3 天核心开发,1 天集成测试。**
339+
340+
---
341+
342+
## 8. 风险与缓解
343+
344+
| 风险 | 缓解措施 |
345+
|------|---------|
346+
| pywinauto-mcp 的 UIA 工具覆盖不全 | 可以 fork 后补充自定义 tools;MCP 协议让替换 server 实现零成本 |
347+
| LLM 评估误判(该走 UIA 的走了 CU,或反过来) | 初期可以加规则硬匹配(如"打开xxx"直接走 UIA),减少 LLM 依赖 |
348+
| Windows MCP Server 进程崩溃 | mcp_adapter 已有 reconnect 机制 |
349+
| 部分应用 UIA 控件树残缺 | assess 阶段已考虑 fallback to CU |
350+
| Docker 部署环境无 Windows | UIA 路径自动禁用,不影响现有功能 |

0 commit comments

Comments
 (0)