Appium UiAutomator2 Server深度解析:架构、配置与实战排障

作为长期跟移动端UI自动化打交道的人,我对Appium UiAutomator2 Server的情绪有点复杂。刚开始接触时,它只是Appium安装目录里一个不起眼的apk文件,直到在真实项目里连续遇到点击不生效、元素查找超时、设备莫名掉线这类问题,我才被逼着去扒它的底层机制,也才真正理解了它在整个Android UI自动化测试链条里的分量。Appium UiAutomator2 Server简单来说就是一个跑在Android设备端的执行代理,它接收电脑端Appium下发的自动化指令,调用系统级UI自动化能力去完成点击、输入、滑动、读取页面结构这些动作,再把结果原样送回测试端。如果你正准备搭建Android平台的UI自动化测试,或者已经在用Appium但一直没搞明白这个server到底干了什么,这篇文章会很有用。我会从架构、搭建、配置、脚本落地到排障,把你可能遇到的关键问题一次性讲清楚,顺便把那些文档里不会写的坑也摆出来。

1. 为什么要为UI自动化单独设一个Server

1.1 从老方案到UiAutomator2的切换逻辑

在Appium 1.x早期,Android端自动化方案主要依赖两条技术线:一条是Instrumentation体系,另一条是Selendroid。Instrumentation擅长在单个应用内部做测试,但遇到跨应用跳转、处理系统级弹窗、切换输入法这些场景就非常吃力,因为传统的测试框架受到系统权限和进程模型的限制,拿不到外部窗口的控制权。Selendroid更是因为在Android系统更新后缺乏维护,API兼容性问题越来越严重,跑一次用例要修的兼容性Bug,比用例本身还多。

Appium团队把默认驱动换成基于UiAutomator2的方案之后,设备端就需要一个独立的辅助服务来承接指令。为什么不能单纯用adb命令去操作手机界面?原因在于adb通道本身不适合高频交互。一条adb shell命令要经过桥接、解析、权限校验,延迟高不说,返回结果还经常因为转义和编码变得不可信,一旦遇到系统动画或者页面刷新,整个过程很容易超时。于是设计上干脆在设备端放一个常驻的socket服务,电脑端通过端口转发和它建立长连接,把自动化指令直接送进去。这个常驻在设备端的小服务,就是标题里的UiAutomator2 Server。

1.2 UiAutomator2 Server到底解决了什么问题

它解决了三个层次的问题。第一是稳定性。设备端进程常驻,避免了每条命令都走完整adb链路,操作和结果通过socket传输,速度快很多,也大大降低了命令丢失和字符转义出错的风险。第二是能力边界。因为它构建在现代UI自动化框架之上,可以直接拿到界面层级结构,对WebView、混合应用、复杂自定义控件都有比较完整的支持,而老方案在这些场景里往往只能靠坐标硬点。第三是可扩展性。Server可以随时向设备端追加执行能力,比如注入脚本、定制等待策略,这些能力不会要求测试端做过多复杂处理。

提示:如果你手里还有老版本Appium的自动化脚本,在切换到新版框架时,不能只看“Appium版本升级了”就以为没问题。驱动一旦变化,元素定位、等待方式、甚至部分API的行为都可能不同,回归测试是必须做的。

2. 核心架构拆解:测试请求如何在设备上落地

2.1 三个组件,各管一段

要想真正理解UiAutomator2 Server,必须先理清整个链路上有哪些参与者。我习惯把它拆成三块:电脑端的Appium Server、电脑端的UiAutomator2 Driver插件、设备端的UiAutomator2 Server与配套的Settings服务。

组件运行位置主要职责技术形态
Appium Server电脑端监听测试脚本发来的HTTP请求,按会话路由给对应driverNode.js进程
UiAutomator2 Driver电脑端解析W3C WebDriver协议命令,维护设备连接与会话状态Appium扩展模块
UiAutomator2 Server设备端执行点击、滑动、查找元素、获取层级等具体UI操作Android apk,长驻socket服务
Settings服务设备端配合调整输入法、权限、网络状态等系统参数Android apk

你写测试脚本时,真正对话的对象是HTTP接口层面,也就是电脑端的Appium Server。UiAutomator2 Driver是Appium Server和物理设备之间的翻译官,它负责把WebDriver标准的命令翻译成设备端server能理解的执行任务。设备端那个apk像是一个被派到手机里的执行员,拿到任务后调用Android系统UI自动化能力,做出真实操作。平时我们经常说的“Appium在设备上自动装的包”,指的就是设备端那个server apk和配套的settings apk。

2.2 一次点击操作的全链路流转

用一次点击按钮动作来串一遍流程会更清楚:

  1. 测试脚本通过WebDriver协议发送一个点击元素命令,目标地址是Appium Server监听的端口(默认4723)。
  2. Appium Server根据当前会话绑定的driver类型,把请求交给UiAutomator2 Driver。
  3. Driver检查设备连接状态,确保adb已经建立端口转发。设备端的server默认监听8200这类端口,Driver会把电脑端的一个随机端口或固定systemPort映射到设备端的8200。
  4. Driver把“点击某个元素”的命令封装成JSON消息,通过socket发到设备端server。
  5. 设备端server解析消息,调用UI自动化框架找到目标元素并执行点击。
  6. 执行结果、错误信息、截图等数据按原路返回,最终回到测试脚本的响应里。

这里最关键的一步是端口转发。adb forward会把电脑端的某个端口映射到手机端,相当于在两者之间拉了一条专线,自动化命令不需要每次都开shell会话,而是直接通过这条专线来回传输。之所以要单独配置systemPort,是因为多设备并行时,每台设备都要有独立的映射端口,否则命令就分不清该发给哪台手机了。

2.3 UiAutomator2 Server的生命周期管理

设备端server并不是无限制一直待在后台。通常第一次创建自动化会话时,Appium会自动把两个apk推送到手机的临时目录(常见路径是/data/local/tmp/),然后启动server进程。如果设备端已经存在旧版本,Appium还会比对版本并升级。会话期间server保持监听状态;会话结束或者超时,它会自动退出,释放端口和内存。Appium在异常关闭后再次启动时,也会主动清理设备上的残留端口和进程,防止新旧会话互相干扰。

配套的settings apk主要照顾那些不通过正常应用代码很难改的系统设置,比如切换输入法、授权弹窗、修改网络状态。自动化最常用的“中文输入不乱码”能力,实际上就依赖settings服务去激活系统里预置的输入法,而不是真的靠测试代码硬塞字符串。

3. 环境准备与快速搭建:让Server先跑起来

3.1 基础依赖清单

搭建环境这件事,看起来简单,但版本不匹配会浪费大量时间。我给自己总结了一套固定版本组合:

  • Node.js:建议18以上,新版Appium对老版本Node支持不好,安装driver容易报错。
  • Java:建议使用8或11,Android构建工具链和部分依赖对Java版本有硬性要求。
  • Android SDK:必须包含platform tools和build tools,至少要有一个已安装的Android平台版本。
  • 连接设备:真机或模拟器都可以,真机要开启USB调试,模拟器要确保adb能识别。

有人会问,Appium明明是Node.js写的,为什么还要Java和Android SDK?因为UiAutomator2 Driver在启动时会调用Android构建工具,生成并安装测试资源,而设备端的UI自动化框架本身是Java体系,整个链路没法绕开Java。这就是新手最容易困惑的地方。

3.2 安装命令走一遍

在命令行里依次执行:

npm install -g appium appium driver list appium driver install uiautomator2

其中appium driver install uiautomator2会是真正把设备端server相关资源下载到本地的命令。安装完成后,可以用appium driver list确认它处于可用的状态。

还有一个非常推荐的工具叫appium-doctor,它会自动检查环境中各项依赖是否就绪。运行:

appium-doctor --android

它会逐项检查Android SDK路径、Java环境、Node版本、以及必要的系统环境变量。如果出现红色的失败项,基本就是后续自动化跑不起来的直接原因。

3.3 最小化启动验证

环境装好后,先别急着写复杂脚本。我的习惯是先用一个最简会话验证链路通不通:

  1. 手机连接电脑,执行adb devices确认设备被识别,注意检查设备状态是否显示为device。
  2. 启动Appium服务,看到监听4723端口的日志。
  3. 在验证脚本里只设置最基本的capabilities,让server完成启动并打开一个空白页面。
  4. 观察Appium日志中是否出现“auto install apk”这样的片段,出现就说明设备端server已经正确安装。

如果在第三步出现超时或者安装失败,通常要往两个方向排查:一是设备端是不是禁止了来自电脑端的安装,二是设备Android版本是否过低,无法兼容当前版本的server apk。

3.4 三个新手容易踩的环境坑

第一个坑是Node版本过低。很多旧教程都推荐Node 12,但新版Appium的依赖树已经很庞大,低版本Node安装扩展时经常直接报语法错误。第二个坑是只装了Android Studio自带的模拟器,但忘记安装platform tools,导致adb命令不可用。第三个坑是设备与电脑之间有多个adb版本冲突,尤其是某些手机厂商的自带驱动和官方adb打架,表现就是设备时连时断,自动化跑一会儿就掉线。

4. 配置项解读:真正控制UiAutomator2 Server的关键参数

4.1 必备Capabilities逐个说

desired capabilities是自动化请求里的参数列表,它决定了会话以什么方式启动。与UiAutomator2 Server关系最紧密的几个必须说清楚。

Capability示例值作用与注意事项
platformNameAndroid声明目标平台,写错直接找不到驱动。
automationNameUiAutomator2指定驱动类型,不写时会用默认驱动,很可能不是UiAutomator2。
deviceName任意字符串旧协议遗留字段,多设备时更建议用udid区分。
udid设备序列号精确指定目标设备,并行测试时必须配置。
app本地apk路径或远程url指定要安装的应用包,一般和appPackage配合使用。
appPackagecom.example.demo目标应用包名,启动哪个App就看它。
appActivity.MainActivity目标启动Activity,写错了会启动失败。
noResettrue不重置应用数据,真机调试时很常用。
autoGrantPermissionstrue自动授予应用权限,减少弹窗干扰。
systemPort8200设备端server的socket端口,多设备时要注意避免冲突。

automationName是决定是否走UiAutomator2这条链路的核心参数。有些脚本明明已经安装了UiAutomator2 Driver,但因为没写automationName: "UiAutomator2",会话就自动走了另一条老驱动,行为完全不同,定位方法也会给出令人困惑的报错。设备端的systemPort一般不需要改,但当你同时跑多台设备时,每台设备必须使用不同的systemPort,否则端口映射就会互相覆盖。

4.2 隐藏参数决定了稳定与速度

除了必备项,还有几个影响执行体验的高级参数:

  • appium:waitForIdleTimeout:设备端在执行操作前等待页面静态的时长,默认大约10000毫秒。页面动画多时,这个值会导致操作变慢,但调太小又可能拿到不完整的页面结构。
  • appium:waitForSelectorTimeout:查找元素时的等待时长上限,合理设置可以防止个别页面元素迟迟不出现导致全局超时。
  • appium:actionAcknowledgmentTimeout:每次操作后等待系统确认的时长。老设备上常常需要调大,否则会出现点击实际生效,但因为确认返回晚,脚本反而报操作失败。
  • appium:unicodeKeyboard与appium:resetKeyboard:配合设备端settings服务切换输入法,解决中文等非ASCII字符输入乱码。
  • appium:ignoreHiddenApiPolicyError:对部分Android版本隐藏API限制的兼容开关,某些页面解析失败时可以尝试开启。

这里要特别提醒:所有陌生的capability参数名,新版Appium里建议加上appium:前缀,一是规范,二是避免被解析成协议保留字段。

4.3 capabilities之间的联动

有些参数单独看都合理,合在一起就出问题。最常见的是noReset和autoGrantPermissions同时使用。noReset: true表示不重置应用数据,而autoGrantPermissions又希望在会话启动时自动授予权限。如果应用之前没有权限记录,后者可能不会触发预期的授权行为,最终测试中途被系统权限弹窗卡住。我的做法是:真机调试优先noReset: true,在第一次安装应用时先手动把权限全部授予,再关闭autoGrantPermissions,这样既稳定又不干扰界面流程。

另外,如果你启用了unicodeKeyboard,请务必记住会话结束或异常退出后,输入法可能没有切换回系统默认状态。这个坑特别隐蔽,表现为手机输入法莫名其妙变成了英文键盘或者测试专用键盘,很多人会以为是系统设置被改坏了,实际上是自动化会话没有正常收尾。

5. 脚本落地:从元素定位到完整用例

5.1 第一个Python脚本长什么样

环境通、参数懂,下一步就是写脚本。我用Python举例,因为生态简单,跑起来最快:

from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC caps = { "platformName": "Android", "automationName": "UiAutomator2", "deviceName": "emulator-5554", "appPackage": "com.example.demo", "appActivity": ".MainActivity", "noReset": True, "unicodeKeyboard": True, "resetKeyboard": False, "systemPort": 8200, } driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps) wait = WebDriverWait(driver, 15) btn = wait.until(EC.presence_of_element_located((AppiumBy.ID, "com.example.demo:id/login_btn"))) btn.click() input_box = wait.until(EC.presence_of_element_located((AppiumBy.ID, "com.example.demo:id/username"))) input_box.send_keys("tester01") submit = driver.find_element(AppiumBy.XPATH, "//android.widget.Button[@text='登录']") submit.click() result = wait.until(EC.presence_of_element_located((AppiumBy.ID, "com.example.demo:id/welcome_text"))) assert "欢迎" in result.text driver.quit()

这段脚本完成的是一个最小登录流程:等待登录按钮出现,点击,输入账号,点击登录,最后断言欢迎信息。注意我全程使用了显式等待,而不是一上来就find_element,这条经验是我在真实项目里用教训换来的。页面渲染带有动画时,元素虽然已经附加到布局,但可点击状态还没就绪,直接点击很容易失败。

5.2 元素定位方式对比

定位元素的方式总结如下:

方式示例适用场景
resource-idAppiumBy.ID大部分原生控件都带稳定的resource-id,首选方式。
accessibility idAppiumBy.ACCESSIBILITY_ID对应content-desc属性,无障碍信息完整的App好用。
xpath//android.widget.TextView[@text='标题']灵活但开销大,无id时兜底方案,尽量写短。
class nameandroid.widget.Button适合批量处理同类控件,但选择不精确。
UiAutomator2原生选择器new UiSelector().text("登录")适合需要复杂条件的深层定位,可以通过AndroidUIAutomator方式传入。

一个非常容易踩的坑是,很多人习惯用text属性去做xpath定位,但如果页面里同一个文本出现多次,xpath就会命中多个元素,点击时程序会报element not interactable。解决方法是尽量结合父节点路径或index来精确缩小范围。

提示:xpath在UiAutomator2驱动下走的是W3C规范解析,和老方案相比,某些函数和轴的使用限制不一样。尽量别依赖/following-sibling::这类复杂语法,换成直接通过resource-id或class组合,性能和可维护性都会好很多。

5.3 隐式等待与显式等待千万别混用

脚本层常见的等待方式有两类。隐式等待是给find_element设置一个全局搜索超时,但它的缺点是只要设置生效,每次查找元素都会等满这个时长,不适合做页面跳转后首屏加载的精确控制。显式等待则针对特定元素设置条件,比如等待元素可见、可点击、文本包含某个值,更灵活。

两条一起用不是不行,但一定要意识到,隐式等待的时长会叠加到显式等待的轮询里,导致实际等待时间比预期长不少。再加上UiAutomator2 Server本身还有设备端的等待策略配合,三层等待叠加下来,用例执行速度会明显变慢。我自己的约定是:全局隐式等待只设短值(比如5秒),页面关键节点全部用显式等待,并且把等待条件和业务动作一一对应,比如“等待加载完成图标消失”就比“等待某个文本出现”更贴近真实用户视角。

6. 高频问题排查与我的经验笔记

6.1 报错速查表

下面是几种高频报错的常见原因和解决思路。大多数问题不是玄学,都能从日志和系统状态里找到答案。

报错现象可能原因排查方向
UiAutomator2 server didn't start设备端server进程启动失败,可能是apk安装失败或端口被占用查看Appium debug日志,检查/data/local/tmp/下的apk是否完整,重启Appium并释放端口
Timeout waiting for server to start设备性能差或应用启动过慢,server在限定时间内没完成握手增大启动超时配置,检查设备网络与CPU占用,老设备降低并行数
Could not find a driver for automationName UiAutomator2没有安装对应的driver插件执行appium driver install uiautomator2,确认driver列表
io.appium.uiautomator2.server not found设备上server apk异常卸载或文件损坏手动卸载残留app,然后重新创建会话让Appium自动安装
Error obtaining UI hierarchy页面结构解析失败,通常是页面还在动画或者WebView内容未载入延长waitForIdleTimeout,用其他定位策略绕开解析问题
中文输入乱码输入法没有切换成功明确unicodeKeyboard,resetKeyboard,并检查会话结束后输入法是否被改回

6.2 日志与排查工具

排查这类问题,日志比“猜”重要得多。Appium服务端在debug模式下会打印每一步请求的分发细节,启动时加上--log-level debug参数非常关键:

appium --log-level debug

设备端可以使用logcat过滤与UiAutomator2相关的日志:

adb logcat -s UiAutomator2

还要检查端口和文件系统是否正常。adb forward --list可以列出当前所有端口映射,如果发现端口没有出现在列表里,说明adb通道在会话创建时没有完成forward,基本可以判断为adb异常或devices列表里的设备状态不对。检查设备端临时目录,能确认apk是否真的安装到位:

adb shell ls /data/local/tmp/

如果文件存在但大小异常,优先考虑卸载残留后重试。

6.3 我的几个避坑心得

经验一:真机上如果打开了“开发者选项”里的某些辅助功能开关,比如“显示指针位置”,会让设备端UI层级解析变得极其缓慢。遇到莫名其妙的元素查找超时,第一件事不是调大超时时间,而是检查手机系统设置,关掉那些调试选项。

经验二:老设备上server进程可能被系统后台回收,尤其在内存压力大、应用频繁切换的测试场景里。此时用例会周期性失败,日志显示socket连接中断。应对方法是适当降低并行设备数量,或者换用性能更好的测试手机,设备端保活这类技巧治标不治本。

经验三:不要在测试脚本和server安装流程上硬扛兼容性问题。不同Android版本的隐藏API限制差异很大,遇到APK解析失败或server启动异常时,优先确认当前驱动版本与设备Android版本的匹配关系,多数开源项目都会在升级日志里注明兼容范围。

经验四:并行测试时,给每台设备分配独立的systemPort和mjpegServerPort,端口规划放在环境配置文件里统一管理,而不是散落在每条用例代码中。良好的端口管理习惯,能省下大量排查“这台设备怎么又跑到那台设备的画面上”这类诡异问题的时间。

最后再分享一个我自己的操作习惯:每次新项目或新设备接入,我会先用最小脚本跑通一次空会话,只启动server并退出,然后再进入真正用例的开发。这样做的价值在于,先把环境变量、设备连接、driver安装这些非业务因素固定下来,之后用例报错时就能大概率把问题定位到业务和脚本层面,而不是每次都在环境的泥潭里打转。

相关新闻

Python Selenium搭建UI自动化测试框架实践指南

Python Selenium搭建UI自动化测试框架实践指南

开篇就直接进入技术主题,不客气一个字。先以一个从业者的视角说出UI自动化测试的现状和痛点,随后围绕标题“Python Selenium搭建UI自动化测试框架”来写。内容会包含完整的设计、环境、执行流程、等待、定位、报告、常见问题,全部拆解成结构清…

2026/10/20 19:14:17 阅读更多 →
从Prompt到Multi-Agent:大模型应用落地的四阶段演进指南

从Prompt到Multi-Agent:大模型应用落地的四阶段演进指南

大模型应用落地这件事,这两年我见过太多团队从"有个API Key"一路走到"生产环境跑通",过程中踩的坑比预想的深得多。很多人一上来就追最热的Multi-Agent,结果连单Agent的工具调用都没理顺,最后整个系统像一盘散…

2026/10/20 19:14:16 阅读更多 →
Python 实战:如何从分钟 K 线中提取指定交易时段的行情?

Python 实战:如何从分钟 K 线中提取指定交易时段的行情?

一句话结论: 从分钟 K 线中提取指定交易时段,关键不是简单地筛选时间,而是先明确交易所时区、K 线时间戳的含义和时段边界,再使用 Pandas 进行时间过滤与数据校验。只有时间口径一致,提取出来的行情才能用于后续指标计…

2026/10/20 19:14:16 阅读更多 →

最新新闻

AI Agent成本结构全解析:从API调用费到隐性人力的完整账本

AI Agent成本结构全解析:从API调用费到隐性人力的完整账本

先说一个我最近复盘的真实项目。某电商团队上线了一个订单查询与退换货的客服 Agent,第一周看账单,推理费一天几百块,负责人很高兴,觉得这玩意儿比招人划算多了。三个月后做财务复盘,把所有配套成本拉出来一算&#xf…

2026/10/20 21:19:04 阅读更多 →
7825张车身缺陷检测数据集:VOC+YOLO双格式标注与YOLOv5训练实践

7825张车身缺陷检测数据集:VOC+YOLO双格式标注与YOLOv5训练实践

简介:面向车身部件损坏与车体缺陷检测的VOCYOLO双格式数据集,对应7825张车辆图像的缺陷标注,涵盖划痕、凹陷、裂缝、破损、褪色等15类常见问题,可直接用于YOLO系列、Faster R-CNN等目标检测模型的训练与评估,服务汽车制…

2026/10/20 21:19:04 阅读更多 →
OpenClaw基于概念的解释:TCAV原理、实践与工程坑

OpenClaw基于概念的解释:TCAV原理、实践与工程坑

模型解释性最近几年都快被聊烂了,但每次有人跑来问我“OpenClaw 能不能做基于概念的解释”,我还是会一下子精神起来。这个问题问得比“你模型准确率多少”有价值多了,因为它背后真正想说的是:模型做判断的理由,能不能用…

2026/10/20 21:19:04 阅读更多 →
TensorFlow 2 复现 Facenet:MTCNN 对齐与三元组损失实战

TensorFlow 2 复现 Facenet:MTCNN 对齐与三元组损失实战

1. 为什么我最终选了 TensorFlow 2 来复现 Facenet1.1 从一次“翻车”的考勤机项目说起前两年我接了一个小活儿,帮一个做企业内训的朋友搞一套“刷脸签到”的演示系统。需求听起来不复杂:员工站在摄像头前,系统认出是谁,自动打勾。…

2026/10/20 21:19:04 阅读更多 →
上下文模式实战:从设计到落地的架构决策与避坑指南

上下文模式实战:从设计到落地的架构决策与避坑指南

1. 从“上下文模式”说起:一个被低估的架构决策第一次看到“context-mode”这个词,很多人会下意识觉得它是个抽象得没边儿的概念——上下文嘛,不就是程序运行时的环境变量、线程本地存储、或者某个框架里的配置对象?但如果你真的在…

2026/10/20 21:19:04 阅读更多 →
STM32智能台灯毕业设计:从硬件选型到PID调光完整实战

STM32智能台灯毕业设计:从硬件选型到PID调光完整实战

简介:本资源为嵌入式方向本科毕业设计「智能台灯」的完整开发套件,面向电子工程、自动化及物联网相关专业学生,解决智能硬件从原理设计到系统落地的全流程实践需求。压缩包含140个文件,总大小162.69MB,涵盖33张硬件调试…

2026/10/20 21:18:02 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →