
最近大半年我一直在跟同一个问题拉扯让大模型直接操作电脑上的界面到底敢不敢放到生产环境里。阶跃星辰把 GUI-MCP 这个概念推到前台之后很多团队都在讨论“模型能不能看懂屏幕”“工具调用顺不顺”但真正决定一个 GUI Agent 能不能长期稳定运行的关键点反而容易被一笔带过——人在回路Human In The LoopHITL在哪个粒度上参与用什么方式参与它才是 GUI Agent 落地的安全气囊。这篇文章不吹概念我会把自己对阶跃星辰 GUI-MCP 的理解、MCP 协议给 GUI 层带来的变化以及 HITL 在工程上到底该怎么嵌进去按实际项目里会遇到的顺序完整梳理一遍。适合正在做智能助理、自动化测试、UI 自动化编排或者自研 RPA 替代方案的开发者参考如果你只是想了解“computer use 和 MCP 区别是什么”也欢迎直接跳到第 2 节那里我做了对比表。1. 为什么说 GUI-MCP 和 HITL 天生是一对1.1 没有回环的 GUI Agent等于把一个陌生司机直接塞进你的车先说 GUI Agent 的本质模型拿到屏幕截图或界面树理解用户意图然后决定执行点击、输入、拖拽、滚动等动作。这个过程看起来流畅但一旦进入真实业务问题就变成一连串的“万一”万一模型把一个“删除”按钮看成了“禁用”按钮万一界面上突然弹出一个非预期对话框把原有目标元素遮住了万一某个操作输入金额之后模型又自动补了一位小数万一它连续执行了 20 步之后第 5 步就做错了但中间没有任何人发现这些问题都不是“提示词写得更好”就能解决的。视觉语言模型再强也不可能对刚刚上线的业务系统建立完整、准确的先验知识。GUI 自动化天生就是带副作用的每点一下都可能产生真实的数据变更、权限变更或者金额损失。所以安全边界不能只靠模型的概率来判断需要把“人”作为控制通道放进执行链路这就是 HITL 的基本理由。1.2 阶跃星辰 GUI-MCP 把“看屏操作”变成了可编排的工具集阶跃星辰这轮 GUI-MCP 给我最大的启发是它把“看屏幕”这件事从模型能力的暗盒里解放出来变成了一套标准化的工具接口。MCP 本身的定位大家都清楚它是一套模型上下文协议让大模型可以动态发现工具、按 JSON Schema 传参数、拿到结构化的执行结果。当这套协议被用于 GUI 操作时模型不再需要靠“背诵界面截图”来硬猜而是可以调用类似get_screen_info、click_element、input_text、scroll_view这样的工具把屏幕里的元素、坐标和动作全部当成可编程资源。这一步的意义在于GUI Agent 不再是一个“独角戏”模型而是一个可以被编排、被审计、被人类随时插入干预的工作流节点。模型只是工作流里的执行引擎MCP Server 是操作层HITL 则是控制层的开关。1.3 这篇文章适合谁以及你会得到什么如果你是刚接触 MCP 的开发者读完可以理解 GUI-MCP 的协议层级、工具定义和 HITL 状态机如果你已经部署过类似 computer use 或自研 UI Agent第 4 节和第 5 节里的工程配置、踩坑记录会更值得看。我不会贴一整份“官方完整配置”而是把我在自己环境里验证过的最小可行方案拆给你并解释每一处关键取舍的原因。2. GUI-MCP 到底在 MCP 生态里占据什么位置2.1 先分清楚computer use、MCP、GUI-MCP 不是同一个东西“computer use”最早是指一类模型能力——模型可以直接观察屏幕、移动鼠标、敲键盘跟人类操作电脑的方式一致。MCP 则是一套客户端与服务端的工具调用协议强调的是如何把外部工具安全地暴露给模型。GUI-MCP 介于两者中间它既依赖模型的视觉理解能力又把 GUI 操作封装成 MCP 工具让模型不是“自己伸手”而是“调用统一接口”。维度直接把截图丢给模型Computer Use 类能力GUI-MCP 类方案屏幕信息来源一次性截图模型自行截屏/录屏MCP 工具返回结构化界面信息动作执行方式模型口头给建议模型直接控制鼠标/键盘通过 Server 端工具执行可插审计人类介入成本只能在结果层面纠正中途很难安全打断HITL 可设计在动作层和任务层可复现性低每次都看心情中容易受环境干扰高工具断言和执行日志可回放并不是说 Computer Use 没价值它适合探索式任务但生产环境的 GUI 自动化需要的是确定性优先、人类可干预。这也是我给团队做选型时宁可多包一层 MCP 的原因。2.2 GUI 操作如何被建模成 MCP 工具在一个典型的 GUI-MCP Server 里核心工具可以分成三类感知类工具获取当前窗口列表、截取屏幕、读取可访问性树、查找目标元素。返回的不只是 PNG 图片还有元素位置、类型、可用状态、文本内容。决策类工具这一步并不直接操作界面而是做条件判断、路径规划。MCP 里通常不单独建模而是模型在对话上下文中完成但在 HITL 流程里我会把“待确认计划”也做成一个结构化结果。操作类工具点击、双击、右键、输入、清空、拖拽、滚动、组合快捷键、等待元素出现。每个工具都尽量只做一件事便于后续约束权限和回滚。举例来说一个最简单的click_element工具描述大概是这样的{ name: click_element, description: 点击当前界面中指定元素坐标需来自最近一次 get_screen_info 或 find_element 的结果不能凭空估算。, inputSchema: { type: object, properties: { element_id: { type: string, description: 目标元素 ID来自元素树 }, click_type: { type: string, enum: [single, double, right], description: 点击类型 }, reason: { type: string, description: 模型执行本次点击的理由用于审计和人类确认 } }, required: [element_id, click_type, reason] } }注意我刻意加了一个reason字段。它看起来多余但对 HITL 极其重要当需要弹给人类确认时人可以不用去看整个对话历史只看模型填写的执行理由就能快速判断要不要允许这个动作。2.3 为什么要通过 MCP 而不是把动作硬编码进模型提示词早期方案里很多人喜欢把“屏幕操作说明”直接写进系统提示词让模型自由发挥。这么做在 Demo 阶段很爽到了生产就难受提示词改动要发版、动作没有统一日志、人类想拦都找不到拦截点。MCP 把工具暴露方式、参数协议、执行结果规范化之后模型的自由度被限制住了但系统自由度反而更大。具体表现在权限可以收敛只暴露当前任务需要的 MCP 工具模型没有机会调用无关操作。拦截可以透明人类审核节点只需要监听模型发出的工具调用请求。审计可以完整每次 GUI 动作的输入、输出、耗时、创建者都会落到日志。扩展可以独立想接入蓝湖 MCP、Figma MCP、Playwright MCP 也可以直接复用同一套协议不用每个平台写一套私有实现。用一个生活化类比来解释MCP 是一套标准插座GUI-MCP 是把“鼠标键盘”做成了标准插头HITL 则是这个插座上单独引出来的一个开关。你有了统一插座才谈得上在关键回路上加开关。3. HITL 的粒度设计在哪个环节把“人”拉进 loop3.1 不是所有操作都需要人工确认关键看三个维度做 HITL 最容易犯的错误是让每个步骤都弹确认框。结果就是用户被频繁打断点了十几次“允许”之后变成机械操作真正危险的动作反而被顺手放行。我实际落地时的判断标准是三个维度可逆性这个动作能不能撤销比如临时隐藏一个元素可逆性高可以不打断删除文件、提交订单、修改权限可逆性低必须人工确认。影响范围动作只影响当前输入框还是会影响整个业务状态比如输入文字只影响当前表单而点击“批量执行”按钮会影响成百上千条数据。歧义置信度模型对目标的识别和动作后果有多确定这种置信度不是模型嘴上说“我很有信心”而是由感知工具的匹配度、截图清晰度、目标元素属性和历史成功率综合算出来的。我把三者的关系总结成一个简单的指标风险分 不可逆程度 × 影响范围 × (1 - 置信度)。风险分超过阈值HITL 节点必须触发低于阈值可以自动放行但依然要记录日志供事后抽查。3.2 我常用的三种 HITL 反馈形式HITL 并不意味着一定要做成“人类输入一段文字告诉模型”。在 GUI 场景下我比较常用三种反馈允许/拒绝最简单适用于动作明确且风险高的情况。修改参数后放行人类看到模型要点击的元素、要填写的文本可以直接改动参数比如把金额从 10000 改成 1000再放行。接管并更正人类直接切到目标界面手动操作一步或几步然后把控制权交还给模型。这个模式适合模型反复在同一个点位上出错的情况。第三种模式特别重要。因为 GUI 操作里很多错误无法靠“纠正参数”解决比如模型找不到目标元素人类手动把弹窗关掉再让模型重新规划。这就需要 GUI-MCP 的工具层支持“会话暂停”和“继续执行”而不是简单地把一次动作的结果返回给模型。3.3 如何避免人类变成“无脑允许机器”一旦 HITL 做得太频繁人的注意力会被稀释。我的经验是人类审批的应该是一个目标或一段子计划而不是每一次鼠标移动。比如模型准备执行“从后台导出上个月订单报表并发送到指定邮箱”人类确认一次“这个子计划可以”而不是分别确认打开后台、点击导出、输入邮箱等 6 个步骤。但计划级确认有个问题模型可能在执行中途因为界面变化而偏离计划。所以我设计了一个双层审批计划级 HITL模型提交一份动作序列人审的是目标和执行范围。动作级 HITL只有在计划执行过程中遇到高风险变更、模型主动发起求助、或者置信度跌破阈值时才进入单动作确认。这样既能避免频繁打断又能在真正的危险点保留人工闸门。4. 配套落地一个带 HITL 的 GUI-MCP Agent 怎么配置4.1 先画最小架构模型、GUI-MCP Server、HITL Service 三件套我在落地时没有直接把 HITL 逻辑塞进 MCP Server 里而是单独拆了一个hitl_service。这样做的原因是职责清晰GUI-MCP Server只负责感知和执行 GUI 动作Agent 编排层负责任务规划、调用 MCP 工具、判断是否触发 HITLHITL Service负责人机交互的会话管理、审批队列、超时处理、审计记录。三件套之间通过标准 HTTP/WebSocket 通信。具体流程简化如下用户给 Agent 一个目标例如“登录后台并生成对账单”。Agent 调用get_screen_info、find_element拿到界面状态规划动作序列。Agent 生成plan_summary和action_sequence发送给 HITL Service。HITL Service 在 Web 端展示确认卡片用户在卡片上点“允许”“拒绝”或“修改参数”。审批结果返回 AgentAgent 继续调用 GUI-MCP Server 执行动作。执行过程中若出现异常或高风险点Agent 再次进入 HITL 流程。4.2 一个可运行的 HITL 状态机HITL 状态机的状态我用四个字段描述PENDING_APPROVAL、APPROVED、REJECTED、AWAITING_CORRECTION。PENDING_APPROVAL ↓ 用户点击允许 APPROVED ↓ Agent 执行动作 EXECUTING ↓ 成功 COMPLETED ↓ 失败且需要人工接管 AWAITING_CORRECTION ↓ 人类手动处理后点击继续 PENDING_APPROVAL重新提交计划这只是最简版本。真实场景里还要处理超时、审批人离线、多个会话串行等状态但核心思路是模型不能自己从 REJECTED 里直接解锁动作。任何拒绝都必须有人类介入后才能重新发起避免模型在失败后无限重试同一个危险操作。4.3 在我的环境里跑通的 HITL 请求示例下面这个 JSON 是我把一次点击请求提交给 HITL Service 时的实际格式{ request_id: hitl_req_001, session_id: agent_session_42, type: action_approval, action: { tool: click_element, args: { element_id: btn_export_report, click_type: single, reason: 用户目标是导出上月销售报表点击导出按钮生成文件 } }, risk_assessment: { reversibility: medium, scope: single_download, score: 0.72 }, require_human: true }HITL Service 收到后会把这段请求渲染成人可读的卡片。这里我犯过的最大的错误是直接展示原始 JSON——人类看不懂也不愿意看。后来我让 GUI-MCP Server 额外返回一段自然语言摘要比如“模型准备点击导出按钮来生成上月报表是否需要允许”审批准确率立刻上来不少。4.4 日志与轨迹回放事后 HITLHITL 不只是事中和事前。还有很多错误属于“事后才发现”比如导出的报表数据不对、发送邮件内容有误。为此我把 GUI-MCP 的全部动作记录成事件流包括截图指纹、元素快照、鼠标坐标、执行耗时、模型命中的元素信息和执行结果。之后可以用时间线回放逐帧检查每个动作前后的界面变化。这个轨迹回放在复现问题时帮助巨大。曾经有个问题表现为“模型偶尔会把 Excel 保存对话框里的文件名清空”看代码和数据都看不出原因最后通过回放轨迹发现是模型在多屏场景下把另一个窗口的键盘事件错误发给了保存对话框。没有轨迹记录这种“灵异问题”几乎是不可排查的。5. 实测过程中的几个高频问题5.1 人类也会基于过期截图做错误判断HITL 引入的最大幻觉是“人类一定比模型强”。实测下来人类也会犯错而且犯错的点很集中审批卡片上的截图是 Agent 几秒前生成的但真实界面可能已经变了。我们遇到过一次情况审批人看到模型要点击“确认支付”按钮截图里金额是 120 元于是点了允许。但实际界面当时已经因为其他地方的操作产生了一笔新的附加费用金额变成了 520 元。模型看到的截图还是 120 元的版本问题不只在模型而是整个感知链路都没有发现界面状态已经失效。解决办法是在 GUI-MCP Server 端增加“动作执行前校验”点击目标元素前重新抓取元素树比对元素 ID、坐标和关键文本是否与发起审批时一致不一致就取消执行并再次上报 HITL。这个机制我现在一直保留着。5.2 并发会话和多人审批的冲突当我尝试同时跑多个 GUI Agent 会话时遇到一个过去单机 Demo 从来没想过的问题两个会话可能操作同一个界面而且 HITL 审批人是同一个人。一个人同时处理两个会话的审批很容易出现“用 A 会话的预期去审 B 会话的请求”的情况。我建议在 HITL Service 里维护一个全局“审批人当前关注会话”的标识同一时刻只允许一个会话弹出确认卡片其他会话的风险动作一律排队等待。虽然会降低吞吐但换来的是审批准确性。如果想要更高的并发就需要把不同 GUI Agent 分配到独立的虚拟机/容器环境从物理上隔离界面。5.3 敏感凭证不能进入模型上下文GUI Agent 在操作真实业务系统时经常要登录、填密码、处理密钥。但 GUI-MCP 不能因此就把所有凭证都塞进对话上下文里因为模型很可能在后续推理过程中复述、误写或者把它写入日志。更严重的风险是某些模型服务端或外部工具链如果记录会话数据凭证就会变成泄露面。我的处理方法是凭证只存在于 HITL Service 的安全存储里模型永远只接触一个 token 引用。当 Agent 需要登录时它调用的不是input_text直接填密码而是调用login_with_saved_credential(account_idxxx)这样带引用语义的工具由 HITL Service 或凭证代理把凭证安全地注入到界面输入框并且不把原始密码放入 Agent 执行日志。这也是 HITL 的另一个隐藏价值真正敏感的输入可以绕开模型直接在人工或专用代理通道完成。5.4 性能和资源占用截图和视频流不能贪多GUI-MCP 在感知环节最容易把资源打爆。一开始我想让 Agent 尽量看得全面所以每秒抓多帧截图还把界面滚动区域全部提取为图。结果在普通办公电脑上单次会话的内存占用超过 2GB推理延迟也高得没法用。后来我做了两件事解决一是用静态元素树优先只有元素树信息不足时才触发截图二是截图采用区域裁剪和 JPEG 压缩只截取模型注意力聚焦的窗口区域而不是整个屏幕。这样既保证质量又让资源占用处于可接受范围。HITL 审批卡片上也只展示关键区域截图避免把整块敏感屏幕都暴露给审批人。6. 从踩坑里得到的经验以及我最后保留的设计6.1 从一个“只做确认”的 GUI-MCP 开始而不是一开始就追求全自动如果让我重新做一个 GUI Agent 项目我会先把自动化范围限制在这种程度模型能规划并执行可逆操作遇到一切不可逆操作都停下来请求人类确认。先把“人类确认”这个循环跑稳定再逐步放开自动执行的比例。这看起来保守却能让团队尽早暴露三个问题工具定义是否清晰、审批卡片是否易于理解、模型是否频繁产生低效动作。这个思路也适合想从零上手 MCP 和相关工具的团队。现在 MCP 生态里已经有 Figma MCP、Playwright MCP、蓝湖 MCP 等大量成熟实现但这些生态更偏向“工具调用”。如果要叠加 GUI 操作最好按照我第 4 节的方式把 HITL 状态机提前加进去否则后面再把人工干预加回来会涉及大量改动。6.2 把“人类战略、模型战术”拆清楚我对 GUI-MCP 与 HITL 配合的理解最终可以收缩成一句话人负责定义目标和边界模型负责执行道路上的可逆操作当道路不可逆或者不清晰时人必须能重新掌控方向。在做任务分派的时候我会明确告诉模型哪些决策不需要人参与哪些必须等人。比如过滤数据列表、切换 Tab、滚动页面这类没有破坏性的动作模型可以自主完成而点击“发送”“支付”“删除”“覆盖文件”“修改权限”等动作模型必须回到 HITL 节点。6.3 我强烈建议保留的一个小机制最后分享一个极其简单但我觉得价值最高的机制让 HITL Service 记录“人类每次是否修改了模型的参数”。例如模型要点击“保存”人类审批时把点击目标从“另存为”改成了“直接保存”这本身就是一个高价值的训练信号。我把这些修改攒起来定期分析发现模型在某个业务模块的请求命中率从 60% 提升到 88%。因为人类修改过的参数、纠正过的动作相当于免费标注数据。即使你不打算重新微调模型也可以把这些修正后的动作作为“用户偏好配置”在下一次同类任务开始时直接复用减少 HITL 的触发次数。GUI Agent 的未来一定不是“无人驾驶”式全裸自动化而是“自动驾驶 人工接管”的分层协同。阶跃星辰 GUI-MCP 提供的是操作层和协议层的地基HITL 则是保证这个地基不会因为一次偶发的错误导致整栋楼倒塌的承重墙。谁先把这套协作机制打磨到位谁才能真正把 GUI Agent 从演示厅搬进业务现场。