
1. 项目缘起为什么编码代理得看得见屏幕1.1 终端型代理的盲区先说结论我最近搞了个免费开源的 AI 编码代理coding agent核心卖点是三件事——能直接操控图形界面GUI、原生支持 MCPModel Context Protocol协议、整个项目打包成单文件运行。为什么要做这么个东西因为传统编码代理有个很尴尬的盲区。市面上主流的 coding agent工作方式基本都是在终端里跑命令、读写文件、执行测试。这套模式对后台任务确实够用比如让我重构代码、修 linter 报错、补单元测试都能干得有声有色。可一旦任务需要看一眼界面它就彻底抓瞎了。举个我真实遇到的场景我让某个开源的 agent 帮我在一个桌面软件里完成设置向导结果对话框明明弹出来了下一步按钮就在屏幕上它却只能干瞪眼因为它根本不知道屏幕上发生了什么也没办法移动鼠标去点击。这就很离谱。人类操作电脑的方式明明是眼睛看屏幕、手点鼠标键盘为什么模型反而要绕开这条路去走一条看不见的下水道1.2 回归人类操作电脑的本质我花了很多时间想这个问题。本质上人类操作电脑就是一个闭环观察看屏幕→ 判断理解当前状态→ 操作点击/输入→ 再观察确认结果有没有生效。我决定让编码代理也走这条路给它装上眼睛和手。所谓眼睛就是屏幕截图能力所谓手就是跨平台的鼠标键盘控制能力。模型的推理链路会变成截一张图作为视觉输入结合用户的任务描述决定下一步做什么执行一次鼠标或键盘操作然后再截一张图确认结果。如果结果不对就继续调整直到任务完成。听起来简单但真做起来要解决一堆底层问题截图和鼠标坐标怎么统一窗口缩放和 DPI 变化怎么处理OCR 识别定位怎么做模型输出坐标后要不要安全校验这些问题我在后面会逐个拆开讲。1.3 为什么还要接 MCP只解决看得见屏幕、点得了鼠标还不够。真正的编码工作流里模型还得读代码仓库、查数据库、操作浏览器、跑测试框架。如果每个能力都自己造轮子工程量巨大而且每接一个新工具都要重新写适配怕是写完天都亮了。MCPModel Context Protocol模型上下文协议就是来填这个坑的。它是一套开放标准协议定义了模型如何以统一格式发现外部工具、调用外部工具、获取结果。简单说MCP 相当于给模型装了一个通用插座任何工具只要实现了 MCP 服务器端模型就能直接插上使用不用关心对方内部是怎么实现的。所以这个项目的最终形态是双引擎架构一个引擎负责 GUI 操控另一个引擎负责 MCP 工具调用。两者既能独立作战也能互相配合。比如先用 MCP 查数据库拿到用户信息再打开 GUI 把数据填充到表单里并点击提交整个链路非常自然。2. 核心设计拆解GUI 操控与 MCP 双引擎2.1 GUI 操控模块的三个核心环节GUI 自动化绕不开三件事截图、定位、输入模拟。每个环节都有不少坑我一个个说。截图层面我优先用系统级 API 而不是单一第三方库。原因很简单很多第三方截图库在高分屏、多显示器、混合缩放的环境下会翻车截出来的图跟真实屏幕尺寸对不上后面坐标全错位。我的做法是跨平台分开处理——Windows 上走 Win32 的屏幕捕获接口macOS 上走系统自带的截屏命令行Linux 上走 X11 或 Wayland 对应的截屏工具。截完图统一转成标准格式喂给视觉模型。这样做的代价是代码里多了一层平台判断但换来的是坐标系的稳定这笔账非常划算。定位层面我做了三层递进策略。第一层是模板匹配适合找图标、logo、固定形状的按钮特征越明显越准。第二层是 OCR 文字定位专治确定取消下一步这类文字按钮先用 OCR 把文字位置提取出来再映射到屏幕坐标。第三层是把整张截图直接交给多模态大模型由模型理解图像内容后给出目标控件的坐标预测。三层策略按顺序尝试绝大多数交互场景都能覆盖。如果三层都找不到目标代理就会如实上报无法定位而不是瞎猜一个坐标去点。输入模拟层面我封装了鼠标移动、点击、双击、拖拽、滚轮、键盘输入、快捷键这几种基础操作并且统一遵循一个原则先移动到目标坐标再执行动作。所有操作在执行前都会过一道安全校验坐标超出屏幕边界或者目标窗口未激活直接拦截并报告。这里必须强调安全设计。自动操作 GUI 的工具最怕失控所以在默认配置下代理每执行一次鼠标点击或按键终端都会实时打印类似[ACTION] click(1200, 340)这样的日志用户可以一键暂停、终止或者手动接管。我甚至把高影响操作单独拎出来做二次确认——比如执行系统命令、点击支付类按钮、删除文件之前必须用户手动按确认键。宁可慢一点不能失控。2.2 MCP 集成的两种工作模式MCP 协议本身不复杂核心就是三部分工具声明描述这个工具是干什么的、需要什么参数、调用请求模型发出 JSON-RPC 格式的调用指令、结果返回工具把执行结果送回模型。我实现了两种模式。第一种是作为 MCP client去连接现成的 MCP 服务器。这里有一些现成的选择文件系统服务器、浏览器自动化服务器、数据库查询服务器、甚至 Figma 设计工具服务器。第二种是反过来让我的代理自己作为一个 MCP server 暴露能力这样其他支持 MCP 的开发工具也能反向调用这个代理的 GUI 操控能力。等于说它既会用别人的工具也能被别的模型用。配置文件长这样{ mcp_servers: { filesystem: { command: mcp-server-fs, args: [--root, ./workspace] }, browser: { command: mcp-server-puppeteer } }, model: { endpoint: http://localhost:11434, name: qwen2.5-vl:7b } }注意看model这一段。我特意把模型端点设计成可配置的不绑定任何一家服务商。本地部署的开源模型能用云端商业模型的 API 也能用只要模型具备工具调用能力或者具备视觉理解能力就能接入。这个设计非常实用因为不同用户对模型跑在哪、数据传去哪的敏感度完全不同。2.3 单文件运行背后的取舍单文件运行这个需求做起来远比听起来麻烦但我依然坚持这么做。技术实现上Python 场景我用 zipapp 把所有模块和静态资源打包进一个自包含文件外层加一个启动桩运行时就地解包到临时目录。依赖处理是另一个关键点GUI 控制和图像处理涉及的底层库不少但全都打进包内用户不用先手动装 Python 包。配置不硬编码支持命令行参数覆盖模型端点、工作目录、权限开关等这样单文件只是个壳实际行为完全可控。为什么这么执着于单文件因为真实分发场景里绝大多数人根本没耐心为了跑个工具先折腾半小时环境。一个文件拿过去双击或一条命令就能用出问题也能快速反馈。团队内部协作时单文件方便传阅版本号清晰不会出现我这边的依赖和你那边不一样这种经典扯皮问题。代价也不是没有打包体积会变大首次启动稍慢但这些跟开箱即用带来的便利相比完全值得。3. 上手实操从拿到文件到跑通第一个任务3.1 环境准备与启动细节先讲最简运行条件需要一台能跑 Python 3.10 以上的机器Windows 10、macOS 12、Ubuntu 22.04 我都实测过以及一个有 API 权限的大模型服务。GUI 操控功能在带桌面环境的系统上才有效无头的纯服务器环境请直接用 MCP 模式。下载那个单文件后给它可执行权限然后这样启动./ai-agent --config agent.json启动日志会分成三段初始化模型连接、加载 MCP 服务器、启用 GUI 控制模块。每一段都有明确的状态输出任何一步失败都会给出清晰原因不会让你在那瞎猜。我个人强烈建议第一次跑的时候加一个--dry-run参数模拟运行让代理把将要执行的操作序列完整打印出来但不真正落库、不真正点击。这相当于预演一遍可以在真实操作之前先看看模型的计划是否合理也方便排查配置错误。我实测下来这一步能省掉至少一半的调试时间。3.2 写一个最简单的验证任务我习惯用一个打文件并打开的任务来测试环境让代理在指定目录新建一个 Markdown 文件写入一段摘要然后用系统默认编辑器打开。这个任务能同时验证文件操作、GUI 启动能力、以及任务拆解能力链路短、容易判断成败。任务描述可以这样写在 /tmp/demo 目录下创建 welcome.md内容是 50 字左右的自我介绍 写完后用系统默认的文本编辑器打开它。代理接到任务后先通过文件系统 MCP 创建文件并写入内容再用 GUI 模块模拟调起系统打开方式逻辑。整个过程大约二三十秒日志里每步都很清楚。跑完如果文件真实存在、编辑器真的弹出来了说明环境没问题可以开始尝试更复杂的任务了。3.3 验证任务结果的三层检查任务跑完之后别急着庆祝。我建议分三层验证第一层看代理自己的总结日志——它认为自己干了什么第二层看实际产出——文件系统里是不是真的有对应的内容第三层看操作记录——GUI 操作日志里是不是真的有打开编辑器的那条动作记录。三层都对得上才算真正跑通。这个多信道验证的习惯在自动化场景里极度重要。不要只信模型嘴上说我完成了要以客观状态为准。如果有某层对不上大概率是代理的自我认知和真实状态出现了偏差这种偏差在复杂任务里会被无限放大尽早发现比事后补救强得多。4. 实操案例让代理走完一个完整的安装向导4.1 选定一个现实中典型的测试场景为了写这篇分享我特意找了一个最适合测试 GUI 操控能力的场景用代理去操作某个开源软件的安装向导。这个向导一共三步选择语言、选择安装目录、确认安装最后弹出安装完成的提示窗口。界面元素全部是图标加文字按钮位置固定没有复杂的拖拽操作非常适合验证视觉识别和鼠标点击的配合。更关键的细节是安装向导这类窗口会屏蔽外部输入模态对话框而且下一步按钮会在条件不满足时置灰禁用。这些恰恰是 GUI 自动化最容易翻车的地方。4.2 逐步拆解执行过程第一步向导首页加载后我给代理发指令读取当前界面告诉我下一步应该点击哪个位置。代理先截一张图OCR 定位到Next按钮返回坐标大约在窗口右下角区域。这里有个容易踩坑的地方OCR 返回的是文字在图像像素坐标系里的位置必须换算成屏幕绝对坐标才能驱动鼠标。换算公式是屏幕坐标 图像坐标 × (屏幕宽度 / 图像宽度)同时要处理 DPI 缩放否则点击位置会整体偏移。第二步进入安装目录选择界面代理需要输入自定义路径。它先点击Browse按钮打开目录选择对话框这一步靠模板匹配定位文件夹图标然后通过键盘输入完整路径并回车。这里我遇到过一次大坑某些系统的目录选择对话框不会自动聚焦输入框代理直接输入路径就会输到莫名其妙的地方去。解决办法是先点击一下地址栏输入框再输入路径最后回车确认。这个先聚焦再输入的习惯在 GUI 自动化里永远不过时。第三步点击Install进入安装过程。代理采用轮询策略每 5 秒截一张图检测屏幕上是否出现安装完成字样。轮询过程中它发现Next按钮一度处于置灰状态没有硬点而是继续等待进度条走完。这个判断力我觉得是区分能用和好用的分水岭——很多粗糙的自动化脚本碰到按钮禁用就会反复重试最后卡死而视觉上下文感知让代理明白现在不是点击时机。4.3 运行结果与效率优化的思考整个流程执行完安装目录里出现了预期文件完成窗口也正常弹出。我统计了一下运行数据代理一共执行了 10 次鼠标点击、5 次键盘输入、40 多次截图每一步都有日志记录。如果手动操作这个向导大概只要 1 分钟代理花了 3 分钟——多出来的时间基本都耗在截图→思考→执行的循环上。改进空间也很明确。比如等待进度条这个场景固定间隔轮询截图太费资源完全可以改成视觉变化检测 定时轮询双触发机制平时休眠检测到屏幕像素发生明显变化再醒过来识别效率能提升一大截。这种优化思路在长时间运行的自动化任务里尤为重要。5. 踩坑记录与排查手册5.1 高频问题速查表我把实操中踩过的问题、原因、解法整理成一张表覆盖了最常见的几类情况现象常见原因解决办法截图全黑或内容错位高 DPI 缩放导致截图像素坐标和鼠标坐标不一致把系统缩放临时调成 100%或在代码里开启 DPI 感知并做坐标换算鼠标点击了但没效果目标窗口不在前台点到了背景窗口操作前先执行激活目标窗口步骤把窗口调到前台再操作OCR 识别不到文字字体过小、背景对比度过低、或者界面使用了非常规字体截取局部区域放大后再识别先灰度化、二值化增强对比度MCP 连接超时子进程启动失败、端口被占用、命令路径不对先在终端手动执行 MCP 服务器的 command 和 args确认能正常启动再配置模型返回格式错误的工具调用模型本身不严格支持工具调用协议换一个工具调用能力更强的模型或者关闭强制工具调用模式退回自然语言解析Linux 下无法截屏Wayland 会话对截屏权限限制严格切换到 X11 会话或者改用基于 wire 的屏幕采集接口5.2 三个花钱买来的经验第一个经验是坐标系必须全局统一。截图、图像识别、鼠标控制这三层如果各玩各的坐标系结果必然错位得离谱。我的方案是全局只用屏幕绝对坐标一种语言截图时记录原始分辨率和缩放比例识别时把所有图像坐标统一换算回绝对坐标所有函数接受同一套坐标参数。任何偷偷摸摸的分歧都会在未来某个深夜变成一场灾难。第二个经验是窗口焦点问题。大量自动化脚本的点击失效根本不是坐标算错了而是目标窗口压根不在前台。操作系统只把键盘事件分发给当前激活窗口鼠标点击虽然能落在任意坐标上但弹出的菜单、对话框会优先响应焦点窗口。所以我的操作序列永远以激活目标窗口开头这个前置步骤省掉的话后面整个执行链都是空中楼阁。第三个经验是安全边界必须前置设计。自动操作 GUI 的工具一旦被滥用后果可能非常严重。我在代码里加了两道锁一是应用白名单模型只能操控预先授权的应用启动时通过参数传入二是实时确认机制高影响操作执行命令、点击敏感按钮、删除文件必须经过用户手动确认。这套机制在开发和测试阶段确实增加了操作成本但换来的是我可以放心地让它在真实环境里长期运行。6. 一点个人经验总结做完这个项目我最大的感受是把 GUI 操控和 MCP 装进同一个编码代理里其实是在填一个长期被忽略的洞——改代码和验证界面之间的断层。以前模型改完代码人还得手动去界面上验证效果现在代理可以自己启动应用、点击菜单、观察界面反馈整个开发闭环在原来自动化的基础上往前推了一大步。作为最后的建议我想说的是如果你准备试用这类工具先在低风险任务上跑熟。自动填表、自动打包、自动化 UI 回归测试都是非常好的切入点。等你对代理的行为模式有了足够的把握再逐步放开更高权限的操作。我见过不少人一上来就交给代理最高权限然后被它的一次误操作搞得焦头烂额。工具越强大你越需要在系统层面预留暂停键、日志开关和操作审计。这不只是工程素养更是对自动执行这件事保持敬畏的基本觉悟。