0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用 GPT4V+AI Agent 做自动 UI 测试的探索

京东云 来源:jf_75140285 作者:jf_75140285 2024-06-20 15:42 次阅读

一、背景

从 Web 诞生之日起,UI 自动化就成了测试的难点,到现在近 30 年,一直没有有效的手段解决Web UI测试的问题,尽管发展了很多的 webdriver 驱动,图片 diff 驱动的工具,但是这些工具的投入产出比一直被质疑,自动化率越多维护成本越高,大部分都做着就放弃了,还有一部分在做与不做间纠结。

本文结合一些开源的项目探索使用GPT 自动做 UI 测试的可能性。

二、方案选型

当前UI 的主要问题:一个是通过 Webdriver 控制浏览器执行,这些工具都需要先查找到对应元素的 Elements,无论是录制的还是自己编写的在面对 UI 变化,元素变化时都需要耗费很大的精力去重新识别,解析 Dom 查找,这个工作乏味且没有效率;另一种是通过图像进行点击,比如 Sikuli 这种工具,主要的问题也是复用性较差,换个分辨率的机器或者图片发生少的改动就不可用。

使用 GPT 做 UI 测试尝试了两种方案:

第一种将 Html 元素投喂给 GPT,主要方法获取 Html代码,对 Html 做初步缩减处理,再做向量化,然后喂给 GPT4 自动生成 Webdriver 驱动脚本,效果一般,而且因为 Html 比较大,Token 的消耗很大。

第二种思路是让 GPT 像人一样思考和测试,比如一个人打开一个网页后,他通过眼睛看到的页面文字或图标,然后用手完成点击和输入的操作,最后通过页面的弹窗或者文字来识别是否有错误,这几个动作通过大脑统一协调。

这里主要介绍第二种.

三、新方案实践

1.新方案简介

新的方案主要结合 Playwright,SoM视觉标记,GPT4Vison,GPT4,AutoGen来实现。主要的原理

通过 Playwright进行浏览器操作,包括页面图像的获取、浏览器的各种操作,相当于‘‘手’’;

进行SoM 视觉数据标记,因为 GPT4Vison 在进行页面原始识别时并不是很准确,参考微软的论文可以通过视觉标记的手段来辅助 GPT4V 识别,相当于“眼睛”。

通过GPT4+AutoGen 将这些步骤串起来实现协调控制,相当于“大脑”和“神经中枢”。

2.主要架构



wKgaomZz3VOAPrwVAAH-GDO9wd0403.png

3.实现步骤

1. 使用 Playwright 注入 JS

browser = playwright.chromium.launch(channel="chrome",headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("http://oa.jd.com/")
inject_js ="./pagemark.js"
withopen(inject_js,'r')asfile:
    content =file.read()
    page.evaluate(f"{content}")

2. SoM 视觉提示标记

如前文提到的 GPT4V 并不能有效的识别 Web 的元素,所以在使用 GPT4V 之前进行图像标记,图像标记现在有两种方式,一种是通过 AI 识别图片进行标记,这种主要利用在对静态图片图像的识别,对于 Web 页面的标记,我们可以采用注入 JS 修改页面元素的方式来标记。这里通过在浏览器中注入 pagemark.js,利用 Playwright 执行 js 函数来完成页面的标记,该 JS 能够完成标准的coco annotation的标注。

// DOM Labelerlet labels =[];functionunmarkPage(){
 for(const label of labels){
 document.body.removeChild(label);
 }

 labels =[];
 }

 functionmarkPage(){
 unmarkPage();
 
 var bodyRect = document.body.getBoundingClientRect();

 var items =Array.prototype.slice.call(
 document.querySelectorAll('*')
 ).map(function(element){
 var vw = Math.max(document.documentElement.clientWidth ||0, window.innerWidth ||0);
 var vh = Math.max(document.documentElement.clientHeight ||0, window.innerHeight ||0);
 
 var rects =[...element.getClientRects()].filter(bb=>{
 var center_x = bb.left + bb.width /2;
 var center_y = bb.top + bb.height /2;
 var elAtCenter = document.elementFromPoint(center_x, center_y);
  
  return elAtCenter === element || element.contains(elAtCenter) 
 }).map(bb=>{
 const rect ={
 left: Math.max(0, bb.left),
 top: Math.max(0, bb.top),
 right: Math.min(vw, bb.right),
 bottom: Math.min(vh, bb.bottom)
  };
  return{
 ...rect,
 width: rect.right - rect.left,
 height: rect.bottom - rect.top
  }
  });

  var area = rects.reduce((acc, rect)=> acc + rect.width * rect.height,0);

 return{
 element: element,
 include: 
 (element.tagName ==="INPUT"|| element.tagName ==="TEXTAREA"|| element.tagName ==="SELECT")||
 (element.tagName ==="BUTTON"|| element.tagName ==="A"||(element.onclick !=null)|| window.getComputedStyle(element).cursor =="pointer")||
 (element.tagName ==="IFRAME"|| element.tagName ==="VIDEO")
 ,
 area,
 rects,
 text: element.textContent.trim().replace(/s{2,}/g,' ')
 };
 }).filter(item=>
 item.include &&(item.area >=20)
 );

 // Only keep inner clickable items
 items = items.filter(x=>!items.some(y=> x.element.contains(y.element)&&!(x == y)))

 // Function to generate random colors
 functiongetRandomColor(){
 var letters ='0123456789ABCDEF';
 var color ='#';
 for(var i =0; i < 6; i++){
 color += letters[Math.floor(Math.random()*16)];
 }
 return color;
 }

 // Lets create a floating border on top of these elements that will always be visible
 items.forEach(function(item, index){
 item.rects.forEach((bbox)= >{
 newElement = document.createElement("div");
 var borderColor =getRandomColor();
 newElement.style.outline =`2px dashed ${borderColor}`;
 newElement.style.position ="fixed";
 newElement.style.left = bbox.left +"px";
 newElement.style.top = bbox.top +"px";
 newElement.style.width = bbox.width +"px";
 newElement.style.height = bbox.height +"px";
 newElement.style.pointerEvents ="none";
 newElement.style.boxSizing ="border-box";
 newElement.style.zIndex =2147483647;
 // newElement.style.background = `${borderColor}80`;
 // Add floating label at the corner
 var label = document.createElement("span");
 label.textContent = index;
 label.style.position ="absolute";
 label.style.top ="-19px";
 label.style.left ="0px";
 label.style.background = borderColor;
 label.style.color ="white";
 label.style.padding ="2px 4px";
 label.style.fontSize ="12px";
 label.style.borderRadius ="2px";
 newElement.appendChild(label);
 
 document.body.appendChild(newElement);
  labels.push(newElement);
  console.log(index)
  
  });
  })
 }

以某系统为例,标注后的效果如下图:

wKgZomZz3VSARCAcAAchE3Vf-v4276.png

将标记元素的位置编号保存到本地coco.json

{ 
    "1":{"x":"10","y":"40","w":"8","h":"10","center_x":"30","center_y":"13"}, 
    "2":{"x":"20","y":"40","w":"16","h":"10","center_x":"30","center_y":"21"}, 
    "10":{"x":"40","y":"80","w":"16","h":"10","center_x":"80","center_y":"21"}}

其中 center_x, center_y 为元素的中心点坐标

3.GPT4V 识别

Prompt

我上传了一张网页截图,页面元素已经使用COCO Annotator进行了数字标记。
请分析这张图片,并识别出网页的用途以及各个标记元素的功能。基于你的分析,请生成一个规划路径来完成以下任务:
- 输入ERP搜索。            
- 检查列表是否为空            
请使用图片中的数字标记来描述完成任务的具体步骤。

GPT4V Response

这张图片显示的是一个具有多个数字标记的网页截图。根据这些标记,我们可以推测出网页的用途以及各个元素的功能。
为了完成您提出的任务,我们可以按照以下步骤操作:
nn1. 使用标记为10的搜索框输入ERP搜索词。这个搜索框的标签显示为“搜索框输入erp”,表明它用于输入搜索词。
nn2. 点击标记为17的搜索按钮。这个按钮的标签是“搜索”,表明它用于提交搜索请求。
nn3. 检查列表是否为空。这个步骤可能需要查看标记为19的区域,这个区域被标记为“列表内容”,如果这个区域没有显示任何内容或者有提示信息显示列表为空,则说明搜索结果为空。
nn以 上步骤基于图片中的数字标记和元素标签来描述完成任务的具体操作。"

提取元素坐标

利用正则表达式从GPT4V 的 response 中提取查询到的元素的 bbox id= 10,17,19, 结合在 SoM 标记中记录的 json 文件,找到编号 10 的元素坐标"10":{"x":"40","y":"80","w":"16","h","10","center_x":"80","center_y":"21"}

class GPT4VRecognize
     def get_location(self, query):  
         coco_json='./coco.json'
         withopen(coco_json,'r') as file: 
             content =file.read() 
         matches=re.findall(r'd+',gpt4v_response_content)
         num=-1
         iflen(matches)>0:
             num=matches[0]
         data = json.loads(json_str) 
         center_x = data[num]["center_x"]
         center_y = data[num]["center_y"]
         return center_x,center_y
  

4.Playwright操作页面

Playwright是一个非常强大的操作浏览器的工具,这里因为前面已经通过 GPT4V 识别了图片,所以我们主要通过 坐标 的方式来控制元素,不再需要解析Dom 来控制,主要的包括,点击,双击,鼠标拖动,输入,截图等:

class Actions:
    page=None
    __init__(self,url):
        global page
        browser = playwright.chromium.launch(channel="chrome",headless=False)
        context = browser.new_context()
        page = context.new_page()
        page.goto("http://oa.jd.com/")
    def mouse_move(self,x,y):
        page.mouse.move(self,x,y)
    def screenshot(self):
        page.screenshot()
    def mouse_click(self,x,y):
        page.mouse.click(self,x,y)
    def input_text(self,x,y,text):
        page.mouse.click(self,x,y)
        page.keyboard.type(text) 
    def mouse_db_click(self,x,y):
    def select_option(self,x,y,option):
    ......

5.使用 AutoGen编排

AutoGen是一个代理工具,它能够代理多个 LLM在不同会话间切换,能够自动的调用预定的函数,并协调这些 LLM 完成任务。

在上面的程序中,实现了:眼睛:通过 GPT4V 来识别元素;手:通过 Playwright 来做各种操作;后面需要通过一个大脑来协调手、眼完成任务,这里通过 GPT4+AutoGen 来实现大脑的协同调度。

config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
assistant= autogen.AssistantAgent(
name="assistant",
system_message=
    """
    You are the orchestrator responsible for completing a task involving the UI window. 
    Utilize the provided functions to take a screenshot after each action. 
    Remember to only use the functions you have been given and focus on the task at hand.
     """,
 llm_config={"config_list": config_list},
)
 user_proxy = autogen.UserProxyAgent(
 name="brain_proxy",
 human_input_mode="NEVER",
 code_execution_config={"work_dir":"coding"},
 max_consecutive_auto_reply=10,
 llm_config={"config_list": config_list},)

action = Actions(url)
gpt4v=GPT4VRecognize()
user_proxy.register_function(
     function_map={
         "get_location": gpt4v.get_location,
         "mouse_move":action.mouse_move,
         "screenshot":action.screenshot,
         "mouse_click":action.mouse_click,
         "mouse_dbclick":action.mouse_dbclick,
         "select_option":action.select_option 
     })
def run(message_ask):
    user_proxy.initiate_chat(assistant,message=message_ask)

if __name__ =="__main__":
    run("通过 输入erp 'wwww30' 搜索结果,并检查是否返回空列表")
 

四、问题和后续

1.当前的主要问题

本文主要抛砖引玉,通过一种完全按人类思维进行 UI测试的方式,在实验过程中还有很多问题待解决。

1. GPT 在中文语境下识别的不太友好,在实验过程中对中文的 prompt 理解有误,需要不断的优化 prompt,尤其是页面中的中文元素。

2. AutoGen 对于处理预定义的动作也会有问题,需要不断调优。

3. GPT4V 真的很贵。

2.未来的想法

1. 将每次向 GPT4V请求的图像识别做本地化处理,结合现有的一些测试方法,从而减少 Token,缩短执行耗时。

2. 面向业务的 GPT需要不断训练,将系统使用手册和一有的 PRD 文档投喂给 GPT,增强 gpt 的系统识别和测试能力。

五、参考

1.Set-of-Mark Prompting Unleashes Extraordinary Visual Grounding in GPT-4V

2.Microsoft AutoGen

3.GPT-4V-ACT

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 测试
    +关注

    关注

    8

    文章

    5269

    浏览量

    126599
  • AI
    AI
    +关注

    关注

    87

    文章

    30728

    浏览量

    268892
  • GPT
    GPT
    +关注

    关注

    0

    文章

    352

    浏览量

    15343
收藏 人收藏

    评论

    相关推荐

    微软Dynamics365集成10大自主AI Agent,引领智能自动化新时代

    近日,微软宣布在Dynamics365中集成了10个全新的自主AI Agent,这一创新举措将为企业带来前所未有的智能自动化工作模式。这些AI Ag
    的头像 发表于 10-23 11:25 352次阅读

    OpenAI解锁GPT-4o定制功能,助力企业精准优化AI应用

    在8月21日的最新动态中,OpenAI 宣布了一项革命性的新功能,正式向企业用户开放其顶尖AI模型GPT-4o的定制能力。这一举措标志着OpenAI在激烈的企业级AI应用市场中迈出了重要一步,旨在帮助企业客户实现更精准、高效的
    的头像 发表于 08-21 16:06 457次阅读

    OpenAI 推出 GPT-4o mini 取代GPT 3.5 性能超越GPT 4 而且更快 API KEY更便宜

    OpenAI推出了GPT-4o mini模型,用来取代GPT-3.5.这是目前市场上最具成本效益的小模型。   该模型在MMLU上得分为82%, 在LMSYS排行榜上的聊天偏好测试中表现优于
    的头像 发表于 07-21 10:20 1024次阅读
    OpenAI 推出 <b class='flag-5'>GPT-4</b>o mini 取代<b class='flag-5'>GPT</b> 3.5 性能超越<b class='flag-5'>GPT</b> <b class='flag-5'>4</b> 而且更快 API KEY更便宜

    开发者如何调用OpenAI的GPT-4o API以及价格详情指南

    ​目前,OpenAI新模型GPT-4o和GPT-4 Turbo的价格如下: GPT-4o 对比 GPT-4 Turbo GPT-4o 拥有与
    的头像 发表于 05-29 16:00 1.1w次阅读
    开发者如何调用OpenAI的<b class='flag-5'>GPT-4</b>o API以及价格详情指南

    Azure AI Studio现已支持提供GPT-4o API

    微软公司在最近的Build 2024开发者大会上宣布了一个重要更新。据微软CEO萨提亚·纳德拉介绍,Azure AI Studio现已支持OpenAI开发的最新旗舰模型GPT-4o,并作为API提供。
    的头像 发表于 05-22 11:45 794次阅读

    GPT-4o更像“人”,AI“疾步”走向商业化应用

    )等。OpenAI的CEO奥特曼称之为“人类级别的响应”。GPT-4o一出,各企业开始纷纷再度亮出“家伙什”了,微软宣布投资40亿欧元加码AI领域、谷歌一夜发布十几
    的头像 发表于 05-22 08:04 497次阅读
    <b class='flag-5'>GPT-4</b>o更像“人”,<b class='flag-5'>AI</b>“疾步”走向商业化应用

    OpenAI推出面向所有用户的AI模型GPT-4o

    在周一的直播盛会上,OpenAI揭开了其最新的人工智能模型GPT-4o的神秘面纱。这款新模型旨在为其著名的聊天机器人ChatGPT提供更强大、更经济的支持。GPT-4o是此前备受瞩目的GPT-4模型的升级版,自推出以来已满一年有
    的头像 发表于 05-15 09:23 399次阅读

    OpenAI全新GPT-4o能力炸场!速度快/成本低,能读懂人类情绪

    电子发烧友网报道(文/李弯弯)当地时间5月13日,OpenAI举行春季发布会,宣布将推出桌面版ChatGPT,并发布全新旗舰AI模型GPT-4
    的头像 发表于 05-15 00:15 7817次阅读

    鸿蒙OS开发实战:【自动测试框架】使用指南

    为支撑HarmonyOS操作系统的自动测试活动开展,我们提供了支持JS/TS语言的单元及UI测试框架,支持开发者针对应用接口进行单元测试
    的头像 发表于 04-08 14:49 1372次阅读
    鸿蒙OS开发实战:【<b class='flag-5'>自动</b>化<b class='flag-5'>测试</b>框架】使用指南

    微软Copilot全面更新为OpenAI的GPT-4 Turbo模型

    起初,Copilot作为Bing Chat AI助手推出,初期采用GPT-3.5模型,随后升级至GPT-4取得显著进步,如今再次更新至性能卓越的GPT-4 Turbo模型,这无疑将使得
    的头像 发表于 03-13 13:42 724次阅读

    新火种AI|秒杀GPT-4,狙杀GPT-5,横空出世的Claude 3振奋人心!

    2024年第一季度才刚过半,AI领域就大动作不断,大家卯着劲的出新品,可谓卷出天际。   3月4日,Anthropic发布了最新的Claude 3系列模型,用Anthropic的话说,Claude
    的头像 发表于 03-06 22:22 634次阅读
    新火种<b class='flag-5'>AI</b>|秒杀<b class='flag-5'>GPT-4</b>,狙杀<b class='flag-5'>GPT</b>-5,横空出世的Claude 3振奋人心!

    Anthropic推出Claude 3系列模型,全面超越GPT-4,树立AI新标杆

    近日,AI领域的领军企业Anthropic震撼发布了全新的Claude 3系列模型,该系列模型在多模态和语言能力等关键领域展现出卓越性能,成功击败了此前被广泛认为是全球最强AI模型的GPT-4,树立了新的行业基准。
    的头像 发表于 03-05 09:49 680次阅读

    微软发布Agent框架UFO,引领UI交互新纪元

    微软近日宣布推出全新的Agent框架——UFO(UI-Focused Agent),旨在构建更智能、更直观的用户界面交互体验。该框架基于OpenAI的GPT-4V图像识别模型开发,专为
    的头像 发表于 02-19 11:15 1185次阅读

    谷歌DeepMind资深AI研究员创办AI Agent创企

    近日,刚从谷歌DeepMind离职的资深AI研究员Ioannis Antonoglou宣布创办了一家名为“AI Agent”的创企。Ioannis Antonoglou常驻伦敦,此前曾担任谷歌DeepMind的首席开发人员,自去
    的头像 发表于 02-04 10:02 784次阅读

    AI Agent爆发在即!深剖AI Agent技术原理及发展趋势

    电子发烧友网报道(文/李弯弯)AI Agent指人工智能代理,是一种能够感知环境、进行决策和执行动作的智能实体。AI Agent通常基于机器学习和人工智能技术,具备自主性和自适应性,在
    的头像 发表于 01-12 01:01 3957次阅读