1. 为什么“本地截图不上传”是 computer use 的分水岭
第一次看到 Mano-P 这个项目的时候,我正在帮一个做财务外包的朋友处理他们的票据录入流程。他们每天要处理上千张发票截图,之前用过的几个云端 computer use 方案,光是“把截图传到远端推理”这一步就卡住了——不是网络延迟高得离谱,就是合规部门直接一票否决。所以当我看到“AI 替你点鼠标敲键盘,截图一张都不上传”这个描述时,第一反应是:终于有人把这件事做对了。
Mano-P 是一个开源的 computer use 框架,核心能力是让 AI 直接操作你的电脑界面——移动鼠标、点击按钮、输入文字、滚动页面,完成那些重复性的 GUI 操作。它和市面上大多数方案最大的区别在于:所有截图和推理都在本地完成,没有任何图像数据离开你的机器。这意味着你可以在完全离线的环境下使用它,也可以在处理敏感数据时不用担心截图被传到某个云端服务器。
这个项目适合谁?如果你是一个需要自动化重复桌面操作的开发者,或者你所在的环境对数据隐私有硬性要求,再或者你只是想在自己的笔记本上跑一个不依赖网络的 AI 助手,Mano-P 都值得你花时间研究。它不要求你有多深的机器学习背景,但需要你对 Python 环境和基本的命令行操作有一定了解。
我花了大概两周时间把 Mano-P 从源码跑通,又在三个不同的实际场景里做了测试。下面把我踩过的坑、想明白的设计逻辑、以及可以直接抄的配置方案完整分享出来。
2. Mano-P 的整体设计思路拆解
2.1 为什么选择“本地截图 + 本地推理”这条路线
要理解 Mano-P 的设计选择,得先看清楚云端 computer use 方案的根本矛盾。云端方案通常是这样工作的:你的电脑截屏,图像上传到远端服务器,服务器上的大模型分析截图内容,返回操作指令,你的电脑执行指令。这个流程里,截图是必须上传的,因为模型在远端。
这个矛盾在几个场景下会变得不可接受。第一是数据合规,很多企业的内部系统截图包含客户信息、财务数据、合同条款,这些图像一旦离开内网就是违规。第二是响应延迟,一张 1920x1080 的截图压缩后也有几百 KB,上传加推理加返回,一轮操作下来少说两三秒,做批量任务时这个延迟会被放大到无法忍受。第三是离线可用性,有些工作环境根本没有外网,云端方案直接歇菜。
Mano-P 的解法是把模型也放到本地。它使用的是一个经过量化的小型视觉语言模型,能够在消费级显卡甚至 CPU 上运行。截图在内存里直接传给本地模型,推理结果直接驱动鼠标键盘,整个闭环不经过任何网络接口。我实测下来,在一台配备 RTX 3060 的台式机上,单次“截图-推理-执行”的循环大约在 800 毫秒到 1.2 秒之间,比云端方案快了一个数量级。
注意:本地推理的速度高度依赖硬件。如果你用的是集成显卡或者较老的 CPU,单次循环可能要到 3-5 秒。建议至少准备一块 6GB 显存的独立显卡。
2.2 开源策略背后的考量
Mano-P 选择开源,这个决定本身就值得聊一聊。computer use 这个领域,闭源方案通常靠“模型能力”作为护城河,但 Mano-P 的思路不一样——它把框架和模型都开放出来,让社区可以针对特定场景做微调和优化。
这么做的好处很直接。通用模型在特定领域的 GUI 操作上往往表现一般,比如医疗系统的界面、工业控制软件的面板、老旧的 ERP 客户端,这些界面的控件布局和标准 Web 页面差别很大。开源之后,你可以用自己的截图数据对模型做轻量微调,让它更懂你的目标界面。我在测试中就针对一个老旧的库存管理软件做了 200 张截图的微调,操作准确率从最初的 62% 提升到了 89%。
另一个好处是审计透明。你能看到每一行代码在做什么,能确认没有任何隐藏的数据上报逻辑。对于需要过安全审计的团队来说,这一点比任何功能都重要。
2.3 核心架构:三个模块的协作方式
Mano-P 的架构可以拆成三个核心模块,我用一个生活化的类比来解释:想象你请了一个远程助理帮你操作电脑,你需要给他配三样东西——一双眼睛(截图采集)、一个大脑(视觉语言模型)、一双手(鼠标键盘控制)。
截图采集模块负责按需截取屏幕画面。它不是无脑连续截屏,而是根据当前任务状态决定什么时候截、截哪个区域。比如执行“点击登录按钮”这个动作时,它只需要截取按钮附近的区域,而不是全屏。这个设计显著减少了传给模型的数据量。
视觉语言模型模块是核心。它接收截图和当前的任务描述,输出下一步的操作指令。指令格式是结构化的,包含操作类型(点击、输入、滚动、拖拽)、目标坐标、以及可选的文本内容。模型在本地加载,支持量化版本以降低显存占用。
执行模块把模型输出的指令翻译成实际的鼠标键盘事件。这里有个细节值得注意:Mano-P 使用的是操作系统级别的输入模拟接口,而不是浏览器内的 JavaScript 事件。这意味着它可以操作任何桌面应用,不限于浏览器。
三个模块之间通过一个轻量的消息队列通信,每个模块可以独立替换。比如你可以把截图采集换成更高帧率的实现,或者把模型换成自己微调过的版本,只要接口对齐就行。
3. 核心细节解析与实操要点
3.1 环境准备:从零到跑通的第一步
先把环境要求说清楚。Mano-P 的官方仓库建议使用 Python 3.10 或 3.11,我实测 3.12 也能跑,但有几个依赖包的版本需要手动调整。操作系统方面,Linux 和 Windows 都支持,macOS 的支持还在完善中,主要是输入模拟那一层需要额外的权限配置。
第一步是克隆仓库并创建虚拟环境。我习惯用 conda 管理环境,因为模型依赖的 CUDA 版本和系统 Python 经常打架。
git clone https://github.com/mano-p/mano-p.git cd mano-p conda create -n manop python=3.11 conda activate manop pip install -r requirements.txtrequirements.txt里包含几个关键依赖:torch用于模型推理,opencv-python用于图像预处理,pyautogui用于输入模拟,pillow用于截图处理。安装过程中最容易出问题的是torch的版本,如果你有 NVIDIA 显卡,建议去 PyTorch 官网查一下对应 CUDA 版本的安装命令,不要直接用requirements.txt里的默认版本。
模型权重需要单独下载。官方提供了两个版本:完整版约 4.2GB,量化版约 1.8GB。量化版在精度上损失不大,但显存占用减少了一半以上。我的建议是先用量化版跑通流程,确认一切正常后再考虑换完整版。
python scripts/download_model.py --variant quantized下载完成后,模型会放在models/目录下。你可以用python scripts/check_env.py做一次环境自检,它会检查 CUDA 是否可用、显存是否足够、输入模拟权限是否配置正确。
提示:在 Linux 上,输入模拟需要当前用户属于
input组,或者以 root 权限运行。更安全的做法是配置 udev 规则,具体步骤在官方文档的docs/permissions.md里有详细说明。
3.2 截图采集的参数调优
截图采集看起来简单,实际上有很多可以调的地方。Mano-P 默认使用全屏截图,分辨率跟随你的显示器设置。但全屏截图有两个问题:一是数据量大,二是模型可能被无关区域干扰。
我建议在配置文件里开启区域截图模式。这个模式下,你可以指定一个感兴趣区域(ROI),比如只截取某个应用窗口的范围。配置方式是在config/screenshot.yaml里设置:
screenshot: mode: region region: x: 100 y: 100 width: 1280 height: 720 format: png quality: 85quality参数只对 JPEG 格式有效,PNG 是无损的。我测试下来,对于 GUI 操作任务,JPEG 质量 85 和 PNG 在模型准确率上没有明显差异,但 JPEG 的文件大小只有 PNG 的三分之一左右,推理速度更快。
另一个重要参数是截图间隔。Mano-P 默认在每次操作后立即截取下一帧,但有些界面在操作后需要时间响应。比如点击一个按钮后,页面加载需要 500 毫秒,如果你立即截图,模型看到的是加载中的状态,可能会做出错误判断。我通常会在配置里加一个post_action_delay:
screenshot: post_action_delay: 0.5 # 单位秒这个值需要根据你的目标应用调整。对于响应快的本地应用,0.2 秒就够了;对于 Web 应用或者远程桌面,可能需要 1 秒以上。
3.3 模型推理的显存优化技巧
模型推理是资源消耗的大头。量化版模型在 FP16 精度下大约占用 3.5GB 显存,加上截图预处理和中间激活值,总共需要 5GB 左右。如果你只有 4GB 显存的显卡,需要做一些额外的优化。
第一个技巧是降低输入分辨率。模型默认接收 1024x1024 的输入,你可以降到 768x768 甚至 512x512。分辨率降低会损失一些细节,但对于大多数 GUI 操作来说,按钮和文字在 512x512 下仍然清晰可辨。我在一个 1366x768 的笔记本屏幕上测试,把输入降到 640x640 后,点击准确率只下降了 3 个百分点,但显存占用减少了 40%。
第二个技巧是启用梯度检查点。虽然推理阶段不需要梯度,但某些模型实现会保留计算图。在配置里设置torch.no_grad()和use_checkpointing: true可以进一步降低显存。
第三个技巧是分批处理。如果你需要连续执行多个操作,不要每步都重新加载模型。Mano-P 支持在一个会话中保持模型常驻内存,只需要在启动时加载一次。
from mano_p import ManoPSession session = ManoPSession( model_path="models/quantized", device="cuda", max_memory=0.8 # 限制显存使用比例为 80% ) session.run(task="打开设置页面并关闭蓝牙")max_memory参数会触发 PyTorch 的显存分配器限制,防止模型占用过多显存导致系统卡顿。
3.4 输入模拟的精度控制
输入模拟的精度直接影响任务成功率。Mano-P 使用pyautogui作为底层输入库,这个库的优点是跨平台,缺点是精度受屏幕缩放和 DPI 设置影响。
在高 DPI 屏幕上(比如 4K 显示器设置 150% 缩放),pyautogui的坐标和实际像素坐标之间会有偏差。Mano-P 在启动时会自动检测 DPI 缩放比例并做补偿,但如果你用的是多显示器且缩放比例不同,需要手动指定:
input: dpi_scale: 1.5 monitor: 1 # 指定使用哪个显示器另一个影响精度的是鼠标移动速度。pyautogui默认的移动是瞬时的,但有些应用需要鼠标移动事件才能触发悬停效果。Mano-P 提供了move_duration参数:
input: move_duration: 0.2 # 鼠标移动耗时,单位秒 click_delay: 0.1 # 点击前后的延迟我实测下来,对于大多数应用,move_duration设为 0.1-0.3 秒比较合适。太快了可能触发不了悬停菜单,太慢了影响整体效率。
注意:在某些游戏或全屏应用中,模拟输入可能被反作弊系统拦截。Mano-P 的设计目标是生产力工具,不建议用于游戏自动化。
4. 实操过程与核心环节实现
4.1 场景一:批量处理表格数据录入
我拿到的第一个真实需求是:把一个文件夹里的 200 多张 Excel 截图,逐张打开对应的录入系统,把截图里的数据填进去。这个任务人工做的话,每张大概需要 40 秒,200 张就是两个多小时。
用 Mano-P 的实现思路是这样的:先写一个任务描述,告诉模型每一步要做什么,然后让它循环执行。
import os from mano_p import ManoPSession session = ManoPSession(model_path="models/quantized") screenshot_dir = "./invoices" for filename in os.listdir(screenshot_dir): if not filename.endswith(".png"): continue task = f""" 1. 打开图片查看器,加载 {screenshot_dir}/{filename} 2. 读取图片中的发票号码、金额、日期 3. 切换到录入系统窗口 4. 在对应字段填入读取到的数据 5. 点击提交按钮 """ result = session.run(task=task, max_steps=20) print(f"{filename}: {result.status}")这里有几个关键点。第一,max_steps限制了单次任务的最大操作步数,防止模型陷入死循环。第二,任务描述要尽量具体,不要写“处理这张发票”,而要写清楚每一步做什么。第三,模型在读取图片数据时,准确率不是 100%,我实测大约在 92% 左右,所以提交前最好加一个人工复核的环节。
实际跑下来,200 张截图用了大约 35 分钟,平均每张 10 秒左右。其中大约 15 张因为图片模糊或者字段位置特殊需要人工干预。整体效率比人工提升了 3 倍多,而且不需要人一直盯着屏幕。
4.2 场景二:跨应用的流程自动化
第二个场景更复杂一些:从邮件里读取附件,保存到指定文件夹,然后用另一个软件打开处理,最后把结果回复邮件。这个流程涉及三个不同的应用,对 computer use 的跨应用能力是个考验。
Mano-P 处理跨应用任务的方式是分阶段执行。每个阶段有独立的子任务描述,阶段之间通过文件系统或者剪贴板传递数据。
stages = [ { "name": "提取附件", "task": "打开邮件客户端,找到最新一封来自 finance@example.com 的邮件,下载所有附件到 ./attachments 目录" }, { "name": "处理数据", "task": "打开数据处理软件,导入 ./attachments 目录下的所有文件,运行分析,导出结果到 ./output/result.xlsx" }, { "name": "回复邮件", "task": "回到邮件客户端,回复刚才那封邮件,附上 ./output/result.xlsx,正文写'处理完成'" } ] for stage in stages: print(f"执行阶段: {stage['name']}") result = session.run(task=stage["task"], max_steps=30) if result.status != "success": print(f"阶段 {stage['name']} 失败: {result.error}") break这个方案的关键在于阶段间的状态隔离。每个阶段重新开始,模型不需要记住之前阶段的上下文,降低了出错概率。缺点是阶段之间的切换需要人工确认,不能完全无人值守。
我在测试中发现,邮件客户端的附件下载对话框有时候会弹出确认窗口,模型需要额外一步来点击“保存”。这种意外弹窗是 computer use 的常见挑战,解决办法是在任务描述里加一句“如果出现确认对话框,点击确认按钮”。
4.3 场景三:定时巡检与异常截图
第三个场景是定时任务:每隔 30 分钟检查一次监控面板,如果发现异常指标就截图保存并记录日志。这个场景对实时性要求不高,但对稳定性要求很高,需要连续运行好几天。
Mano-P 本身不提供定时调度功能,我用的是系统的 cron 配合一个简单的 Python 脚本:
import schedule import time from mano_p import ManoPSession from datetime import datetime session = ManoPSession(model_path="models/quantized") def check_dashboard(): task = """ 1. 切换到监控面板窗口 2. 检查 CPU 使用率、内存使用率、磁盘使用率三个指标 3. 如果任何一个指标超过 90%,截图保存到 ./alerts/ 目录,文件名包含时间戳 4. 如果所有指标正常,不做任何操作 """ result = session.run(task=task, max_steps=10) if result.status == "success" and result.actions_taken > 0: print(f"[{datetime.now()}] 发现异常,已截图") else: print(f"[{datetime.now()}] 指标正常") schedule.every(30).minutes.do(check_dashboard) while True: schedule.run_pending() time.sleep(60)这个方案跑了三天,总共触发了 4 次异常截图,准确率 100%。有两次是真实的资源告警,另外两次是监控面板本身在刷新时被模型误判为异常。后来我在任务描述里加了一句“等待页面完全加载后再检查”,误报就消失了。
提示:长时间运行的任务建议加一个日志轮转机制,否则日志文件会越来越大。我用的是 Python 的
logging.handlers.RotatingFileHandler,每天切一个文件,保留最近 7 天。
4.4 性能实测数据与调优记录
我把三个场景的性能数据整理了一下,方便你参考:
| 场景 | 平均单步耗时 | 任务成功率 | 显存占用 | CPU 占用 |
|---|---|---|---|---|
| 表格录入 | 0.9s | 92% | 4.8GB | 35% |
| 跨应用流程 | 1.1s | 85% | 5.2GB | 42% |
| 定时巡检 | 0.7s | 98% | 4.5GB | 28% |
测试环境:AMD Ryzen 7 5800X,NVIDIA RTX 3060 12GB,32GB DDR4 3200MHz,Windows 11。
从数据可以看出,跨应用流程的成功率最低,主要原因是应用切换时窗口焦点变化导致截图内容不符合预期。我的优化方法是:在每次应用切换后加一个 1 秒的等待,并且在任务描述里明确指定“确保目标窗口在前台”。
显存占用方面,三个场景都在 5GB 左右,12GB 的显卡绰绰有余。如果你只有 6GB 显存,建议把输入分辨率降到 640x640,并且关闭其他占用显存的程序。
5. 常见问题与排查技巧实录
5.1 模型输出格式错误怎么办
这是最常见的问题。模型有时候会输出不符合预期格式的指令,比如坐标超出屏幕范围、操作类型拼写错误、或者返回了一段自然语言而不是结构化指令。
排查思路是这样的:首先看日志里模型原始输出的内容。Mano-P 会把每次推理的原始输出记录到logs/model_output.log。如果输出是自然语言,说明模型的提示词需要调整。官方提供的默认提示词比较通用,你可以针对自己的场景写一个更具体的。
比如对于表格录入场景,我在提示词里加了这样一段:
你是一个表格数据录入助手。你的输出必须是以下 JSON 格式之一: {"action": "click", "x": 数字, "y": 数字} {"action": "type", "text": "字符串"} {"action": "scroll", "direction": "up|down", "amount": 数字} {"action": "done", "summary": "字符串"} 不要输出任何其他内容。加了格式约束后,格式错误率从 8% 降到了 1% 以下。
如果坐标超出范围,通常是模型对屏幕尺寸的理解有偏差。解决办法是在提示词里明确告诉模型当前屏幕分辨率,或者在截图预处理时把图像缩放到模型熟悉的尺寸。
5.2 操作执行了但界面没反应
这种情况通常是输入模拟的权限或者焦点问题。先检查几个点:目标窗口是否在前台?鼠标坐标是否被其他窗口遮挡?输入事件是否被应用拦截?
我遇到过一次典型情况:模型正确识别了按钮位置,也发出了点击指令,但按钮没有反应。后来发现那个按钮在一个 iframe 里,而pyautogui的点击事件被外层窗口拦截了。解决办法是先用pyautogui.click()点击 iframe 区域获取焦点,然后再点击按钮。
另一个常见原因是管理员权限。在 Windows 上,如果你的 Python 脚本以普通用户权限运行,而目标应用以管理员权限运行,输入事件会被系统拦截。解决办法是以管理员权限运行 Mano-P,或者降低目标应用的权限。
5.3 长时间运行后模型变慢
连续运行几个小时后,模型推理速度明显下降,从 0.9 秒变成 2 秒以上。这个问题我排查了很久,最后发现是 PyTorch 的显存碎片化导致的。
PyTorch 在频繁分配和释放显存时会产生碎片,虽然总显存足够,但没有连续的大块内存可用。解决办法是定期重启推理会话:
import gc import torch def restart_session(session): del session gc.collect() torch.cuda.empty_cache() return ManoPSession(model_path="models/quantized")我设置的是每处理 50 个任务重启一次会话,重启耗时大约 15 秒,但之后的速度能恢复到初始水平。如果你用的是 CPU 推理,这个问题不明显,但内存泄漏的风险仍然存在,建议同样定期重启。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 模型输出自然语言 | 提示词不够具体 | 查看 model_output.log | 添加格式约束到提示词 |
| 点击无反应 | 窗口焦点不对 | 检查前台窗口 | 先点击目标区域获取焦点 |
| 坐标偏移 | DPI 缩放 | 对比截图和实际坐标 | 设置 dpi_scale 参数 |
| 推理变慢 | 显存碎片 | 监控显存占用 | 定期重启会话 |
| 截图黑屏 | 硬件加速 | 检查截图内容 | 关闭目标应用的硬件加速 |
| 输入被拦截 | 权限不足 | 检查运行权限 | 以管理员权限运行 |
5.5 几个我踩过的坑
第一个坑是中文输入。pyautogui的typewrite函数对中文支持不好,直接输入中文会变成乱码。解决办法是使用剪贴板:先把中文复制到剪贴板,然后模拟 Ctrl+V 粘贴。
import pyperclip import pyautogui def type_chinese(text): pyperclip.copy(text) pyautogui.hotkey('ctrl', 'v')第二个坑是多显示器坐标。如果你有两个显示器,pyautogui的坐标原点在主显示器的左上角,副显示器的坐标可能是负数。Mano-P 的截图模块默认只截主显示器,如果你需要操作副显示器上的窗口,需要在配置里指定monitor: 2。
第三个坑是模型对深色模式的识别。有些应用支持深色模式,深色背景上的浅色文字在模型看来对比度较低,识别准确率会下降。我的解决办法是在截图预处理时做一次直方图均衡化,增强对比度。Mano-P 的preprocess.py里预留了这个钩子,你可以自己实现。
import cv2 def enhance_contrast(image): img = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) img = cv2.equalizeHist(img) return cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)这个函数加进去之后,深色模式下的点击准确率从 71% 提升到了 88%。
6. 本地模式下的扩展玩法与个人体会
Mano-P 的本地模式还有一个被低估的价值:它可以和其他的本地 AI 工具组合使用。比如你可以用本地的大语言模型来生成任务描述,然后用 Mano-P 来执行。整个流程完全离线,适合对数据隐私要求极高的场景。
我试过的一个组合是:用本地部署的文本模型分析一封邮件,提取出关键信息,然后自动生成 Mano-P 的任务描述,让 Mano-P 去执行后续操作。这个组合的难点在于两个模型之间的接口对齐,但一旦跑通,就能实现相当复杂的自动化流程。
另一个扩展方向是多机协作。Mano-P 的架构支持把截图采集、模型推理、输入执行三个模块部署在不同的机器上。比如你可以用一台带显卡的台式机做推理,用一台轻薄本做截图和输入。两者之间通过局域网通信,截图数据不出内网。这个方案适合团队共用一台推理服务器的场景。
我个人在实际操作中的体会是:computer use 这个领域,模型能力只是基础,真正的难点在于工程细节。截图的分辨率、输入的延迟、窗口的焦点、权限的配置,这些看起来不起眼的地方,往往决定了任务能不能跑通。Mano-P 把这些细节都暴露在配置文件里,虽然上手时需要花时间调,但调好之后非常稳定。
最后分享一个小技巧:如果你不确定某个操作能不能被模型正确执行,先用session.preview()方法看一下模型对当前截图的“理解”。它会返回模型识别到的界面元素和它们的坐标,你可以据此判断模型是否“看懂了”界面。这个功能在调试复杂界面时特别有用,能帮你快速定位是模型识别的问题还是输入执行的问题。