ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

纯本地运行的“赛博女友“:基于 Qwen3 + Whisper + Realtime API 的端到端语音对话系统

2026/8/4 1:29:03 拓冰建站 浏览量
纯本地运行的“赛博女友“:基于 Qwen3 + Whisper + Realtime API 的端到端语音对话系统 前言随着 Qwen3 系列模型和 Realtime API 协议的开源本地搭建一个低延迟、全离线的实时语音 AI 伴侣已经不再是难事。本文介绍一个名为cybergirl-bundle赛博女友整合包的开源项目它把 LLM 推理、语音识别、语音合成、网页前端全部打包成一个双击即用的整合包目标用户是希望在自己电脑上跑一个会说话的 AI 伴侣的开发者。项目核心特点全离线部署完成后断网可用所有模型在本地推理双击启动一个.bat拉起三个服务并自动打开浏览器OpenAI Realtime API 协议浏览器通过 WebSocket 直连语音服务GPU 加速llama.cpp CUDA 12.4 PyTorch cu124可分发整合包内置 uv、Python、ffmpeg接收方无需预装任何开发环境一、系统架构整个系统由三个独立服务组成通过 HTTP 和 WebSocket 串联┌──────────────┐ HTTP /v1 ┌──────────────────┐ WebSocket ┌──────────────┐ │ llama-server│ ◄──────────► │ speech-to-speech │ ◄─────────► │ Browser │ │ (LLM 大脑) │ OpenAI API │ (语音中枢) │ Realtime │ (呼吸球 UI) │ │ 端口 8080 │ │ 端口 8765 │ API │ 端口 7860 │ └──────────────┘ └──────────────────┘ └──────────────┘ Qwen3-4B GGUF Whisper Qwen3-TTS Web Audio API1.1 服务①LLM 推理llama.cpp使用 llama.cpp 的llama-server.exe加载 Qwen3-4B-Instruct-2507 的 Q4_K_M 量化版本对外暴露 OpenAI 兼容的/v1接口。关键启动参数llama-server.exe -m %MODEL_PATH% -c 8192 -fa on --port 8080 -ngl 99参数含义-c 8192上下文窗口显存吃紧可降到 4096-fa onFlash Attention 加速-ngl 99全部层 offload 到 GPU显存充裕12GB时可切换到 Qwen3-30B-A3B-InstructMoE 架构在消费级显卡上也有可接受的速度。1.2 服务②语音中枢speech-to-speech这是整个系统的核心基于 speech-to-speech 项目在一个进程内串联了三件事STTopenai/whisper-large-v3中文识别LLM 转发通过responses-api后端把请求转发给本地 llama-serverTTSQwen3-TTS-1.7B支持多音色和参考音频克隆对外暴露一个 WebSocket 端点ws://localhost:8765/v1/realtime实现了OpenAI Realtime API 协议前端可以像调用 OpenAI 官方 Realtime 接口一样使用它。关键启动参数speech-to-speech.exe ^ --mode realtime ^ --stt whisper --stt_model_name openai/whisper-large-v3 ^ --language zh ^ --llm_backend responses-api ^ --model_name qwen3-4b ^ --responses_api_base_url http://127.0.0.1:8080/v1 ^ --responses_api_stream ^ --tts qwen3 --qwen3_tts_backend torch ^ --qwen3_tts_speaker vivian ^ --qwen3_tts_language zh ^ --enable_live_transcription⚠️ Windows 上必须加--qwen3_tts_backend torch因为默认的 ggml 后端依赖 C 包在 Windows 上经常缺失。1.3 服务③Web 网页FastAPI 静态前端[server.py](file:///h:/赛博女友/cybergirl-bundle/web/server.py) 只是一个极简的 FastAPI 静态文件载体真正的逻辑全在 [index.html](file:///h:/赛博女友/cybergirl-bundle/web/static/index.html) 里。浏览器加载页面后直接通过 WebSocket 连到 s2s 服务中间不经过任何代理appFastAPI(title赛博女友,docs_urlNone,redoc_urlNone)app.mount(/static,StaticFiles(directorySTATIC_DIR),namestatic)app.get(/,response_classHTMLResponse)asyncdefindex():returnFileResponse(STATIC_DIR/index.html,media_typetext/html; charsetutf-8)这种前端直连 Realtime API的设计让音频流无需经过 Web 服务转发延迟更低。二、核心技术实现2.1 OpenAI Realtime API 协议落地前端连接 WebSocket 后第一件事是发送session.update配置会话sendJson({type:session.update,session:{type:realtime,// 必填否则被拒绝instructions:settings.instructions,// 系统提示词audio:{input:{transcription:{model:whisper-large-v3},turn_detection:{type:server_vad,threshold:0.2,// VAD 灵敏度prefix_padding_ms:1000,// 语音前填充silence_duration_ms:1000,// 静音判定时长},},output:{voice:settings.voice},// 实时切换音色},},});几个踩坑点值得注意type: realtime字段必填缺少这个字段请求会被直接拒绝voice字段支持运行时切换通过再次发送session.update即可热切换音色无需重连VAD 参数调优threshold0.2silence_duration_ms1000是为了能捕获拜拜这种短语音默认参数会截断到 480ms 导致 whisper 报 “too few tokens”2.2 Web Audio API 流式播放TTS 返回的是 PCM 音频块audio.delta事件base64 编码前端需要用 Web Audio API 实时播放。这里有几个容易踩的坑坑1AudioBufferSourceNode 被 GC 回收如果创建AudioBufferSourceNode后立即start()而不保留引用浏览器可能在播放前就把它当垃圾回收了表现为长回复播到一半就停。解决方案是维护一个activeSources数组播放结束才释放constactiveSources[];src.onended(){constiactiveSources.indexOf(src);if(i0)activeSources.splice(i,1);};activeSources.push(src);src.start(nextPlayTime);坑2AudioContext 被浏览器挂起当标签页切到后台浏览器会自动suspendAudioContext导致currentTime停止增长预调度循环空转。需要在 pump 循环里检测并恢复if(playCtx.state!running){dbg(WARN,⚠ playCtx stateplayCtx.state);playCtx.resume();return;// 下一轮再调度}坑3预调度过早导致缓冲被丢弃浏览器会丢弃调度时间过远的 buffer。需要限制nextPlayTime - currentTime ≤ PRE_SCHEDULE_S默认 1 秒才创建 source用pendingChunks队列 setTimeout延迟调度。2.3 半双工防回环全双工模式下AI 说话的声音会被麦克风回采触发 VAD 误判形成自言自语回环。项目的解决方案是半双工静音caseresponse.created:// AI 开始生成立即静音麦克风上行micMutedByHalfDuptrue;break;caseresponse.done:// 不能立即解除否则 TTS 尾音还会触发 VADsetTimeout((){micMutedByHalfDupfalse;},1500);break;2.4 短语音识别优化中文里拜拜“嗯”好这种极短词很容易被 VAD 截断成 480ms 的片段whisper 会报 token 不足。优化手段VAD 参数放宽silence_duration_ms1000、prefix_padding_ms1000短音频补静音到 2 秒前后各补一半whisper 强制max_new_tokens30、min_new_tokens4三、整合包工程化这个项目最值得借鉴的是它的整合包工程化思路——让一个依赖 CUDA、PyTorch、多个大模型的应用可以像绿色软件一样分发。3.1 uv 包管理器 内嵌 Python整个项目用 uv 管理 Python 环境并把 Python 解释器缓存到项目目录内set UV_PYTHON_INSTALL_DIR%~dp0python-cache接收方电脑不需要预装 Python首次运行首次部署.bat时 uv 会自动从缓存安装。3.2 CUDA 版 PyTorch 强制锁定PyPI 默认的 torch 是 CPU 版直接装会导致推理慢死。通过pyproject.toml强制指定 CUDA 12.4 源[[tool.uv.index]] name pytorch-cu124 url https://download.pytorch.org/whl/cu124 explicit true [tool.uv.sources] torch { index pytorch-cu124 } torchaudio { index pytorch-cu124 }3.3 离线模式启动脚本里设置两个环境变量强制使用本地缓存模型避免运行时尝试联网set HF_HUB_OFFLINE1 set TRANSFORMERS_OFFLINE13.4 端口就绪检测三个服务有启动顺序依赖用 PowerShell 脚本轮询端口而不是死等# wait-port.ps1while($elapsed-lt$Timeout){try{Invoke-WebRequesthttp://127.0.0.1:$Port/health-TimeoutSec 2-ErrorAction StopWrite-Host$Nameready;exit0}catch{Start-Sleep-Seconds 2}}3.5 模型分发策略国内从 HuggingFace 下载极慢项目改用魔搭社区ModelScope模型用途体积Qwen3-4B-Instruct-2507-GGUFLLM 大脑~2.5GBQwen3-30B-A3B-Instruct-2507-GGUFLLM 大脑进阶~18GBwhisper-large-v3语音识别~3GBQwen3-TTS-1.7B语音合成~3.4GBwhisper 和 TTS 模型预置在s2s\.hf-cache\随包分发LLM 模型因体积大由用户手动下载。四、TTS 音色与声音克隆Qwen3-TTS-1.7B 支持CustomVoice模式内置多个音色音色性别备注vivian女默认serena/ono_anna女—aiden/ryan男—进阶用法是参考音频克隆通过--qwen3_tts_ref_audio和--qwen3_tts_ref_text指定一段参考音频TTS 会模仿其音色合成。这个参数与--qwen3_tts_speaker互斥。项目还支持运行时通过session.update的audio.output.voice字段实时切换音色无需重启服务。五、资源占用实测在 RTX 3090 24GB 32GB 内存的真实环境下的实测数据组件显存内存llama-serverQwen3-4B-c 32768~7.4GB—speech-to-speechwhisper TTS VAD—~7.8GB系统 浏览器—~1.3GB合计~7.4GB~16.5GBLLM 的内存占用大头是 KV cache-c 32768会吃掉约 4.8GB。降到-c 8192可省 3GB。8GB 显存的显卡可以跑 Qwen3-4B 8192 上下文12GB 显存可以尝试 30B-A3B。六、部署流程速览接收方最终用户只需三步解压整合包到任意目录不要放 OneDrive 同步目录双击首次部署.bat下载 PyTorch 约 2.5GB耗时 5-15 分钟双击启动赛博女友.bat浏览器自动打开硬件要求项目最低推荐显卡NVIDIA 8GB 显存RTX 30/40 系 12GB内存16GB32GB硬盘25GBSSD 30GB仅支持 NVIDIA 显卡AMD/Intel 显卡无法运行。七、踩过的坑与解决方案整理几个实际开发中遇到的关键问题现象原因解决torch 报 CUDA 不可用装成 CPU 版pyproject.toml锁定 cu124 源网页点球没反应WS 地址填了127.0.0.1必须填localhost:8765长回复播到一半停AudioBufferSourceNode 被 GC维护activeSources数组切后台后音频停AudioContext 被 suspendpump 循环检测并resume()拜拜识别失败VAD 截断太短放宽 VAD 参数 短音频补静音AI 自言自语回环扬声器回采触发 VAD半双工静音 延迟解除.bat 中文乱码编码问题必须用 GBK 编码保存Windows 拒绝运行 bat无数字签名“更多信息→仍要运行”八、总结这个项目展示了一个完整的本地实时语音 AI工程化方案几个值得学习的设计协议选型直接复用 OpenAI Realtime API前端可以无缝替换后端整合包思路uv 内嵌 Python 预置依赖让 CUDA 应用也能像绿色软件分发Web Audio API 实战流式 PCM 播放的 GC、suspend、预调度问题及解法半双工防回环消费级麦克风场景下的实用方案适合想要学习端到端语音 AI 系统、或者想在自己电脑上跑一个离线 AI 伴侣的开发者参考。整个系统模块清晰STT/LLM/TTS 三个组件都可以单独替换扩展性强。分享通用链接 https://my.feishu.cn/wiki/J8yCwIDSGifI4jkIg9Yca7Xynuc?fromfrom_copylink提取码: rbdb2u需要的自取