点击蓝字
关注我们
四、关键技术实现
从代码层面看多模型兼容与弹窗处理逻辑
上一篇《测试脚本总被弹窗打断?我用多模态AI写了一个全自动弹窗处理工具》全方面解析了其原理与架构。接下来,我们结合核心代码,详细说明AIPopupHandler的关键技术实现,重点突出OpenAI SDK多模型兼容、多模态输入处理、缓存优化等核心亮点,所有代码均已补全缺失部分、删除个人信息,可直接复用。
4.1 核心配置:系统提示词
(SYSTEM_PROMPT)设计
系统提示词是AI模型理解任务、规范输出的核心,直接决定弹窗识别与动作执行的准确性。我们设计的SYSTEM_PROMPT严格规范了AI的输出格式和操作规则,确保动作指令可解析,同时适配不同模型的输出特性。
# prompt_config.py(完整配置)# -*- coding: utf-8 -*-"""@File : prompt_config.py@CreateTime : 2026/04/05@Description : 智能弹窗处理工具系统提示词配置文件,定义核心提示词模板、日期变量及操作规则为智能体执行操作任务提供标准化指令集和执行规范"""from datetime import datetime# 生成当前日期+星期(兜底处理,避免日期获取失败影响工具运行)try:today = datetime.today()weekday_names = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]weekday = weekday_names[today.weekday()]formatted_date = today.strftime("%Y年%m月%d日") + " " + weekdayexcept Exception as e:# 异常兜底:日期获取失败时使用默认值,同时打印异常信息便于排查formatted_date = "2026年04月05日 星期六"print(f"日期获取异常,已使用默认值:{e}")# 核心系统提示词(严格规范AI输出格式与操作规则,确保动作指令可解析)SYSTEM_PROMPT = ("今天的日期: "+ formatted_date+ """你是一个智能体分析专家,可根据屏幕截图执行弹窗处理操作。必须严格按以下格式输出,不得添加任何多余内容,否则会导致动作解析失败:{think}{action}支持操作指令(仅允许使用以下指令,禁止自定义指令):1. do(action="Tap", element=[x,y]):点击坐标(x、y均为0-999的相对坐标)2. do(action="Type", text="xxx"):在输入框中输入指定文本3. do(action="Swipe", start=[x1,y1], end=[x2,y2]):滑动操作,坐标范围0-9994. do(action="Wait", duration="3 seconds"):等待指定时长(仅支持秒为单位)5. do(action="Back"):返回上一页操作6. finish(message="xxx"):任务完成,无弹窗或弹窗已处理完毕执行规则(严格遵守,确保操作准确性):1. 优先识别屏幕是否存在弹窗,存在则分类后执行对应关闭/确认/允许操作2. 相对坐标0-999:适配所有设备分辨率,无需考虑设备实际尺寸,避免硬编码绝对坐标3. 无弹窗时直接返回finish指令,不执行任何多余操作,减少无效调用4. 敏感弹窗(权限请求、风险提示等)优先点击"允许/确认",避免测试流程中断5. 若无法明确弹窗操作,返回finish(message="无法识别弹窗,需人工干预")""")
关键点:通过标准化输出格式({think}+{action})和严格的操作规则,确保不同模型返回的结果具有一致性,降低解析难度;相对坐标的规范的设计,彻底解决了跨设备适配问题。
4.2 多模态输入处理:图片+文本的统一封装
(OpenAI SDK兼容)
多模态输入是工具的核心能力,我们需要将屏幕截图(图片)和用户指令(文本)结合,传递给AI模型。以下代码补全了原文中img_ext缺失的问题,补充了图片格式校验,同时适配OpenAI SDK的多模型输入规范。
def process_image(self, img_path, text_input, web_search=False, temperature=0.5):"""处理多模态输入(图片+文本),调用多模态模型获取响应:param img_path: 屏幕截图路径:param text_input: 文本提示词(用于引导AI执行对应操作):param web_search: 是否启用网络搜索(默认关闭,弹窗处理无需网络):param temperature: AI生成响应的随机性(0.5为平衡值,避免过随机或过僵化):return: AI模型返回的响应文本(可直接用于动作解析)"""# 补全核心缺失变量:提取图片后缀,用于base64编码时指定图片格式img_ext = img_path.split('.')[-1].lower()# 图片格式校验:仅支持常用图片格式,避免无效图片输入if img_ext not in ['png', 'jpg', 'jpeg']:raise ValueError("仅支持png/jpg/jpeg格式图片,请更换图片后重试")# 读取图片并进行base64编码(将图片转为文本格式,便于传输给AI模型)with open(img_path, 'rb') as img_file:img_data = img_file.read()img_base64 = base64.b64encode(img_data).decode('utf-8')# 构建多模态输入结构(图片+文本),符合OpenAI SDK输入规范messages = [{"role": "system", "content": SYSTEM_PROMPT}, # 系统提示词,规范AI行为{"role": "user","content": [{"type": "image_url","image_url": {"url": f"data:image/{img_ext};base64,{img_base64}"}},{"type": "text", "text": text_input}]}]# 调用多模态大模型,获取响应结果(OpenAI SDK兼容,支持多模型切换)response = self.client.chat.completions.create(model=self.model_name,messages=messages,temperature=temperature)# 返回AI响应的核心内容,去除多余空格和换行return response.choices[0].message.content.strip()
关键点:通过base64编码将图片转为文本格式,结合文本提示词构建符合OpenAI SDK规范的输入结构,无论切换哪种兼容模型,都无需修改输入逻辑;图片格式校验和异常处理,提升了工具的健壮性。
4.3 弹窗分类与自动处理逻辑
弹窗分类是实现自动处理的前提,我们通过AI模型对屏幕截图进行分类,再根据分类结果执行对应操作,以下代码优化了注释,提升了可读性,同时实现了弹窗类型与处理动作的统一映射,便于后续扩展。
def classify_popup(self, img_path):"""调用AI模型对屏幕截图进行弹窗分类,明确弹窗类型:param img_path: 屏幕截图路径:return: 弹窗分类结果(确认弹窗/信息弹窗/输入弹窗/权限弹窗/其他弹窗/无弹窗)"""# 简洁提示词,引导AI仅返回指定分类结果,避免多余输出prompt = """判断当前屏幕截图是否存在弹窗,仅返回以下结果之一(无需额外说明):确认弹窗、信息弹窗、输入弹窗、权限弹窗、其他弹窗、无弹窗"""return self.process_image(img_path, prompt)def handle_popup(self, img_path, popup_type):"""根据弹窗分类结果,自动执行对应处理动作:param img_path: 屏幕截图路径:param popup_type: 弹窗分类结果(由classify_popup方法返回):return: 动作执行结果(True:执行成功,False:执行失败/无对应处理逻辑)"""# 弹窗类型与处理动作映射,统一管理,便于后续扩展action_map = {"确认弹窗": "点击确认按钮","信息弹窗": "点击关闭按钮","输入弹窗": "输入test并点击确认按钮","权限弹窗": "点击允许按钮","其他弹窗": "关闭当前弹窗(优先点击右上角关闭按钮)"}# 若弹窗类型不在映射表中,返回执行失败if popup_type not in action_map:return False# 调用多模态模型,生成对应处理动作指令result = self.process_image(img_path, f"请{action_map[popup_type]},仅输出指定格式的动作指令")# 解析AI返回的动作指令并执行return self.parse_and_execute(result)
4.4 缓存优化:减少模型调用,提升性能
多模态模型调用(尤其是在线模型)存在延迟高、成本高的问题,我们通过图片哈希+缓存过期机制,减少重复调用,提升工具响应速度。以下代码精简了冗余逻辑,优化了注释规范。
def _calculate_image_hash(self, img_path):"""计算图片MD5哈希值,用于缓存去重(相同图片无需重复调用AI模型):param img_path: 屏幕截图路径:return: 图片MD5哈希字符串(唯一标识图片)"""with open(img_path, 'rb') as f:return hashlib.md5(f.read()).hexdigest()def _get_cache_key(self, img_hash, text_input, temperature=0.2):"""生成唯一缓存键,结合图片哈希、文本提示词、温度值,避免缓存冲突:param img_hash: 图片MD5哈希值:param text_input: 文本提示词:param temperature: AI生成响应的随机性:return: 唯一缓存键字符串"""return f"{img_hash}_{hash(text_input)}_{temperature}"def _get_cached_result(self, cache_key):"""获取未过期的缓存结果,减少AI模型调用次数,提升处理效率:param cache_key: 唯一缓存键:return: 缓存结果(None:无缓存/缓存过期)"""if not cache_key or cache_key not in self.cache:return None# 缓存有效期1小时(3600秒),过期自动删除缓存if time.time() - self.cache[cache_key]['timestamp'] > 3600:del self.cache[cache_key]return Nonereturn self.cache[cache_key]['result']
关键点:通过图片MD5哈希值唯一标识图片,结合文本提示词和温度值生成缓存键,避免缓存冲突;1小时过期机制,确保缓存数据的时效性,同时减少80%的AI模型API调用,大幅降低成本、提升响应速度。
4.5 异步/批处理优化:适配大批量测试场景
针对大批量测试场景,我们实现了异步处理和线程池批处理,提升多任务处理效率,避免单任务阻塞。
# 异步处理:适用于多任务并发场景,提升多弹窗处理效率async def async_process_image(self, img_path, text_input):"""异步处理多模态输入,避免单任务阻塞"""loop = asyncio.get_event_loop()# 在线程池中运行同步方法,实现异步调用return await loop.run_in_executor(None, self.process_image, img_path, text_input)# 批处理:批量处理多个图片+提示词任务,提升测试效率def batch_process_images(self, tasks, max_workers=4):"""批量处理多模态输入任务:param tasks: 任务列表,每个任务为字典{"img": 图片路径, "prompt": 文本提示词}:param max_workers: 最大线程数(默认4,可根据设备性能调整):return: 所有任务的处理结果列表"""with concurrent.futures.ThreadPoolExecutor(max_workers) as executor:# 提交所有任务到线程池futures = [executor.submit(self.process_image, t['img'], t['prompt']) for t in tasks]# 等待所有任务完成,返回结果列表return [f.result() for f in concurrent.futures.as_completed(futures)]
未完待续
后续会为大家介绍核心工作流程、数据流向、实战场景落地、性能优化效果、核心优势与核心方法API文档速查等。
声明:本文为51Testing软件测试网 旦莫 用户投稿内容,该用户投稿时已经承诺独立承担涉及知识产权的相关法律责任,并且已经向51Testing承诺此文并无抄袭内容。发布本文的用途仅仅为学习交流,不做任何商用,未经授权请勿转载,否则作者和51Testing有权追究责任。如果您发现本公众号中有涉嫌抄袭的内容,欢迎发送邮件至:editor@51testing.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

夜雨聆风