WorkBuddy 的 Windows Control MCP — 项目总结与积分消耗深度分析
一句话总结:成功将 Codex Computer Use 的 Windows 桌面控制能力移植到 WorkBuddy MCP 框架,功能更全(36 个工具 vs 原版约 30 个),但积分消耗是同等操作的 40-50 倍。根因在于架构差异——Codex 是多模态模型原生"看"屏幕,而 MCP 是文本模型通过 base64 图片"读"屏幕。
从零开发 WorkBuddy Windows Control MCP:36 个工具让 AI 操控任意桌面应用
目录
- 项目概况
- 架构对比:为什么积分消耗天差地别
- 实测积分消耗数据
- 优化方案
- 使用建议
1. 项目概况
成果
| 指标 | 数值 |
|---|---|
| MCP 工具总数 | 36 个 |
| 测试通过率 | 10/10 (100%) |
| 在线 MCP 验证 | 36/36 工具全部可用 |
| 代码量 | ~1400 行 Python |
| 依赖 | mcp SDK, uiautomation, pywin32, PIL, easyocr, opencv, psutil |
工具分类
| 类别 | 数量 | 代表性工具 |
|---|---|---|
| 截屏与视觉 | 8 | screenshot, observe_screen, extract_text (OCR), find_text, find_image |
| 鼠标 | 4 | click, move_mouse, drag_mouse, scroll |
| 键盘 | 4 | type_text, press_key, hotkey, type_unicode |
| 窗口管理 | 7 | list_windows, focus/move/resize/minimize/maximize/close_window |
| UI Automation | 6 | get_ui_tree, find_element, click_element, set_element_value |
| 剪贴板 | 2 | get/set_clipboard |
| 进程 | 3 | run_program, list_processes, kill_process |
| 工具 | 2 | wait, batch_actions |
文件位置
~/.workbuddy/skills/windows-control/ ├── server.py # MCP 服务器(1400 行) └── SKILL.md # WorkBuddy 技能文档 ~/.workbuddy/mcp.json # MCP 配置(windows-control 条目)超越 Codex 原版的增强
- OCR 双引擎:pytesseract 优先 + easyocr 后备(无需系统安装 Tesseract)
- 图像搜索:
find_image用 OpenCV 模板匹配定位屏幕元素 - 文字搜索:
find_text用 OCR 定位文字并返回坐标 - 完整窗口管理:移动/缩放/最小化/最大化/关闭
- 进程管理:启动/列出/终止进程
- 批量操作:
batch_actions一次执行多个工具调用
2. 架构对比:为什么积分消耗天差地别
2.1 Codex Computer Use 的工作方式
用户指令 "点击保存按钮" │ ▼ ┌─────────────────────────────────────────────┐ │ Codex 多模态 VLM (单次 API 调用) │ │ │ │ 1. 截取屏幕 → 像素直接进入视觉编码器 │ │ (像素数据不进入文本上下文,0 token 开销) │ │ │ │ 2. VLM 视觉推理: │ │ "我看到桌面,保存按钮在坐标 (x, y)" │ │ │ │ 3. 执行工具调用:computer(action=click, x, y) │ │ │ │ 【单次调用总 token 消耗: ~5K】 │ └─────────────────────────────────────────────┘关键点:Codex 的模型原生支持视觉输入。截图作为像素直接输入视觉编码器,不经过文本 tokenizer。模型"看"到屏幕就像人眼看屏幕一样自然,不产生 token 开销。
2.2 WorkBuddy MCP 的工作方式
用户指令 "点击保存按钮" │ ▼ ┌──────────────────────────────────────────────────────┐ │ 回合 1: 截图 (screenshot) │ │ │ │ AI 发送: { tool: "screenshot" } │ │ 服务器返回: base64 PNG 图片 (~528KB → ~180K tokens) │ │ 【回合 1 token 消耗: ~200K (含系统上下文)】 │ │ │ ├──────────────────────────────────────────────────────┤ │ 回合 2: AI 分析截图 │ │ │ │ AI 思考: "我看到桌面上有一个保存按钮..." │ │ AI 输出: ~1K tokens │ │ 【回合 2 token 消耗: ~30K (上下文膨胀)】 │ │ │ ├──────────────────────────────────────────────────────┤ │ 回合 3: 点击 (click) │ │ │ │ AI 发送: { tool: "click", x: 500, y: 300 } │ │ 服务器返回: "clicked at (500, 300)" │ │ 【回合 3 token 消耗: ~15K】 │ │ │ ├──────────────────────────────────────────────────────┤ │ 回合 4: AI 确认 │ │ │ │ AI 输出: "已点击保存按钮" │ │ 【回合 4 token 消耗: ~10K】 │ └──────────────────────────────────────────────────────┘ 一次简单操作总消耗: ~255,000 tokens vs Codex CC: ~5,000 tokens ──────────────────────────────── 差距: 约 51 倍2.3 根因总结
| 维度 | Codex Computer Use | WorkBuddy MCP | 差距 |
|---|---|---|---|
| 模型类型 | 多模态 VLM(原生视觉) | 文本 LLM(图片=base64文本) | 本质差异 |
| 截图开销 | 0 token(像素直入视觉编码器) | ~180K tokens(528KB PNG → base64) | ∞ |
| 工具调用次数 | 1 次(截图+推理+操作合一) | 3-5 次(截图→分析→定位→操作→确认) | 3-5x |
| 单次上下文 | 固定(视觉 token 为固定嵌入) | 线性增长(每轮累积历史) | 上下文逐轮膨胀 |
| 每次操作消耗 | ~5K tokens | ~200-300K tokens | 40-60x |
一句话:Codex 的模型"看"屏幕,MCP 的模型"读"屏幕图片的文字表示。前者是视觉,后者是翻译。
3. 实测积分消耗数据
3.1 单工具调用 token 估算
基于测试数据 + 标准 tokenizer 估算(1 token ≈ 4 字节 base64 或 4 字符文本):
| 工具 | 返回数据大小 | 估算 token | 积分消耗(约) |
|---|---|---|---|
screenshot | 528KB PNG → 704KB base64 | ~180,000 | 巨额 |
screenshot(半分辨率 JPEG Q60) | 127KB → 169KB base64 | ~43,000 | 中等 |
observe_screen | 完整 UI 树 JSON + 截图 | ~100,000 | 巨额 |
list_windows | 26 窗口详情 JSON | ~10,000 | 小 |
extract_text(OCR) | 全屏文字 (~3KB) | ~1,000 | 极小 |
list_processes(全量) | 104KB JSON | ~26,000 | 中等 |
get_ui_tree | 控件树 JSON (depth=2) | ~5,000 | 小 |
get_clipboard/press_key/click | <1KB | ~200 | 可忽略 |
3.2 开发+测试阶段的累计消耗
在本次开发会话中,我们执行了:
| 阶段 | 操作 | 估算 token |
|---|---|---|
| 开发阶段 | 代码编写、MCP 握手测试 | ~50K |
| 离线测试 | 10 项 Python 测试脚本 | 0(本地执行) |
| 在线 MCP 测试 | screenshot (595KB PNG) | ~190K |
| 在线 MCP 测试 | get_screen_size + cursor + windows + clipboard | ~15K |
| 在线 MCP 测试 | observe_screen (UI树+截图) | ~100K |
| 在线 MCP 测试 | list_processes (全量 104KB) | ~26K |
| 在线 MCP 测试 | get_ui_tree + find_element + get_window_text | ~15K |
| 在线 MCP 测试 | extract_text (OCR) | ~2K |
| 在线 MCP 测试 | set_clipboard + focus_window | ~5K |
| 累计 | ~400K+ tokens |
注意:这只是 MCP 工具本身的 token 消耗。再加上每轮对话的系统上下文(~15K/轮)和历史累积,实际消耗更高。
4. 优化方案
4.1 立即可行的优化(降低 70-80% 消耗)
A. 截图压缩(最大优化点)
当前take_screenshot()返回全分辨率 PNG(528KB)。改为:
def take_screenshot(region=None, hwnd=None, quality=60, scale=1.0): """quality: JPEG quality 1-100; scale: 0.25-1.0""" # ... grab image ... if scale < 1.0: img = img.resize((int(img.width*scale), int(img.height*scale))) buf = io.BytesIO() img.save(buf, format="JPEG", quality=quality) return buf.getvalue()效果:
| 配置 | 大小 | Token | 节省 |
|---|---|---|---|
| PNG 全分辨率(当前) | 528KB | 180K | — |
| JPEG Q80 全分辨率 | 560KB | 191K | -6%(JPEG不适合截图) |
| JPEG Q50 全分辨率 | 394KB | 134K | 26% |
| JPEG Q60 半分辨率 | 127KB | 43K | 76% |
| JPEG Q40 1/4 分辨率 | ~40KB | ~13K | 93% |
注:JPEG 对截图(大量文字+UI 元素)压缩率不如 PNG。半分辨率才是真正的大头节省。
B. 限制返回数据量
| 工具 | 当前行为 | 优化后 |
|---|---|---|
list_windows | 返回所有窗口的完整信息 | 加max_results=10参数 |
list_processes | 返回全部进程(104KB) | 加name_filter默认只返回匹配的,否则截断 |
observe_screen | 截图+完整UI树 | 加mode="light"跳过 UI 树,只返回基本信息和低清缩略图 |
get_ui_tree | 全控件树 | 默认depth=2, max_children=20 |
C. 截图缓存
对同一轮对话中的重复截图做缓存(时间戳 + 哈希),避免相同画面重复传输。
4.2 中长期优化(降低 95%+ 消耗)
D. 本地视觉推理层(最佳方案)
在 MCP 服务器端集成一个本地小模型做视觉推理:
用户指令 "点击保存按钮" │ ▼ MCP 服务器: 截图 → 本地视觉模型分析 → 返回结构化结果 │ │ "桌面上有这些可点击元素: │ - 保存按钮: (500, 300), confidence=0.95 │ - 取消按钮: (600, 300), confidence=0.92" │ ▼ AI: 执行 click(500, 300) 【总 token: ~5K,接近 Codex 水平】可选技术方案:
- OmniParser(微软):专为 GUI Agent 设计的屏幕解析模型,输出结构化 UI 元素
- UI-TARS(字节):GUI 操作专用 VLM
- Florence-2(微软):轻量级视觉基础模型
E. 工具合并
将"截图→分析→点击"合并为一个smart_click(description)工具,减少往返次数。
5. 使用建议
何时使用 Windows Control MCP
| 场景 | 推荐 | 原因 |
|---|---|---|
| 点击已知坐标的按钮 | ✅ 可以 | 只需 click(x,y),消耗极低 |
| 输入文字、按快捷键 | ✅ 可以 | type_text/press_key 几乎不消耗积分 |
| 读写剪贴板 | ✅ 可以 | 纯文本操作,零负担 |
| 窗口管理(最大化/最小化) | ✅ 可以 | 只需窗口句柄,轻量 |
| 需要看屏幕上有什么 | ⚠️ 谨慎 | 用半分辨率截图或 observe_screen(light) |
| 复杂的 GUI 自动化流程 | ❌ 不推荐 | 多次截图+OCR 会很快耗尽积分 |
| 对 Adobe/Office 操作 | ❌ 用 Flue | Flue 走脚本 API,0 截图开销 |
最佳实践
- 截图优先用低分辨率:在
screenshot工具中指定quality=50, scale=0.5(等实现压缩参数后) - 能用 Flue 就用 Flue:有脚本 API 的应用(Adobe, Office, Blender)用 Flue,零积分消耗
- 减少"看屏幕"的次数:尽量凭窗口标题、UI 控件树定位,而不是每次都截图
- 批量操作:用
batch_actions合并多次操作为一次调用 - 关闭不必要的工具:如果只需要简单操作,在 MCP 配置中 disable 不用的工具
与 Flue 的分工
| Flue | Windows Control | |
|---|---|---|
| 适用应用 | 13 个专业应用(Adobe/Office/Blender等) | 任意Windows 应用 |
| 操作方式 | 脚本 API(JSX/VBA/Python) | GUI 模拟(鼠标键盘+UI树) |
| 积分消耗 | 零(本地执行脚本) | 高(截图=大量token) |
| 精确度 | 完美(直接调用API) | 依赖屏幕识别 |
| 速度 | 快 | 较慢(需要截图/OCR) |
规则:优先 Flue → 不支持时降级到 Windows Control → 控制截图频率。
附录:技术细节
关键 Bug 修复记录
| 问题 | 修复 |
|---|---|
ctypes.INT不存在 | →ctypes.c_int |
win32gui.EnumWindows在线程池中返回空 | → 改用 ctypesEnumWindows+WNDENUMPROC回调 |
GetDC(0)64位溢出 | → 声明user32.GetDC.argtypes = [wintypes.HWND]等所有 Win32 函数签名 |
| COM 卸载导致 uiautomation 间歇失败 | → 移除CoUninitialize(),COM 保持在线程中存活 |
| Tesseract 未安装导致 OCR 不可用 | → 添加 easyocr 后备引擎(纯 Python,自动下载模型) |
测试环境
- OS: Windows 11
- 屏幕: 2560×1440
- Python: 3.13.12 (managed venv)
- 测试窗口: WorkBuddy, ChatGPT, VS Code, ChatCut, Edge, 豆包, 百度网盘, Affinity Designer