基于Qwen3-VL-2B-Instruct的GUI自动化测试实践:多模态大模型驱动UI操作
1. 项目概述:当大模型“看见”你的屏幕
最近在折腾自动化测试的朋友,估计都绕不开一个痛点:UI自动化。传统的基于坐标定位、元素ID识别的框架,比如Selenium、Playwright,虽然强大,但维护成本高得吓人。页面改个按钮样式、换个布局,脚本就得跟着大改,脆弱得像玻璃。更别提那些用传统CV方法做图像匹配的,对分辨率、缩放、主题色敏感得要命。
这时候,多模态大模型(Multimodal LLM)的出现,给这个领域撕开了一道口子。它不再需要你告诉它按钮的XPath是什么,它自己就能“看”懂屏幕截图,理解“点击登录按钮”这个指令。我最近深度折腾了通义千问开源的 Qwen3-VL-2B-Instruct 这个模型,一个仅20亿参数、支持视觉理解的小巧模型,用它来驱动GUI自动化测试,效果出乎意料地扎实。这不仅仅是“用AI搞自动化”的噱头,而是一套切实可行、能显著降低脚本编写和维护心智负担的新思路。
简单说,这个项目的核心就是: 让Qwen3-VL模型充当你的“眼睛”和“大脑”,你只需要用自然语言告诉它“在屏幕上做什么”,它来分析截图,并生成对应的操作指令(如点击坐标、输入文本),再由自动化框架(如PyAutoGUI、playwright)去执行。 它特别适合处理那些元素结构复杂、动态生成、或者没有稳定标识符的GUI界面,比如一些桌面客户端、老旧系统、或者游戏界面。
如果你正在被繁重的UI测试回归所困扰,或者对“智能体(Agent)”如何落地到具体工程场景感兴趣,那么这篇手把手的实践指南,应该能给你带来不少直接的启发和可复现的代码。
2. 核心思路与方案选型:为什么是Qwen3-VL-2B-Instruct?
在决定用大模型做GUI自动化之前,市面上其实已经有一些方案,比如基于GPT-4V的API调用,或者一些商业化的AI测试工具。但最终选择Qwen3-VL-2B-Instruct,是经过一番权衡的,主要基于以下几点考量:
2.1 离线与隐私安全 这是最硬核的需求。很多企业的测试环境是内网隔离的,涉及到的软件界面可能包含敏感业务数据。将屏幕截图源源不断地发送到第三方云服务(如OpenAI)是不可接受的。Qwen3-VL-2B-Instruct作为一个开源模型,可以完全部署在本地或公司内网的服务器上,所有数据处理都在可控范围内,彻底杜绝了数据泄露风险。
2.2 成本与响应速度 GPT-4V等闭源模型API调用是按次计费的,在自动化测试这种需要高频截屏、分析的场景下,长期成本会非常可观。而本地部署的模型,一次部署,无限次使用。虽然2B参数的模型在理解能力上可能略逊于千亿级模型,但对于GUI自动化这种相对“刻板”的任务(识别按钮、输入框、文本),其精度已经足够。更重要的是,本地推理的延迟是稳定的,不受网络波动影响,这对于需要确定性的自动化流程至关重要。
2.3 模型尺寸与硬件门槛 “2B”意味着20亿参数,这在多模态模型中属于“轻量级”。它可以在消费级显卡(如RTX 3060 12GB)上流畅运行,甚至通过量化技术(如INT4、INT8)在只有CPU的机器上也能以可接受的速度推理。这大大降低了尝试和部署的门槛。相比之下,更大的视觉模型(如Qwen-VL-72B)需要昂贵的专业显卡,不适合作为常驻的测试服务。
2.4 指令跟随(Instruct)能力 这个模型后缀中的“Instruct”非常关键。它意味着模型被专门训练来理解和遵循用户的指令。我们的工作流是:给模型一张截图和一句如“请点击‘登录’按钮”的指令。Instruct版本模型更擅长将这种开放式指令,转化为对图片中特定区域的关注和描述,从而输出我们需要的坐标信息。非Instruct版本的视觉模型可能更倾向于描述整张图片,而不是执行具体操作。
2.5 与现有工具链的整合 我们并非要取代Selenium或Playwright,而是增强它们。我们的架构是“大模型决策 + 传统框架执行”。Qwen3-VL负责“感知”和“规划”,识别出目标;PyAutoGUI、pywinauto或Playwright自身则负责“执行”,执行点击、输入等底层操作。这种松耦合的设计,使得我们可以利用现有自动化框架的稳定性和丰富功能,同时注入大模型的灵活性。
注意: 这里的一个核心认知转变是,我们从“基于元素属性的定位”转向了“基于视觉语义的定位”。前者依赖HTML/DOM结构,后者依赖模型对像素画面的理解。后者天生对UI的变化更具鲁棒性。
3. 环境搭建与模型部署:从零开始的实操指南
理论说完,我们进入实战。第一步是把模型跑起来。整个过程我会在Linux(Ubuntu 22.04)和Windows 11下分别说明,确保大家都能复现。
3.1 基础Python环境准备 首先需要一个干净的Python环境(推荐3.9或3.10),使用conda或venv创建。
# 创建并激活虚拟环境
conda create -n qwen_vl_test python=3.10 -y
conda activate qwen_vl_test
3.2 关键依赖安装 我们需要安装模型推理框架、图像处理库和自动化操作库。
# 安装PyTorch(请根据你的CUDA版本到官网选择命令)
# 例如,CUDA 11.8
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# 安装Transformers和加速库(用于模型加载和推理)
pip install transformers accelerate
# 安装Pillow用于图像处理
pip install Pillow
# 安装屏幕截图和自动化操作库
# 方案一:跨平台的PyAutoGUI(推荐初学者)
pip install pyautogui
# 方案二:Windows原生控件操作(对Windows应用支持更好)
pip install pywinauto
# 方案三:Web自动化(可结合使用)
pip install playwright
playwright install chromium
# 安装模型可能需要的额外依赖
pip install timm einops
3.3 下载与加载Qwen3-VL-2B-Instruct模型 这里我们使用Hugging Face的 transformers 库来加载模型。模型文件较大(约几个GB),建议在网络通畅的环境下进行。
from transformers import Qwen3VLForConditionalGeneration, AutoTokenizer
from PIL import Image
import torch
# 指定模型路径(Hugging Face Hub上的模型ID)
model_name = "Qwen/Qwen3-VL-2B-Instruct"
# 加载tokenizer和模型
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
# 注意:首次运行会下载模型,需要较长时间和足够磁盘空间
model = Qwen3VLForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.float16, # 使用半精度减少显存占用
device_map="auto", # 自动分配模型层到GPU/CPU
trust_remote_code=True
).eval() # 设置为评估模式
print("模型加载完毕!")
实操心得: 如果显卡显存不足(比如小于8GB),可以将
torch_dtype改为torch.float32甚至结合device_map=”cpu”在CPU上运行,但速度会慢很多。更优的方案是使用量化版本,社区可能有提供GGUF或GPTQ格式的量化模型,能大幅降低资源需求。
3.4 设计你的第一个提示词(Prompt)模板 与大模型沟通,提示词是关键。我们需要设计一个能让模型稳定输出坐标的提示词。
经过多次测试,一个有效的模板如下:
你是一个GUI自动化助手。我将给你一张软件界面截图和一个任务指令。
你的任务是:1. 理解指令。2. 在图中找到指令对应的可操作元素(如按钮、输入框)。3. 以JSON格式输出该元素的中心点坐标。
坐标格式为:{“x”: x坐标, “y”: y坐标},坐标原点在图片左上角。
只输出JSON,不要有任何其他解释。
截图:[IMAGE]
指令:{user_instruction}
这个模板明确了角色、任务、输出格式,并强制要求“只输出JSON”,这对于后续程序解析至关重要。
4. 核心工作流实现:截图、分析与执行
环境准备好后,我们来搭建核心的自动化循环: 截图 -> 模型分析 -> 执行操作 。
4.1 屏幕截图与预处理 我们需要捕获当前屏幕或特定窗口的图像,并可能进行一些预处理(如缩放)以适应模型输入。
import pyautogui
from PIL import Image
import json
import re
def capture_screen(region=None):
"""
截取屏幕。
:param region: 一个四元组 (left, top, width, height),指定截取区域。None为全屏。
:return: PIL.Image对象
"""
# pyautogui截图返回的是PIL.Image对象
screenshot = pyautogui.screenshot(region=region)
# 模型可能有最大分辨率限制,这里缩放到适合的尺寸,例如1024x1024
target_size = (1024, 1024)
screenshot.thumbnail(target_size, Image.Resampling.LANCZOS)
return screenshot
# 示例:截取全屏
current_screen = capture_screen()
4.2 调用模型进行分析 将截图和用户指令组合成模型能理解的输入。
def analyze_with_qwenvl(model, tokenizer, image_pil, instruction):
"""
使用Qwen3-VL模型分析图片,根据指令返回目标坐标。
"""
# 构建消息列表,符合Qwen-VL的对话格式
messages = [
{
"role": "user",
"content": [
{"type": "image"},
{"type": "text", "text": instruction}
]
}
]
# 将图片和文本信息预处理为模型输入
# 注意:这里使用了模型特定的预处理方法 `apply_chat_template`
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 准备图像输入
image_inputs = model.image_preprocess(image_pil)
# 将文本和图像输入转换为模型可接受的输入ID和像素值
inputs = tokenizer(
text,
return_tensors="pt",
padding=True
).to(model.device)
# 将图像数据也放到正确的设备上
image_inputs = {k: v.to(model.device) for k, v in image_inputs.items()}
inputs.update(image_inputs)
# 生成回答
with torch.no_grad(): # 禁用梯度计算,加快推理速度
generated_ids = model.generate(
**inputs,
max_new_tokens=100, # 限制生成长度
do_sample=False, # 贪婪解码,保证输出稳定性
temperature=0.1,
)
# 解码生成的文本
generated_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
# 从生成的文本中提取JSON部分
# 模型可能会在JSON前后添加一些话,我们需要用正则表达式提取
json_match = re.search(r'\{.*\}', generated_text, re.DOTALL)
if json_match:
json_str = json_match.group()
try:
coord = json.loads(json_str)
return coord
except json.JSONDecodeError:
print(f"模型返回了非标准JSON: {generated_text}")
return None
else:
print(f"模型未返回JSON: {generated_text}")
return None
# 示例:分析截图,寻找登录按钮
instruction = “点击‘登录’按钮”
coordinates = analyze_with_qwenvl(model, tokenizer, current_screen, instruction)
if coordinates:
print(f"找到目标坐标:{coordinates}")
else:
print(“模型未能识别出目标。”)
4.3 执行自动化操作 拿到坐标后,我们需要将其转换为屏幕上的绝对坐标(因为截图可能被缩放),然后执行操作。
def execute_click(coord, screen_region=None):
"""
根据模型返回的坐标(相对图片)和截图区域,执行点击操作。
:param coord: 字典 {“x”: x, “y”: y},图片内的相对坐标。
:param screen_region: 截图时的区域 (left, top, width, height)。如果是全屏则为None。
"""
if not coord or ‘x’ not in coord or ‘y’ not in coord:
print(“坐标无效,无法执行点击。”)
return
img_x, img_y = coord[‘x’], coord[‘y’]
if screen_region:
# 如果截取了部分屏幕,需要将图片坐标映射回屏幕坐标
left, top, width, height = screen_region
# 假设图片缩放过,这里需要知道缩放比例。简化处理:假设截图后未缩放,或已知缩放因子。
# 更严谨的做法:记录截图时的实际屏幕区域和图片处理后的尺寸。
scale_x = width / current_screen.width
scale_y = height / current_screen.height
screen_x = left + img_x * scale_x
screen_y = top + img_y * scale_y
else:
# 全屏截图,且图片缩放过,需要计算缩放比例
screen_width, screen_height = pyautogui.size()
scale_x = screen_width / current_screen.width
scale_y = screen_height / current_screen.height
screen_x = img_x * scale_x
screen_y = img_y * scale_y
# 移动鼠标并点击
pyautogui.moveTo(screen_x, screen_y, duration=0.5) # 添加移动动画,更拟人
pyautogui.click()
print(f“已在屏幕位置({screen_x:.0f}, {screen_y:.0f})执行点击。”)
# 执行点击
if coordinates:
execute_click(coordinates)
4.4 组合成一个完整的自动化任务 现在,我们将上述步骤组合起来,完成一个“打开记事本并输入文字”的简单自动化流程。
import time
def automate_with_vision(model, tokenizer, task_steps):
"""
执行一个多步骤的自动化任务。
:param task_steps: 列表,每个元素是一个字典,包含‘instruction’和可选的‘wait’(等待秒数)。
"""
for step in task_steps:
instruction = step[‘instruction’]
wait_time = step.get(‘wait’, 2) # 默认等待2秒让界面稳定
print(f“执行指令: {instruction}”)
time.sleep(wait_time)
# 1. 截图
screen = capture_screen()
# 2. 模型分析
coords = analyze_with_qwenvl(model, tokenizer, screen, instruction)
if coords:
# 3. 执行操作(这里假设都是点击)
execute_click(coords)
else:
print(f“步骤‘{instruction}’执行失败,停止流程。”)
break
# 定义一个任务:打开Windows运行框(Win+R),输入notepad,回车
# 注意:这个任务需要你的桌面是Windows且开始菜单已知
task = [
{‘instruction’: ‘按下键盘上的Win键’, ‘wait’: 1}, # 这个指令需要特殊处理,见下文说明
{‘instruction’: ‘点击屏幕左下角的“搜索”框’, ‘wait’: 2},
{‘instruction’: ‘在搜索框中输入“notepad”’, ‘wait’: 1}, # 输入也需要特殊处理
{‘instruction’: ‘点击搜索结果中的“记事本”应用’, ‘wait’: 3},
]
# 由于涉及键盘操作和输入,我们需要扩展execute_click函数
注意事项: 上述示例中,
按下Win键和输入文字不是简单的点击操作。我们需要扩展执行器,使其能处理不同类型的指令。这引出了下一个关键点: 动作空间的抽象 。
5. 动作抽象与流程设计:超越简单点击
一个完整的GUI自动化,不仅仅是点击。它应该包括: 点击(Click)、输入(Type)、悬停(Hover)、拖拽(Drag)、滚动(Scroll)、读取(Read) 等。我们需要设计一个更强大的系统。
5.1 定义动作枚举和参数 我们可以让模型不仅输出坐标,还输出建议的动作类型。或者,由我们的控制逻辑根据指令语义来决定动作。
from enum import Enum
import pyautogui
class ActionType(Enum):
CLICK = “click”
DOUBLE_CLICK = “double_click”
RIGHT_CLICK = “right_click”
TYPE = “type”
PRESS_KEY = “press_key” # 按下某个键,如 Enter, Tab
HOVER = “hover”
DRAG_TO = “drag_to”
SCROLL = “scroll”
READ_TEXT = “read_text” # 从图片中读取文本
def execute_action(action_type, coord=None, text=None, key=None, **kwargs):
"""
执行一个抽象的动作。
"""
screen_x, screen_y = None, None
if coord:
# 转换坐标(复用之前的逻辑)
screen_x, screen_y = _convert_coordinates(coord)
if action_type == ActionType.CLICK:
if screen_x and screen_y:
pyautogui.click(screen_x, screen_y)
elif action_type == ActionType.TYPE:
if text:
pyautogui.write(text, interval=0.1) # 以0.1秒的间隔输入
elif action_type == ActionType.PRESS_KEY:
if key:
pyautogui.press(key)
elif action_type == ActionType.HOVER:
if screen_x and screen_y:
pyautogui.moveTo(screen_x, screen_y)
# ... 其他动作的实现
else:
print(f“未支持的动作类型:{action_type}”)
5.2 增强提示词以输出结构化动作 我们可以修改提示词,让模型直接输出包含动作和坐标的JSON。
你是一个GUI自动化助手。我将给你一张软件界面截图和一个任务指令。
你的任务是:1. 理解指令。2. 判断需要执行的动作类型(click, type, press_key等)。3. 找到目标位置(如果需要)。4. 以JSON格式输出。
JSON格式必须严格遵循以下示例:
- 点击:{“action”: “click”, “coordinates”: {“x”: 100, “y”: 200}}
- 输入文字:{“action”: “type”, “text”: “hello world”}
- 按键:{“action”: “press_key”, “key”: “enter”}
- 组合:{“action”: “click_and_type”, “coordinates”: {“x”: 100, “y”: 200}, “text”: “abc”} (如果需要先点击再输入)
只输出JSON,不要有任何其他解释。
截图:[IMAGE]
指令:{user_instruction}
5.3 设计鲁棒的任务流程 一个健壮的自动化流程需要容错和验证机制。
- 循环检测与超时: 如果模型一次没识别到,可以尝试小范围移动鼠标后重新截图识别,循环几次。
- 验证点(Checkpoint): 关键步骤后,截图让模型验证是否成功。例如,点击登录后,让模型判断“当前界面是否出现了‘登录成功’或用户头像”。
- 条件分支: 根据验证结果决定后续流程。这需要模型具备一定的判断能力(“请判断当前页面是登录成功页面还是失败页面”)。
def robust_click(model, tokenizer, instruction, max_attempts=3, region=None):
"""
鲁棒的点击操作,尝试多次直到成功或超限。
"""
for attempt in range(max_attempts):
screen = capture_screen(region)
coords = analyze_with_qwenvl(model, tokenizer, screen, instruction)
if coords:
execute_click(coords, region)
# 点击后等待并验证
time.sleep(1)
verify_screen = capture_screen(region)
# 可以添加一个验证指令,比如“是否还在登录页面”
# 如果验证失败,可以break或重试
return True
else:
print(f“第{attempt+1}次尝试识别‘{instruction}’失败。”)
# 可以轻微晃动鼠标或滚动一下屏幕,改变界面状态再试
pyautogui.moveRel(10, 10, duration=0.2)
pyautogui.moveRel(-10, -10, duration=0.2)
print(f“经过{max_attempts}次尝试,仍无法识别‘{instruction}’,流程终止。”)
return False
6. 性能优化与实战技巧:让流程更快更稳
直接使用原始模型进行每一次推理,速度可能无法满足高频测试需求。以下是一些优化技巧:
6.1 模型量化 使用 bitsandbytes 库进行4位或8位量化,能大幅降低显存占用,在CPU上推理速度也可能更快。
from transformers import BitsAndBytesConfig
import torch
quantization_config = BitsAndBytesConfig(
load_in_4bit=True, # 4位量化
bnb_4bit_compute_dtype=torch.float16
)
model = Qwen3VLForConditionalGeneration.from_pretrained(
model_name,
quantization_config=quantization_config, # 加入量化配置
device_map=“auto”,
trust_remote_code=True
).eval()
6.2 缓存与预热 对于不变的界面元素(如软件的主菜单栏),可以首次识别后缓存其坐标,后续直接使用,无需重复调用模型。
6.3 图像预处理优化
- 局部截图: 不要总是截全屏。如果知道目标大致区域(如弹窗总是在中间),只截取相关区域,能减少图像数据量,加快模型处理速度。
- 分辨率调整: 模型有最佳输入分辨率。将截图缩放到模型训练时常用的尺寸(如448x448, 1024x1024),比直接输入高分辨率原图效果更好、更快。
6.4 提示词工程
- 具体化指令: “点击那个蓝色的、写着‘提交’的按钮”比“点击提交按钮”更好。
- 提供上下文: 对于复杂任务,可以在历史消息中提供前几步的截图和指令,帮助模型理解任务流(多轮对话能力)。
- 负面示例: 在系统提示词中告诉模型“不要点击灰色的不可用按钮”。
6.5 与现有框架结合 不要试图用Qwen-VL完全重写所有测试用例。将其用于最棘手的部分:
- 动态内容识别: 列表中新增加的条目。
- 非标准控件操作: 自定义绘制的图表、游戏界面。
- 视觉验证: 断言某个图标是否出现、页面布局是否正确。
- 辅助定位: 先用模型找到某个复杂区域的参考点,再用相对坐标进行传统自动化操作。
例如,在Playwright脚本中嵌入视觉判断:
import asyncio
from playwright.async_api import async_playwright
# ... 假设有上面的模型分析函数 ...
async def hybrid_test():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto(‘https://example.com/login’)
# 传统方式:填充已知输入框
await page.fill(‘#username’, ‘testuser’)
await page.fill(‘#password’, ‘password123’)
# 难点:登录按钮是动态生成的,没有稳定selector
# 步骤1:用Playwright截图
screenshot_bytes = await page.screenshot()
image_pil = Image.open(io.BytesIO(screenshot_bytes))
# 步骤2:用Qwen-VL识别登录按钮并点击
coords = analyze_with_qwenvl(model, tokenizer, image_pil, “点击登录按钮”)
if coords:
# 将图片坐标转换为页面坐标(需要计算比例)
viewport_size = await page.viewport_size()
img_width, img_height = image_pil.size
scale_x = viewport_size[‘width’] / img_width
scale_y = viewport_size[‘height’] / img_height
page_x = coords[‘x’] * scale_x
page_y = coords[‘y’] * scale_y
await page.mouse.click(page_x, page_y)
await browser.close()
7. 常见问题、局限性与应对策略
在实际使用中,你肯定会遇到各种问题。以下是我踩过的一些坑和解决方案:
7.1 模型识别不准或找不到元素
- 可能原因1:截图质量。 确保截图清晰,目标元素完整可见。避免模糊、遮挡或动态模糊(如滚动中)。
- 可能原因2:指令模糊。 “点击那个按钮”可能指代不明。改为“点击右上角红色的‘关闭’按钮”。
- 可能原因3:模型能力边界。 2B模型对非常细小、密集或图标抽象的控件识别可能有限。尝试放大截图区域或使用更详细的描述。
- 解决方案: 实现上文提到的
robust_click重试机制。结合传统方法,如果模型多次失败,可以回退到基于坐标的备选方案(如果位置相对固定)。
7.2 坐标映射错误
- 问题: 模型返回的是图片内的坐标,但屏幕分辨率、缩放比例(尤其是Windows的显示缩放设置为125%、150%)会导致点击位置偏移。
- 解决方案: 在坐标转换函数
_convert_coordinates中,必须考虑系统显示缩放因子。可以通过ctypes调用Windows API或使用screeninfo库获取真实的屏幕缩放比例。
import ctypes
try:
# Windows DPI感知
awareness = ctypes.c_int()
ctypes.windll.shcore.GetProcessDpiAwareness(0, ctypes.byref(awareness))
scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100
except:
scale_factor = 1.0 # 非Windows或获取失败,默认为1
def _convert_coordinates(coord, screen_region, screenshot_img):
# ... 原有计算 ...
screen_x *= scale_factor
screen_y *= scale_factor
return screen_x, screen_y
7.3 处理动态界面和等待
- 问题: 点击后界面需要时间加载,模型在加载完成前就截图,会导致识别错误。
- 解决方案: 在每一步操作后加入显式等待(
time.sleep),或更优的是,实现基于视觉的智能等待。例如,循环截图并询问模型“进度条是否消失了?”或“‘加载中’的提示文字是否还在?”,直到条件满足再继续。
7.4 处理列表、表格等重复元素
- 问题: 指令“点击第三个条目”对于模型来说较难,因为它需要计数。
- 解决方案: 让模型识别列表区域,然后由自动化脚本计算相对位置。或者,指令改为“点击名为‘张三’的那一行”,利用模型的文本识别能力。
7.5 成本与速度考量
- 问题: 本地模型推理即使优化后,单次调用也可能需要几百毫秒到几秒,不适合对速度要求极高的超高频操作。
- 解决方案: 将其用于测试用例的“编排”和“关键断言”环节,而不是每一个细小的操作。或者,考虑使用更小的、专门针对GUI元素检测微调过的视觉模型(如基于YOLO微调的),与大模型结合,前者负责快速定位,后者负责复杂理解和决策。
7.6 错误处理与日志 必须建立完善的日志系统,记录每一步的截图、指令、模型返回结果和执行动作。当测试失败时,这些日志是宝贵的调试依据。可以将每次模型调用前的截图和指令保存下来,用于后续分析模型识别失败的原因,甚至可以作为数据来微调模型。
折腾下来,我的体会是,用Qwen3-VL-2B-Instruct做GUI自动化,目前最适合的场景是 辅助测试、快速原型和解决特定难题 。它不是一个能完全替代传统自动化框架的银弹,而是一个强大的“胶水”和“增强组件”。对于测试工程师来说,掌握这套方法,意味着你手里多了一件应对复杂、多变UI界面的利器。尤其是面对那些“测不准”的痛点时,不妨试试让大模型来“看”一眼,或许就有意想不到的收获。
更多推荐
所有评论(0)