Android蓝牙耳机拨打电话全解析:HFP检测、SCO切换与权限避坑
简介蓝牙耳机拨打电话完整工程代码面向嵌入式开发、无线通信及蓝牙协议栈学习者集中展示A2DP音频传输、HSP/HFP免提通话、GAP/GATT设备发现与配对连接等核心机制的代码级实现。资源基于开源工具链构建包含构建脚本与控制程序可通过autogen、configure、make等标准流程完成配置、编译与安装并配套hfconsole交互控制端实现拨号、音量调节、来电处理等操作验证。压缩包整体约864KB以C语言源码工程为主结构紧凑适合直接定位协议处理、音频流与设备控制模块进行针对性研读。已有442人学习使用通过分析源码可深入理解蓝牙通话链路的建立、音频数据收发、控制命令解析以及多线程调度等关键细节对希望从原理走向实践、或在此基础上进行二次开发的开发者具有较高的参考价值。1. 蓝牙耳机拨打电话的全部代码能直接落地还是只能当参考蓝牙耳机拨打电话听起来只是系统电话应用的重定向真正做起来才知道把“拨号”这件事做对需要同时搞定权限、蓝牙连接、声音通道、通话状态监听四层。某公司的模拟项目X 里团队在安卓设备上做耳机侧通话路由光 SCO 建立时机就踩了两周最后发现拨号本身没问题坑全在声音通道上。这份资源把整条链路拆开重排了蓝牙连接检测、权限申请、CALL 拨号、SCO 切声、通话状态监听以及耳机按键触发代码可以直接抄进自己的工程。适合两类人一类是正在写蓝牙耳机配套 App 的安卓开发者另一类是拿耳机做原型验证的硬件工程师。下面按我实际拆这份代码的顺序把选型理由、参数和踩坑一起讲完。2. 蓝牙拨号的三条路径为什么先选 Intent 直达而不是 HFP AT 指令2.1 三条路径的本质差异蓝牙耳机拨打电话在实现层面有三条完全不同的路。第一条是 Intent.ACTION_CALL也就是普通 Android App 里最常见的做法构造一个tel:的 Uri调起系统电话界面并直接拨出。这条路代码量最小不依赖蓝牙协议栈的底层接口只要把CALL_PHONE权限申请下来前台场景下就能稳定工作。第二条是 HFP AT 指令HFPHands-Free Profile是蓝牙耳机与手机之间通话专用的协议拨号操作本质是向免提模块发送一条ATD号码\r的指令。但这条指令的收发通道由蓝牙协议栈管理普通 App 拿不到一般只有系统级应用或者耳机嵌入式侧才能直接操作独立 App 想走这条路的代价很高。第三条是耳机侧按键触发也就是用户按耳机上的接听键来发起动作这条路的本质是媒体按键事件它只是一个入口最终还是要落到 Intent 拨号或者 HFP AT 指令上。这三条路径的差异我整理成了下面这张表选型时基本看这张表就够了。方案入口前置条件主要限制Intent.ACTION_CALLApp 按钮 / 耳机按键触发CALL_PHONE 权限、前台 ActivityAndroid 10 后后台启动 Activity 受限HFP AT 指令嵌入式侧 / 系统级应用系统签名权限、HFP 已连接普通 App 拿不到协议栈接口耳机按键事件用户按耳机接听键注册 MediaSession 并激活只是入口仍需拨号与 SCO 配合我实际用下来这份代码仓库的主路径选的是 Intent.ACTION_CALLHFP AT 指令只在备注里给了方向核心原因还是那句话独立 App 拿不到普通权限之外的协议栈接口。后面逐步展开代码你看到实现细节时会更能理解这个选择。2.2 权限模型哪些能申请哪些是黑匣子拨打电话最直接的权限是CALL_PHONE这是危险权限可以在运行时动态申请也是整套方案里最基础的权限。如果你只想打开拨号盘而不直接拨出可以用ACTION_DIAL那个不需要CALL_PHONE但只做半套意义不大。真正麻烦的是 Android 版本分裂带来的权限变化Android 6 到 11 用的是BLUETOOTH和BLUETOOTH_ADMINAndroid 12 开始改成BLUETOOTH_CONNECT和BLUETOOTH_SCAN而且是运行时权限不动态申请直接拿BluetoothAdapter.getProfileConnectionState()就会崩溃。Android 10 开始系统限制后台应用启动 Activity这意味着 App 退到后台以后按耳机按键想调起拨号界面会失败除非用前台服务保持可见或者申请拨号器角色。Android 8 开始TelephonyManager.endCall()被标记为隐藏 API普通应用不能保证反射成功这也是自动挂断功能最不确定的一环。这些权限里MODIFY_PHONE_STATE和BLUETOOTH_PRIVILEGED属于签名权限普通 App 拿不到。很多人以为把MODIFY_PHONE_STATE写进 Manifest 就能挂断电话实际编译能过运行必报 SecurityException这一点后面避坑章节会再展开。理解权限的边界比抄代码更重要因为 Android 12 以后的闪退大多不是逻辑错误而是权限模型变了。2.3 选型结论主路径用 Intent.ACTION_CALL 的三个理由第一条理由非常直接代码量最少稳定。HFP AT 指令方案需要系统签名或嵌入式配合普通 App 工程里连调试入口都难找。第二条理由是兼容性好Intent.ACTION_CALL 是系统公开能力只要申请了权限不管哪家 ROM 的前台场景都能调起拨号。第三条理由是后续扩展方便这份资源里的耳机按键触发最终也是回调到同一个拨号函数路径换入口不换逻辑改造成本很低。当然Intent 方案也有绕不开的弊端它调起的是系统电话界面不是你自己画的通话界面声音通道切换还是要靠 SCO这部分躲不掉。如果你的项目目标是做整套通话 UI而不是蓝牙耳机拨号功能验证那这条路就不够用了需要去研究 TelecomManager 和 InCallService那就是另一个量级的工程。这份代码的场景很明确蓝牙耳机侧发起拨号、接通、挂断、切声音在这个范围内它足够完整。3. 核心代码落地连接检测、ACTION_CALL 拨号、SCO 切声与通话状态监听3.1 第一步确认耳机已连接 HFP而不是 A2DP拨号前必须先确认蓝牙耳机已经通过 HFPHeadset Profile连接。很多人在这里会犯错用A2DP的连接状态来判断耳机是否可用。A2DP 负责的是音乐播放HFP 才负责通话一个耳机可能 A2DP 已连接但 HFP 还在协商中这时候拨号打过去声音不会进耳机。正确做法是查HEADSETProfile 的连接状态。private val TAG BluetoothDialer /** * 确认当前是否有蓝牙耳机通过 HFP 连接。 * 这里只关心 Profile 连接状态不关心具体是哪个设备。 */ fun isHeadsetConnected(context: Context): Boolean { val adapter BluetoothAdapter.getDefaultAdapter() ?: return false // Android 12 必须先动态申请 BLUETOOTH_CONNECT if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { if (context.checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) ! PackageManager.PERMISSION_GRANTED ) { Log.e(TAG, Android 12 需要先授予 BLUETOOTH_CONNECT) return false } } return adapter.getProfileConnectionState(BluetoothProfile.HEADSET) BluetoothProfile.STATE_CONNECTED }这里的核心逻辑是调用getProfileConnectionState()时传入BluetoothProfile.HEADSET返回值等于STATE_CONNECTED才说明耳机已经在通话协议上就绪。getDefaultAdapter()返回空时直接返回 false避免后续空指针。如果你在 UI 层还需要监听耳机的插拔状态可以动态注册ACTION_ACL_CONNECTED和ACTION_ACL_DISCONNECTED两个广播在广播里重新调用这个函数刷新连接状态。注意ACTION_ACL_*系列广播在 Android 12 上同样需要BLUETOOTH_CONNECT权限漏掉就是闪退。3.2 第二步拨号注意号码里的 # 和 * 别被转义吃掉拨号代码本身不复杂复杂的是号码处理。网上大量教程里的写法是Uri.parse(tel: phoneNumber)这个写法拨普通手机号没问题但一旦号码里包含#或*比如运营商服务码*100##会被默认编码成%23导致拨号盘识别失败。这份资源里的写法做了特殊处理fun dialNumber(context: Context, rawNumber: String) { if (rawNumber.isBlank()) return // 缺少 CALL_PHONE 权限时直接退出避免 startActivity 抛异常 if (context.checkSelfPermission(Manifest.permission.CALL_PHONE) ! PackageManager.PERMISSION_GRANTED ) { Log.e(TAG, 缺少 CALL_PHONE 权限无法直接拨号) return } // 第二个参数 #* 是关键允许 # 和 * 原样保留 val safeNumber Uri.encode(rawNumber, #*) val intent Intent(Intent.ACTION_CALL).apply { data Uri.parse(tel:$safeNumber) flags Intent.FLAG_ACTIVITY_NEW_TASK } context.startActivity(intent) }这里最值得注意的就是Uri.encode(rawNumber, #*)这个重载第二个参数是要保留不编码的字符集合。ACTION_CALL和ACTION_DIAL的区别也顺带说一句ACTION_CALL是直接拨出ACTION_DIAL只弹出拨号界面本场景要的是前者。flags加上FLAG_ACTIVITY_NEW_TASK是因为这里的 context 可能是非 Activity 上下文不加在某些机型上会报错。另外rawNumber建议在使用前做一次 trim去掉空格和换行这个细节能避免不少诡异问题。3.3 第三步SCO 音频通道把通话声音真正切到耳机SCO 是蓝牙耳机通话时专用的音频链路全称是 Synchronous Connection-Oriented。很多人在这里翻车ACTION_CALL已经拨号成功了通话也接通了但声音从手机听筒出来耳机里一片安静问题就是 SCO 没有建立。SCO 的建立不能靠调用isBluetoothScoOn true硬切这个过程是异步的必须配合系统广播确认链路真正连通。class ScoController(private val context: Context) { private val audioManager context.getSystemService(Context.AUDIO_SERVICE) as AudioManager /** 建立 SCO 链路注意这是异步过程不是调用后立刻生效 */ fun startSco() { if (audioManager.isBluetoothScoAvailableOffCall) { audioManager.startBluetoothSco() } } fun stopSco() { audioManager.stopBluetoothSco() audioManager.isBluetoothScoOn false } /** 监听 SCO 状态广播在 UI 层等真正 CONNECTED 后再显示通话中状态 */ fun registerScoReceiver(receiver: BroadcastReceiver) { context.registerReceiver( receiver, IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED) ) } }这段代码里的startSco()只是发起请求系统随后会广播ACTION_SCO_AUDIO_STATE_CHANGED携带的EXTRA_SCO_AUDIO_STATE依次是SCO_AUDIO_STATE_CONNECTING、SCO_AUDIO_STATE_CONNECTED、SCO_AUDIO_STATE_DISCONNECTED。只有在收到CONNECTED后才能认为声音通道切换成功。isBluetoothScoAvailableOffCall这个判断是为了避免在设备本身不支持通话 SCO 时白忙一场。Android 12 以后系统推荐用AudioManager.setCommunicationDevice()新 API但实测中很多国产 ROM 对老接口的兼容更好保守方案是两者都保留优先用新 API失败后回退到老接口。3.4 第四步监听通话状态联动 UI 与声音路由拨号之后要实时感知通话状态才能决定什么时候建立 SCO、什么时候显示挂断按钮。这里用TelephonyManager.listen()注册监听Suppress(DEPRECATION) fun watchCallState(context: Context, callback: (Int, String?) - Unit) { val tm context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val listener object : PhoneStateListener() { override fun onCallStateChanged(state: Int, phoneNumber: String?) { callback(state, phoneNumber) } } tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE) }回调里拿到的state有三种关键取值CALL_STATE_IDLE表示空闲CALL_STATE_RINGING表示来电响铃CALL_STATE_OFFHOOK表示已进入通话。在实际项目里我一般是在OFFHOOK时调用startSco()在IDLE时调用stopSco()这样 SCO 的建立和释放刚好贴着通话生命周期。注意phoneNumber参数在部分 Android 版本和机型上会因为权限限制拿不到不要依赖它做核心逻辑。PhoneStateListener在 Android 12 上已标记弃用推荐用TelephonyCallback但老接口依然可用加Suppress(DEPRECATION)是为了让编译安静不是偷懒。3.5 挂断能反射就反射反射不了就引到通知栏自动挂断是这个资源里最敏感的部分因为系统并没有给普通应用提供公开的挂断接口。Android 8 之前TelephonyManager.endCall()还是公开 API但之后被标记为隐藏。网上很多工程用反射来调这个代码仓库里也保留了这个方案但我必须把边界说清楚fun endCallCompat(tm: TelephonyManager): Boolean { return try { val endCall tm.javaClass.getMethod(endCall) endCall.isAccessible true endCall.invoke(tm) as Boolean } catch (t: Throwable) { Log.w(TAG, endCall 反射失败: ${t.message}) false } }这段代码在 Android 8 以下基本可用在 Android 8 到 10 的多数 ROM 上也能跑通但 Android 11 之后部分厂商加强了隐藏 API 限制反射可能直接被拒。如果你的 App 面向最新系统更稳的做法是在通话状态下弹出一条系统通知引导用户通过通知栏挂断或者直接把挂断动作绑定到耳机侧按键事件上。TelecomManager.endCall()是公开 API但需要MODIFY_PHONE_STATE签名权限普通应用写了等于没写。搞清楚这个边界比找到一个能用的反射代码更重要。3.6 参数速查表函数关键参数作用isHeadsetConnected()BluetoothProfile.HEADSET检查 HFP 连接状态dialNumber()Uri.encode(rawNumber, #*)构造 tel Uri 并保留特殊字符startSco()isBluetoothScoAvailableOffCall发起 SCO 异步建立watchCallState()LISTEN_CALL_STATE监听通话状态变化endCallCompat()hide反射尝试自动挂断失败返回 false4. 避坑记录权限崩溃、后台启动限制与 SCO 无声的五个真实场景4.1 Android 12 上打开页面直接崩溃Android 11 上一切正常现象同一份代码Android 11 手机上跑得好好的换到 Android 12 手机打开蓝牙页面就闪退Logcat 里报SecurityException: Need BLUETOOTH_CONNECT permission。原因Android 12 开始蓝牙相关权限从普通权限升级为运行时权限。Manifest 里声明了BLUETOOTH_CONNECT还不够必须在代码里动态申请否则任何蓝牙 API 调用都会抛异常。解决动态申请BLUETOOTH_CONNECT并处理onRequestPermissionsResult回调。建议在申请前先判断Build.VERSION.SDK_INT 31老版本走老权限逻辑新版本走新权限逻辑。不要想当然地只加 Manifest 声明。4.2 拨号成功通话声音却从手机外放出来现象ACTION_CALL已经调起拨号电话也打通了但声音从手机底部扬声器出来蓝牙耳机里完全没声音。原因SCO 链路没有建立。最典型的原因是调用了startBluetoothSco()后马上设置isBluetoothScoOn true但 SCO 建立是异步的这两个操作之间没有等待系统广播确认链路已连通。解决监听ACTION_SCO_AUDIO_STATE_CHANGED收到SCO_AUDIO_STATE_CONNECTED后再更新音频路由。另外部分 ROM 在OFFHOOK状态刚切进来时立即调用startBluetoothSco()会失效实测需要延迟 200 到 500 毫秒再调用。这一点是这个资源里最值得记住的经验属于那种不踩一遍根本不会想到的细节。4.3 App 退到后台后按耳机按键拨号没有反应现象App 在前台时一切正常按 Home 键退到后台再按耳机上的接听键界面弹不起来Logcat 里提示后台启动 Activity 被限制。原因Android 10 开始限制后台应用启动 Activity。耳机按键触发的拨号本质上是一个 App 进程内的回调回调里调startActivity()时如果 App 不在前台系统直接拦截。解决按耳机按键时先判断应用是否在前台不在前台就通过前台服务把进程状态提升或者弹一条高优先级通知引导用户点击进入。真正要完全绕开这个限制只能引导用户把 App 设为默认拨号器角色这个需要系统设置界面配合普通应用无法自己完成。4.4 拨打运营商服务码 *100# 时号码被截断现象拨普通手机号正常拨打*100#这类服务码时拨号盘显示%23100%23号码无法识别拨号失败。原因Uri.parse(tel: phoneNumber)这个写法里#被默认编码成%23。HTTP 场景下这个编码是对的但电话 Uri 场景下#是号码的一部分不应该编码。解决使用Uri.encode(rawNumber, #*)第二个参数明确放行#和*。这个坑在绝大多数教程里都不会提只有真正打运营商服务码才会遇到。4.5 自动挂断反射调用失败返回 false现象调用endCallCompat()后电话没有挂断返回 false日志里出现NoSuchMethodException或SecurityException。原因TelephonyManager.endCall()在 Android 8 后被标记为隐藏 API不同厂商对反射的限制力度不同。部分严格限制的 ROM 会直接拒绝访问这不是你代码写错了是系统策略问题。解决不要把反射当主力方案。实际项目里我一般把反射挂断作为 Android 10 以下机型的优先方案Android 11 以上引导用户使用通知栏挂断或者利用耳机侧按键事件来挂断。这样既不违背系统限制也不影响用户体验。5. 进阶把耳机按键接进来实现“单击拨号 双击挂断”的完整链路前面几章讲的都是 App 内部主动拨号的场景蓝牙耳机真正的价值在于耳机侧按键操作。这一章把 KEYCODE_HEADSETHOOK 接进来实现单击拨号、双击挂断的完整链路。核心思路是注册一个 MediaSession拦截耳机接听键的媒体按键事件再配合通话状态判断执行不同动作。private val hookClick Handler(Looper.getMainLooper()) private var lastHookClickAt 0L private var singleClickRunnable: Runnable? null fun handleHeadsetHook(callState: Int) { val now SystemClock.uptimeMillis() // 400ms 内收到第二次点击判定为双击 if (now - lastHookClickAt 400L) { singleClickRunnable?.let { hookClick.removeCallbacks(it) } singleClickRunnable null lastHookClickAt 0L endCallCompat(telephonyManager) return } lastHookClickAt now val task Runnable { when (callState) { TelephonyManager.CALL_STATE_IDLE - dialLastOrPreset() TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK - startSco() } } singleClickRunnable task hookClick.postDelayed(task, 500L) }这段逻辑的关键在于单击和双击的互斥处理第一次按键不立即执行动作而是延迟 500 毫秒等第二次按键如果第二次来了就把尚未执行的单击任务取消改为执行挂断。lastHookClickAt用来做双击判定窗口400 毫秒这个值可以根据实际耳机微调不同耳机按键消抖时间不一样太短会漏判双击太长会让单击响应变肉。dialLastOrPreset()是我封装的一个函数优先重拨最近号码没有最近号码就拨打预设号码避免重复读取通话记录权限。实际测试时还有一个容易忽略的坑部分耳机的长按拒接会在底层产生两次 ACTION_DOWN 事件导致单击被误判成双击。我的处理方式是在onMediaButtonEvent的ACTION_UP回调里判断按键持续时长如果超过 600 毫秒就丢弃这次事件不进入上面的双击判定流程。这个细节是在某款国产蓝牙耳机上碰到的折腾了大半天才定位到是按键事件重复上报不是代码逻辑问题。从那以后我每次把这类拨号 Demo 递出去之前都会强制自己走一遍四步检查权限清单是否匹配目标系统版本、拨号时是否在前台、SCO 建立时机是否正确、挂断逻辑有没有回退方案。看起来都是小细节但每个都能让功能直接失效。这套代码仓库把链路都打通了剩下的是按你的目标机型做一轮针对性适配。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

QCC蓝牙耳机调试利器:GaiaClientSrc安卓源码与Gaia协议实战解析

QCC蓝牙耳机调试利器:GaiaClientSrc安卓源码与Gaia协议实战解析

简介:高通QCC514x与QCC304x蓝牙耳机方案开发者适用的官方Android客户端GaiaClientSrc完整工程源码,可自行编译生成APK,用于研究官方App功能实现与蓝牙设备交互逻辑。由于iOS版未在App Store上架,官方只放出源码,Androi…

2026/10/15 12:47:14 阅读更多 →
QT+C++调用SQLite实现安全增删查改实战指南

QT+C++调用SQLite实现安全增删查改实战指南

1. 这不是“学数据库”,而是让C程序真正活起来的实操起点 你写完一个QT界面,按钮点了没反应,输入框填了没保存,列表刷新全是空——问题往往不在UI设计,而在背后缺了一块“记忆”。SQLite就是这块最轻、最稳、最不折腾的…

2026/10/15 12:46:13 阅读更多 →
MyBatisPlus Service层配置详解:从IService到ServiceImpl的实战指南

MyBatisPlus Service层配置详解:从IService到ServiceImpl的实战指南

1. 从IService到ServiceImpl,MyBatisPlus Service层的设计思路先说个结论:MyBatisPlus的Service层配置,本质上就是帮你把“重复的Service代码”砍掉大半,但前提是你得理解它背后的两条设计主线。第一条主线:单表CRUD通…

2026/10/15 12:46:13 阅读更多 →

最新新闻

DMOA优化CNN-LSTM-Attention超参数:Matlab故障诊断实战指南

DMOA优化CNN-LSTM-Attention超参数:Matlab故障诊断实战指南

做故障诊断这块的同行应该都有体会,模型的骨架搭起来并不难,难的是怎么让它稳定到“能打”的状态。CNN提取特征、LSTM抓时序依赖、Attention分配注意力,这三件套用在轴承、齿轮箱、电机这类旋转机械的故障诊断里,早已是主流打法。…

2026/10/15 13:42:12 阅读更多 →
Win10家庭版安装Docker Desktop的WSL2完整指南

Win10家庭版安装Docker Desktop的WSL2完整指南

1. 为什么家庭版用户总在 Docker Desktop 安装界面卡住——不是系统不行,是微软留的“门禁”没打开你点开 Docker Desktop 的 .exe 安装包,进度条走到 85%,弹出一行红字:“Windows Subsystem for Linux (WSL) is not enabled”&am…

2026/10/15 13:42:12 阅读更多 →
手动整合Spring与SpringMVC:深入理解框架底层原理的实战指南

手动整合Spring与SpringMVC:深入理解框架底层原理的实战指南

1. 为什么还要死磕 Spring SpringMVC 这套“老组合”先把结论摆在前面:Spring SpringMVC 这套组合放到今天,依然是最适合用来打通“框架底层认知”的练手项目。你可能已经在用 Spring Boot 写业务了,注解一贴、启动类一跑,接口就…

2026/10/15 13:42:12 阅读更多 →
Java+SpringBoot+SSM爱心公益网站系统开发实战:从需求分解到部署上线

Java+SpringBoot+SSM爱心公益网站系统开发实战:从需求分解到部署上线

接手过这么多公益类网站的需求,"基于JavaSpringBootSSM爱心公益网站"这个标题我可以说非常熟悉。很多同学拿到这种课设或毕设题目时,第一反应是上网找个模板改改,结果项目做完也说不清自己干了什么。这篇文章我把自己做类似项目时的…

2026/10/15 13:42:12 阅读更多 →
阿培利司Vijoice治疗PROS:PIK3CA体细胞突变的靶向治疗逻辑与适应症

阿培利司Vijoice治疗PROS:PIK3CA体细胞突变的靶向治疗逻辑与适应症

PIK3CA 相关过度生长谱系疾病(PROS)是一类由 PIK3CA 体细胞激活突变驱动的罕见病谱系,包含 CLOVES 综合征、巨脑 - 毛细血管畸形综合征(MCAP/M-CM)、Klippel‑Trenaunay 综合征、面部浸润性脂肪瘤病等多种表型&#xf…

2026/10/15 13:42:12 阅读更多 →
【方达炬治学】方达炬:一个国家的领导权,衰弱,崛起;看它的年薪,货,时机;

【方达炬治学】方达炬:一个国家的领导权,衰弱,崛起;看它的年薪,货,时机;

【方达炬治学】方达炬:一个国家的领导权,衰弱,崛起;看它的年薪,货,时机;

2026/10/15 13:41:11 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →