当前位置: 首页 > article >正文

Android Recovery 模式工作原理与定制实战

Recovery 是 Android 的救命系统,负责 OTA 升级、恢复出厂、用户数据加密管理。本文剖析 Recovery 的架构、启动流程、与主系统的通信机制,并演示如何修改并构建一个自定义 Recovery。一、Recovery 到底是什么?很多人以为 Recovery 是 Android 系统的一个模式,其实它是一个完全独立的 Linux 系统:有自己的 Kernel(实际上和主系统共享一个 boot 镜像的内核)、自己的 ramdisk、自己的 init、自己的应用。它和主系统的关系类似:PC 主系统 - PE 启动盘 Android - RecoveryRecovery 启动时只挂载最小化的文件系统,不启动 Android 框架(没有 Java VM、Zygote、SystemServer),纯 C/C 应用,占用资源极小。二、Recovery 的两种存在形式1. 传统形式:独立 recovery 分区分区表: boot (Kernel 主系统 ramdisk) recovery (Kernel recovery ramdisk)启动时 Bootloader 根据按键 / BCB 决定加载哪个 boot image。2. 现代形式:合并到 boot 中(A/B 设备)A/B 设备砍掉了独立 recovery 分区,把 recovery 的内容融合进 boot 的 ramdisk:boot.img ├── kernel └── ramdisk ├── /init ├── /system/bin/recovery ├── /sbin/... └── /etc/recovery.fstab启动到主系统还是 recovery,看 Kernel cmdline:# 主系统启动 androidboot.force_normal_boot1 # Recovery 启动 (不带 force_normal_boot)init在第一阶段读到这个参数后,执行不同的init.rc。三、Recovery 的目录结构(精简版)/ ├── init (静态链接的 init 二进制) ├── init.recovery.${hw}.rc (硬件相关 init 脚本) ├── etc/ │ ├── recovery.fstab (Recovery 用的 fstab) │ └── recovery-resource.dat ├── sbin/ │ ├── recovery (主程序) │ ├── adbd (USB adb 守护进程) │ └── busybox (基础命令) ├── res/ │ ├── images/ (UI 图片) │ └── recovery.cfg ├── system/ │ └── bin/ └── tmp/ (临时挂载点)recovery.fstab描述了 Recovery 需要挂载的分区:# src mnt_point type mnt_flags fs_mgr_flags /dev/block/by-name/system /system ext4 ro,barrier1 wait,first_stage_mount,logical /dev/block/by-name/userdata /data f2fs defaults wait,check,formattable,quota /dev/block/by-name/cache /cache ext4 defaults wait,check /dev/block/by-name/misc /misc emmc defaults defaults /dev/block/by-name/metadata /metadata f2fs defaults wait,formattable四、Recovery 主程序的核心流程源码在bootable/recovery/,核心入口在recovery_main.cpp:intmain(intargc,char**argv){// 1. 重定向 stdio 到 last_logredirect_stdio(/tmp/recovery.log);// 2. 启动 logd 服务staticconstexprstructoptionOPTIONS[]{{locale,required_argument,NULL,0},{fastboot,no_argument,NULL,0},{0,0,0,0},};// 3. 加载 fstabautofstabLoadFstab();// 4. 解析启动参数(来自 BCB)std::vectorstd::stringargsget_args(argc,argv);// 5. 初始化 Device 抽象autodevicemake_device();autouidevice-GetUI();ui-Init(locale);// 6. 进入主循环InstallResult statusINSTALL_NONE;if(update_package!nullptr){// OTA 包安装statusinstall_package(update_package,...);}elseif(should_wipe_data){wipe_data(device);}elseif(should_wipe_cache){wipe_cache(device);}elseif(should_wipe_ab){wipe_ab_device();}else{// 进入交互式菜单statusprompt_and_wait(device,retry_count);}// 7. 写回结果到 BCBfinish_recovery();// 8. 重启reboot(normal);return0;}prompt_and_wait 交互菜单InstallResultprompt_and_wait(Device*device,intretry_count){staticconstchar*HEADERS[]{Android Recovery,Use volume up/down to move highlight;,power button to select.,nullptr,};staticconstchar*ITEMS[]{Reboot system now,Apply update from ADB,Apply update from SD card,Wipe data/factory reset,Wipe cache partition,Mount /system,View recovery logs,Power off,nullptr,};while(true){intchosenget_menu_selection(HEADERS,ITEMS,...);switch(chosen){case0:returnINSTALL_SUCCESS;case1:apply_from_adb(device);break;case2:apply_from_sdcard(device);break;case3:wipe_data(device);break;case4:wipe_cache(device);break;case5:mount(/system);break;case6:choose_recovery_file(device);break;case7:reboot(poweroff);break;}}}五、与主系统的通信:BCB(Bootloader Control Block)我们在前文讲过,misc 分区存放 BCB。Recovery 主要靠 BCB 与外界沟通:主系统触发 Recovery// frameworks/base/services/core/java/com/android/server/RecoverySystem.javapublicstaticvoidrebootWipeUserData(Context context,...){bootCommand(context,--wipe_data,--reasonreason);}privatestaticvoidbootCommand(Context context,String...args){File RECOVERY_DIRnewFile(/cache/recovery);File COMMAND_FILEnewFile(RECOVERY_DIR,command);StringBuilder commandnewStringBuilder();for(String arg:args){command.append(arg).append(\n);}Files.write(command.toString().getBytes(),COMMAND_FILE);// 触发 reboot 到 recoverySystemProperties.set(sys.powerctl,reboot,recovery);}Recovery 启动后读命令std::vectorstd::stringget_args(intargc,char**argv){std::vectorstd::stringargs;// 1. 优先从 BCB 读 (Bootloader 写入)bootloader_message boot;if(read_bootloader_message(boot)){if(boot.command[0]!0){// boot.recovery 中是用 \n 分隔的命令列表std::vectorstd::stringtokensSplit(boot.recovery,\n);args.insert(args.end(),tokens.begin(),tokens.end());}}// 2. 从 /cache/recovery/command 读if(args.empty()){std::string content;if(ReadFileToString(/cache/recovery/command,content)){std::vectorstd::stringtokensSplit(content,\n);args.insert(args.end(),tokens.begin(),tokens.end());}}returnargs;}退出时清理 BCBvoidfinish_recovery(){// 把 BCB 清掉,下次启动直接进主系统bootloader_message boot{};write_bootloader_message(boot);// 删除 /cache 中的命令文件unlink(/cache/recovery/command);}六、OTA 安装的核心:install_packageRecovery 最重要的工作就是安装 OTA 包。流程:InstallResultinstall_package(conststd::stringpath,...){// 1. 校验 ZIP 签名 (PKCS#7)if(!verify_package(path,key_path)){returnINSTALL_CORRUPT;}// 2. 打开 ZIPZipArchiveHandle zip;if(OpenArchive(path.c_str(),zip)!0){returnINSTALL_CORRUPT;}// 3. 提取并执行 META-INF/com/google/android/update-binaryintpipefd[2];pipe(pipefd);pid_t pidfork();if(pid0){// 子进程close(pipefd[0]);charstatus_fd[8];snprintf(status_fd,sizeof(status_fd),%d,pipefd[1]);execl(/tmp/update-binary,update-binary,3,// versionstatus_fd,path.c_str(),nullptr);exit(1);}// 父进程读 update-binary 的进度close(pipefd[1]);FILE*ffdopen(pipefd[0],r);charbuf[256];while(fgets(buf,sizeof(buf),f)){// 解析 ui_print xxx, progress xxx, set_progress xxxhandle_progress(buf);}intstatus;waitpid(pid,status,0);returnWEXITSTATUS(status)0?INSTALL_SUCCESS:INSTALL_ERROR;}update-binary 协议update-binary通过文件描述符 3 与 Recovery 主进程通信,简单的文本协议:ui_print Hello world!\n progress 0.5 30\n (进度条 50%,持续 30 秒动画) set_progress 0.75\n (进度条 75%) firmware hboot hboot.img\n clear_display\n七、Recovery 的 UI 系统Recovery UI 是个独立的图形系统,不依赖 SurfaceFlinger / WindowManager,直接操作 framebuffer / DRM。核心类:RecoveryUI// bootable/recovery/recovery_ui/include/recovery_ui/ui.hclassRecoveryUI{public:virtualvoidInit(conststd::stringlocale)0;virtualvoidSetBackground(Icon icon)0;virtualvoidSetProgress(floatfraction)0;virtualvoidPrint(constchar*fmt,...)0;virtualintWaitKey()0;virtualvoidShowText(boolvisible)0;};具体实现ScreenRecoveryUI直接操作 framebuffer:voidScreenRecoveryUI::draw_screen_locked(){if(!show_text){// 显示进度条 logodraw_background_locked();draw_foreground_locked();}else{// 显示文字菜单SetColor(MENU);// ...for(inti0;imenu_items;i){if(iselected){DrawHighlightBar(0,y,width,char_height);SetColor(MENU_SEL_BG);}gr_text(menu_font,x,ybaseline,items[i].text,1);}}}voidScreenRecoveryUI::update_screen_locked(){draw_screen_locked();gr_flip();// 把 framebuffer 内容显示到屏幕}gr_flip()内部通过 ioctl 通知 DRM 切换显示缓冲区:intgr_flip(void){gr_drawgr_backup_disp_buffer(gr_draw);structfb_var_screeninfovi;ioctl(fd,FBIOGET_VSCREENINFO,vi);vi.yoffset(current_buffer?vi.yres:0);ioctl(fd,FBIOPAN_DISPLAY,vi);current_buffer!current_buffer;return0;}八、定制 Recovery 实战如果想给设备做一个自定义 Recovery,通常要做几件事:1. 准备源码# 拉 AOSP 源码repo init-uhttps://android.googlesource.com/platform/manifest-bandroid-13.0.0_r80 reposync# 配置自己的设备sourcebuild/envsetup.sh lunchyour_device-userdebug2. 修改设备 Device 类// device/yourcompany/yourdevice/recovery/recovery_ui.cpp#includerecovery_ui/device.h#includerecovery_ui/screen_ui.hclassYourDevice:publicDevice{public:YourDevice(RecoveryUI*ui):Device(ui){}boolPostWipeData()override{// 擦数据后做点啥ResetCustomerSettings();returntrue;}BuiltinActionInvokeMenuItem(size_t menu_position)override{// 添加自定义菜单项if(menu_positionYOUR_CUSTOM_ITEM){DoSomethingCool();returnNO_ACTION;}returnDevice::InvokeMenuItem(menu_position);}};Device*make_device(){returnnewYourDevice(newScreenRecoveryUI);}3. 修改 BoardConfig.mk# device/yourcompany/yourdevice/BoardConfig.mk TARGET_RECOVERY_UI_LIB : librecovery_ui_yourdevice TARGET_RECOVERY_FSTAB : device/yourcompany/yourdevice/recovery.fstab # 启用 fastbootd TARGET_USERIMAGES_USE_F2FS : true BOARD_USES_RECOVERY_AS_BOOT : true BOARD_BUILD_SYSTEM_ROOT_IMAGE : false # UI 主题 TARGET_RECOVERY_PIXEL_FORMAT : RGBX_88884. 编译makebootimage -j$(nproc)# 或者只编译 recovery (传统 boot/recovery 分离的设备)makerecoveryimage -j$(nproc)输出在out/target/product/device/:boot.img— A/B 设备recovery.img— 传统设备5. 刷写adbrebootbootloader# A/B 设备fastboot flash boot boot.img# 传统设备fastboot flash recovery recovery.img九、minimal recovery UI 代码示例(脱离 AOSP)下面是一个最简化的 framebuffer Recovery UI 主循环,展示原理:#includestdio.h#includestdint.h#includefcntl.h#includeunistd.h#includestring.h#includelinux/fb.h#includelinux/input.h#includesys/ioctl.h#includesys/mman.hstructfb_ctx{intfd;uint8_t*pixels;intwidth,height,stride;};staticintfb_init(structfb_ctx*fb){fb-fdopen(/dev/graphics/fb0,O_RDWR);if(fb-fd0)return-1;structfb_var_screeninfovi;structfb_fix_screeninfofi;ioctl(fb-fd,FBIOGET_VSCREENINFO,vi);ioctl(fb-fd,FBIOGET_FSCREENINFO,fi);fb-widthvi.xres;fb-heightvi.yres;fb-stridefi.line_length;size_tsizefb-stride*fb-height;fb-pixelsmmap(0,size,PROT_READ|PROT_WRITE,MAP_SHARED,fb-fd,0);return(fb-pixelsMAP_FAILED)?-1:0;}staticvoidfb_fill(structfb_ctx*fb,uint32_tcolor){uint32_t*p(uint32_t*)fb-pixels;intcountfb-stride*fb-height/4;for(inti0;icount;i)p[i]color;}staticintread_key(intinput_fd){structinput_eventev;while(read(input_fd,ev,sizeof(ev))sizeof(ev)){if(ev.typeEV_KEYev.value1){// key downreturnev.code;}}return-1;}intmain(void){structfb_ctxfb;if(fb_init(fb)0){fprintf(stderr,fb init failed\n);return1;}intinput_fdopen(/dev/input/event0,O_RDONLY);intselected0;constchar*items[]{Reboot system,Wipe data,Apply update,Power off,};intn_itemssizeof(items)/sizeof(items[0]);while(1){// 简化:仅用纯色背景表示当前选项uint32_tcolors[]{0xFF008000,0xFF800000,0xFF000080,0xFF808000};fb_fill(fb,colors[selected]);intkeyread_key(input_fd);if(keyKEY_VOLUMEUP)selected(selected-1n_items)%n_items;if(keyKEY_VOLUMEDOWN)selected(selected1)%n_items;if(keyKEY_POWER){printf(Selected: %s\n,items[selected]);if(selected0)execl(/sbin/reboot,reboot,NULL);if(selected3)execl(/sbin/poweroff,poweroff,NULL);break;}}return0;}这个程序展示了 Recovery UI 的底层本质:直接 mmap framebuffer 读 input event,没有任何 GUI 库。十、踩坑经验fstab 字段错一个,挂载失败:Recovery 没法挂数据分区,wipe 不了 → 注意wait,formattable这些 flagAVB 拒绝刷未签名的 recovery:解锁后才能刷自制版本,或者要用 OEM 签名sideload(adb sideload)的工作目录:推过来的包默认存到/tmp/update.zip,大包会 OOM,要把/tmp挂大点fastbootd 和 recovery 共享 ramdisk:同一个二进制,只是启动参数不同(--fastboot)国行机型可能锁 AVB key:无法刷自制 Recovery,需要单独的解锁工具十一、总结Recovery 是一个被严重低估的系统:它是一个完整的 Linux 系统,只是为了救命而设计得极度精简BCB /cache/command是主系统与 Recovery 之间的桥梁OTA 安装 update-binary是它的核心使命直接操作 framebuffer让它在最恶劣的环境下也能工作理解 Recovery 不仅能帮你做 OEM 定制,也能帮你在用户报开不了机时,快速定位 BCB 或者 fstab 的问题。最后一篇我们来讲 Bootloader 的世界 — U-Boot 的移植实战。

相关文章:

Android Recovery 模式工作原理与定制实战

Recovery 是 Android 的"救命系统",负责 OTA 升级、恢复出厂、用户数据加密管理。本文剖析 Recovery 的架构、启动流程、与主系统的通信机制,并演示如何修改并构建一个自定义 Recovery。一、Recovery 到底是什么? 很多人以为 Recovery 是 Android 系统的一个"模…...

高性能缓冲管理中的数组翻译技术解析

1. 高性能缓冲管理中的数组翻译技术解析在现代数据库系统中,缓冲管理器是连接内存与持久化存储的关键组件,其核心任务是将逻辑页ID映射到物理内存帧。传统方案如哈希表或指针交换存在三个根本性缺陷:内存开销随数据集线性增长、并行访问时的锁…...

OpenGL 调试方式

调试手段总览 API 级错误检查:glGetError、断言、包装宏调试输出机制:GL_KHR_debug、glDebugMessageCallback、QOpenGLDebugLogger着色器与程序调试:编译/链接日志、离线编译器、颜色编码调试渲染结果调试:FBO 检查、glReadPixels…...

2026 国产桌面 AI 智能体横向评测:博云 BoClaw vs AutoClaw vs QClaw vs MaxClaw vs WorkBuddy

一、引言2026 年初,一款名为 OpenClaw 的开源 AI 智能体框架以创纪录的速度蹿红全球——短短数月突破 30 万 GitHub Star,Token 使用量一度占据 OpenRouter 平台总量的约 13%。它之所以引发轰动,核心在于首次让 AI 真正实现从“动口”到“动手…...

基于Council框架的多智能体协作:构建专家委员会式AI决策系统

1. 项目概述:一个智能化的团队决策引擎最近在开源社区里看到一个挺有意思的项目,叫“Cat-tj/council-tj”。这个名字乍一看有点抽象,但拆开来看,“Council”在英文里是“议会”或“委员会”的意思,而“tj”通常是“Tav…...

Taotoken标准OpenAI协议兼容性在实际项目迁移过程中带来的便利

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken标准OpenAI协议兼容性在实际项目迁移过程中带来的便利 1. 项目背景与迁移动因 我们维护着一个内部知识库问答系统&#x…...

被安排做“脏活累活”怎么办?聪明人把它变成了核心竞争力

在软件测试的职业旅程中,几乎每一位从业者都会遇到这样的时刻:领导把最繁琐的模块分给你,把重复度最高的回归用例交给你,把无人问津的旧系统兼容性测试派给你。这些任务往往技术含量看似不高、耗时巨大且难以在简历上写出亮点&…...

对话式AI智能中继与编排框架:构建高可用AI应用的核心架构

1. 项目概述:一个面向对话式AI的智能中继与编排框架最近在折腾一个挺有意思的开源项目,叫ChatAgentRelay。乍一看这个名字,可能觉得它又是一个聊天机器人框架,但深入把玩之后,我发现它的定位其实更精准,也更…...

ARM活动监控器(AMU)架构与AMCFGR寄存器详解

1. ARM活动监控器架构概览 在现代处理器设计中,性能监控单元(PMU)是系统调优和性能分析的关键组件。ARM架构中的活动监控器(Activity Monitors)作为PMU的核心部分,通过硬件计数器实现了对处理器行为的细粒度追踪。不同于传统的性能计数器,AMU…...

2026 最新 6 款漏洞扫描工具!一篇全覆盖

渗透测试收集信息完成后,就要根据所收集的信息,扫描目标站点可能存在的漏洞了,包括我们之前提到过的如:SQL注入漏洞、跨站脚本漏洞、文件上传漏洞、文件包含漏洞及命令执行漏洞等,通过这些已知的漏洞,来寻找…...

高速SOIC插座技术解析:从原理到工程实践

1. 高速SOIC插座的技术演进与核心价值在射频和高速数字电路设计中,工程师们经常面临一个经典矛盾:既要保证芯片测试的便捷性,又不能牺牲信号完整性。传统DIP插座在MHz级频率下尚能应付,但当频率攀升至GHz领域时,其机械…...

基于Google Workspace API与LLM的办公自动化技能框架设计与实现

1. 项目概述:当Google Workspace遇上AI技能 如果你和我一样,日常重度依赖Google Workspace(以前叫G Suite)来处理邮件、文档、表格和日历,那你肯定也想过:要是这些工具能更“聪明”一点就好了。比如&#…...

蕲艾壹号模式开发介绍(代码)

以下是关于蕲艾壹号模式开发的介绍和代码示例:蕲艾壹号模式开发介绍蕲艾壹号通常指基于蕲艾(一种中药材)相关产品的电商或健康管理平台。开发模式可能包含以下核心模块:电商功能模块 商品展示、购物车、订单管理、支付接口集成&am…...

重磅!国家首部NAD⁺抗衰共识发布,这11条建议必读!

2026年4月,国内首个《NAD⁺在衰老相关疾病中的作用及临床应用中国专家共识(2026版)》正式发布!这份由中华医学会老年医学分会牵头、汇聚全国衰老医学、代谢病、心血管病及神经病学等领域权威专家共同制定的国家级共识,…...

0.2mm间距测试探针技术解析与应用指南

1. 0.2mm间距测试探针的技术突破与应用价值在半导体测试领域,随着芯片封装尺寸的持续缩小和信号频率的不断提升,传统测试探针已难以满足高密度互连与高频测试的双重需求。Aries Electronics最新推出的0.2mm间距测试探针,采用镀金铍铜材料和特…...

实时语音AI对话应用开发:从WebRTC到LLM集成的全栈实践

1. 项目概述:实时语音对话的AI应用实践最近在GitHub上看到一个挺有意思的项目,叫proj-airi/webai-example-realtime-voice-chat。光看名字,就能猜到个大概:这是一个基于Web的、利用AI技术实现的实时语音聊天示例。作为一个在音视频…...

政务知识图谱 + 大模型:打造可解释、可信任 AI

在数字政务加速迈向智能化的今天,AI 技术已深度渗透到政务服务、社会治理、机关办公等各个场景,从智能问答、政策解读到辅助决策、风险预警,AI 正在成为提升政务效能、优化服务体验的核心力量。但与此同时,传统 AI 技术在政务领域…...

手把手教你逆向分析PerimeterX px3:从混淆还原到参数解密全流程

逆向工程实战:PerimeterX px3防护体系深度解析与突破 在当今数字化时代,网站安全防护与数据采集之间的博弈从未停止。作为前端安全领域的标杆解决方案,PerimeterX的px3防护机制以其复杂的混淆技术和动态行为分析著称,成为众多安全…...

LLM赋能网页抓取:基于ChatGPT的智能数据提取实战指南

1. 项目概述与核心价值最近在数据采集和自动化领域,一个名为“oxylabs/chatgpt-web-scraping”的项目引起了我的注意。乍一看,这像是把两个热门概念——大型语言模型(LLM)和网页抓取(Web Scraping)——强行…...

FPGA上LUT-DNN稀疏连接优化技术SparseLUT详解

1. 项目概述在边缘计算场景中,FPGA因其可重构性和低功耗特性成为部署深度神经网络(DNN)的理想平台。然而传统DNN在FPGA上的实现面临资源占用高、延迟大等挑战。基于查找表(LUT)的DNN通过将神经元计算映射到FPGA原生LUT资源,显著提升了硬件效率。但现有LU…...

AWorksLP嵌入式系统移植FatFs驱动SD卡:从原理到实践全解析

1. 项目概述:为什么要在AWorksLP上折腾FatFs和SD卡?如果你正在用AWorksLP这类面向物联网的轻量级实时操作系统(RTOS)平台做开发,大概率会遇到一个经典需求:如何可靠、高效地存储数据。无论是记录传感器日志…...

【综合能源】电热冷综合能源优化调度研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

基于Circuit Playground Express与3D打印的机械心脏制作指南

1. 项目概述:一个会“呼吸”的机械心脏如果你对创客、STEAM教育或者互动艺术装置感兴趣,那么亲手制作一个能模拟真实心跳、并且心率可以手动调节的解剖心脏模型,绝对是一个能让你成就感爆棚的项目。这不仅仅是一个静态的展示品,它…...

NotebookLM音乐学应用的5个致命误区(附诊断清单),90%新手在第3步就误入歧途导致文献溯源失效

更多请点击: https://intelliparadigm.com 第一章:NotebookLM音乐学研究辅助的底层逻辑与适用边界 NotebookLM 本质是一个基于用户上传文档构建私有语义索引的轻量级 AI 助手,其核心并非通用大模型的自由生成,而是“引用驱动型推…...

ARMv8 PMU架构与性能监控实战指南

1. ARMv8 PMU架构深度解析在ARMv8架构中,性能监控单元(Performance Monitor Unit, PMU)是处理器微架构层面的重要组件,它为开发者提供了硬件级别的性能数据采集能力。不同于传统的软件性能分析工具,PMU通过专用寄存器直接监控处理器内部事件&…...

在DOSBox中运行Appler模拟器:重温Apple II的复古计算体验

1. 项目概述:在DOS的土壤里复活Apple II的灵魂如果你和我一样,对计算机历史的交汇点着迷,那么“在8086的机器上模拟一颗6502的心脏”这个想法本身就充满了极客浪漫主义色彩。Appler正是这样一个跨越时代的产物——一个专为MS-DOS编写的Apple …...

开源HR智能体:基于LLM与Agent架构的自动化HR流程实践

1. 项目概述:一个开源的HR智能体最近在关注AI如何真正落地到具体业务场景,而不是停留在概念演示。一个让我眼前一亮的项目是ArjunFrancis/openhr-agent。简单来说,这是一个开源的、基于大语言模型(LLM)的HR&#xff08…...

RAG系统评估实战:使用renumics-rag进行量化分析与性能优化

1. 项目概述:一个为RAG应用量身定制的开源评估工具如果你正在构建或优化一个基于检索增强生成(RAG)的系统,那么你大概率会遇到一个核心痛点:如何科学、量化地评估它的好坏?是看它回答得“像不像人”&#x…...

基于BLE与NeoPixel的智能眼镜控制:在ATtiny85上实现无线光效交互

1. 项目概述与核心价值几年前,当我第一次把玩Adafruit的NeoPixel灯环时,就被其绚丽的色彩和简单的控制方式所吸引。后来,一个很自然的想法冒了出来:能不能把这些灯珠集成到一副眼镜上,并且用手机来无线控制它&#xff…...

基于Arduino与步进电机的DIY无线电动相机滑轨制作全攻略

1. 项目概述:打造你的第一台无线电动相机滑轨如果你玩摄影或者视频创作,肯定对那种平滑、富有电影感的平移镜头(Dolly Shot)着迷过。专业级的电动滑轨动辄大几千甚至上万,让很多个人创作者望而却步。今天,我…...