--- 总体)
将冗长的UI操作压缩为少量API调用将传统桌面工作流如GitHub提交查询带入手机。1.1 端云协同MAI-UI是原生设备-云协作系统阶跃星辰也是端-云协同豆包应该也是类似方式。本地轻量Agent常驻设备端负责处理大多数任务并扮演“轨迹监控员”的角色。云端强大Agent当本地监控员发现任务执行出现偏差如卡住、操作错误且当前不涉及敏感隐私数据时会触发向云端Agent的切换。关键创新本地模型经过专门训练不仅会执行任务还会判断是否偏离目标并在切换时生成一个“错误摘要”发给云端帮助云端快速理解问题、接手完成。1.2 应对挑战MAI-UI也使用MCP来应对现实挑战。ask_user动作当指令模糊时如“把最近的文件发给他”缺收件人和文件MAI-UI会主动暂停生成一个提问动作向用户请求澄清。mcp_call动作MAI-UI可以调用外部工具通过Model Context Protocol, MCP。例如比较两个地址的开车时间不需要在地图App里手动输入直接调用“高德地图API”即可在手机上查询GitHub提交历史也只需一个API调用。下图为MCP的动作空间。1.3 核心Agent两类核心Agent如下Agent文件任务输出协议MAIGroundingAgentsrc/mai_grounding_agent.pyUI 元素定位单步grounding_think./grounding_think{coordinate:[x,y]}坐标基于 SCALE_FACT0R999 归一化MAIUINavigationAgentsrc/mai_navigation_agent.py多步移动端GUI导航支持ask_user与mcp_call.tool_call{json}/tool_call多轮带历史截图1.4 整体架构图整体架构图如下关键约束如下src/内为扁平导入from base import调用方需把 src/插入sys.pathrequirements.txtagent 客户端与evaluation/grounding/requirements.txt评测含 vLLM/torch两套独立1.5 评测流程图0x02 MCP在MAI-UI中的作用为什么 MAI-UI 要把 MCP 拉进来这是为了解决 GUI Agent 的三个老大难问题纯 GUI 路径的痛点MCP 给出的解法效率查个公交路线要点 5-10 屏一次 mcp_call(amap_route, ...) 直接拿结构化结果能力天花板模型识别能力 / 屏幕信息有限长链路任务容易掉链子把 查询、计算、第三方业务 外包给确定性 API数据敏感性 / 设备-云协同端上小模型搞不定的专业任务必须走云MCP 调用本身就是云侧能力的入口与 README 里 Device-Cloud Collaboration 同源这就是 “Agent-user interaction and MCP augmentation enabling agent to interact with user and use MCP tools to complete the task。MAI-UI 并不是MCP的实现方而是MCP的消费方一它把外部MCP 工具的能力以“额外动作“的形式注入到prompt里让模型在合适的时候选择直接调工具而不是去点屏幕。MCP是给GUIAgent加一条“绕过屏幕“的快捷通道。2.1 MCP与GUI操作的分工分工具体如下图三者同级共存于同一个动作集合由模型自主判断该用哪个。2.2 实现代码中实现如下实例化 Agent 时把 工具清单JSON-Schema 风格的列表通过mcp_tools[...]传进来Agent 用 Jinja2 把这份清单渲染进 system prompt的 ##MCP Tools区块模型在某一步输出tool_call{name:..., arguments*:{...}}/tool_call;客户端外层负责真正去调那个 MCP服务项目本身不内嵌MCP客户端 / 不内嵌网络层拿到结果后把字符串结果塞到下一步 obs[mcp_response*]Agent 在_build_messages 时把它作为新的 user 消息追加。2.3 一次完整MCP往返的时序下图是一次完整MCP往返的完整时序。关键三步模型吐 tool_call ──► 外层调真实 MCP ──► 结果作为纯文本 mcp_response 回灌下一步predict。Agent 本身不执行网络调用只负责传话。要点模型对 GUI 动作和 MCP 调用使用同一种输出语法都是tool_call{name,arguments}/tool_call客户端通过 name 是否在 mcp_tools 里来分流工具调用的真正执行完全在仓库之外让你想接什么 MCP 服务高德地图、12306、淘宝、企业内网工具都行只要能给出 JSON-Schema 描述并自己接通网络。2.4 MCP如何把长的UI操作压缩为少量的API调用2.4.1 问题的本质问题的本质GUI路径 VS API路径的“步数 × 单步成本“差距GUI路径里每一步都包含一次完整的多模态推理单步GUI 成本 encode截图 几千vision token encodehistory_n张历史截图 模型decodethinkingtool_call 客户端反归一化坐标 真机点击 等待UI渲染 重新截图而MCP调用一次的成本如下单次MCP成本 encodeMCP返回JSON字符串几十~几百token 模型decode下一个动作 客户端走HTTP拿结构化结果确定性、毫秒级量纲上压缩比通常是10× -100× —因为一张手机截图的视觉token数 ~ 几千而一段JSON文本 几百。2.4.2 为什么MAI-UI恰好让这种“压缩“是天然成立的MCP之所以能把长UI操作压缩成少量API调用核心是用“低成本、确定性、结构化“的文本通道替换“高成本、概率性、像素级“的视觉通道 ----- 而MAI-UI刚好通过统一tool_call语法 文本回灌mcp_response 工具schema一次性渲染这三件事从而让这种压缩在工程上自然成立、不需要额外特化的代码路径。GUI比如mai_naivigation_agent.py的_build_messages()每一步都把最近history_n张截图重新base64后塞回messages。纯GUI路径下messages体积膨胀 step 0: [sys, img0] ──► ~3k tok step 1: [sys, img0, assto, img1] ──► ~7k tok step 2: [sys, img0, asst0, img1, asst1, img2] ──► ~10k tok step 3: [sys, img1, asst1, img2, asst2, img3]滑窗 ──► ~10k tok对应公式纯GUI完成任务N_ui × C_visionN_ui 大、C_vision 也大乘积爆炸。GUIMCP而把同一段流程换成“GUIMCP以后具体如下GUIMCP路径下messages体积 step 0: [sysMCP_tools_decl,img0] step 1: ◄── tool_call:amap_route(...) ← 模型一次决定走MCP step 2: [..., user(textmcp_response_json)] ← 外层把JSON灌回 ◄── tool_call:open(Notes) step 3: [...,img_after_open_notes] ← 才需要再来一张截图 step 4: ◄── tool_calltype行程已规划要点_build_messages里如果某TrajStep没有携带新screenshot而携带mcp_response只追加一段纯文本user 消息不会追加图片这一步视觉token增量0只多几十~几百文本token。mcp_tools列表只在system prompt里渲染一次由Jinja2的[%if tools%} 控制不会每步重发。模型用同一种tool_call语法统一表达GUI动作与MCP调用所以decode 长度量级一致一压缩完全靠“省掉了一连串需要看屏幕的中间步”。2.4.2 一张直观对比图任务“帮我规划现在去招商银行取钱再去城西银泰城公交地铁总时长 2h把计划写进笔记App。A. 纯 GUI 路径无 MCPstep 1 打开高德 screenshot ● step 2 点搜索框 screenshot ● step 3 键入招商银行 screenshot ● step 4 选最近一家 screenshot ● step 5 点路线 screenshot ● step 6 切到公交 screenshot ● step 7 设起点 screenshot ● step 8 读屏判断时长 screenshot ● step 9 返回再搜下一段 screenshot ● step 10 ...重复5-8.. screenshot ●●●● step 14退出高德 screenshot ● step 15打开笔记 screenshot ● step 16 新建 screenshot ● step 17 输入标题 screenshot ● step 18输入内容 screenshot ● step 19保存 screenshot ● __________________ ~19步 x ~10k vision tok ~190k tok ~19次模型RTT 真机渲染等待19次B. GUI MCP 路径step 1 mcp_call(amap_route, {from:阿里云谷, to:招商银行, constraints:{radius_km:4,mode:transit}}) text-only ○ step 2 mcp_call(amap_route, {from:招商银行, to:城西银泰城, mode:transit}) text-only ○ step 3 open(Notes) screenshot ● step 4 click(新建) screenshot ● step 5 type(标题) screenshot ● step 6 type(正文-把两段路线 JSON 拼起来) screenshot ● step 7 click(保存) screenshot ● __________________ 7 步仅 5 张截图 ≈ 5 × 10k 2 × 0.5k ~51k tok 2 次 HTTP RTT 真机渲染等待 5 次 节省步数 19→7 (-63%)视觉 token 190k→50k (-73%)决策延迟同比下降。