这是 lmrobot-app Combrabo Voice 一阶段的最小 external runtime helper。它的长期定位是 LiveKit media worker:连接房间、发布 bot 音轨、订阅用户音轨、搬运 / 观测 PCM、输出脱敏诊断。
当前职责分两层:
一阶段固定主动问候职责有 4 件事:
CombraboVoiceRuntimeServiceImpl 注入的 CV_* 环境变量;calls/end 触发 stop。2026-06-24 起进入 helper 下一阶段入口:默认开启用户上行音频观测,先做远端用户音轨订阅和音频帧摘要日志,不做 ASR/LLM/TTS。
它**不承担**鉴权、数据库、订单、旧 TRTC、角色 / 提示词、正式 ASR/LLM/TTS 编排、消息写入、计费或 diagnostics 聚合。上述业务能力继续由 lmrobot-app Java 后端复用现有体系承接。
本定位已按 cb-sdk 真实链路校准:服务端 worker 负责 LiveKit 用户音频输入与 bot 音频输出,后端 speech-runtime 负责 ASR / Agent / TTS / turn 状态。lmrobot 当前 helper 只对齐 media worker / rtc 边界,不新建第二套业务后端。
helper 编译固定分为“开发调试线”和“部署验证线”。详细口径见:
doc/task/202606/0615-nativesdk-combrabo-voice-migration/29-helper编译与验证线路说明.md
本机开发调试优先复用已下载的 LiveKit WebRTC 预编译缓存:
export LK_CUSTOM_WEBRTC="$HOME/.cache/combrabo/livekit-webrtc/mac-arm64-release-webrtc-51ef663"
然后执行:
cargo fmt --manifest-path tools/combrabo-voice-runtime-helper/Cargo.toml --check
cargo check --manifest-path tools/combrabo-voice-runtime-helper/Cargo.toml
cargo test --manifest-path tools/combrabo-voice-runtime-helper/Cargo.toml
LK_CUSTOM_WEBRTC 指向的是 macOS host 开发调试缓存,不能直接用于 Linux Docker 镜像构建。
cargo build --manifest-path tools/combrabo-voice-runtime-helper/Cargo.toml --release
helper 目录内带 .cargo/config.toml,本机构建建议通过 run-local.sh 或进入 helper 目录执行,确保使用同一套 registry / retry 配置。
TTS streaming 相关改动优先跑一条不依赖 LiveKit / WebRTC native 编译链路的快速线:
node tools/validate-turn-stream-fixture.mjs fixtures/turn-stream-happy.ndjson
node tools/validate-turn-stream-fixture.mjs fixtures/turn-stream-mp3-chunks.ndjson
这条快速线只校验 NDJSON contract、事件顺序和 pcm_s16le / mp3 chunk 基本约束,用于提前发现 replyPlaybackMode、reply_state、reply_audio_chunk、turn_completed 等字段破坏。它不能替代 Docker 镜像构建、真实 LiveKit smoke 或 iPhone 真机验收。
推荐通过包装脚本启动:
./tools/combrabo-voice-runtime-helper/run-local.sh
如果本地还没有 release 二进制,脚本会先执行一次构建。
开发调试时建议显式带上本机 WebRTC 缓存:
LK_CUSTOM_WEBRTC="$HOME/.cache/combrabo/livekit-webrtc/mac-arm64-release-webrtc-51ef663" \
COMBRABO_VOICE_RUNTIME_HELPER_MODE=host \
./tools/combrabo-voice-runtime-helper/run-local.sh --prepare
lmrobot-app 线上形态不再适合每次通话直接用命令行拉起 helper。当前 helper 支持 service 外壳:
CV_HELPER_SERVICE_ENABLED=true \
CV_HELPER_SERVICE_BIND=127.0.0.1:18080 \
CV_HELPER_AUTH_TOKEN=local-helper-token \
CV_RUNTIME_TURN_BRIDGE_TOKEN=local-turn-bridge-token \
./target/release/combrabo-voice-runtime-helper
service 模式下,helper 只暴露控制面接口:
GET /healthGET /internal/combrabo-voice/healthPOST /internal/combrabo-voice/sessions/startGET /internal/combrabo-voice/sessions/{callId}POST /internal/combrabo-voice/sessions/{callId}/stopsessions/start 收到 Java 传入的 LiveKit bot 入房材料后,会拉起现有 worker 子进程承接媒体链路。helper service 本身不做 ASR / LLM / TTS / 消息 / 计费,也不持久化业务数据。
鉴权口径:
Authorization: Bearer {helperAuthToken}。authProfile 只是非敏感 alias,首版允许 default / local-dev / dev。turnBridgeToken,再用于调用 Java internal turn bridge。.env、Jenkins credentials 或服务器 ENC 配置,不写入 Git。Docker service mode 本地启动时,run-local.sh 会把 CV_HELPER_SERVICE_BIND=127.0.0.1:18080
映射为容器内 0.0.0.0:18080 并发布到宿主 127.0.0.1:18080。因此本机探活使用:
CV_HELPER_SERVICE_ENABLED=true \
CV_HELPER_SERVICE_BIND=127.0.0.1:18080 \
CV_HELPER_AUTH_TOKEN=local-helper-token \
CV_RUNTIME_TURN_BRIDGE_TOKEN=local-turn-bridge-token \
COMBRABO_VOICE_RUNTIME_HELPER_MODE=docker \
./run-local.sh
curl http://127.0.0.1:18080/health
sessions/start 会等待 worker 回报真实 readiness:worker 在 LiveKit connect 后输出bot_participant_joined,在 bot audio track 发布后输出 bot_track_ready。service 捕获这些
结构化事件后才返回 STARTED + botTrackReady=true;如果 worker 失败或超时,则返回结构化RUNTIME_START_FAILED / RUNTIME_START_TIMEOUT。
helper 当前 MVP 支持 WAV / MP3 音频自动识别。主动问候 prepare 生成的 MP3 可以直接进入 helper;本地 smoke 仍可使用 WAV fixture 作为固定兜底样本。
在 macOS local 环境,推荐先生成一份本机固定问候 WAV fixture:
./tools/combrabo-voice-runtime-helper/generate-local-fixture.sh
默认输出:
tools/combrabo-voice-runtime-helper/.local/greeting-local.wav
lmrobot-app local 推荐设置:
export COMBRABO_VOICE_RUNTIME_WORKDIR=/Users/ar/Applications/combrabo/wwww
export COMBRABO_VOICE_RUNTIME_LAUNCH_COMMAND=./tools/combrabo-voice-runtime-helper/run-local.sh
export COMBRABO_VOICE_RUNTIME_FALLBACK_GREETING_AUDIO_PATH=/Users/ar/Applications/combrabo/wwww/tools/combrabo-voice-runtime-helper/.local/greeting-local.wav
helper 会在播放主动问候前输出脱敏音质摘要,覆盖:
SkippedData / InsufficientData 计数。本地排查音质问题时,可以额外设置 debug dump 目录:
export CV_AUDIO_DEBUG_DUMP_DIR=/tmp/combrabo-voice-audio-debug
开启后 helper 会保留两类文件:
<callId>-greeting-source.<wav|mp3>
<callId>-greeting-target.wav
其中 source 是原始主动问候音频,target 是推送给 LiveKit 前的 48kHz/mono/16-bit WAV。文件只用于本地回听排查,不进入 Git、不写入协作事件正文,不上传到线上环境。
helper 默认开启下一阶段入口观测:
export CV_ENABLE_USER_AUDIO_OBSERVER=true
如需临时回退为纯固定问候播放器,可关闭:
export CV_ENABLE_USER_AUDIO_OBSERVER=false
开启后 helper 会监听 LiveKit TrackSubscribed 事件,并对远端用户音频轨道输出脱敏日志:
runtime helper user_track_subscribe_requestedruntime helper user_track_subscribedruntime helper user_audio_frame_receivedruntime helper user_audio_frame_summaryruntime helper user_audio_stream_ended这些日志只记录 call_id、trace_id、脱敏 participant alias、脱敏 track sid、采样率、声道、帧数和时间摘要。禁止记录 token、room secret、真实 participantIdentity、完整 roomId、音频内容、ASR 文本、用户语音内容或 AI 回复文本。
在确认 helper 能收到用户上行音频帧后,helper 默认开启轻量 VAD:
export CV_ENABLE_SIMPLE_VAD=true
首版 VAD 不引入外部模型,只基于上行 PCM frame 的 RMS / peak 做保守阈值判断。配置了 Java runtime turn bridge 后,helper 会在有效 vad_speech_end 后把本轮 PCM 写成 user.wav artifact,并调用 Java 内部 bridge;helper 仍不做 ASR / LLM / TTS / 消息落库。
可调参数:
export CV_VAD_RMS_THRESHOLD=0.012
export CV_VAD_PEAK_THRESHOLD=0.08
export CV_VAD_START_FRAMES=5
export CV_VAD_END_SILENCE_MS=700
export CV_VAD_MIN_SPEECH_MS=300
export CV_VAD_MAX_TURN_MS=10000
export CV_VAD_INITIAL_IGNORE_MS=500
export CV_VAD_GATE_UNTIL_GREETING_DONE=true
export CV_VAD_POST_GREETING_DELAY_MS=800
Java turn bridge 相关配置:
export CV_RUNTIME_TURN_BRIDGE_URL=http://127.0.0.1:11102/internal/sdk/combrabo-voice/runtime/turns
export CV_RUNTIME_TURN_BRIDGE_TOKEN=local-dev-token
export CV_RUNTIME_TURN_ARTIFACT_DIR=/tmp/combrabo-voice-runtime/turn-artifacts
export CV_RUNTIME_SESSION_NONCE=runtime-session-nonce
这些值由 lmrobot-app 启动 runtime helper 时注入。Docker 模式会透传 env,并把 CV_RUNTIME_TURN_ARTIFACT_DIR 挂载进容器。日志不得打印 CV_RUNTIME_TURN_BRIDGE_TOKEN。
本机 Docker 模式下,run-local.sh 会自动把 CV_RUNTIME_TURN_BRIDGE_URL 中的 127.0.0.1 / localhost 改写为 host.docker.internal,避免 helper 容器把 Java internal turn bridge 误解析为容器自身。
开启后新增脱敏事件:
runtime helper vad_disabled_greetingruntime helper vad_enable_scheduledruntime helper vad_enabledruntime helper vad_ignored_before_enabledruntime helper vad_speech_startruntime helper vad_speech_endruntime helper vad_speech_too_shortruntime helper vad_no_speech_summaryruntime helper turn_artifact_writtenruntime helper turn_bridge_completedruntime helper turn_bridge_failedruntime helper turn_bridge_skipped这些事件只记录 call_id、trace_id、脱敏 participant alias、脱敏 track sid、turn 序号、起止时间、帧数、样本数、RMS / peak 摘要、结束原因、artifact 字节数、bridge HTTP / reasonCode 摘要。它们不记录用户音频内容、ASR 文本、LLM 回复、TTS URL、bridge token 或本机绝对 artifact 路径。
默认启用 CV_VAD_GATE_UNTIL_GREETING_DONE=true,即主动问候播放完成前不产生 vad_speech_start/end。问候播放结束后,helper 会按 CV_VAD_POST_GREETING_DELAY_MS 延迟开启 VAD;门禁期间收到的用户音频帧只输出 vad_ignored_before_enabled 摘要,用于证明上行音频仍在,但不会形成用户 turn。
当前 local 真机复测默认 CV_VAD_POST_GREETING_DELAY_MS=800,用于在主动问候实际写完后保留短尾缓冲,避免 15 秒固定禁听窗口吞掉用户首句。若需要做受控回声隔离实验,可以临时调大该值,但不得作为产品化默认值。
CV_GREETING_AUDIO_FILE:优先读取本地 WAV / MP3 文件;CV_GREETING_AUDIO_URL:支持下载后按 WAV / MP3 解析;calls/start。user.wav artifact 并调用 Java internal turn bridge;bridge 配置缺失时只记录 turn_bridge_skipped,不阻断 helper 进程。