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

    文章

    4666

    浏览量

    125466
  • AI
    AI
    +关注

    关注

    87

    文章

    27475

    浏览量

    265149
  • GPT
    GPT
    +关注

    关注

    0

    文章

    333

    浏览量

    15099
收藏 人收藏

    评论

    相关推荐

    risc-v多核芯片在AI方面的应用

    应用中的成本。 最后,RISC-V多核芯片不仅可以应用于AI边缘计算领域,还可以扩展到其他领域,如数据中心、云计算、自动驾驶、机器人等,为这些领域提供高效、灵活和安全的解决方案。 总的来说,RISC-
    发表于 04-28 09:20

    怎样使用STM32MP157A-DK1探索板的m4和SAI协议音频开发,比如录音?

    怎样使用STM32MP157A-DK1探索板的m4和SAI协议音频开发,比如录音? M4的开发包没有audio codec的接口可以使用,如何初始化codec,音量控制? 新人小白求
    发表于 04-11 06:53

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

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

    微软推出首个专为Windows定制的Agent

    随着人工智能技术的飞速发展,全球科技巨头纷纷在这一领域布局。OpenAI以其强大的技术实力在视频领域掀起了一场革命,而微软则悄然对传统用户界面发起了挑战。近日,微软最新发布了一款名为UFO(UI-Focused Agent)的Agent
    的头像 发表于 02-19 11:41 541次阅读

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

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

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

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

    新火种AI|从GPT-5到AI芯片厂,山姆·奥特曼在下一盘多大的棋?

    标题:从GPT-5到AI芯片厂,山姆·奥特曼在下一盘多大的棋? 转发语:山姆·奥特曼暴露野心,同时挑战英伟达和台积电?
    的头像 发表于 01-26 09:54 255次阅读
    新火种<b class='flag-5'>AI</b>|从<b class='flag-5'>GPT</b>-5到<b class='flag-5'>AI</b>芯片厂,山姆·奥特曼在下一盘多大的棋?

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

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

    AGI时代的奠基石:Agent+算力+大模型是构建AI未来的三驾马车吗?

    AI Agent的训练离不开算力,服务器作为一个强大的计算中心,为AI Agent提供算力基础,支持其进行复杂计算和处理大规模数据的任务,包括模型训练、推理和处理大规模数据集。
    的头像 发表于 12-21 13:34 904次阅读
    AGI时代的奠基石:<b class='flag-5'>Agent</b>+算力+大模型是构建<b class='flag-5'>AI</b>未来的三驾马车吗?

    HamronyOS自动测试框架使用指南

    概述 为支撑 HarmonyOS 操作系统的自动测试活动开展,我们提供了支持 JS/TS 语言的单元及 UI 测试框架,支持开发者针对应用接口进行单元
    发表于 12-19 10:26

    为什么Agent落地这么难?AI最大赛道Agent机遇全解析

    “如果一篇论文提出了某种不同的训练方法,OpenAI内部会嗤之以鼻,认为都是我们玩剩下的。但是当新的AI Agent论文出来时,我们会十分认真且兴奋地讨论。普通人、创业者和极客在构建AI Agents方面相比OpenAI这样的公
    的头像 发表于 11-25 15:54 1580次阅读
    为什么<b class='flag-5'>Agent</b>落地这么难?<b class='flag-5'>AI</b>最大赛道<b class='flag-5'>Agent</b>机遇全解析

    我们心中AI Agent的现在和未来

    在大模型技术上领先的 OpenAI 同样对 AI Agent 十分感兴趣,它们的首席科学家 Ilya Sutskever 不止一次表达过 OpenAI 对 AI Agent 技术的关注
    的头像 发表于 11-09 16:20 476次阅读

    采用 STM32H750 探索套件的无线测温集中器的UI设计

    采用 STM32H750 探索套件的无线测温集中器的UI设计
    的头像 发表于 09-27 15:41 641次阅读
    采用 STM32H750 <b class='flag-5'>探索</b>套件的无线测温集中器的<b class='flag-5'>UI</b>设计

    【KV260视觉入门套件试用体验】八、VITis AI自动驾驶多任务执行MultiTask V3

    d58cbda2-97976be7__640x360.avi MultiTask V3 旨在同时执行自动驾驶场景中的不同任务,同时实现优异的性能和效率。这些任务包括对象检测、分 割、车道检测、可行驶区域分割和深度估算,这些都是自动
    发表于 09-26 16:43

    直播倒计时 | 《GPT 时代人类再腾飞》新书共读

    增强人类的能力。7 月 19 日,我们诚邀您收看新书共读活动直播,聆听大咖分享,探索未来的可能性。点击下方【预约】按钮,即可预约直播。 下面,让我们一起来读读微软前全球副总裁陆奇博士推荐序“参与和探索AI新时代”,以及微软全球资
    的头像 发表于 07-19 00:15 446次阅读
    直播倒计时 | 《<b class='flag-5'>GPT</b> 时代人类再腾飞》新书共读