)
1. 為什么要做一個能“看見”屏幕的編碼代理1.1 傳統(tǒng)編碼代理為什么操作不了 GUI做 AI 編碼代理的人不算少但大部分代理都活在終端里你說一句需求它改幾個文件跑幾條命令再給你貼一段輸出。這套流程在處理“寫代碼、調(diào)接口、查日志”這類任務時確實順手可一旦目標換成老舊的 Windows 窗體程序、Electron 應用、設計軟件、網(wǎng)后臺系統(tǒng)傳統(tǒng)代理就立刻變成了盲人摸象——因為它根本看不見屏幕。我這幾周一直在折騰一個偏向“動手”的 AI 編碼代理目標很直接讓代理除了會改代碼還能像人一樣操作圖形界面。最后做出來的東西是一個免費工具單文件就能跑支持調(diào)用鍵盤鼠標完成點擊、輸入、拖拽同時通過 MCP 協(xié)議接入外部工具和業(yè)務系統(tǒng)。今天這篇就是把整個項目的設計思路、實現(xiàn)細節(jié)和踩過的坑一并記錄下來給同樣在搗鼓 AI 自動化、被“代碼改得動但界面點不動”這件事卡住的朋友一些參考。為什么會存在這個盲區(qū)因為傳統(tǒng)的編碼代理依賴的是文件系統(tǒng)和命令行它天然缺少“視覺”和“操作”兩個通道。我讓代理去改一個配置文件它能通過讀取和寫入輕松搞定但讓它在登錄界面里找到用戶名輸入框這就完全不是一回事了。沒有截圖能力沒有屏幕坐標系沒有鼠標鍵盤事件代理連按鈕在哪都不知道。你可以給它配一個 OCR 腳本但那只是孤立的工具和代理的推理過程無法形成閉環(huán)。1.2 給代理裝上“手和眼睛”我想要的不是“能用腳本臨時湊合”而是一個真正具備閉環(huán)能力的代理它能截圖、能看到界面元素能規(guī)劃下一步動作能真實地移動鼠標點擊目標然后再截一張圖確認操作結果。整個過程就像給代理裝上了手和眼睛它不再是只改文件的暗房間工人而是能直接面對用戶界面的操作員。這件事真正做起來很有意思。很多 GUI 自動化工具一直都在比如按鍵精靈那一類但它們是“錄制好的固定腳本”遇到界面變化就傻眼。而把我做的代理接上大模型之后它可以根據(jù)截圖實時推理彈窗位置偏移了也能隨機應變。關鍵點在于模型必須有自己的判斷邏輯而不是機械執(zhí)行預錄步驟。這也引出了這個項目的第二個關鍵詞 MCP。GUI 操控負責解決“表面操作”MCP 負責解決“背后數(shù)據(jù)”。如果我只做 GUI代理最多像個點鼠標的機器人如果只做 MCP代理又回到了數(shù)據(jù)管道里。兩者結合起來代理才能做到真正意義上的“眼手腦并用”。2. 技術選型為什么是 MCP 單文件方案2.1 MCP 不是錦上添花而是標準接口先聊 MCP 協(xié)議。可能有些人第一次接觸這個概念簡單說MCP 的全稱是 Model Context Protocol模型上下文協(xié)議它在 AI 代理和外部工具之間定義了一個統(tǒng)一的信息交換規(guī)范。類比生活場景的話它有點像 USB-C 接口以前你給設備充電要準備各種線現(xiàn)在一根線通用MCP 做的事情類似——讓不同的 AI 客戶端、不同的工具服務端能夠用同一種方式對話不用為每種工具各寫一套私有接口。我在選型時本來也考慮過自己定義一套工具調(diào)用的 JSON 協(xié)議后來想想還是放棄了。道理很簡單生態(tài)。MCP 是社區(qū)在共同推進的標準從文件系統(tǒng)、數(shù)據(jù)庫到瀏覽器操作已經(jīng)有大量現(xiàn)成的服務器實現(xiàn)。我自己寫一套協(xié)議等于重新發(fā)明輪子而且要自己維護文檔、處理兼容性最后用戶還不買賬。使用 MCP代理的行為對用戶是透明的他們拿已有的工具直接接進來就能用學習成本低很多。從架構角度講MCP 把工具注冊和調(diào)用過程抽象成了標準信息單元??蛻舳素撠煱l(fā)現(xiàn)工具服務端負責執(zhí)行中間用 JSON-RPC 通信。所以我只需要實現(xiàn)一個輕量的 MCP 客戶端把工具列表暴露給模型即可后續(xù)每次增加功能都只是添加一個工具函數(shù)而不是改動核心流程。2.2 單文件交付背后的工程取舍標題里寫了“單文件運行”這也是我花費心思最多的部分。做一個需要安裝幾十個依賴的項目不難難的是讓別人用一個文件就能跑起來。我在打包時用過不少工具最后選擇了把運行時依賴內(nèi)嵌進一個可執(zhí)行文件里支持 Linux、Windows、macOS 三個平臺文件體積控制在一個很小的量級。對于有跨平臺需求的讀者建議用各自平臺原生支持的打包方式來做比如在 Windows 上使用打包相關工具鏈在 macOS 上用對應的腳本盡量保證不依賴外部運行環(huán)境。單文件交付帶來的好處非常明顯不需要配置 Python 解釋器、不需要安裝 Node 運行時、不需要處理包沖突下載下來 chmod x 就能跑特別適合塞進 CI 或者拿給同事做演示。但也有代價最直接的就是軟件體積和啟動速度的取舍內(nèi)嵌依賴會讓二進制體積變大。另外單文件在部署時需要處理臨時目錄的權限問題有些系統(tǒng)不允許可執(zhí)行文件在隨機位置寫配置我通過把配置路徑設定在用戶目錄下規(guī)避了這個坑。還有一個工程細節(jié)值得展開。所謂“單文件運行”不僅是把代碼打包它意味著程序內(nèi)的一切資源都要一體化。我項目里的 GUI 操控模塊、MCP 客戶端模塊、提示詞模板、默認配置全部以嵌入方式編譯進二進制避免運行時還要找外部資源文件。好處是用戶再怎么把文件從根目錄挪到子目錄程序都能正常工作壞處是如果用戶想自定義資源就需要通過外部配置文件覆蓋默認值而這個在 GUI 層面是透明的。3. 核心實現(xiàn)GUI 操控鏈路是怎么打通的3.1 GUI 操控鏈路截圖、識別、規(guī)劃、執(zhí)行整個 GUI 操控模塊的核心是一條循環(huán)鏈路可以概括為四步截圖、識別、規(guī)劃、執(zhí)行。第一步代理調(diào)用底層截圖接口拿到當前屏幕畫面第二步視覺識別模型或本地模板匹配算法從畫面中定位出候選操作區(qū)域第三步大模型根據(jù)用戶指令和識別結果規(guī)劃出具體的動作序列比如點擊某個坐標、向某個輸入框發(fā)送文本第四步執(zhí)行器調(diào)用系統(tǒng)輸入接口完成鼠標或鍵盤操作。這四步里最容易被低估的是“識別”環(huán)節(jié)。如果你只用本地模板匹配界面稍有變化就會失效如果完全依賴視覺大模型做識別每次執(zhí)行都調(diào)用云端接口延遲和費用又不劃算。我目前采用的是一種分層策略先通過本地截圖把圖像壓縮到合理分辨率再借助可選配的視覺描述模型生成版面描述只有在遇到復雜界面元素時才會請求云端大模型細化分析。這樣既不犧牲識別能力也能把普通場景的響應時間控制在可接受的范圍內(nèi)。規(guī)劃環(huán)節(jié)同樣需要仔細設計。模型輸出動作不能只給一句“點擊登錄按鈕”這種描述必須輸出結構化的動作指令。我給模型設計了統(tǒng)一的動作格式里面包含動作類型、目標元素的描述、必要時附帶優(yōu)先級和等待條件。模型執(zhí)行完動作后系統(tǒng)還會主動觸發(fā)一次驗證也就是重新截圖由模型判斷是否達到了預期狀態(tài)這一點對防止“盲點”至關重要。3.2 輸入模擬與坐標映射執(zhí)行環(huán)節(jié)涉及的操作系統(tǒng)接口比較敏感。Windows 上我使用的是系統(tǒng)提供的輸入事件發(fā)送接口macOS 上使用的是對應的輔助功能接口Linux 下則通過擴展輸入設備接口實現(xiàn)。這些接口本身不難難的是坐標映射。我試過縮放比例不同的屏幕遇到最多的問題就是坐標錯位。比如圖像識別得到目標在截圖中位于 1000x600 的位置但實際屏幕是 1920x1080截圖被壓縮過那就必須在執(zhí)行時把截圖坐標轉(zhuǎn)換回真實屏幕坐標。這個轉(zhuǎn)換公式其實不復雜就是等比縮放關鍵是必須在截圖時記錄當時的屏幕尺寸和縮放比例而不是事后猜。還有一個隱蔽問題一條軸上可能接了兩個不同縮放比例的顯示器鼠標跨越屏幕時坐標會跳變。我目前的處理方式是暫時只操作主屏幕多屏幕的支持還在后續(xù)計劃里。文本輸入也是很容易翻車的地方。很多程序的輸入框看起來普通但對字符編碼的要求很嚴格直接通過鍵盤事件逐字符發(fā)送遇到中文輸入法就經(jīng)常出差錯。我后來改用剪貼板中轉(zhuǎn)的方式先把要輸入的文本寫入剪貼板再模擬 CtrlV 粘貼。這樣效率高也規(guī)避了輸入法狀態(tài)干擾。代價是剪貼板內(nèi)容會被覆蓋所以執(zhí)行前我會先備份原剪貼板內(nèi)容操作完再恢復。3.3 MCP 工具注冊的極簡實現(xiàn)MCP 這一塊我理解的實現(xiàn)核心就是“注冊 路由”。我給代理內(nèi)置了一個工具注冊表每個工具包含名字、描述、參數(shù)結構、實際函數(shù)地址。模型通過名字調(diào)用工具路由層校驗參數(shù)后調(diào)用對應函數(shù)結果返回給模型。這樣設計的好處是新增工具只需寫一個符合規(guī)范的函數(shù)注冊進表里完全不需要改大模型側(cè)的代碼。我寫過一個最簡示例來驗證 MCP 工作流程大概長這樣# 偽代碼展示 MCP 工具注冊的基本結構 TOOL_REGISTRY {} def register_tool(name, description, params_schema): def decorator(func): TOOL_REGISTRY[name] { description: description, params_schema: params_schema, handler: func } return func return decorator register_tool( nameclick_element, description在屏幕上點擊指定名稱的界面元素, params_schema{element_name: {type: string}} ) def click_element(element_name: str): # 調(diào)用 GUI 執(zhí)行器 coord find_element_on_screen(element_name) return {x: coord.x, y: coord.y}這只是演示用的骨架代碼但核心邏輯已經(jīng)完整了。實際項目中這個注冊表會跨越多個模塊有操作文件的工具、有執(zhí)行命令的工具、有讀取數(shù)據(jù)庫的工具還有上面截圖里看到的 GUI 操控工具。所有工具統(tǒng)一走 MCP 協(xié)議暴露給模型外部客戶端不管是用什么語言寫的只要能傳遞 JSON-RPC 請求就能復用同一套工具。4. 實操下載、啟動和第一次跑通4.1 環(huán)境要求與最小配置雖然目標是不依賴一堆環(huán)境但 GUI 操控本身仍然需要系統(tǒng)層面的支持。在 macOS 上需要給終端授予輔助功能權限在 Windows 上某些受保護窗口需要以管理員權限運行Linux 上則要給進程 DISPLAY 或 Wayland 相關的環(huán)境變量。這幾個前置條件我在項目文檔里標得很清楚避免用戶啟動以后發(fā)現(xiàn)點不了、截不了圖再回頭排查。啟動方式非常簡單。下載對應平臺的文件后直接運行chmod x ai-agent ./ai-agent第一次啟動它會創(chuàng)建一個配置文件默認使用本地模型還是云端模型取決于你選擇哪種接入方式。如果你有大模型的 API 密鑰填寫到配置項里即可如果你什么都不配置它也能啟動但只能執(zhí)行那些不依賴大模型推理的簡單命令比如截圖保存。這里我給的建議是先跑通最簡單的截圖功能再逐步加入模型推理和動作執(zhí)行一次引入一個變量出了問題才好定位。4.2 實操驅(qū)動一個桌面程序完成數(shù)據(jù)錄入我隨手搭一個場景展示這套工具在真實環(huán)境里是怎么工作的。假設我需要讓代理打開 Windows 自帶的計算器執(zhí)行幾個數(shù)值相加再把結果界面截圖保存下來。用戶只需要輸入一行自然語言代理會自動完成后續(xù)解析和動作編排。正常情況下代理會按下面的邏輯拆解任務調(diào)用啟動相關工具打開計算器應用等待窗口出現(xiàn)截圖確認界面狀態(tài)識別數(shù)字按鈕在屏幕上的位置逐個點擊數(shù)字再點擊加號點擊等號后截圖識別結果是否出現(xiàn)保存最終截圖到指定路徑我這里截取一段動作解析器實際輸出供參考{ actions: [ {type: open_app, app: calculator}, {type: wait, condition: window_visible, timeout: 5}, {type: click_text, text: 5}, {type: click_text, text: }, {type: click_text, text: 3}, {type: click_text, text: }, {type: screenshot, save_to: result.png} ] }這段 JSON 是模型規(guī)劃完之后的最終輸出實際效果中它能夠穩(wěn)定地完成操作因為每一步之間都有等待條件不會出現(xiàn)按鈕還沒渲染出來就點上去的情況。這套“動作序列 條件等待”的設計是很多 GUI 自動化工具容易忽視的地方。固定延遲的方案雖然實現(xiàn)簡單但遇到性能波動就亂了等待條件能讓執(zhí)行過程具備自適應能力。4.3 連接你自己的 MCP 工具以數(shù)據(jù)庫為例GUI 是代理的“手”數(shù)據(jù)是代理的“腦”兩者都需要。項目支持用戶按 MCP 標準添加自己的工具比如連接一個數(shù)據(jù)庫讓代理能夠查詢、更新數(shù)據(jù)。配置方式也很簡單在配置里聲明一個 MCP 服務器地址和工具前綴代理啟動時會自動拉取工具列表。以 MySQL 或 Oracle 這類數(shù)據(jù)庫為例我可以把數(shù)據(jù)庫操作封裝成兩個工具query 和 execute。注冊結構大致如下{ mcp_servers: [ { name: database, url: http://127.0.0.1:8080/mcp, auth_type: token, tools: [query, execute] } ] }連接成功后模型的每次數(shù)據(jù)庫操作都會不再依賴硬編碼 SQL而是直接通過查詢工具獲取表結構、分析數(shù)據(jù)、再生成更新語句。很多人在配置 MCP 時容易忽視鑒權比如直接把 token 寫到配置文件里我強烈不建議這么做特別是代理文件單文件運行后可能被拷貝到多處環(huán)境應該通過環(huán)境變量或密鑰管理服務動態(tài)注入。5. 踩坑實錄與排查速查表5.1 最常翻車的 5 個節(jié)點第一坑是系統(tǒng)級權限。macOS 上經(jīng)常出現(xiàn)“能截圖但無法執(zhí)行點擊操作”原因是輔助功能權限沒有授給啟動代理的那個終端程序。這個問題藏得很深截圖權限和輔助功能權限是分開管理的必須到系統(tǒng)設置里分別授予。第二坑是高分辨率屏幕的坐標偏移。如果你用的顯示器是 2K 或 4K 級別并且開啟了系統(tǒng)縮放那識別出來的坐標如果直接使用大概率點偏。必須通過縮放因子換算。換算公式非常簡單但如果你截圖時用的分辨率和畫面實際輸出分辨率不一致就會出問題。我后來統(tǒng)一采用“截圖分辨率 物理屏幕分辨率”的策略從源頭避免差異。第三坑是窗口層級遮擋。有時候目標窗口不是最前面那個或者有彈窗蓋住了按鈕截圖里能看到按鈕位置但實際點擊卻被擋住了。解決辦法是執(zhí)行點擊前先調(diào)用一次窗口置前操作把目標窗口帶到最上層。第四坑是輸入法干擾。前面已經(jīng)提到的剪貼板方案能解決絕大多數(shù)文本輸入問題但還是有特例。一些金融類的安全輸入控件會禁止模擬粘貼這時候只能走逐鍵輸入而逐鍵輸入又會被輸入法攔截。我的處理辦法是強制在操作前切換到英文輸入狀態(tài)雖然不強求但能在多數(shù)場景下正常工作。第五坑是 MCP 工具超時。模型調(diào)用數(shù)據(jù)庫工具時如果查詢時間超過預設的超時閾值整個動作鏈都會被中斷。這個坑排查起來很隱蔽表面看起來像是模型變笨了實際上是下游工具超時導致的上下文缺失。我建議把工具超時設置得足夠?qū)捤刹⑶覍赡荛L時間運行的查詢設置獨立超時。5.2 問題排查速查表下面這張表是我自己排查問題時最常用的對照依據(jù)現(xiàn)象可能原因快速驗證/解決方法截圖黑屏或空白屏幕錄制權限未授予到系統(tǒng)設置授予權限重啟終端能截圖但點擊無效輔助功能權限未授予在權限設置中勾選對應終端或進程點擊位置偏右/偏上屏幕縮放比例未正確計算確認截圖分辨率與物理分辨率一致窗口彈窗蓋住目標窗口層級問題點擊前執(zhí)行窗口置前操作輸入中文亂碼輸入法狀態(tài)干擾使用剪貼板粘貼或臨時切換英文輸入法MCP 工具調(diào)用超時服務端處理慢或地址不通檢查服務地址、防火墻、超時閾值代理無法識別按鈕界面元素對比度過低提高截圖清晰度使用增強對比度預處理單文件在 Linux 啟動失敗缺少執(zhí)行權限或動態(tài)庫chmod x 檢查優(yōu)先選靜態(tài)編譯版本這張表覆蓋了我遇到的大部分問題。如果你的使用場景與我的環(huán)境不同建議在排查時先記錄一下問題發(fā)生的上下文尤其是截圖和模型輸出很多時候問題根源在上下文信息不足而不是工具本身出錯。6. 局限與后續(xù)可擴展的方向6.1 現(xiàn)在還不能做到的事情必須坦誠地說這個項目目前還不夠完美。第一對復雜界面的識別準確度仍然有限。比如一個表格里有多行按鈕模型可能會點錯行。我目前的辦法是在提示詞里補充更多的上下文約束但這屬于軟性優(yōu)化硬性問題還是要靠更好的視覺模型去解決。第二多屏幕支持還很初級副屏上的窗口操作經(jīng)常出現(xiàn)坐標錯位我強烈建議當前版本先只在單屏幕上使用。第三安全機制還有提升空間。代理一旦擁有操控 GUI 的權限就意味著它能夠點擊任何按鈕這在不加約束的情況下是有風險的操作所以我在設計時加入了操作確認模式讓用戶在執(zhí)行高風險動作前看到動作序列。這些局限性不影響它作為一個實驗工具的日常使用但離“全職幫你操作電腦”還有距離。我在項目規(guī)劃里給它設定的定位是“一個可信賴的助手而不是可以扔出去不管的替身”。安全問題不能偷懶尤其是模型偶爾會規(guī)劃出一些預料之外的動作時手動確認是最后一道防護。6.2 我會繼續(xù)怎么改后續(xù)的優(yōu)化方向上我給自己列了一個不錯的清單。首先是視覺識別能力升級計劃接入更細粒度的小尺寸視覺模型讓它能夠直接輸出按鈕和輸入框的邊界框減少對云端模型的依賴。其次是動作鏈的持久化與回放把一次成功的操作記錄保存下來遇到相同場景時可以直接復用省去重復的模型推理。最后是 MCP 工具生態(tài)的擴展后續(xù)打算把更多常用工具封裝成 MCP 服務至少是瀏覽器控制、郵件處理和文件轉(zhuǎn)換這三類高頻需求。單文件運行這個特性我還會繼續(xù)保留因為它是降低用戶上手門檻最好的方式。我會在打包流程中進一步優(yōu)化體積和啟動速度讓下載體驗更像一個原生應用而不是一個需要逐步手工安裝配置的復雜工具鏈。最后分享一個小習慣無論任務看起來有多簡單我每次都會保證在執(zhí)行完操作后截一張圖回傳模型做確認這個反饋閉環(huán)表面上會多花一點時間但它實際上救了我很多次。每次自以為點擊已經(jīng)成功了截圖出來才發(fā)現(xiàn)彈窗還在那里。自動化的世界里守住每一個驗證節(jié)點比追求速度重要得多。這也是這個項目做下來最值得記住的一條經(jīng)驗。