ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零搭建paperclip:让AI像人一样操作电脑的完整实战

从零搭建paperclip:让AI像人一样操作电脑的完整实战 如果你最近关注AI agent的方向应该没少看到类似“让模型自己点鼠标操作电脑”的演示。这类工具里paperclip是一个绕不开的代号。它本身是“回形针”的意思寓意很直接像回形针把散落的文件夹在一起一样把“看屏幕、想动作、点下去”这三个环节夹成一个闭环让AI像人一样直接操作任何桌面软件而不需要对方提供API或插件。这篇文章我会把自己从零搭一个paperclip、真实跑通任务、以及踩坑修bug的完整过程写出来。如果你也想做一个能自动操作电脑的AI助手或者只是想搞清楚这类工具到底怎么工作、实际效果有多少水分那这篇文章应该能给你一个相当靠谱的参考。1. paperclip是什么从名字到本质先说结论paperclip不是一个“某个大厂官方出品”的单一软件而是社区里一类桌面AI代理项目的统称代际。很多开源仓库和内部工具都用它命名。这类项目的核心目标是一致的通过截取屏幕画面让视觉语言模型理解界面内容然后生成鼠标键盘动作最终自主完成一个用户在电脑上的操作任务。1.1 为什么让AI操作电脑这么难很多人第一次接触这类工具时会问“不就是模拟点击吗pyautogui不是早就能干这个了”确实传统的桌面自动化脚本早就存在但它们解决的是“固定路径”问题你告诉脚本在坐标(100, 200)点击脚本就去点击。一旦窗口移动了、按钮尺寸变了、界面改版了脚本就立刻失效。这是传统自动化的框架性瓶颈——它看得见坐标但理解不了界面。而paperclip这类agent要解决的是“非固定路径”问题。它没有预设好的点击序列而是像人一样先截一张屏幕图模型看到这张图判断“当前窗口里有哪些按钮、哪个按钮对应目标操作”然后决定“先双击这个文件夹图标再右键再选择重命名”。每一步都是根据当前屏幕内容实时生成的所以哪怕界面长得很不一样只要语义没变它也能适应。要做到这一点核心不是鼠标控制而是“理解”。这也决定了整个项目的技术路线必须围绕视觉语言模型来搭建而不是围绕坐标脚本。1.2 核心闭环截图-感知-决策-动作一个能用的paperclip实现跑起来其实就是一个四步闭环环节做什么常见实现截图获取当前屏幕或指定窗口画面mss、pyautogui.screenshot、系统级截屏API感知让视觉模型“看懂”截图中有什么GPT-4o、Claude、Qwen2-VL、MiniCPM-V决策模型输出下一步动作点击/输入/滚动结构化输出JSON如{x, y, action, reason}动作执行模型给出的鼠标键盘指令pyautogui、pywinauto、QuartzmacOS闭环跑完一遍之后回到第一步重新截图再感知、再决策、再动作。这就是agent和普通脚本最大的区别它每走一步都会重新观察一次环境像人一样“看一眼做一步再看一眼”。我自己第一次跑通这个闭环的时候说实话有点震撼。因为整个链路里没有任何一行代码写死了“去哪里点”全凭模型看着屏幕临场发挥。但也是从那一刻起我才意识到这套系统真正难的地方不在闭环本身而在闭环之外的一系列工程细节。2. 从零搭一个可运行的paperclip如果你也想搭一个最小可运行的版本环境准备其实相当轻量。我自己用的配置是Python 3.11 macOS但Windows上同样能跑只是权限处理稍有不同。2.1 环境准备需要安装的东西大概分三类截图库macOS上我用mss跨平台速度比pyautogui自带的截图快不少。Windows上如果涉及高DPI缩放还需要额外处理DPI感知。自动化库Windows用pyautogui或pywinautomacOS上用pyautogui需要先在“系统设置-辅助功能”里给终端授权否则鼠标键盘事件会被系统拦截。视觉模型SDK我用的OpenAI的openai库因为这个方向它效果最稳定。如果你想完全离线跑可以接Qwen2-VL但推理速度会明显慢后面会细说。这里有一个特别容易踩的坑macOS的屏幕录制权限。截图功能单独需要“屏幕录制”权限自动化点击需要“辅助功能”权限。这两个权限是分开的缺一个都不会报错只会静默失败——截图截出来是黑的或者鼠标没反应。我第一次跑的时候就是截图权限没开模型拿着一张全黑图硬是分析了半天“界面是深色模式”。2.2 模型选型效果和成本怎么平衡模型是整个paperclip的大脑选型直接决定上限。我三个方向都实测过云端闭源模型GPT-4o、Claude理解能力强能处理复杂的界面语义比如“这个按钮虽然长得像链接但实际上可以点击”。缺点是每次调用都有延迟和成本一个任务动辄几十次调用要做好心理准备。开源视觉模型Qwen2-VL 7B、MiniCPM-V可以本地跑隐私性好成本可控。但7B级别模型在复杂软件界面上的表现明显弱一截经常混淆弹窗和主界面对图标语义的理解也比较差。极轻量方案OCR 普通LLM先OCR提取屏幕文字再让普通大模型根据文字内容做决策。这个方案在文本密集的场景比如文件管理器、Excel效果意外地好而且便宜很多缺点是无法理解纯图形界面。我的经验是如果你只是想体验直接上云端闭源模型如果想做一个低成本长期运行的工具OCR 小模型兜底是性价比最高的路线。这部分后面在优化章节会详细展开。2.3 最小闭环代码一个能跑的最小示例核心逻辑大概像这样import mss import pyautogui import base64 from openai import OpenAI client OpenAI() def capture_screen(): with mss.mss() as sct: monitor sct.monitors[0] # 主显示器 img sct.grab(monitor) # 转成PNG字节流 from PIL import Image import io pil_img Image.frombytes(RGB, img.size, img.rgb) buf io.BytesIO() pil_img.save(buf, formatPNG) return base64.b64encode(buf.getvalue()).decode() def ask_model(screen_b64, task, history): response client.chat.completions.create( modelgpt-4o, messages[ {role: system, content: ( 你是桌面自动化助手。你会收到一张屏幕截图和一个任务。 请输出下一步动作必须是JSON {action: click|type|scroll|finish, x: 0, y: 0, text: , reason: } 注意x和y必须是原图坐标。不要想象只根据截图内容判断。 )}, *history, { role: user, content: [ {type: image_url, image_url: {url: fdata:image/png;base64,{screen_b64}}}, {type: text, text: f任务{task}}, ], }, ], ) return response.choices[0].message.content def execute(action): if action[action] click: pyautogui.click(action[x], action[y]) elif action[action] type: pyautogui.write(action[text]) elif action[action] scroll: pyautogui.scroll(-int(action[text])) # text传滚动行数 elif action[action] finish: print(任务完成) history [] task 打开下载文件夹把里面的PDF文件按修改时间排序 for step in range(30): # 最多30步 screen capture_screen() raw ask_model(screen, task, history) action json.loads(raw) print(fStep {step}: {action[reason]}) if action[action] finish: break execute(action) history.append({role: assistant, content: raw})这段代码虽然简陋但已经把闭环跑通了。实际用的时候你会发现几个问题截图分辨率可能是2K甚至4K直接丢给模型会超出视觉模型的输入分辨率限制坐标如果不做换算模型看到的图和实际点击的位置会对不上。这就引出了下一节的关键工程细节。3. 关键工程细节坐标换算、动作执行与安全边界把闭环跑起来只是第一步真正让它稳定工作需要处理三个工程问题。3.1 屏幕坐标换算模型看到的不等于真实坐标这是paperclip类项目最容易翻车的地方。大部分视觉模型会把输入图片缩放到固定分辨率比如最大1280像素所以模型返回的坐标是“它在缩放后图片上看到的坐标”而不是你屏幕的真实坐标。假设你的屏幕分辨率是2560x1440截图传给模型后被缩放到1280x720模型返回点击坐标(640, 400)那真实坐标应该是(1280, 800)。换算逻辑很简单scale_x screen_width / model_image_width scale_y screen_height / model_image_height real_x model_x * scale_x real_y model_y * scale_y但这里有个隐蔽的坑很多库在缩放时会保持宽高比导致图片不是正好缩放到1280x720而是1280x720以内的某个尺寸比如1280x640。如果你直接用目标尺寸算缩放比例坐标会整体偏移。正确做法是拿到模型实际接收的宽高后再算比例或者干脆在发给模型之前就自己把图片Resize成固定尺寸比如1280x720这样计算就干净了。我自己习惯的做法是截完图后用PIL统一thumbnail((1280, 1280))同时记录缩放后的实际宽高再按照这个宽高算比例。多显示器环境下还要考虑每个显示器可能有不同的坐标原点和缩放比例这个更复杂建议第一版先只支持主显示器。3.2 动作执行与防误触坐标算对了接下来是动作执行。pyautogui本身有PAUSE和DURATION参数我强烈建议不要用默认值。默认的点击速度太快模型规划的动作本身已经是按人类速度设计的太快会造成界面状态还没响应完下一步就来导致一连串误操作。更重要的一个教训是任何自动化都要做应用白名单。让AI自由操作你的整台电脑风险远大于收益。我一开始没做限制结果有一次它把系统设置里的网络配置窗口打开了我旁边坐着客户场面一度很尴尬。后来我在代码里加了一道拦截执行click之前先检查当前活跃窗口的标题如果不在白名单内就跳过并提醒模型“当前窗口不允许操作”。白名单逻辑大概是这样的allowed_windows [下载, 资源管理器, Finder, Visual Studio Code, Terminal] current_title get_active_window_title() if current_title not in allowed_windows: print(f警告窗口 {current_title} 不在白名单操作已拦截) continue这不是保守这是基本的安全意识。AI agent迟早会点错东西白名单就是最后的闸门。3.3 双确认机制高风险动作必须暂停除了白名单我还会区分动作风险等级。点击、输入属于低风险删除文件、拖拽、右键菜单操作、点击对话框里的“确定/覆盖”等属于高风险。高风险动作执行前需要人工按一下回车确认。实现方式不复杂在execute()里如果动作类型命中风险清单就弹一个终端提示输入y后再真正执行。这看起来降低了自动化程度但实际用下来这种“半自动”模式反而让任务完成率更高——因为模型经常会在弹窗出现时犹豫你介入确认一下它就能继续往下走。4. 实测让paperclip自动整理下载文件夹光说原理容易虚我拿一个相对安全、结果可检验的任务做了实测自动整理下载文件夹把不同类型的文件移动到对应子目录。选这个任务是因为它涉及窗口切换、列表操作、右键菜单、多选、拖拽等多种动作非常考验agent的界面理解能力同时即使操作失败也不会造成严重损失。4.1 任务设定与提示词写法同样的任务提示词写法不同效果天差地别。我第一版提示词写的是“整理一下下载文件夹”模型跑了半天先打开了一个无关的浏览器窗口又跑到桌面转了一圈最后停在一个全屏视频前发愣。原因很简单任务指令太空泛没有给它可执行的边界。优化后的提示词长这样任务整理下载文件夹 要求 1. 打开“下载”文件夹窗口放在屏幕中央 2. 按文件类型分类图片、文档、压缩包、安装包、其他 3. 如果对应分类目录不存在先创建目录 4. 移动文件后不要关闭窗口报告每个分类移动了多少个文件 5. 每一步只做一个操作做完一步先观察再行动关键变化有两点一是明确了“先确认环境再行动”的流程二是把任务拆成了可检验的步骤。模型每做完一步我都能在截图里看到效果它自己也能据此修正下一步。4.2 跑通全过程记录我记录了第一次完整跑通的agent行为序列步骤agent做了什么结果1点击Dock上的“下载”图标打开下载窗口2截图后识别出窗口里有“图片”“文档”“压缩包”等分类目录发现已有部分分类目录3点击“下载”搜索栏旁的排序按钮选择“名称”排序文件列表按名称排列4滚动文件列表逐个识别文件类型模型通过扩展名判断类型准确率高5拖拽一个JPG文件到“图片”文件夹成功移动6重复第5步24次全部成功7遇到DOCX文件重名冲突弹窗停留在弹窗前等待输入8人工确认覆盖后继续后续文件移动正常完成9输出统计报告“图片15个文档8个安装包3个”整个过程耗时约11分钟25个文件全部正确分类。中间只有一次需要人工介入重名覆盖弹窗其他步骤agent都独立完成了。这个结果比我预期好不少但也暴露出一个关键问题速度还是太慢。如果文件数量翻倍模型调用次数成倍增长等待时间会线性上升。4.3 失败与卡点这个任务我跑了三次前两次分别是这样失败的第一次agent打开了下载窗口但没等窗口完全加载就开始点击文件夹图标结果点在了窗口滚动条上误打开了一个文件夹。这暴露了“动作后未验证”的问题——它点击后没有重新截图确认界面变化而是直接执行了下一个计划好的动作。第二次更典型模型把“下载窗口里的侧边栏”和“系统设置里的侧边栏”搞混了认为当前窗口是文件管理器实际是某个安装包的解压界面。这种混淆在视觉模型里很常见尤其是界面布局相似的场景。5. 踩坑与优化从“能跑”到“好用”能跑通一个demo不难难的是稳定复用。这一个月踩的坑主要集中在四个方面。5.1 窗口漂移最破坏信任感的问题窗口漂移指的是模型基于截图像素做出点击决策但截图和点击之间用户移动了窗口或弹出了新窗口导致坐标完全错位。最典型的情况是你在用电脑的过程中某个后台弹窗突然出现在屏幕中央模型下一跳点击就落在弹窗上可能关掉你的重要页面甚至触发某些不可逆操作。我的解决办法是双保险一是尽量把任务限定在“全屏独占”的应用里比如给agent指定一个独立的虚拟桌面减少外部弹窗干扰二是在每次动作执行前做一次轻量校验——比较当前活跃窗口标题和上一次截图时的窗口标题不一致就暂停。在macOS上用虚拟桌面隔离agent效果很好。Windows可以用Windows自带的虚拟桌面但Python控制起来不够优雅也可以用“窗口前置置顶”的方式近似实现。5.2 模型不听话的常见原因模型经常不按提示词要求的JSON格式输出或者输出一个看起来合理但实际无关的动作。我总结下来原因基本是这三个第一截图信息量太大。2K分辨率全屏图模型很容易把注意力放在视觉中心区域忽略屏幕角落的按钮。解决方法是裁剪如果目标窗口已知先定位窗口再截图只给模型看窗口区域而不是整个屏幕。第二缺少“当前上下文”信息。一个纯截图没有时间戳、没有窗口标题、没有系统状态模型只能靠猜。我在发给模型的消息里强制附加一行“当前窗口标题xxx上次动作结果成功/失败/弹窗等待”给了这些上下文之后执行准确率提升非常明显。第三任务步骤太长。模型在一个prompt里规划五六个动作思考链条越长越容易出错。后来我改成强约束“一次只输出一个动作”虽然调用次数变多但每个动作的可靠性大幅提升。5.3 性能与成本优化云端模型的成本是绕不开的话题。我统计过一个20步的任务大约消耗约10万tokens图像按token折算折合人民币大概3-6元。如果每天跑几十个任务一个月成本就上来了。针对这个我用了两个手段一是小模型预筛选。用一个便宜的开源OCR模型比如PaddleOCR先提取屏幕上的文字块和位置把“有没有目标文件名”“文件类型是什么”这类简单判断交给规则完成。只有当规则无法确定动作时才升级到大模型。这样大约能省掉60%的模型调用。二是缓存重复截图。相同或相近的截图不重复调用模型直接复用上一次的决策结果。下载文件夹这类静态列表很适合这种策略。策略节省成本效果OCR预筛选约60%调用简单文件排序任务完全够用截图相似度缓存约30%调用重复界面不重复推理小窗口裁剪单次token减少40%注意力更集中准确率提升6. 从paperclip到更多可能性桌面点击式的agent只是这个方向的开端。跑通之后你会很快意识到有些场景用“视觉鼠标”是杀鸡用牛刀有更精准的路线可以走。6.1 浏览器内的路线CDP协议的加入如果任务场景集中在浏览器里没必要模拟真实鼠标移动。Chrome DevTools Protocol可以让agent直接调用浏览器内部接口读取DOM、点击元素、操作页面完全绕开坐标——准确性是像素级点击无法比的。我后来把整理文件的场景换成网页端的同类操作比如整理某个云盘里的文件用CDP路线稳定性和速度都提升了一个量级。一个比较务实的思路是桌面操作和浏览器操作双通道并存。能在浏览器里完成的走CDP浏览器之外的走视觉点击两者由一个统一的任务规划器调度。这也是现在很多商用AI助手产品的底层设计。6.2 组合玩法让agent更像“同事”我还开发了一套比较顺手的组合玩法OCR识别屏幕内容形成可搜索索引VLM负责理解界面和决策传统脚本负责高精度重复动作比如批量重命名文件名最后由规则引擎校验结果。这四层分工各自干自己最擅长的事效果远比单一模型大包大揽好。举个例子批量处理文件时VLM发现“这个文件是重复的需要确认”直接调用一个预先写好的弹窗处理函数而不是自己尝试点击可能会有歧义的按钮。这种“模型决策、脚本执行”的混合架构是稳定性的主要来源。6.3 对普通用户的价值对我个人来说paperclip类项目最大的价值不是“替代人”而是让我重新理解了“自动化”这件事。过去写自动化脚本要求我精确知道每一步逻辑现在只需要描述你想要的结果agent帮你尝试到达那里。门槛从“会编程”降到“会说清楚”这对普通办公用户来说意义很大。我也必须承认现阶段它离“全自动替你干完所有电脑活”还差很远。复杂软件里的层级菜单、模糊语义、抽象图标仍然是模型经常翻车的地方。但如果你愿意把一个具体的、小范围的固定任务交给它跑起来你会发现它的实用性比想象中好得多。我从这个项目里最大的体会是别急着做一个通用的电脑管家先挑一件你每天都在做、规则相对明确、错了也没关系的小事让paperclip接过去。让它成为你的第一个“数字实习生”从整理下载文件夹开始。
返回列表