恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
免费开源AI编码代理:GUI操控与MCP集成,单文件运行
首页
资讯中心
/
免费开源AI编码代理:GUI操控与MCP集成,单文件运行
免费开源AI编码代理:GUI操控与MCP集成,单文件运行
发布时间:2026/10/15 12:36:06
我做了个免费 AI 编码代理支持操控 GUI 和 MCP单文件运行。这东西不是什么大厂产品是我自己利用业余时间写的一个开源小工具核心就三件事让大模型不光能写代码还能直接操作你屏幕上的图形界面程序接入 MCP 协议把外部工具链变成模型的手脚整个项目打包成一个可执行文件双击就能跑。先说清楚它适合谁。如果你平时用 AI 写代码但经常被“你去打开这个软件点几下”“把这个 Excel 里的数据导入那个系统”这类需求卡住或者你想把自己的内部工具通过 MCP 协议暴露给 AI 用同时又不想装一堆 Python 虚拟环境和 SDK那这篇文章应该能帮上忙。我会把它的设计思路、GUI 操控的实现细节、MCP 接入方式以及我在开发过程中踩过的坑全部摊开来讲。1. 为什么我需要一个能“看见屏幕”的编码代理项目起源与定位1.1 一个被 GUI 卡住的 AI 编程场景事情起源于一次很无聊的重复劳动。我在帮一个旧的进销存系统写数据迁移脚本这个系统没有 API只有一套 Windows 客户端。我想要的数据都显示在界面上导出功能又只支持单页 Excel。这意味着我要么人工对着屏幕把每页数据复制出来要么写一个脚本模拟鼠标键盘去操作那个客户端。尝试过用现有的编码代理帮我写这个自动化脚本但我很快发现了一个尴尬的问题市面上的编码代理大多活在终端里。它们能跑命令、改文件、调 API但遇到图形界面就抓瞎——它们不“看不见”屏幕也不知道鼠标应该点到哪里。1.2 现有工具的两大缺口当时的工具生态大致有两大缺口终端型 Agent 摸不到图形界面。它们能帮你写好一段 PyAutoGUI 脚本但脚本跑起来之后按钮位置一变、弹窗一出现脚本就废了。你没法让模型看着屏幕实时调整只能来回改代码、重跑、再改。整个流程非常磨损耐心。SDK 集成的门槛太高。把 Claude、GPT 这类模型接到你自己的工具链里需要处理 API 鉴权、多轮对话状态、函数调用的参数校验。如果只是内部用一次这个成本还不如手动点鼠标。1.3 工具定位与核心决策所以我自己写了一个轻量的编码代理核心决策很简单免费且开源纯本地运行只消耗你自带的大模型 API Key没有订阅费。能操控 GUI通过截图识别、像素比对、窗口消息机制让模型能“看到”屏幕并真实地操作鼠标键盘。支持 MCP允许用户把任意命令行工具、内部脚本、浏览器接口等通过 MCP 协议接入模型可以按需调用。单文件运行一个二进制文件包含全部代码和静态资源不依赖 Python 环境不装机不弹命令行黑框。这套组合在当时的开源项目里不太常见现在类似形态的工具也开始出现了但我在设计时踩过的坑、绕过的弯路还是有不少值得分享的细节。2. GUI 操控模块不是截图加提示词那么简单2.1 技术路线选型模板匹配、OCR、还是无障碍树GUI 操控看起来简单——截个图给模型让它返回坐标然后移动鼠标点击。但真正落地时我对比了三条技术路线方案原理优点缺点模板匹配OpenCV提前截取目标按钮的图片用像素匹配在屏幕上找位置稳定、速度快、离线可用按钮外观一变就失效高 DPI 缩放场景容易错位OCR如 Tesseract / PaddleOCR识别屏幕上的文字根据文字位置定位控件对动态内容适应性好识别有误差中文小字号场景误报率高无障碍树Windows UI Automation通过系统接口读取控件层级和名称定位最准、可读属性部分老旧软件不暴露控件跨平台兼容性差我的最终选择是把三者做成一条流水线而不是只用其中一种。2.2 坐标定位与点击链路先看树再模板匹配最后 OCR 兜底实际操作顺序是这样的优先走无障碍树。调用 Windows UI Automation API把当前活动窗口的控件列表提取出来模型直接看到的是“按钮确定编辑框数量列表框导出 Excel”这样的结构化描述而不是一张图片。这一步能解决 80% 的定位问题。无障碍树拿不到信息时退回到模板匹配。我会让模型截取目标控件的小块图片然后在全屏截图里做多尺度匹配找到相似度最高的位置。如果模板也没有最后用 OCR 定位文字。比如一个按钮上写着“确认”OCR 找到“确认”两个字所在的矩形区域点击矩形中心。这套流水线的好处是模型不需要每次都能处理复杂的“像素级坐标推理”它只需要知道“我要点哪个按钮”剩下的定位逻辑全部由伪装层完成。2.3 输入处理中文输入法、剪贴板注入与防锁键要说 GUI 操控最容易翻车的地方键盘输入绝对排前三。第一个坑是中文输入法。直接调用keyboard.type()输入中文是不可行的——它只是模拟按键不经过输入法转换。我的做法是剪贴板注入# 把要输入的文字写入剪贴板然后模拟 CtrlV 粘贴 def paste_text(text: str): import pyperclip pyperclip.copy(text) time.sleep(0.2) pyautogui.hotkey(ctrl, v) time.sleep(0.3)这个方案对中文、英文、特殊符号都通用而且比逐字模拟按键快得多。另一个坑是锁键比如某些软件里 CtrlV 被禁用了。这种情况我会转而使用 Windows 的SendMessage机制直接往窗口的消息队列里投递字符消息绕过快捷键拦截。当然这个方案只在窗口未无响应时有效。2.4 从截屏到闭环视觉反馈回路GUI 操控的关键不是“第一次点对”而是“每次点击后都能确认结果”。我的代理在每一步操作之后都会重新截图当前活动窗口做一次轻量级比对如果截图区域没有变化可能说明点击没有生效或者弹窗被焦点阻挡了。如果出现了新的弹窗模型会读取弹窗内容判断是继续、取消还是输入信息。这个视觉反馈回路我会在后面的实测部分展示一个具体案例。简单说这等于给模型装了一条“眼睛—手—眼睛”的闭环控制链而不是只装了一双手。3. MCP 接入逻辑把外部工具变成模型的手脚3.1 MCP 协议到底在解决什么问题MCPModel Context Protocol模型上下文协议是这两年 AI 工具链里很热的一个词它做的事情用一句大白话说就是给大模型一个标准端口让它可以动态地“看到”并调用你本地的工具。在没有 MCP 之前如果你想给 AI 接一个自定义工具通常得像给 GPT 写 function calling 一样把函数的描述和参数 schema 写死在代码里。换个工具就要改代码。MCP 的思路则完全不同模型通过一个标准协议直接询问服务器“你有哪些工具”然后按规范发起调用。我的代理内置了一个 MCP 客户端支持两类传输方式stdio 传输本地启动一个子进程和进程的标准输入输出直接 JSON-RPC 2.0 通信。适合那些已经打包成命令行工具的脚本和程序。HTTP/SSE 传输通过网络连接你部署在远程或用本机的 MCP Server适合那些需要跨机器共享或高并发的场景。3.2 服务端集成自定义 MCP Server 注册进代理接入一个新的 MCP Server 非常简单。你只需要在配置目录下放一个 JSON 文件声明服务器名称、启动命令、环境变量代理启动时就会去自动拉起它。# config/mcp-servers.json { mcpServers: { my-erp: { command: python, args: [C:/path/to/erp_mcp_server.py], env: { ERP_TOKEN: xxxx } }, browser-assistant: { command: npx, args: [myscope/browser-mcp-server] } } }我之所以设计成这样主要是考虑到团队里的同事不一定懂编程。他们只需要改一行 JSON就能把新的工具挂给 AI 用完全不需要碰代码。3.3 让我印象很深的一个接入案例用 MCP 接通浏览器和本地工具开发过程中我常常需要让代理去查内部文档再去修改代码文件。做法是写了一个非常简单的 MCP Server暴露了三个工具search_internal_docs(关键词)—— 调内部 Confluence 的开放接口做搜索read_file(路径)—— 读取本地文件内容write_file(路径, 内容)—— 写文件但会先自动生成带时间戳的备份。代理在和你对话时如果它觉得应该查文档就会主动通过 MCP 调用search_internal_docs读完文档之后直接改代码。我全程只说了句“帮我把缓存失效逻辑重构干净”剩下流程全跑通了。这个过程让我意识到MCP 最大的价值不是省掉了一次两次函数调用而是替你把工具的动态发现和错误处理都标准化了。工具下线了服务器会返回-32601 method not found这样的标准错误模型也能读懂。3.4 工具命名与安全护栏当然光是“能调用”还不够安全边界是必须处理的。我给 MCP 工具做了三层保护命令白名单通过 MCP 启动的外部进程默认只有只读权限需要特殊声明的操作才能拿写权限。操作确认对涉及删除、覆盖文件、执行系统命令的操作代理会让用户看到确认按钮而不是直接执行。上下文限制工具返回的文本长度默认截断到 8000 字符防止工具输出把模型上下文占满了导致后续推理质量下降。这个设计平衡了“好用”和“可控”。我见过不少工具直接把 root 权限全给 AI结果一个误操作把配置文件清空了教训相当深刻。4. 单文件分发架构编译线、资源内嵌与启动时序4.1 为什么拒绝安装包和 Python 虚拟环境如果这个项目只是我自己用随便怎么折腾都行。但既然决定开源出去就必须考虑普通用户的使用体验。我见过太多优秀的 Python 项目因为要装 Python、建虚拟环境、pip install 一堆依赖把非技术用户直接劝退。所以我把“单文件运行”当成一个硬性需求而不是可选优化项。4.2 单文件打包技术选型Go embed 还是 Python PyInstaller这里我纠结过一段时间。GUI 操作和 MCP 客户端如果用 Python 写生态比较顺手PyAutoGUI、OpenCV、mcp 库一应俱全。但 Python 打包成单文件的问题在于PyInstaller 打出来的体积通常在 100MB 以上而且启动时要先释放临时文件杀毒软件经常误报。我最终采用了 Go 作为主程序框架通过go:embed把前端静态资源和服务端二进制全部塞进一个可执行文件。体积控制在 30MB 左右启动速度也快。GUI 操作部分我封装了一层 CGO 调用 Windows 的user32.dll和Oleacc.dll无障碍树接口在 Windows 上额外嵌入了打包好的 OCR 库定位精度和原生写 Python 没有明显差异。整体架构大概是这样代理主程序Go 二进制 ├── 内嵌前端 UIWeb 页面通过本地端口渲染 ├── 内嵌 GUI 操控引擎截图、模板匹配、无障碍树、键鼠模拟 ├── 内嵌 LLM 客户端同时支持 OpenAI 兼容 API 和 Anthropic API ├── 内嵌 MCP 客户端stdio HTTP/SSE └── 内嵌 MCP Server SDK用于自定义工具的快速编写4.3 内嵌资源的版本管理与热更新单文件架构有一个代价更新起来不如多文件方便。我目前的做法是配置目录独立。用户的数据、模型 Key、MCP Server 配置、历史记录都存放在程序旁边的agent-data文件夹里。升级程序本体时只需要替换那一个可执行文件配置和数据全部保留。这个设计在上周的一次小版本升级里帮了大忙。我修了一批 GUI 定位的 bug直接把新二进制发给朋友替换完就完事没有遇到任何“配置丢了”的求助。4.4 启动时序与首次运行引导单文件还有一个容易被忽略的问题用户第一次双击运行之后会发生什么我专门设计了一个“向导式”启动流程检测配置文件是否存在不存在则弹出欢迎页要求填入模型 API Key 和模型名。自动检查系统权限包括屏幕录制权限macOS和安全操作权限Windows。拉起 MCP Server 列表逐个测试握手失败的会提示是协议问题还是路径配置问题。全部就绪后在主界面显示一个“我可以看到你的屏幕了”的状态提示。这个流程看起来琐碎但如果没有它小白用户会把“配置错误”和“程序跑不动”混为一谈。我收到的最多的反馈从“怎么打不开”变成了“按向导走完就正常了”。5. 一次完整实测让代理打开一个 GUI 工具并完成取数光听设计思路不过瘾我们直接跑一遍真实任务。为了写这篇文章我在一台干净无预装多余软件的 Windows 11 虚拟机上用代理完成了一个典型任务。5.1 任务设定我给代理提了一句自然语言指令打开桌面上的“销售统计工具”在第一个表单里输入“华东”点击“查询”把结果表格里的前三行数据整理成一封 JSON 格式的摘要。这个任务看起来简单但包含了很多 GUI 操作的难点程序不是默认打开的活动窗口需要先找到并激活它。查询结果会动态刷新模型需要等待数据加载完成。输入框和按钮的尺寸没有文档完全依靠视觉定位。5.2 代理的执行轨迹我把代理的执行轨迹打了出来部分节选这里展示 GLSL、MSS 等核心步骤只保留关键动作[09:02:11] 用户指令已接收。任务拆解 1. 查找并打开“销售统计工具” 2. 在输入框输入“华东” 3. 点击“查询” 4. 等待表格加载完成 5. 读取前三行数据并输出 JSON [09:02:13] 开始搜索桌面图标发现“销售统计工具”位于桌面第三行。 [09:02:15] 双击图标。窗口启动已确认活动窗口标题为“销售统计工具 - 数据查询”。 [09:02:18] 读取无堣障碍树找到输入框控件。使用草地模型判断控件类型为 Edit。 [09:02:20] 焦点定位至输入框。尝试键盘输入“华东”输入法冲突检测改用剪贴板注入。 [09:02:23] 剪切板注入成功。输入框内文字已确认。 [09:02:26] 开始查找“查询”按钮。由于无障碍树中按钮的 Name 属性返回空字符串转为模板匹配。 [09:02:29] 模板匹配成功点击坐标 (523, 384)。 [09:02:31] 等待查询结果。检测到表格区域内容刷新等待 2 秒后重新截图。 [09:02:38] 表格数据已完成加载读取前三行内容如下 - 华东 A区 1284 万元 - 华东 B区 976 万元 - 华东 C区 1320 万元 [09:02:41] 生成 JSON 摘要任务完成。从发出指令到完成全程约 30 秒没有人工干预。5.3 中途发生的异常与自动纠错最有价值的其实是过程中两次“意外”。第一次意外输入框聚焦明明成功了但键盘事件没有进去。日志里显示是我的代理在走“键盘消息直投”路径时目标进程刚启动还在进行初始化消息队列没有响应。自动回退方案启动改走剪贴板注入问题解决。第二次意外点击查询按钮时按钮无堣碍树属性异常导致定位失效。代理立刻切换到模板匹配路径先用一小块“查询”按钮的区域图片在整屏截图上做相似度匹配匹配度数达到 0.92 后完成点击。这次实测让我笃定了一个观点给 AI 用的 GUI 操控层必须内置容错和降级而不是只给一个截图接口就完事。否则换个软件、换个分辨率代理就瘫了。5.4 实测结果与耗时统计整个过程耗时分布如下阶段耗時任务拆解2 秒打开窗口4 秒定位与输入8 秒点击查询3 秒等待加载与读取10 秒生成 JSON3 秒合计 30 秒。如果人工做这件事熟练的操作员大概也需要一分钟以上。对日常办公自动化来说这个速度是能接受的。6. 我踩过的坑与排查链路从坐标偏移到循环死锁开发三个月踩坑记录写了满满一页。这里挑四个最典型的把排查链路完整写出来方便你将来遇到类似问题时有个参考。6.1 高 DPI 缩略图的坐标偏移截图正常但点击错位现象在 4K 加 150% 缩放的 Windows 机器上截图识别到的按钮位置和实际鼠标点击位置错位了大约 20 像素。排查链路第一反应是模板匹配的精度问题调整了多尺度匹配参数无效。打印了屏幕坐标和窗口坐标发现是两套坐标系混用。截图时用的是物理像素而 PyAutoGUI 点击用的是逻辑像素。在 150% 的缩放比例下偏差正好被放大。修复方案统一换算成逻辑坐标截图后把找到的物理坐标除以缩放系数scaleFactor再交给鼠标模块。这个坑在旧代码里非常隐蔽——在 100% 缩放的开发机上一切正常一到别人的高分屏就“点不准”。后来我加了启动时自动读取系统 DPI 的步骤并在每次点击前做坐标校验。6.2 弹窗焦点抢断明明点的是主窗口动作却被弹窗吃掉了现象在查询过程中程序弹出“连接超时是否重试”的对话框但代理没有检测到继续往主窗口的输入框里输入内容。结果文字全部打到了弹窗上。排查链路查看截图发现弹窗确实出现在画面中央于是确认了“视觉已看到但被忽略”的问题代理只读取了无堣碍树里主窗口的控件没有监听系统级的“新窗口激活”事件。修改方案在每一个操作循环开始前先检查“是否有未处理的新窗口弹窗”这个信号。具体做法是通过监听 Windows 的全局事件或者直接比较活动窗口标题和上一轮是否一致。如果不一致就先不走控件操作而是先报告窗口状态再由模型决定如何响应弹窗。这个修复把自动化任务的失败率降了一截。6.3 代理陷入了循环重试现象某个操作一直失败模型就开始反复重试同一个动作中间不带间隔CPU 占用率直接拉满日志里刷出几百条重复错误。排查链路先看日志发现每次重试的时间戳间隔 0.1 秒左右这说明模型根本不带“冷却等待”地在努力。根因是模型觉得“上次失败可能是因为瞬间状态问题”但没有明显的状态转移依据所以它会一直执行同样的点击。修复方案在循环体内加了两条硬规则。同一个动作连续失败超过 3 次就必须切换方法例如从高堣碍树切换为模板匹配或从剪贴板注入切换为键盘模拟。连续 5 次失败后强制停止该步骤的推进并向用户请求下一步指令。这两条规则本质上是“给模型装一块刹车”避免它在无人值守时烧掉系统资源。6.4 MCP 服务握手超时stdio 传输的启动竞争现象自定义 MCP Server 启动时经常握手失败报Timeout错误但手动启动却没问题。排查链路手动测试服务器确认可用。查看代理日志发现握手超时的时间是 5 秒而服务器是一个 Python 脚本因为需要 import 一堆依赖启动耗时超过了 8 秒。修复方案修改 MCP 客户端握手超时逻辑改成动态等待 指数退避。第一次等待 2 秒失败后依次等待 4 秒、8 秒直到连接成功或达到最大重试次数。这个坑提醒我外部的进程启动时间你是没法控制的尤其是当工具链越来越长时握手逻辑必须比脚本更耐心。6.5 安全边界的妥协与坚持期间也有用户提过需求希望默认跳过所有确认弹窗让代理完全自动化执行。我没有妥协。因为“完全自动化”听起来很爽但当代理连接的是你的文档、你的数据库、你的生产环境时一旦模型推理出错后果可能是一批文件被覆盖、一批数据被删。我见过有人把 AI 接到生产数据库上AI 生成了一条没有 WHERE 的 UPDATE 语句。如果是真实执行那画面不敢想。我现在保留的默认策略是读操作全自动写操作先确认。这个策略牺牲了一点效率但换来了安全。我想这也是一个编码代理应该有的克制。7. 几个可以立刻上手的用法与后续扩展7.1 用五六十行代码写出你自己的 MCP Server你在压缩包里能找到一个server-example文件夹里面是一个极简 MCP Server 模板。核心逻辑长这样import json import sys def handle_request(request): if request[method] tools/list: return { tools: [ { name: get_system_uptime, description: 返回系统运行时长, inputSchema: { type: object, properties: {} } } ] } if request[method] tools/call: if request[params][name] get_system_uptime: import time uptime time.time() - time.process_time() return {content: [{type: text, text: f系统运行了 {uptime:.2f} 秒}]} return {error: {code: -32601, message: Method not found}} for line in sys.stdin: request json.loads(line) response handle_request(request) sys.stdout.write(json.dumps(response) \n) sys.stdout.flush()这个模板不是完整实现但这个框架能让你明白 MCP 到底有多轻——它就是“标准输入进、标准输出出”的 JSON-RPC 2.0。你的内部脚本只要包一层这样的壳立刻就能被 AI 调用。7.2 把代理跑成后台自动化助手单文件程序不一定要保持窗口开着。我在项目里加了一个--headless模式启动后代理常驻系统托盘你通过本地浏览器或者命令行发任务它执行完把结果写回指定文件然后通知你。这个模式适合定时任务比如每天早上去某个老旧 OA 系统里截取报表、整理成本地文件。我自己的用法是每天早上跑一次“从旧系统导出昨日销售数据写入内部数据库”已经稳定运行了一段时间。7.3 后续可以这样扩展从单一代理到多 AI 协作目前它还是单代理模型“自己推理 - 调用工具”。我的下一步计划是支持多代理协作一个主协调代理负责拆任务把 GUI 操作、MCP 调用、代码生成分别交给不同的子代理。这涉及到共享上下文管理、任务队列和结果合并复杂度不低但想象空间很大。如果你感兴趣可以从一个最简单的协作模式开始两个代理共用同一个 MCP ServerA 负责搜索信息B 负责执行操作。它们之间通过一段“共享便签”Shared Note交换中间结果不需要复杂的调度器。这个模式实现起来远比你想象的简单而且效果不错。最后分享一个我个人的体会给 AI 写工具最有成就感的一瞬间不是模型准确执行了一长串指令而是它发现自己陷入困境时能主动换一条路走通——比如从点击失效切换到剪贴板注入从模板匹配失败切换到 OCR 兜底。这种“容错式”的设计才是把 AI 从玩具变成生产力的关键。也正是基于这个想法我坚持把 GUI 操控层、MCP 接入层和单文件分发做成一体让这个工具可以真的在别人的电脑上跑起来而不只是我自己的演示品。