news 2026/8/10 5:13:39

音乐应用UI自动化测试实战:从Appium框架选型到播放状态验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
音乐应用UI自动化测试实战:从Appium框架选型到播放状态验证

1. 项目概述:为什么音乐应用是UI自动化测试的“硬骨头”?

做UI自动化测试的同行,估计都听过一个说法:音乐类应用是自动化测试的“地狱级”副本。这话一点不假。几年前,我接手一个主流音乐App的自动化项目时,也是这么想的。界面元素动态加载、音频播放状态难以捕获、复杂的用户交互流(比如收藏、评论、滑动切歌),还有那无处不在的个性化推荐和广告弹窗,每一个点都足以让传统的录制回放脚本瞬间崩溃。

但恰恰是这些挑战,让音乐应用成为了锤炼UI自动化技能的绝佳沙场。它几乎涵盖了移动端和桌面端应用UI测试的所有典型难题:状态依赖、异步操作、非标准控件、多媒体内容验证。把这个“副本”打通了,你手里掌握的就不再是几个孤立的脚本,而是一套能应对复杂场景的自动化工程方法和实战经验。今天,我就以一次真实的音乐应用UI自动化实战为例,拆解从零到一构建稳定、可维护测试套件的完整思路、技术选型、核心实现以及那些只有踩过坑才知道的“避雷”技巧。

2. 整体方案设计与框架选型

面对一个功能完备的音乐应用,直接上手写脚本是最大的忌讳。第一步必须是顶层设计,明确测试范围、技术栈和框架。

2.1 核心测试场景与需求拆解

首先,我们把音乐应用的核心用户旅程(User Journey)梳理出来,转化为可测试的自动化场景:

  1. 核心播放流程:启动App -> 搜索歌曲 -> 点击播放 -> 验证播放状态(播放图标、进度条、时间) -> 暂停/继续 -> 切歌(上一首/下一首)-> 退出。
  2. 媒体库与用户交互:登录 -> “我的收藏”列表加载与点击 -> 创建/删除歌单 -> 歌曲添加到歌单/从歌单移除。
  3. UI状态与响应:在不同网络状态(Wi-Fi/4G/弱网)下,首页推荐、榜单等Feed流的加载与渲染。滑动列表时,元素是否正常回收与复用。
  4. 跨页面流程:从播放页点击歌手头像进入歌手主页,再返回,播放是否中断或继续。

这些场景的共同特点是:强状态依赖(播放状态影响按钮UI)、异步操作密集(网络请求、图片加载)、需要模拟真实用户操作(滑动、长按)。因此,我们的框架必须能优雅地处理等待、可靠地定位元素、并支持复杂的操作链。

2.2 主流UI自动化框架横向对比

市面上框架很多,选型的核心是匹配项目技术栈和团队能力。以下是针对移动端(以Android/iOS原生或React Native等跨平台应用为例)的常见选择:

框架核心优势适用场景在音乐应用测试中的考量
Appium跨平台(Android, iOS, 甚至桌面)、支持多种语言(Java, Python, JS等)、社区生态庞大。需要同时覆盖多端UI测试,团队语言栈不统一。首选。对原生和混合应用支持良好,能处理音乐App常见的WebView组件(如活动页)。通过UIAutomator2(Android)和XCUITest(iOS)驱动,稳定性较高。
Espresso (Android) / XCTest (iOS)官方出品,运行速度快,与开发环境集成度极高。纯原生应用,追求极致的执行速度和稳定性,测试代码与App代码同仓库管理。备选。如果团队是原生开发主导,且测试深度绑定业务代码(如测试特定ViewModel逻辑),可以考虑。但跨端需要维护两套脚本,学习成本双倍。
Airtest / Poco基于图像识别和UI控件树,对游戏或重度自定义UI的应用友好,脚本编写直观。应用UI变化频繁,或包含大量非标准控件、Canvas绘制的元素。特殊情况。如果音乐App有大量炫酷的动画效果(如播放页的频谱可视化),传统控件定位失效时,可作为补充。但图像识别对设备分辨率、亮度敏感,稳定性是挑战。
Cypress / Playwright针对Web应用,速度快,自带调试工具,自动等待机制优秀。App内嵌了大量H5页面(如会员中心、活动专题页)。补充角色。主要用于测试App内的WebView内容。可以与Appium组合使用,实现“原生+Web”的全链路覆盖。

实操心得:对于大多数综合性的音乐应用,我推荐“Appium为主,Cypress/Playwright为辅”的方案。Appium解决90%以上的原生页面测试,用专门的Web测试工具来攻克内嵌H5的复杂交互,这样工具链最清晰,维护成本相对可控。

2.3 项目结构与技术栈落地

确定了Appium为主力后,我们规划项目结构,这直接关系到后续的协作效率和脚本可维护性。

music_app_ui_auto/ ├── config/ # 配置文件 │ ├── capabilities.json # 设备与App配置(应用包名、活动名、设备UDID等) │ └── pytest.ini # 测试运行配置 ├── pages/ # 页面对象模型(Page Object) │ ├── base_page.py # 页面基类,封装公共方法(查找、等待、滑动) │ ├── home_page.py # 首页页面类 │ ├── search_page.py # 搜索页面类 │ ├── player_page.py # 播放器页面类 │ └── my_music_page.py # 我的音乐页面类 ├── test_cases/ # 测试用例 │ ├── test_playback.py # 播放相关测试用例 │ ├── test_search.py # 搜索相关测试用例 │ └── test_playlist.py # 歌单相关测试用例 ├── utils/ # 工具类 │ ├── driver_manager.py # 单例模式管理Appium Driver │ ├── logger.py # 自定义日志模块 │ └── common_actions.py # 通用操作封装(如处理权限弹窗) ├── reports/ # 测试报告输出目录 ├── conftest.py # Pytest共享Fixture(如驱动初始化、清理) └── requirements.txt # Python依赖包列表

技术栈说明

  • 语言:Python。语法简洁,生态丰富(Pytest, Allure),适合测试快速开发。
  • 测试框架:Pytest。功能强大,Fixture机制非常适合管理测试生命周期(如启动/关闭App)。
  • 报告:Allure。生成美观的交互式报告,便于查看步骤、截图和错误信息。
  • 设备管理:如果有多设备并行需求,可以引入appium-device-farmSelenium Grid的思路,但初期单设备调试即可。

3. 核心难点解析与实战解决方案

音乐应用的UI自动化有三大“拦路虎”:异步加载、播放状态验证、复杂手势。下面我们逐个击破。

3.1 异步加载与智能等待策略

音乐App的首页、榜单、歌单列表都是动态加载的。使用time.sleep()是绝对的下策。我们必须使用显式等待(Explicit Wait)

错误示范

# 糟糕的硬编码等待 search_box = driver.find_element_by_id("com.music.app:id/search_box") search_box.click() time.sleep(5) # 魔法数字,网络慢时可能不够,快时又浪费 results = driver.find_elements_by_class_name("android.widget.TextView")

正确实践:封装一个健壮的等待查找方法在base_page.py中。

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from appium.webdriver.common.appiumby import AppiumBy class BasePage: def __init__(self, driver): self.driver = driver def wait_for_element(self, locator, timeout=10, poll_frequency=0.5): """等待元素出现并返回该元素""" try: element = WebDriverWait(self.driver, timeout, poll_frequency).until( EC.presence_of_element_located(locator) ) return element except TimeoutException: # 这里可以结合截图和日志,方便排查 self.driver.save_screenshot(f"timeout_{locator}.png") self.logger.error(f"元素 {locator} 在 {timeout} 秒内未找到。") raise def wait_for_element_clickable(self, locator, timeout=10): """等待元素可点击""" return WebDriverWait(self.driver, timeout).until( EC.element_to_be_clickable(locator) ) # 在页面对象中使用 class SearchPage(BasePage): SEARCH_BOX = (AppiumBy.ID, "com.music.app:id/search_box") SEARCH_RESULT_ITEM = (AppiumBy.XPATH, "//android.widget.TextView[contains(@text, '周杰伦')]") def search_song(self, keyword): # 等待搜索框出现并点击 search_box = self.wait_for_element_clickable(self.SEARCH_BOX) search_box.click() search_box.send_keys(keyword) # 等待搜索结果出现,这里用presence_of_all_elements_located等待至少一个结果 WebDriverWait(self.driver, 15).until( EC.presence_of_all_elements_located(self.SEARCH_RESULT_ITEM) ) # 然后才进行后续操作,比如点击第一个结果 results = self.driver.find_elements(*self.SEARCH_RESULT_ITEM) if results: results[0].click()

避坑指南:对于音乐App的Feed流(如“每日推荐”),列表元素可能不会一次性全部加载。单纯的presence_of_element_located可能只等到第一个元素就返回了。此时,更佳策略是结合自定义等待条件,例如等待列表元素数量达到某个阈值,或者等待某个特定的“加载完成”标识(如“没有更多了”的TextView)出现。

3.2 播放状态验证:超越UI,触及核心

点击播放按钮后,如何断言“歌曲真的在播放”?只看播放按钮图标变成“暂停”是不够的,因为可能遇到UI更新了但音频流未加载成功的边缘情况。

多维度验证策略

  1. UI状态验证:检查播放按钮的selected属性或图片资源ID是否变为“暂停”状态。
  2. 进度条动态验证:等待并检查播放进度条(SeekBar)的progress属性是否在短时间内(如3秒后)大于0且在增长。这是比静态UI更可靠的指标。
  3. 系统音频焦点(Android):对于更底层的验证,可以尝试通过adb shell dumpsys audio命令检查音频焦点状态。但这需要App有相应权限,且更偏向系统级测试。
  4. 网络请求监听(高级):在测试开始时,通过代理工具(如MitmProxy)或Appium的performancecapability监听网络请求。当点击播放后,验证是否有对应的媒体文件(.mp3, .m4a)的请求发出且返回状态码为206(部分内容)或200。

代码示例(结合UI与进度条)

class PlayerPage(BasePage): PLAY_BUTTON = (AppiumBy.ID, "com.music.app:id/play_pause_btn") SEEK_BAR = (AppiumBy.ID, "com.music.app:id/play_seekbar") CURRENT_TIME = (AppiumBy.ID, "com.music.app:id/current_time") def play_and_verify(self): """点击播放并验证播放状态""" play_btn = self.wait_for_element_clickable(self.PLAY_BUTTON) play_btn.click() # 验证1: 按钮状态变为“暂停”(假设暂停按钮resource-id不同或selected=true) # 这里需要根据实际App的UI实现来定位暂停按钮或检查属性 # 例如,如果播放和暂停是同一个按钮,通过selected属性判断 time.sleep(2) # 给UI和音频缓冲一点时间 is_paused = play_btn.get_attribute("selected") # 或其他属性,如`content-desc` assert is_paused == 'true', "播放后按钮未变为暂停状态" # 验证2: 进度条在前进 initial_progress = self.driver.find_element(*self.SEEK_BAR).get_attribute("progress") time.sleep(3) # 等待几秒 later_progress = self.driver.find_element(*self.SEEK_BAR).get_attribute("progress") assert float(later_progress) > float(initial_progress), f"进度条未前进。初始: {initial_progress}, 之后: {later_progress}" # 验证3: 当前时间文本在更新 initial_time_text = self.driver.find_element(*self.CURRENT_TIME).text time.sleep(2) later_time_text = self.driver.find_element(*self.CURRENT_TIME).text assert later_time_text != initial_time_text, "播放时间未更新" self.logger.info("播放状态验证通过。")

3.3 复杂手势与滑动操作优化

歌单列表、歌词滚动、切换Tab都需要精准的滑动。Appium提供了TouchActionW3C ActionsAPI。关键点是计算滑动的起止坐标,并控制滑动速度

通用滑动方法封装

from appium.webdriver.common.touch_action import TouchAction class BasePage: # ... 其他代码 ... def swipe_up(self, duration_ms=800): """从屏幕中部向上滑动""" size = self.driver.get_window_size() start_x = size['width'] * 0.5 start_y = size['height'] * 0.7 end_x = size['width'] * 0.5 end_y = size['height'] * 0.3 action = TouchAction(self.driver) action.press(x=start_x, y=start_y).wait(duration_ms).move_to(x=end_x, y=end_y).release().perform() def swipe_to_find_element(self, locator, max_swipes=5, direction='up'): """滑动查找元素,适用于无限滚动列表""" for _ in range(max_swipes): try: element = self.driver.find_element(*locator) if element.is_displayed(): return element except: pass if direction == 'up': self.swipe_up(duration_ms=1000) # 查找时滑动慢一点 elif direction == 'down': self.swipe_down() time.sleep(1) # 滑动后等待内容加载 raise Exception(f"滑动 {max_swipes} 次后未找到元素: {locator}")

音乐应用特有场景歌词滚动同步验证。这需要结合滑动手势和文本断言。思路是:先获取当前播放句的歌词文本,然后手动向上滑动一段距离,再次获取当前高亮句的文本,断言两者不同,证明歌词确实随滑动或播放而更新了。

4. 完整测试用例实现与编排

有了稳固的基础设施和解决方案,我们来组装一个完整的端到端测试用例:“搜索特定歌曲并加入‘我喜欢的音乐’歌单”

4.1 测试用例设计

这个用例覆盖了:搜索、列表交互、播放器浮层操作、歌单管理。我们将其拆分为清晰的步骤,并对应到不同的页面对象。

# test_cases/test_search_and_add_to_fav.py import pytest from pages.home_page import HomePage from pages.search_page import SearchPage from pages.player_page import PlayerPage from pages.my_music_page import MyMusicPage class TestSearchAndAddToFavorites: """测试搜索歌曲并添加到‘我喜欢的音乐’""" @pytest.fixture(autouse=True) def setup(self, app_driver): # app_driver 来自 conftest.py 的 fixture self.driver = app_driver self.home_page = HomePage(self.driver) self.search_page = SearchPage(self.driver) self.player_page = PlayerPage(self.driver) self.my_music_page = MyMusicPage(self.driver) def test_search_song_and_add_to_favorites(self): """ 步骤: 1. 从首页进入搜索页 2. 搜索关键词“七里香” 3. 在结果列表中点击第一个匹配的歌曲项 4. 在播放页(或歌曲详情浮层)点击“收藏”或“喜欢”按钮 5. 返回首页,进入“我的音乐” 6. 进入“我喜欢的音乐”歌单 7. 断言歌单中存在歌曲“七里香” """ # 1. 进入搜索 self.home_page.navigate_to_search() # 2. 执行搜索 self.search_page.search_song("七里香") # 3. 点击第一个搜索结果(假设SearchPage的方法返回了歌曲条目页面对象) # 这里 search_and_enter_first_result 是一个组合方法,它完成了搜索并点击进入播放页 self.search_page.search_and_enter_first_result("七里香") # 4. 在播放页收藏歌曲 # 注意:有些App收藏按钮在播放页,有些可能在弹出的更多菜单里 self.player_page.add_current_song_to_favorites() # 可以加一个Toast验证,如果App有“已收藏”的Toast提示 # self.player_page.assert_toast_message("已添加至“我喜欢的音乐”") # 5. 返回首页并进入“我的音乐” self.player_page.navigate_back_to_home() # 封装多次back直到首页 self.home_page.navigate_to_my_music() # 6. 进入“我喜欢的音乐”歌单 self.my_music_page.enter_favorite_playlist() # 7. 断言歌单列表包含目标歌曲 favorite_songs = self.my_music_page.get_song_list_in_playlist() song_titles = [song['title'] for song in favorite_songs] # 假设方法返回包含标题的字典列表 assert "七里香" in song_titles, f"‘我喜欢的音乐’歌单中未找到‘七里香’,当前列表:{song_titles}" # 8. (可选)清理测试数据:移除刚添加的歌曲,保证用例可重复执行 self.my_music_page.remove_song_from_favorites("七里香")

4.2 页面对象(Page Object)的精髓

上面用例读起来像自然语言,这归功于页面对象模式。每个页面类封装了该页面的元素定位和操作。以PlayerPage的部分为例:

# pages/player_page.py class PlayerPage(BasePage): # 定位器 MORE_MENU_BTN = (AppiumBy.ACCESSIBILITY_ID, "更多选项") # 使用无障碍ID更稳定 ADD_TO_FAV_BTN = (AppiumBy.XPATH, "//*[@text='收藏' or @text='喜欢' or contains(@content-desc, '收藏')]") FAVORITES_CONFIRM = (AppiumBy.ID, "com.music.app:id/add_to_fav_confirm") PLAYING_SONG_TITLE = (AppiumBy.ID, "com.music.app:id/song_title") def add_current_song_to_favorites(self): """将当前播放的歌曲添加到‘我喜欢的音乐’""" # 点击更多菜单 self.wait_for_element_clickable(self.MORE_MENU_BTN).click() # 在弹出菜单中点击收藏 self.wait_for_element_clickable(self.ADD_TO_FAV_BTN).click() # 如果有确认对话框(如添加到哪个歌单),点击确认 try: confirm_btn = WebDriverWait(self.driver, 3).until( EC.element_to_be_clickable(self.FAVORITES_CONFIRM) ) confirm_btn.click() self.logger.info("已点击收藏确认按钮。") except TimeoutException: # 没有确认对话框是正常情况 self.logger.info("无收藏确认对话框,操作完成。") # 等待一个短暂的UI反应时间 time.sleep(1) def get_current_song_title(self): """获取当前播放歌曲的标题""" title_element = self.wait_for_element(self.PLAYING_SONG_TITLE) return title_element.text

核心技巧:定位器优先使用resource-idaccessibility_id,它们通常最稳定。其次是xpath,但尽量使用相对路径和属性组合,避免绝对路径,因为UI结构一变就失效。像//android.widget.TextView[@text="七里香"]就比一长串的绝对路径要好得多。

5. 常见问题排查与稳定性提升

即使设计得再好,在真实设备上运行UI自动化脚本也总会遇到各种“妖”。下面是我总结的几个高频问题及应对策略。

5.1 元素定位失败:动态ID与多上下文

问题:今天还能找到的com.music.app:id/title,明天可能就变成了com.music.app:id/title_abcdefg(动态生成)。或者,一点击WebView,元素就找不到了。

解决方案

  1. 对抗动态ID:使用其他稳定属性组合定位,如textcontent-descclass。或者与开发约定,为关键测试元素设置稳定的accessibilityId(在Android是contentDescription,iOS是accessibilityIdentifier)。
  2. 处理WebView:Appium需要在Native和WebView上下文之间切换。使用driver.contexts获取所有上下文,然后切换到对应的WebView上下文(通常名字包含WEBVIEW_)。
    # 切换到WebView上下文 webview_context = None for context in self.driver.contexts: if 'WEBVIEW' in context: webview_context = context break if webview_context: self.driver.switch_to.context(webview_context) # 现在可以使用Selenium的方式定位Web元素了 element = self.driver.find_element(By.CSS_SELECTOR, ".song-name") # 操作完成后,切回Native上下文 self.driver.switch_to.context('NATIVE_APP')

5.2 测试偶发性失败:弹窗与中断

问题:测试正执行着,突然弹出“评价提醒”、“消息推送”、“网络异常Toast”,脚本卡住或点错地方。

解决方案:在BasePage或一个全局的before each操作中,封装一个“弹窗清理”方法。

def dismiss_random_popups(self): """尝试关闭常见的干扰弹窗""" common_popup_selectors = [ (AppiumBy.ID, "com.music.app:id/btn_cancel"), # 更新弹窗取消 (AppiumBy.ID, "com.android.packageinstaller:id/permission_deny_button"), # 权限拒绝(可能) (AppiumBy.XPATH, "//*[@text='以后再说' or @text='忽略' or @text='我知道了']"), ] for locator in common_popup_selectors: try: # 快速查找,不等待 element = self.driver.find_element(*locator) if element.is_displayed(): element.click() self.logger.warning(f"已关闭弹窗: {locator}") time.sleep(0.5) # 关闭后稍作停顿 except: pass

在关键操作(如点击、输入)前调用这个方法。但要注意,不要误关测试需要的对话框。

5.3 性能与稳定性:截图、日志与重试机制

问题:测试在CI/CD上跑,失败了不知道现场发生了什么。

解决方案

  1. 失败自动截图:利用Pytest的@pytest.hookimpl钩子,或在BasePage的异常捕获中自动截图。
    # conftest.py import pytest from datetime import datetime @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield rep = outcome.get_result() if rep.when == "call" and rep.failed: driver = item.funcargs.get('app_driver') if driver: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") screenshot_path = f"./reports/screenshots/failure_{item.name}_{timestamp}.png" driver.save_screenshot(screenshot_path) rep.extra = [{"type": "image", "name": "失败截图", "value": screenshot_path}]
  2. 结构化日志:使用Python的logging模块,为不同级别(INFO, DEBUG, ERROR)配置输出到文件和控制台,在关键步骤(如页面跳转、元素操作)记录日志。
  3. 重试机制:对于网络波动等导致的偶发失败,可以使用pytest-rerunfailures插件,为不稳定的用例添加重试次数。
    pytest test_cases/ --reruns 2 --reruns-delay 2

5.4 数据依赖与测试隔离

问题:测试用例“搜索周杰伦并播放”依赖于歌曲“周杰伦”必须存在于搜索库中。或者,测试“添加歌曲到歌单”会污染线上用户的真实数据。

解决方案

  1. 使用测试专用数据:与后端开发协调,搭建一套测试环境,并准备稳定的测试数据池(如固定的测试歌手、歌曲)。
  2. 用例自清理:每个可能修改数据的用例,最后一步都应该是清理自己产生的数据(如取消收藏、删除测试歌单),如上面用例中的remove_song_from_favorites
  3. Mock外部依赖:对于极不稳定的依赖(如第三方版权歌曲接口),可以在测试框架层使用Mock,返回固定的、预期的响应,确保UI流程可测。但这需要更复杂的架构支持。

UI自动化测试,尤其是对于音乐这样复杂的应用,从来不是一蹴而就的。它更像是一个持续迭代、不断加固的过程。从核心流程开始,逐步覆盖边缘场景,不断优化定位策略和等待机制,补充必要的监控和排查手段。这套实战经验的核心,不在于记住了多少Appium的API,而在于建立起一套应对UI不确定性的系统性思维:如何设计健壮的定位器?如何编写可读可维护的页面对象?如何让脚本在充满变数的真实环境中依然可靠?把这些想明白了,任何应用的UI自动化测试,你都能找到突破口。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/10 5:13:37

WPF中使用MaterialDesignInXAML实现现代化UI

1. MaterialDesignInXAML 项目概述MaterialDesignInXAML 是一个开源的 WPF 控件库,它将 Google 的 Material Design 设计语言完美地带到了 Windows Presentation Foundation (WPF) 应用程序中。作为一名长期从事 WPF 开发的工程师,我可以负责任地说&…

作者头像 李华
网站建设 2026/8/10 5:13:10

VS Code 1.110智能体插件功能详解与应用实践

1. Visual Studio Code 1.110版本核心更新解析微软于2024年4月发布了VS Code 1.110稳定版,这次更新中最引人注目的莫过于智能体插件功能的开发者预览。作为代码编辑器领域的标杆产品,VS Code此次更新再次展现了其在AI辅助编程方向的战略布局。智能体插件…

作者头像 李华
网站建设 2026/8/10 5:12:09

弹唱党怎么买第一把或长期主力吉他?6款不同预算吉他参考推荐

最近很常见的一类提问是:我主要想学弹唱,到底该看大桶、看木材,还是先看品牌?这几个点当然都重要,但如果只挑一个最先看的,我会把“人声贴不贴、扫弦顺不顺”放在最前面。因为对弹唱来说,吉他不…

作者头像 李华
网站建设 2026/8/10 5:09:29

YOLOv11涨点改进| Arxiv 2026 |独家创新、特征融合改进篇| 引入OAM正交注意力融合机制,优化浅层细节特征与深层语义特征,助力红外小目标检测,遥感目标检测、多模态融合目标检测有效涨点

一、本文介绍 🔥本文给大家介绍使用OAM正交注意力融合机制改进YOLOv11网络模型,主要作用在特征融合或解码阶段优化浅层细节特征与深层语义特征的连接过程,缓解普通注意力机制因全局池化导致的空间位置信息丢失问题。OAM 通过沿水平和垂直两个正交方向分别建模注意力,使网…

作者头像 李华
网站建设 2026/8/10 5:08:10

EdgeClaw Box:基于云边协同的AI智能体硬件平台开发实战

1. 项目概述:EdgeClaw Box,一个“两栖”AI智能体的物理化身最近在AI智能体这个圈子里,一个叫“EdgeClaw Box”的硬件产品引起了我的注意。它的创造者是面壁智能,这个名字在AI圈里不算陌生,之前他们搞的“ChatDev”和“…

作者头像 李华