Midscene.js:视觉驱动的UI自动化运行时原理与应用实践

📅 2026/6/24 17:08:15
Midscene.js:视觉驱动的UI自动化运行时原理与应用实践
1. 项目概述重新认识 Midscene.js最近在技术社区里Midscene.js 这个名字开始频繁出现很多人把它简单地理解为“用自然语言描述然后自动帮你点击按钮”的工具。如果你也这么想那可能就错过了它最核心的价值。作为一个在自动化领域摸爬滚打了十多年的老手我花了不少时间深入研究了它的源码和设计理念发现它的定位远比“点按钮”要深远得多。本质上Midscene.js 构建了一套全新的“会看屏幕的 UI 自动化运行时”。这听起来有点抽象我来打个比方。传统的 UI 自动化比如 Selenium 或 Puppeteer更像是一个“盲人指挥家”。你事先写好乐谱脚本告诉它“去点击那个 id 是 ‘submit-btn’ 的按钮。” 它很听话但前提是它必须“摸到”那个按钮通过 DOM 选择器。一旦页面结构变了按钮的 id 或 class 变了或者按钮根本还没加载出来这位“指挥家”就懵了脚本会直接报错比如你常看到的“指定窗口或窗口组件不存在或尚未载入”。而 Midscene.js 引入了一个根本性的转变它给自动化程序装上了“眼睛”和“大脑”。它的核心能力是实时理解屏幕上的视觉信息而不仅仅是依赖底层 DOM 结构。你说“点击那个蓝色的登录按钮”它真的会去“看”屏幕找到所有看起来像按钮的、蓝色的、带有“登录”文字的区域然后执行操作。这意味着你的自动化脚本第一次具备了类似人类的环境感知和自适应能力。它不是另一个录制回放工具也不是一个简单的自然语言转 API 调用的翻译器而是一个完整的、以视觉理解为驱动的运行时环境。这套运行时负责从“看到屏幕”到“理解意图”再到“执行操作”的全链路这才是它被称为“运行时”而非“库”或“框架”的原因。2. 核心原理拆解视觉驱动与意图解析的双引擎要理解 Midscene.js 为何不同我们需要拆开它的引擎盖看看里面两套并行的核心系统是如何工作的。这不仅仅是技术实现更是一种设计哲学的体现。2.1 视觉感知层从像素到语义对象传统自动化依赖的是浏览器提供的 DOM 树这是一个结构化的、确定性的信息源。Midscene.js 则选择了一条更接近人类感知的路径计算机视觉CV。它通过截取或流式获取屏幕图像可以是整个桌面也可以是某个浏览器窗口作为其感知世界的原始输入。目标检测与识别这是第一道工序。运行时内置或可集成目标检测模型如基于 YOLO 或 DETR 的变体用于在像素图像中定位和识别出基本的 UI 元素例如按钮Button、输入框Text Field、复选框Checkbox、下拉菜单Dropdown、文本标签Label、图片Image等。每个被识别出的元素除了有边框位置Bounding Box还会被打上类型标签和提取出的文本内容通过 OCR。视觉特征编码仅仅知道“那里有个按钮”还不够。Midscene.js 会为每个检测到的 UI 元素计算一组丰富的视觉特征向量。这些特征可能包括外观特征颜色直方图主色调是否为蓝色、形状描述符圆角矩形还是直角、纹理信息。文本特征通过 OCR 提取的文本内容以及文本的字体、大小、颜色。空间关系特征该元素相对于其他元素的位置例如“提交”按钮通常在表单底部“取消”按钮在它左边。上下文特征该元素所在区域的整体语义例如一个包含“用户名”和“密码”输入框的区域很可能是一个登录表单。所有这些特征被编码成一个高维向量我们称之为该 UI 元素的“视觉指纹”。这个指纹是后续进行模糊匹配和意图理解的基础。关键在于这个“视觉指纹”的生成完全不依赖于 DOM 的 id 或 class只依赖于它看起来是什么样子。这就从根本上解决了因前端代码重构、动态加载、框架差异如 React, Vue, Angular导致的元素定位失效问题。2.2 自然语言意图解析层从指令到可执行动作当用户发出“点击登录按钮”这样的指令时Midscene.js 的另一个核心引擎开始工作。这不是简单的关键词匹配。指令的语义解构首先自然语言指令被送入一个轻量级的 NLP 模块进行解析。这个模块会识别出指令中的核心动作Action和目标对象Target。动作如click,type,select,scroll,hover等。Midscene.js 维护了一个动作映射表。目标对象描述这是更精妙的部分。描述可以是属性描述“蓝色的”、“大的”、“带图标的”。文本描述“写着‘登录’的”、“包含‘搜索’文字的”。关系描述“在密码框下面的”、“最右边的那个”。复合描述“那个蓝色的、写着‘提交’的大按钮”。从描述到视觉指纹的匹配解析出的目标对象描述会被转换成一个“查询向量”。这个查询向量不是去数据库里查而是去和当前屏幕中所有 UI 元素的“视觉指纹”进行相似度计算。系统会计算查询向量与每个元素指纹的余弦相似度或欧氏距离。举个例子指令是“点击登录按钮”。查询向量会强调“文本内容包含‘登录’”和“元素类型是按钮”这两个特征。然后系统遍历所有检测到的元素计算每个元素的指纹与这个查询向量的相似度。那个文本内容是“登录”且被识别为按钮的元素相似度得分会最高。排序与决策通常系统会返回一个按相似度排序的候选列表。真正的“运行时”智能就体现在这里它并非总是选择 top-1。它会结合一些启发式规则比如可见性与可交互性被遮挡或禁用的元素即使匹配优先级也会降低。空间位置偏好对于“上面的”、“左边的”这类关系描述会加强空间权重。历史交互记录如果之前在同一场景下成功点击过某个元素下次会略微提升其置信度。最终运行时选择一个置信度最高的元素并将解析出的动作如click绑定到该元素上生成一个可执行的动作指令Action Command。注意这里有一个非常重要的设计取舍。Midscene.js 的匹配是“模糊”和“概率性”的这与传统自动化“精确”且“确定性”的定位如#submit截然不同。这带来了强大的鲁棒性但也意味着你需要接受偶尔的“误判”。它的设计目标是“在绝大多数情况下都能找到正确的元素”而不是“绝对精确”。理解这一点是用好它的前提。3. 运行时架构与工作流程理解了双引擎原理我们再来看看它们是如何协同工作构成一个完整运行时的。下图清晰地展示了从指令输入到屏幕动作的完整数据流和决策链flowchart TD A[用户输入自然语言指令br如“点击登录按钮”] -- B[NLP意图解析引擎] B -- C{解析指令} C --|提取出| D[动作: “click”] C --|提取出| E[目标描述: “文本含‘登录’ 类型为按钮”] F[屏幕像素流] -- G[视觉感知引擎] G -- H[目标检测与OCR] H -- I[为每个UI元素生成br“视觉特征指纹”] I -- J[特征匹配与排序] E -- J J -- K[生成候选元素列表br按匹配度排序] D -- L[动作执行器] K -- M[选择最佳匹配元素] M -- L L -- N[驱动系统/浏览器br执行点击操作] N -- O[观察结果br进入下一轮循环]这个工作流程揭示了 Midscene.js 作为“运行时”的本质它是一个持续运行的感知-决策-执行循环。它主动管理着从环境感知屏幕捕捉到任务执行驱动交互的整个生命周期。这与只提供 API 调用、需要用户自己管理流程的传统库有本质区别。初始化与场景绑定运行时启动后首先需要绑定到一个“屏幕源”可以是整个显示器、某个应用窗口或者一个浏览器标签页。这一步通常需要操作系统级别的权限如录屏权限。主循环Event Loop运行时进入一个主循环不断执行以下步骤感知Perception捕获当前屏幕帧送入视觉感知引擎更新当前的 UI 元素状态列表包括位置、文本、状态等。这个列表是动态的随着屏幕变化而实时更新。指令监听Instruction Listening等待用户输入。输入可以是单条自然语言指令也可以是一个预先编写的、包含多条指令的脚本脚本内部指令也可以是自然语言。规划与决策Planning Decision如图中流程所示解析指令匹配元素规划动作序列。对于复杂指令如“登录邮箱然后发送邮件”运行时内部会将其分解为多个原子动作定位邮箱输入框、输入文本、定位密码框、定位登录按钮、点击...并处理动作之间的依赖和状态判断。执行Execution通过操作系统提供的无障碍接口如 Windows 的 UI Automation, macOS 的 Accessibility API或浏览器驱动如 WebDriver执行规划好的原子动作如移动鼠标、点击、键盘输入等。观察与反馈Observation Feedback执行后运行时不会立即进行下一步。它会短暂等待并重新“感知”屏幕观察UI状态是否如预期般变化例如点击登录后是否出现了新的页面或错误提示。这个反馈机制对于处理网络延迟、动态加载的页面至关重要使得脚本具备了基本的“容错”和“等待”能力。状态管理与上下文保持运行时内部维护着一个“上下文”Context。这个上下文记录了当前可能处于哪个“场景”例如“在登录页面”、“在收件箱”以及之前成功交互过的元素信息。这有助于解决指代模糊的问题比如在登录后的页面指令“点击第一个链接”系统会结合上下文知道是在当前页面内寻找链接而不是回到登录页去找。4. 与传统UI自动化方案的深度对比为了更清晰地看到 Midscene.js 的革新之处我们将其与主流方案放在一起对比特性维度传统方案 (如 Selenium/Puppeteer)录制回放工具 (如 Selenium IDE)Midscene.js (视觉运行时)定位原理依赖DOM/CSS选择器精确但脆弱。前端微改即可导致脚本失效。录制时生成选择器同左同样脆弱。依赖视觉特征匹配不关心底层代码抗前端变更能力强。脚本编写需编程直接操作DOM API学习成本高。无代码但录制的脚本可维护性极差。自然语言或类自然语言意图导向更贴近人类思维。动态内容处理需显式编码等待逻辑WebDriverWait复杂且易出错。通常处理不好容易因加载超时失败。内置感知与等待通过持续“看”屏幕来判断状态更智能。跨平台/跨应用主要用于Web对其他桌面应用支持有限或复杂。通常仅限于浏览器。理论上可操作任何屏幕上可见的应用潜力更大。健壮性低与前端实现紧耦合。非常低。高面向视觉呈现与实现解耦。执行速度快直接调用浏览器接口。快。相对较慢涉及图像分析、OCR有计算开销。适用场景稳定Web应用的自动化测试、数据抓取。简单的、一次性的Web操作演示。快速原型、辅助工具、不稳定或常变界面的自动化、RPA机器人流程自动化。从这个对比可以看出Midscene.js 并非要取代 Selenium 在稳定Web测试中的地位而是开辟了一个新的赛道处理那些“不稳定”、“变化快”、“跨应用”或“无需深度编程”的自动化需求。比如公司内部一个老旧的、没有API的C/S客户端软件或者一个经常调整UI的运营后台用传统方法维护脚本成本极高而视觉运行时方案则能大幅降低维护负担。5. 实战应用搭建一个简易的桌面自动化助手理论说再多不如动手试一下。我们来构想一个实际场景创建一个桌面助手用语音或文字指令让它帮你打开音乐播放器并播放某一首特定的歌曲。这个流程涉及跨应用操作从指令界面到音乐软件传统自动化很难无缝衔接但用 Midscene.js 的思路可以构建原型。由于 Midscene.js 本身可能还在演进其具体API可能会变但我们可以根据其原理用现有的开源工具链模拟实现核心步骤。这里我们以 Python 生态为例组合几个库来模拟一个“简化版”的视觉运行时。5.1 环境准备与核心工具选型我们需要几个关键组件来模拟“视觉感知”和“自动化执行”视觉感知部分mss: 一个快速跨平台的屏幕截图库。opencv-python(cv2): 用于图像处理和显示。pytesseract: Google Tesseract OCR 的 Python 封装用于从图片中提取文字。ultralytics(YOLOv8): 一个简单易用的现代目标检测框架我们可以用它预训练的模型或自己标注数据训练一个简单的 UI 元素检测模型。自动化执行部分pyautogui: 跨平台的 GUI 自动化库可以控制鼠标、键盘。pygetwindow: 用于获取和操作桌面窗口。speech_recognition(可选): 如果要做语音指令输入。意图解析简化我们可以先用简单的规则匹配或关键词提取后期可以集成spaCy或Rasa NLU来增强。安装命令如下pip install mss opencv-python pytesseract pyautogui pygetwindow # 安装 YOLOv8 pip install ultralytics # 可选语音识别 pip install SpeechRecognition pyaudio5.2 核心模块代码实现我们创建几个 Python 文件来模拟运行时的核心模块。模块一screen_observer.py(视觉感知模块)这个模块负责“看”屏幕并识别出 UI 元素。import cv2 import numpy as np from mss import mss from ultralytics import YOLO import pytesseract from dataclasses import dataclass from typing import List, Tuple dataclass class UIElement: 表示一个识别出的UI元素 bbox: Tuple[int, int, int, int] # x1, y1, x2, y2 label: str # 检测出的类别如 button, input, text confidence: float text: str # 通过OCR提取的文本 visual_feature: np.ndarray None # 简化的视觉特征例如颜色直方图 class ScreenObserver: def __init__(self, model_pathui_element_detector.pt): 初始化观察者 model_path: 训练好的YOLO模型路径用于检测UI元素 self.sct mss() # 加载一个预训练的YOLO模型需自己先训练或使用通用目标检测模型微调 # 这里假设我们已经有一个能识别button, input, text的模型 self.detector YOLO(model_path) if model_path else None self.current_elements: List[UIElement] [] def capture_screen(self, monitor_id1): 捕获指定显示器的屏幕 mon self.sct.monitors[monitor_id] screenshot np.array(self.sct.grab(mon)) # mss 返回的是 BGRA 转为 BGR 供 OpenCV 使用 return cv2.cvtColor(screenshot, cv2.COLOR_BGRA2BGR) def analyze_screen(self, image): 分析屏幕图像识别UI元素并提取信息 elements [] if self.detector: # 使用YOLO进行目标检测 results self.detector(image)[0] for box in results.boxes: xyxy box.xyxy[0].cpu().numpy().astype(int) conf box.conf[0].cpu().numpy() cls int(box.cls[0].cpu().numpy()) label results.names[cls] # 裁剪出元素区域进行OCR x1, y1, x2, y2 xyxy element_img image[y1:y2, x1:x2] # 转为灰度图提升OCR精度 gray cv2.cvtColor(element_img, cv2.COLOR_BGR2GRAY) text pytesseract.image_to_string(gray, config--psm 7).strip() # psm 7 假设为单行文本 # 计算简单的颜色直方图作为视觉特征简化版 hsv cv2.cvtColor(element_img, cv2.COLOR_BGR2HSV) hist cv2.calcHist([hsv], [0, 1], None, [12, 4], [0, 180, 0, 256]) cv2.normalize(hist, hist).flatten() ui_element UIElement( bboxtuple(xyxy), labellabel, confidenceconf, texttext, visual_featurehist ) elements.append(ui_element) self.current_elements elements return elements def find_element_by_description(self, description: dict) - List[UIElement]: 根据描述查找元素简化版匹配 description: 字典例如 {text_contains: 登录, label: button} candidates [] for elem in self.current_elements: score 0.0 # 1. 匹配标签 if label in description and elem.label description[label]: score 0.4 # 2. 匹配文本包含关系 if text_contains in description and description[text_contains].lower() in elem.text.lower(): score 0.6 # 这里可以扩展更多匹配规则颜色、位置等 if score 0: candidates.append((score, elem)) # 按匹配度降序排序 candidates.sort(keylambda x: x[0], reverseTrue) return [elem for _, elem in candidates]模块二intent_parser.py(意图解析模块)这个模块负责理解用户的自然语言指令。import re class SimpleIntentParser: 一个简单的基于规则的意图解析器 ACTION_MAP { 点击: click, 打开: open, 输入: type, 双击: double_click, 右击: right_click, 按: press_key, 播放: play, 搜索: search } LABEL_MAP { 按钮: button, 输入框: input, 链接: link, 图片: image, 文字: text, 窗口: window } def parse(self, instruction: str) - dict: 解析自然语言指令返回结构化的动作和对象描述 返回格式: {action: click, target: {text_contains: 登录, label: button}} result {action: None, target: {}} # 1. 提取动作 for chi_action, eng_action in self.ACTION_MAP.items(): if chi_action in instruction: result[action] eng_action # 简单移除动作词便于后续提取目标 instruction instruction.replace(chi_action, ) break # 2. 提取目标对象描述这里用非常简单的规则 words instruction.strip().split() # 匹配标签词 for chi_label, eng_label in self.LABEL_MAP.items(): if chi_label in instruction: result[target][label] eng_label # 匹配引号内的文本或明显的名称简化处理 # 例如“播放‘夜曲’” text_match re.search(r[“](.?)[”], instruction) if text_match: result[target][text_contains] text_match.group(1) else: # 如果没有引号假设最后一个词或短语是目标名称 # 这是一个非常粗糙的假设实际需要更复杂的NLP if words: # 过滤掉常见的修饰词这里列一个简表 stop_words [那个, 这个, 一个, 大的, 蓝色的] filtered_words [w for w in words if w not in stop_words] if filtered_words: result[target][text_contains] filtered_words[-1] # 可以在这里添加更多规则提取颜色、位置等属性 # 例如如果指令包含“蓝色的”则 result[target][color] blue return result模块三action_executor.py(动作执行模块)这个模块负责执行具体的自动化操作。import pyautogui import time from screen_observer import ScreenObserver, UIElement class ActionExecutor: def __init__(self, observer: ScreenObserver): self.observer observer # 设置pyautogui安全特性鼠标移到角落可紧急停止 pyautogui.FAILSAFE True pyautogui.PAUSE 0.5 # 每个动作后暂停0.5秒 def execute(self, action: str, target_description: dict, **kwargs): 执行动作 action: click, type, open等 target_description: 目标描述字典 print(f执行动作: {action}, 目标描述: {target_description}) # 首先让观察者分析当前屏幕找到目标元素 screen_img self.observer.capture_screen() elements self.observer.analyze_screen(screen_img) candidates self.observer.find_element_by_description(target_description) if not candidates: print(f未找到匹配描述 {target_description} 的元素) return False # 选择匹配度最高的元素 target_element: UIElement candidates[0] print(f找到目标元素: {target_element.label}, 文本: {target_element.text}, 位置: {target_element.bbox}) # 计算元素的中心点 x1, y1, x2, y2 target_element.bbox center_x (x1 x2) // 2 center_y (y1 y2) // 2 # 根据动作类型执行 if action click: pyautogui.moveTo(center_x, center_y, duration0.3) pyautogui.click() print(f已在 ({center_x}, {center_y}) 位置点击) return True elif action double_click: pyautogui.moveTo(center_x, center_y, duration0.3) pyautogui.doubleClick() return True elif action type and text in kwargs: # 对于输入动作先点击输入框再输入文字 pyautogui.moveTo(center_x, center_y, duration0.3) pyautogui.click() time.sleep(0.2) pyautogui.write(kwargs[text]) return True elif action open: # “打开”动作可能比较特殊这里假设目标是可执行程序或文件 # 我们可以用操作系统的命令来打开这里简化处理 print(f执行打开操作目标: {target_description}) # 实际应用中这里可能需要调用 os.startfile() 或 subprocess return True else: print(f暂不支持的动作类型: {action}) return False模块四main_runtime.py(主运行时循环)这是我们的“简化版Midscene.js运行时”主程序。import time from screen_observer import ScreenObserver from intent_parser import SimpleIntentParser from action_executor import ActionExecutor class SimpleVisionRuntime: 一个简化的视觉自动化运行时 def __init__(self): print(初始化简化视觉运行时...) # 初始化各个模块 self.observer ScreenObserver(model_pathNone) # 此处未提供模型将跳过检测仅演示流程 self.parser SimpleIntentParser() self.executor ActionExecutor(self.observer) self.is_running False def process_instruction(self, instruction: str): 处理单条自然语言指令 print(f\n处理指令: 「{instruction}」) # 1. 解析意图 parsed self.parser.parse(instruction) print(f解析结果: {parsed}) if not parsed[action]: print(无法识别指令中的动作) return False # 2. 执行动作 success self.executor.execute( actionparsed[action], target_descriptionparsed[target] # 可以传递额外参数例如输入的文字 ) return success def run_interactive(self): 以交互模式运行 self.is_running True print(\n简化视觉运行时已启动。输入指令中文输入退出结束。) while self.is_running: try: user_input input(\n请输入指令: ).strip() if user_input.lower() in [退出, exit, quit]: self.is_running False print(运行时停止。) break if user_input: self.process_instruction(user_input) except KeyboardInterrupt: print(\n用户中断。) self.is_running False except Exception as e: print(f处理指令时出错: {e}) if __name__ __main__: runtime SimpleVisionRuntime() # 这里为了演示我们直接调用一个测试指令 # 注意由于我们没有真正的UI检测模型这里主要展示流程 print( 演示流程开始 ) # 模拟场景假设我们想让助手“点击登录按钮” # 在实际运行前你需要确保屏幕上有一个包含“登录”文字的区域 test_instruction 点击登录按钮 runtime.process_instruction(test_instruction) print(\n 演示流程结束 ) print(提示要完整运行你需要) print(1. 训练或获取一个能检测按钮、输入框的YOLO模型。) print(2. 调整 find_element_by_description 中的匹配逻辑。) print(3. 扩展 intent_parser 以支持更复杂的指令。)5.3 运行与调试要点运行这个简化版运行时你会更深刻地理解 Midscene.js 的原理和挑战模型是关键ScreenObserver中使用的 YOLO 模型是整个系统的眼睛。你需要收集大量包含按钮、输入框、图标等UI元素的截图并进行标注训练一个专属的检测模型。通用目标检测模型如 COCO 预训练在 UI 元素检测上效果通常不好。这是最大的工程门槛。OCR 精度pytesseract的精度受字体、背景、光照影响很大。在实际应用中可能需要针对特定软件的字体进行微调或者使用更先进的 OCR 服务如 PaddleOCR。意图解析的复杂性我们的SimpleIntentParser极其简陋。真实的指令如“点击登录按钮下面那个灰色的链接”会涉及空间关系需要更复杂的解析。可以考虑集成如Rasa这样的对话式AI框架来提升理解能力。执行可靠性pyautogui的坐标点击是“绝对”的如果窗口移动了就会点错地方。更健壮的做法是结合pygetwindow先定位目标窗口并将坐标转换为窗口相对坐标后再操作。性能考量全屏幕截图目标检测OCR 是非常耗时的操作可能每秒只能处理几帧FPS。在实际产品中Midscene.js 肯定会做大量优化比如区域截图只对变化区域或感兴趣区域进行分析。缓存机制如果界面没有变化则复用上一帧的分析结果。模型轻量化使用更小、更快的神经网络模型如 MobileNet 作为 YOLO 的骨干网络。6. 应用场景与未来展望通过上面的原理拆解和实战模拟我们可以更准确地定位 Midscene.js 这类技术的应用场景快速自动化原型Rapid Automation Prototyping当你需要快速为一个没有API或自动化接口的软件创建一个自动化流程时视觉运行时可以让你用自然语言描述任务快速验证想法的可行性而无需等待开发团队提供接口或学习复杂的逆向工程。面向非开发者的自动化工具Citizen Developer RPA业务人员、运营人员可以用他们最熟悉的语言自然语言来描述重复的电脑操作由运行时来执行。这极大地降低了自动化的使用门槛。UI 变化频繁的自动化测试对于敏捷开发、UI 经常变动的项目如创业公司早期产品维护基于 DOM 的自动化测试脚本成本高昂。视觉测试对 UI 变化的容忍度更高只要核心功能点的“样子”和“文字”没变测试脚本就能继续工作。跨平台、跨应用的复杂工作流传统的自动化框架往往被限制在单一平台或应用内。视觉运行时“看到什么就能操作什么”的特性使其天然适合编排涉及多个独立软件的工作流例如从邮箱客户端下载附件用特定软件打开提取数据再填入网页表单。无障碍辅助技术为视障人士或行动不便者提供通过语音或简单指令控制电脑的另一种可能。系统可以持续描述屏幕内容并执行用户的语音指令。未来的挑战与演进方向精度与速度的平衡如何在保证高准确率的同时降低计算延迟达到实时交互的水平。复杂指令的理解如何处理多步骤、带条件分支“如果出现错误弹窗就点击取消”、涉及记忆“找到我刚才看过的那个文档”的复杂指令。3D 与游戏界面当前的 CV 技术主要针对 2D 平面界面。对于游戏、3D 设计软件等复杂界面需要全新的感知模型。隐私与安全持续截取和分析屏幕内容涉及极高的隐私风险。必须在本地完成所有处理并确保数据不被泄露。Midscene.js 所代表的“视觉驱动UI自动化运行时”范式正在模糊人类指令与机器操作之间的鸿沟。它可能不会完全取代传统的、基于 API 的自动化方法但在那些需要灵活性、适应性和低代码的领域它无疑打开了一扇新的大门。对于开发者而言理解其原理有助于我们思考如何将类似的“感知-决策”循环应用到更广泛的自动化场景中。