☰
AI Agent接管移动端自动化:视觉理解、动作规划与真机稳定性三大考点
2026/10/19 2:48:41 网站建设 项目流程

1. 移动端自动化的新拐点:从脚本点击到智能体接管

移动端自动化这件事,做了七八年的人都有一个共识:它比 Web 自动化难伺候得多。Web 上你抓个 DOM,用选择器定位元素,稳得像老狗;到了手机上,光是不同厂商的 ROM 差异、分辨率适配、输入法弹窗、权限弹窗,就够你喝一壶的。过去我们做移动端自动化,主流思路无非两条:一条是基于坐标的脚本回放,另一条是基于控件树的 UI 遍历。前者脆得像薯片,换个分辨率全废;后者稍微稳一点,但遇到 Flutter、Unity 渲染的界面,控件树直接给你一片空白。

现在情况变了。AI Agent 开始真正“操作”真实手机——不是模拟器里跑跑 demo,而是插上数据线、连上真机,让一个具备视觉理解能力的智能体去看屏幕、做决策、点按钮、滑页面。这个转变带来的不只是“更智能”,而是整个自动化范式的重构。以前你写的是“第 3 步点这个坐标”,现在你写的是“帮我把购物车里最便宜的那件商品删掉”,Agent 自己去理解界面、规划路径、执行操作。

这个变化对做移动端自动化的同学来说,意味着三个全新的考点浮出水面。这三个考点不是简单的技术升级,而是从“脚本思维”到“智能体思维”的底层切换。我最近花了不少时间在这上面折腾,踩了一堆坑,也摸出了一些门道。这篇文章就把这三个考点掰开揉碎讲清楚,从原理到实操,从工具选型到避坑经验,尽量让不同基础的朋友都能拿走能用的东西。

先说清楚这篇文章适合谁看。如果你正在做移动端自动化测试、RPA 流程搭建、或者想用 AI Agent 做一些手机上的重复性操作,那这篇内容会对你有直接帮助。如果你只是听说过 AI Agent 但没动过手,也没关系,我会把基础概念用生活化的方式讲明白。核心关键词就三个:视觉理解、动作规划、真机稳定性。这三个词贯穿全文,也是我认为移动端自动化在 Agent 时代最核心的三个新考点。

2. 考点一:视觉理解——Agent 怎么“看懂”手机屏幕

2.1 为什么控件树不够用了

传统移动端自动化最依赖的就是控件树。Android 上有 UiAutomator,iOS 上有 XCUITest,它们能拿到界面上每个元素的层级、ID、文本、坐标。这套东西在原生应用上很好使,但现实是,现在越来越多的 App 用跨平台框架开发,界面渲染方式五花八门。Flutter 自绘引擎把整个界面画在一张画布上,控件树里只有一个 FlutterView;游戏引擎渲染的界面更是完全拿不到控件信息;就连一些原生应用,为了性能也会把复杂列表做成自定义 View,控件树里只剩一个空壳。

我实测过一个典型的电商 App,商品列表页用 UiAutomator 抓下来,只有十几个节点,全是容器,真正的商品卡片信息一个都拿不到。这种情况下,基于控件树的自动化直接瘫痪。而 AI Agent 走的是另一条路:它不依赖控件树,而是像人一样“看”屏幕。截图进来,视觉模型理解画面上有什么,按钮在哪、文字写的什么、当前处于什么状态,然后决定下一步动作。

这个思路的转变很关键。控件树是结构化的、精确的,但覆盖不全;视觉理解是通用的、模糊的,但几乎什么界面都能处理。Agent 时代的选择是后者,因为通用性比精确性更重要——你不可能为每个 App 都写一套控件适配,但视觉模型可以一套打天下。

2.2 视觉理解的技术路线拆解

目前让 Agent 看懂手机屏幕,主流有三条技术路线,各有优劣,我逐个说。

第一条是纯视觉大模型方案。直接把截图丢给多模态大模型,让它输出“点击坐标 (x, y)”或者“点击‘确认’按钮”。这条路线最省事,不需要任何界面适配,但问题也很明显:大模型的坐标定位精度不够。你让它输出坐标,它经常给你一个大概位置,偏差几十个像素是常事。而且大模型推理有延迟,一张图几百毫秒到几秒不等,对于需要快速连续操作的场景,这个延迟很难接受。

第二条是视觉检测模型 + 规则引擎。先用目标检测模型(比如 YOLO 系列)识别出屏幕上的按钮、输入框、图标等元素,拿到它们的边界框,然后结合规则引擎决定点哪个。这条路线精度高、速度快,但需要针对不同 App 做标注和训练,通用性差。而且手机界面千变万化,你很难训练一个覆盖所有场景的检测模型。

第三条是视觉语言模型 + 坐标映射,这也是我目前最推荐的方案。核心思路是:用视觉语言模型理解屏幕内容,输出结构化的界面描述(比如“屏幕顶部有一个搜索框,中间是商品列表,底部有导航栏”),然后通过一个轻量的坐标映射模块,把“点击搜索框”这样的语义指令转换成精确的屏幕坐标。这个映射模块可以基于控件树(如果有的话)做精确定位,也可以基于视觉特征做近似定位。

我实际用下来,第三条路线在精度和通用性之间取得了最好的平衡。具体实现上,我会用视觉语言模型做高层理解,用 OCR 做文字定位,用图像模板匹配做图标定位,三者结合。比如要点击“确认”按钮,先让模型确认屏幕上确实有“确认”按钮,然后用 OCR 找到“确认”两个字的精确位置,最后点击文字中心。这样既保证了理解能力,又保证了点击精度。

2.3 实操:搭建一个能看懂屏幕的视觉理解模块

下面是我实际在用的一个视觉理解模块的搭建过程,基于 Python,核心依赖是截图工具、OCR 引擎和视觉语言模型 API。

第一步,解决截图问题。Android 上用 adb 截图是最稳的,命令很简单:

adb exec-out screencap -p > screen.png

这条命令直接把截图输出到标准输出,重定向到文件,比先存到手机再 pull 出来快得多。iOS 上稍微麻烦一点,需要用到 WebDriverAgent 或者类似的工具,但思路一样。截图频率是个关键参数,太高了手机扛不住,太低会漏掉界面变化。我实测下来,对于大多数操作场景,每秒 2 到 3 帧足够了,也就是间隔 300 到 500 毫秒截一次。

第二步,接 OCR。我常用的是 PaddleOCR,中文识别效果好,而且能返回每个文字块的精确坐标。代码大概长这样:

from paddleocr import PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang='ch') result = ocr.ocr('screen.png', cls=True) # result 结构:[[[坐标四点], (文字, 置信度)], ...] for line in result[0]: box = line[0] # 四个角点坐标 text = line[1][0] # 识别出的文字 confidence = line[1][1] # 置信度 print(f"文字: {text}, 位置: {box}, 置信度: {confidence}")

拿到文字和坐标之后,就可以做语义匹配了。比如 Agent 决定要点击“确认”,我就在 OCR 结果里找文字等于“确认”或者包含“确认”的块,取它的中心坐标作为点击目标。这里有个细节:OCR 可能会把“确认”识别成“确 认”或者“确认 ”(带空格),所以匹配的时候要做一下文本清洗,去掉空格和特殊字符再比对。

第三步,接视觉语言模型做高层理解。这一步的目的是让 Agent 知道当前屏幕是什么状态、有哪些可操作的元素。我会把截图传给模型,问它几个结构化的问题:当前页面是什么类型?有哪些可点击的元素?每个元素的功能是什么?模型返回的结果用来指导后续的动作规划。

这里有个经验:不要指望模型一次就能给出完美答案,也不要让它直接输出坐标。我的做法是让模型输出结构化的 JSON,比如:

{ "page_type": "商品列表页", "clickable_elements": [ {"name": "搜索框", "description": "顶部搜索入口", "action": "点击后进入搜索"}, {"name": "第一个商品卡片", "description": "包含商品图片和价格", "action": "点击进入详情"} ], "current_state": "正常展示" }

然后我再根据这个 JSON,结合 OCR 和模板匹配,去定位具体坐标。这样分工明确:模型负责“理解”,定位模块负责“精确”。

2.4 视觉理解的常见坑与应对

第一个坑是截图延迟和界面不同步。你截的图可能是 500 毫秒前的界面,等你决策完要点击的时候,界面已经变了。这个问题在页面加载、动画过渡的时候特别明显。我的应对方法是:截图后先做一次界面稳定性检测,连续截两帧,如果两帧差异很小,说明界面稳定了,再往下走;如果差异大,等 200 毫秒再截一次。这个逻辑写起来不复杂,但能避免大量“点空”的情况。

第二个坑是视觉模型的幻觉。模型有时候会“看到”屏幕上并不存在的东西,比如你问它有没有“提交”按钮,它说有,但实际上没有。这个问题的根源是模型倾向于给出肯定回答。我的应对方法是:模型输出的每个元素,都要经过 OCR 或模板匹配的二次验证,验证不通过就不执行。宁可漏点,不可错点。

第三个坑是动态内容的干扰。比如倒计时、轮播图、视频播放,这些内容一直在变,会让视觉理解变得不稳定。我的做法是在截图前先判断页面是否有动态区域,如果有,尽量避开这些区域做决策,或者等动态内容稳定后再操作。

提示:视觉理解模块的调试成本很高,建议先把截图、OCR、模型理解三个环节拆开单独调试,每个环节都确认没问题了再串起来。我一开始图省事直接端到端跑,出了问题根本不知道是哪一环的锅,排查起来非常痛苦。

3. 考点二:动作规划——Agent 怎么决定“下一步做什么”

3.1 从固定流程到动态规划

传统自动化的动作是写死的:第一步点这里,第二步滑那里,第三步输入文字。这种固定流程在界面稳定、路径唯一的场景下没问题,但真实手机上,弹窗、广告、权限请求、网络异常,随时可能打断你的流程。你写的是“点击购买按钮”,结果弹出来一个“是否允许发送通知”,脚本就卡死了。

AI Agent 的动作规划是动态的。它不预设固定步骤,而是根据当前屏幕状态和目标,实时决定下一步做什么。比如目标是“完成购买”,Agent 看到当前是商品详情页,它会规划:先点“加入购物车”或“立即购买”,如果弹出规格选择,就选规格,如果弹出权限请求,就先处理权限,如果跳转到登录页,就先登录。每一步都是根据当前状态动态生成的。

这个能力背后是任务分解和状态机的结合。Agent 先把高层目标拆解成子任务,比如“完成购买”拆成“选择商品→确认规格→提交订单→完成支付”。然后每个子任务对应一个状态,Agent 在当前状态下,根据屏幕内容决定触发哪个动作,动作执行后进入下一个状态。如果遇到异常状态(比如弹窗),就插入一个异常处理子任务,处理完再回到主流程。

3.2 动作规划的核心:状态识别与路径选择

动作规划最关键的一步是状态识别。Agent 必须准确知道当前处于哪个状态,才能决定下一步。状态识别靠的是视觉理解模块的输出——页面类型、可点击元素、当前状态描述。但光有这些还不够,还需要一个状态映射表,把视觉理解的结果映射到预定义的状态上。

我一般会定义一个状态表,类似这样:

状态名称识别特征可执行动作下一状态
商品详情页有“加入购物车”按钮点击加入购物车规格选择页或购物车页
规格选择页有规格选项和“确定”按钮选择规格后点确定购物车页
购物车页有商品列表和“结算”按钮点击结算订单确认页
订单确认页有收货地址和“提交订单”按钮点击提交订单支付页
支付页有支付方式和“确认支付”按钮选择支付方式后确认支付完成页
权限弹窗有“允许”和“拒绝”按钮点击允许返回上一状态
登录页有用户名密码输入框输入账号密码后登录返回上一状态

这个表不是写死的,而是可以根据实际运行情况动态扩展。Agent 遇到表里没有的状态时,会尝试用视觉理解能力去判断这个状态是什么,然后决定是处理它还是跳过它。处理完之后,把新的状态和动作记录下来,下次遇到就能直接用了。

路径选择是另一个关键点。同一个目标可能有多种路径,比如“完成购买”可以走“立即购买”也可以走“加入购物车→结算”。Agent 需要根据当前状态选择最优路径。我的做法是给每条路径定义一个成本(比如步骤数、预计耗时),Agent 优先选择成本低的路径。如果某条路径执行失败,就回退到上一个状态,换另一条路径。

3.3 实操:用状态机 + 视觉理解实现动态动作规划

下面是我实际在用的一个动作规划框架的简化版,核心是一个状态机循环。

class MobileAgent: def __init__(self, goal, max_steps=50): self.goal = goal # 高层目标,比如"完成购买" self.max_steps = max_steps self.state = "unknown" self.history = [] # 记录执行历史 def run(self): for step in range(self.max_steps): # 1. 截图并理解当前屏幕 screen = self.capture_screen() understanding = self.understand_screen(screen) # 2. 识别当前状态 self.state = self.identify_state(understanding) self.history.append({"step": step, "state": self.state}) # 3. 检查是否达成目标 if self.is_goal_achieved(understanding): print(f"目标达成,共执行 {step} 步") return True # 4. 决定下一步动作 action = self.plan_action(self.state, understanding) if action is None: print(f"在状态 {self.state} 下无法规划动作,终止") return False # 5. 执行动作 self.execute_action(action) # 6. 等待界面稳定 self.wait_for_stable() print("达到最大步数,未达成目标") return False def identify_state(self, understanding): # 根据视觉理解结果匹配状态表 page_type = understanding.get("page_type", "") elements = understanding.get("clickable_elements", []) # 简化的状态匹配逻辑 if "加入购物车" in str(elements): return "商品详情页" elif "结算" in str(elements): return "购物车页" elif "提交订单" in str(elements): return "订单确认页" elif "确认支付" in str(elements): return "支付页" elif "允许" in str(elements) and "拒绝" in str(elements): return "权限弹窗" else: return "未知状态" def plan_action(self, state, understanding): # 根据状态和当前理解决定动作 action_map = { "商品详情页": {"type": "click", "target": "加入购物车"}, "购物车页": {"type": "click", "target": "结算"}, "订单确认页": {"type": "click", "target": "提交订单"}, "支付页": {"type": "click", "target": "确认支付"}, "权限弹窗": {"type": "click", "target": "允许"}, } return action_map.get(state) def execute_action(self, action): if action["type"] == "click": # 定位目标元素的坐标并点击 coords = self.locate_element(action["target"]) if coords: self.tap(coords[0], coords[1]) else: print(f"无法定位元素: {action['target']}")

这个框架的核心逻辑很清晰:截图→理解→识别状态→规划动作→执行→等待稳定→循环。实际用的时候,每个环节都需要大量细节填充,比如locate_element要结合 OCR 和模板匹配,wait_for_stable要做帧差检测,understand_screen要调视觉模型 API。但整体骨架就是这样,先跑通再优化。

3.4 动作规划的避坑经验

第一个经验是动作要幂等。什么意思?就是同一个动作执行两次和执行一次效果一样。比如点击“加入购物车”,如果第一次点击后界面没反应,Agent 可能会再点一次,结果加了两件。为了避免这个问题,我在执行动作后会检查界面是否发生了变化,如果没变化才重试,而且重试次数限制在 2 次以内。

第二个经验是设置合理的超时和重试。手机操作有时候会卡顿,点击后界面半天不响应。我的做法是每个动作执行后等待最多 3 秒,如果 3 秒内界面没变化,就认为动作失败,进入重试或异常处理。重试最多 2 次,还不行就跳过这个动作,尝试其他路径。

第三个经验是记录执行轨迹。Agent 的决策过程是个黑盒,出了问题很难排查。我会把每一步的截图、理解结果、状态、动作、执行结果都记录下来,存成日志。出问题的时候回放日志,一眼就能看出是哪一步决策错了。这个日志在调试阶段特别有用,我靠它定位了好几个视觉理解的 bug。

注意:动作规划不要追求一步到位。我一开始想让 Agent 自己规划所有路径,结果它经常绕远路或者陷入死循环。后来改成“预定义主路径 + 动态异常处理”的混合模式,主路径写死,异常情况让 Agent 自己处理,稳定性和效率都好了很多。

4. 考点三:真机稳定性——Agent 在真实设备上的生存法则

4.1 真机和模拟器的本质差异

模拟器上跑得好好的自动化,搬到真机上经常各种翻车。这个差异不是一点半点,我列几个最要命的。

性能差异。模拟器用的是电脑的 CPU 和内存,性能强劲,截图、渲染、响应都很快。真机性能参差不齐,低端机截图要一两秒,界面渲染也慢,Agent 的决策速度必须跟着降下来。我在一台低端机上测试,截图加 OCR 加模型理解,一轮下来要 3 到 4 秒,而模拟器上只要 500 毫秒。这个差距直接影响了 Agent 的操作节奏。

系统差异。不同厂商的 ROM 对权限管理、后台限制、弹窗策略都不一样。有的 ROM 会频繁弹权限请求,有的会杀后台,有的会限制 adb 连接。这些差异在模拟器上完全体现不出来,到了真机上就是一个个坑。

网络差异。真机用的是移动网络或 Wi-Fi,网络不稳定是常态。Agent 操作过程中如果遇到网络加载慢,界面一直转圈,它可能会误判为“界面无响应”而执行错误动作。模拟器通常用电脑的网络,稳定得多。

硬件差异。真机有物理按键、有传感器、有摄像头,这些在模拟器上都是模拟的。有些 App 会检测是否是真机,如果是模拟器就限制功能。Agent 在真机上操作,必须考虑这些硬件因素。

4.2 真机稳定性的三个核心保障

针对这些差异,我总结了三个核心保障措施,实测下来能解决 80% 以上的稳定性问题。

第一个保障:设备状态监控。Agent 在操作过程中,要持续监控设备的关键状态:电量、网络、屏幕是否亮着、当前前台应用是什么。电量低于 20% 要提醒,网络断了要等待,屏幕灭了要唤醒,前台应用不对要切回来。这些监控逻辑不复杂,但能避免大量“莫名其妙”的失败。

我一般会每 10 步检查一次设备状态,检查项和应对策略如下:

检查项正常范围异常应对
电量> 20%低于 20% 暂停任务并提醒
网络已连接断开时等待 30 秒,超时则终止
屏幕状态亮屏灭屏时发送唤醒命令
前台应用目标应用不对时重新启动目标应用
adb 连接正常断开时尝试重连,最多 3 次

第二个保障:界面稳定性检测。前面提过,截图后要判断界面是否稳定。我的做法是连续截两帧,计算两帧的差异度。差异度低于阈值(比如 5%)认为稳定,可以继续;高于阈值认为界面还在变化,等待 200 毫秒再截。这个逻辑用 OpenCV 或者 PIL 都能实现,计算量很小。

from PIL import Image import numpy as np def is_stable(img1_path, img2_path, threshold=0.05): img1 = np.array(Image.open(img1_path).convert('L')) img2 = np.array(Image.open(img2_path).convert('L')) # 计算差异像素比例 diff = np.abs(img1.astype(int) - img2.astype(int)) diff_ratio = np.mean(diff > 30) # 差异超过30的像素占比 return diff_ratio < threshold

第三个保障:异常恢复机制。Agent 操作过程中难免遇到异常:弹窗、崩溃、卡死、跳转到未知页面。这时候不能直接放弃,要有恢复机制。我的恢复策略分三级:一级是重试当前动作,二级是回退到上一个已知状态,三级是重启应用从头开始。每级恢复都有次数限制,超过限制就终止任务并报警。

4.3 实操:真机环境搭建与稳定性调优

真机环境搭建有几个关键步骤,我按顺序说。

第一步,设备连接与授权。Android 真机通过 USB 连接电脑,开启开发者模式和 USB 调试。这里有个坑:不同厂商开启开发者模式的方式不一样,有的要连续点击版本号 7 次,有的在设置里直接有开关。连接后要用adb devices确认设备被识别。如果识别不到,可能是驱动问题或者 USB 线问题,换线换口试试。

第二步,分辨率与 DPI 适配。不同手机分辨率不同,Agent 的坐标定位必须做适配。我的做法是统一用相对坐标,也就是把绝对坐标除以屏幕宽高,得到 0 到 1 之间的比例。点击的时候再乘以目标设备的宽高,换算成绝对坐标。这样一套逻辑可以适配所有分辨率。

def relative_to_absolute(rel_x, rel_y, screen_width, screen_height): abs_x = int(rel_x * screen_width) abs_y = int(rel_y * screen_height) return abs_x, abs_y # 获取屏幕分辨率 def get_screen_size(): result = subprocess.run( ['adb', 'shell', 'wm', 'size'], capture_output=True, text=True ) # 输出格式:Physical size: 1080x2340 size_str = result.stdout.strip().split(': ')[1] width, height = map(int, size_str.split('x')) return width, height

第三步,输入法处理。真机上输入文字是个大坑。默认输入法可能会弹候选词、自动纠错、联想输入,干扰 Agent 操作。我的做法是安装一个干净的输入法(比如 ADBKeyboard),通过 adb 命令直接输入文字,绕过输入法界面。

# 安装 ADBKeyboard adb install ADBKeyboard.apk # 设置为默认输入法 adb shell ime set com.android.adbkeyboard/.AdbIME # 输入文字 adb shell am broadcast -a ADB_INPUT_TEXT --es msg '要输入的文字'

第四步,稳定性调优。环境搭好后,要跑一段时间的稳定性测试,观察失败率。我一般会跑 100 次相同的任务,统计成功率和失败原因。如果失败率超过 5%,就要分析日志找原因。常见的失败原因和调优方法如下:

失败原因占比调优方法
界面未加载完就操作35%增加界面稳定性检测,延长等待时间
弹窗干扰25%增加弹窗识别和处理逻辑
坐标定位偏差20%优化定位算法,增加二次验证
网络超时15%增加网络监控和重试机制
其他5%具体问题具体分析

4.4 真机稳定性的独家避坑心得

第一个心得:不要用无线调试。无线调试虽然方便,但稳定性远不如 USB 连接。我实测无线调试的断连率是 USB 的 5 倍以上,而且延迟高,截图经常超时。如果必须用无线,也要确保设备和电脑在同一个稳定的网络下,并且设置合理的超时和重连机制。

第二个心得:给手机散热。长时间跑自动化,手机发热严重,性能下降,截图变慢,甚至自动降亮度。我的做法是给测试手机加一个小风扇,或者每隔半小时暂停几分钟让手机降温。这个细节看起来不起眼,但对长时间任务的稳定性影响很大。

第三个心得:准备备用机。真机自动化最怕的就是设备突然出问题——死机、重启、USB 断连。如果任务紧急,一台设备出问题整个流程就卡住了。我的做法是准备两台同型号手机,一台主用一台备用,主用出问题立刻切到备用。切换逻辑可以写进 Agent 里,检测到设备异常就自动切换。

提示:真机稳定性的调试是个长期过程,不要指望一次调好。我的经验是,每跑一个新任务,都会遇到新的稳定性问题,慢慢积累解决方案,形成自己的“避坑库”。跑得多了,你会发现大部分问题都是重复的,有现成的应对方案。

5. 三个考点的协同:从单点突破到系统能力

5.1 视觉、规划、稳定性的三角关系

这三个考点不是孤立的,它们构成了一个三角关系。视觉理解是基础,没有准确的视觉理解,动作规划就是瞎猜;动作规划是核心,没有合理的规划,视觉理解再准也没用;真机稳定性是保障,前两者再好,设备不稳定一切白搭。

我实际搭建 Agent 的时候,发现这三个模块必须协同设计,不能分开做。比如视觉理解的输出格式,要直接考虑动作规划的需要;动作规划的状态定义,要考虑真机稳定性的异常处理。如果先做完视觉理解再做规划,经常要返工改接口。

我的做法是先定义好三个模块之间的接口,然后并行开发。接口定义包括:视觉理解输出什么格式的数据、动作规划需要什么输入、稳定性模块在什么时机介入。接口定好了,三个模块可以独立开发和测试,最后集成。

5.2 一个完整的端到端案例

下面用一个完整的案例,把三个考点串起来。目标是让 Agent 在真实手机上完成“打开购物 App,搜索指定商品,加入购物车,完成结算”这个任务。

视觉理解环节:Agent 每步截图,用 OCR 识别文字,用视觉模型理解页面类型。比如打开 App 后,识别到首页有搜索框,输出{"page_type": "首页", "elements": [{"name": "搜索框", "action": "点击搜索"}]}。

动作规划环节:根据视觉理解结果,Agent 识别当前状态为“首页”,规划动作“点击搜索框”。执行后进入搜索页,识别状态为“搜索页”,规划动作“输入关键词并搜索”。搜索后进入结果页,识别状态为“搜索结果页”,规划动作“点击第一个商品”。进入详情页后,规划动作“加入购物车”。进入购物车后,规划动作“结算”。进入订单确认页后,规划动作“提交订单”。

稳定性保障环节:每一步执行后,检查设备状态(电量、网络、前台应用),检查界面稳定性(连续两帧差异小于阈值),检查是否出现异常弹窗(权限、广告、更新提示)。如果出现异常,插入异常处理子任务,处理完回到主流程。

这个案例跑下来,完整流程大概需要 15 到 25 步,耗时 1 到 2 分钟,成功率在 90% 以上。失败的 10% 主要是网络波动和偶发弹窗,通过重试和异常处理能挽回大部分。

5.3 性能优化:让 Agent 跑得更快更稳

Agent 跑得慢是个普遍问题。视觉理解要调模型 API,动作规划要推理,稳定性检测要截图对比,每个环节都有延迟。我实测下来,一轮完整的“截图→理解→规划→执行→检测”大概要 2 到 4 秒,对于需要几十步的任务,总耗时就很可观了。

优化方向有几个。第一,减少不必要的截图。不是每一步都要重新截图,如果上一步动作后界面没有变化,可以复用上一次的截图和理解结果。第二,并行化。截图和 OCR 可以并行,视觉模型理解和状态识别可以并行,能省不少时间。第三,缓存。同一个页面多次出现时,视觉理解的结果可以缓存,不用每次都调模型。第四,降级策略。对于简单的状态识别,用轻量级的规则匹配代替模型推理,速度快很多。

我做了这些优化后,单步耗时从平均 3 秒降到了 1.5 秒左右,整体任务耗时减少了一半。对于追求速度的场景,还可以进一步优化,比如用本地部署的小模型代替云端大模型,用 GPU 加速推理等。

6. 常见问题速查与排查技巧

6.1 视觉理解类问题

问题:OCR 识别不准,特别是小字和特殊字体。

排查思路:先确认截图清晰度,截图模糊的话 OCR 肯定不准。然后检查 OCR 的语言设置,中文和英文要分开设置。如果还是不准,可以尝试换 OCR 引擎,或者对截图做预处理(放大、锐化、二值化)。

问题:视觉模型返回的结果不稳定,同一个界面两次理解结果不一样。

排查思路:这是模型幻觉的典型表现。应对方法是增加二次验证,模型输出的每个元素都要经过 OCR 或模板匹配确认。另外可以降低模型的 temperature 参数,让输出更稳定。

问题:界面有动态内容,截图总是抓不到稳定状态。

排查思路:识别动态区域,在截图后把动态区域遮罩掉,只对静态区域做理解。或者等动态内容播放完再截图,比如视频广告等它播完。

6.2 动作规划类问题

问题:Agent 陷入死循环,反复执行同一个动作。

排查思路:检查状态识别是否准确,如果状态识别错了,Agent 会一直以为自己在同一个状态。另外检查动作执行后的界面变化检测,如果动作没生效但 Agent 以为生效了,也会死循环。应对方法是增加历史记录,检测到重复动作时强制切换策略。

问题:Agent 规划的动作不是最优路径,绕远路。

排查思路:检查路径成本定义是否合理,如果成本定义不准确,Agent 会选错路径。另外可以增加路径优先级,让 Agent 优先尝试预定义的主路径。

问题:遇到未知状态时 Agent 不知道怎么办。

排查思路:这是正常的,Agent 不可能认识所有状态。应对方法是设置一个“未知状态处理策略”,比如尝试返回上一页、重启应用、或者跳过当前步骤。同时把未知状态记录下来,后续补充到状态表里。

6.3 真机稳定性类问题

问题:adb 连接频繁断开。

排查思路:先换 USB 线,劣质线材是断连的主要原因。然后检查 USB 口是否松动,换一个口试试。如果还不行,可能是手机省电策略杀了 adb 进程,在开发者选项里关闭“USB 调试自动断开”之类的设置。

问题:截图速度慢,影响 Agent 响应。

排查思路:用adb exec-out screencap -p代替adb shell screencap再 pull,速度快很多。另外可以降低截图分辨率,用adb shell wm size临时改小分辨率,截图后再改回来。

问题:输入文字时输入法干扰。

排查思路:用 ADBKeyboard 代替默认输入法,通过广播直接输入文字,绕过输入法界面。如果必须用默认输入法,可以在输入前先清空输入框,输入后按回车确认,避免候选词干扰。

6.4 独家避坑技巧汇总

第一个技巧:给 Agent 加一个“紧急停止”机制。Agent 跑飞的时候,要能立刻停下来。我的做法是监听一个特定的文件或端口,一旦收到停止信号,Agent 立即终止当前任务。这个机制在调试阶段特别有用,避免 Agent 把手机点得乱七八糟。

第二个技巧:用录屏代替截图做调试。Agent 出问题的时候,光看日志很难还原现场。我会用adb shell screenrecord录屏,把 Agent 操作的全过程录下来,出问题的时候回放录屏,一目了然。

第三个技巧:建立自己的元素库。常用的按钮、图标、弹窗,截图存下来,做成模板库。Agent 定位元素的时候,先查模板库,匹配上了直接用,匹配不上再走 OCR 和模型理解。这样能大幅提升定位速度和准确率。

第四个技巧:定期清理手机。长时间跑自动化,手机会积累大量缓存和日志,影响性能。我一般每周清理一次手机,删除无用文件,重启设备,保持手机在最佳状态。

7. 我在这条路上踩过的几个大坑

第一个大坑是过度依赖视觉模型。一开始我觉得视觉模型万能,什么都让它做,结果发现模型推理慢、不稳定、还贵。后来改成“模型做理解,规则做执行”的混合模式,模型只负责判断页面类型和元素功能,具体的坐标定位和动作执行用规则引擎,又快又稳。

第二个大坑是忽略设备差异。我在一台手机上调好的 Agent,换一台手机就各种问题。后来才意识到,不同手机的截图速度、渲染方式、权限策略都不一样。现在我会在至少三台不同型号的手机上测试,确保 Agent 的兼容性。

第三个大坑是没有异常处理。早期版本的 Agent 遇到弹窗就卡死,遇到网络慢就超时,遇到未知页面就崩溃。后来加了完整的异常处理机制,包括弹窗识别、超时重试、未知状态处理,稳定性才上来。异常处理的工作量比主流程还大,但这是必须的。

第四个大坑是调试成本被低估。Agent 的调试比传统脚本难得多,因为它的行为是不确定的。同一个任务,这次跑成功,下次可能失败,原因还不一样。我的应对方法是建立完善的日志和录屏系统,每次失败都能还原现场,找到根因。这个投入是值得的,没有好的调试工具,Agent 的迭代速度会非常慢。

8. 后续可以扩展的方向

这套 Agent 框架跑通之后,可以往几个方向扩展。一个是多设备并行,同时控制多台手机执行任务,适合批量操作场景。另一个是跨应用流程,Agent 在多个 App 之间跳转完成任务,比如从聊天记录里提取地址,然后打开地图 App 导航。还有一个是自适应学习,Agent 把每次执行的经验记录下来,遇到类似场景时直接复用,越跑越快。

多设备并行这块,核心是设备管理和任务调度。每台设备跑一个 Agent 实例,用一个调度器分配任务。设备之间要隔离,避免相互干扰。我试过同时控制 3 台手机,稳定性还可以,但设备多了之后 USB 带宽和电脑性能会成为瓶颈。

跨应用流程的难点在于应用切换和状态保持。Agent 需要知道当前在哪个 App,切换后如何回到之前的上下文。我的做法是用一个全局的状态管理器,记录跨应用的任务上下文,切换 App 时保存上下文,回来时恢复。

自适应学习是最有意思的方向。Agent 每次执行都记录状态、动作、结果,形成一个经验库。下次遇到相同状态时,直接查经验库,不用重新推理。经验库越大,Agent 越快越准。这个机制我还在摸索中,目前能做到简单的状态-动作记忆,更复杂的泛化还在研究。

最后分享一个小技巧:Agent 的提示词工程很关键。同样的模型,提示词写得好不好,效果差很多。我的经验是,提示词要具体、结构化、带示例。不要问模型“屏幕上有什么”,而是问“请按以下 JSON 格式输出屏幕上的可点击元素:{...}”。给出明确的格式和示例,模型的输出会稳定很多。这个技巧在视觉理解和动作规划两个环节都适用,值得花时间打磨。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询