01
核心业务
全双工语音模型由三部分组成:流式识别把用户声音编码成帧,9B 的 Thinker 每 80 毫秒一步决定继续听、开口还是调用工具,dots 把回复文字合成为语音。用户可以在助手说话时直接插话,助手会停下来重新听。原推理服务一次只服务一个会话,第二个人连接会被拒绝。
项目在同一张 H20 上把它改成多路服务,并补齐让别人真正用起来的部分:鉴权与排队网关、手机网页与安卓 App、电脑编程助手插件的一键安装、手机下发任务给电脑执行的协议、管理员后台、跨会话记忆和录音归档。这张卡同时运行其他业务,显存与压测时间窗口需要协调。
- 01多路推理
- 每个会话在共享模型里占一行状态,一步前向同时推进所有在线会话;单步耗时只取决于在线路数和最长上下文。
- 02实时语音
- 听和打断对延迟敏感,说话(语音合成)是算力瓶颈;两者同卡运行时用 CUDA Stream 优先级避免互相挤占。
- 03接入与权限
- 邀请码、飞书登录、电脑端设备授权码和个人密钥分别对应不同用户;满员排队,前面有人挂断后自动接通。
- 04手机与电脑协作
- 手机上的语音助手把任务原话交给电脑上的编程助手,电脑执行、回报进度,敏感操作回到手机确认。
02
使用方式
直接和助手语音对话,边说边听,随时打断。
- 实现
- 网页与安卓 App 共用同一套协议;登录后每个人有独立会话和跨会话记忆,可在通话中附加文字。
- 输出
- 实时语音与字幕;打断响应 p50 约 0.8–1.5 秒,含确认「真的有人在说话」的 0.5–0.8 秒。
- 边界
- 单次通话最长 20 分钟;模型调用记忆工具仍不稳定。
在电脑终端里和编程助手语音协作,读代码、改文件、跑命令。
- 实现
- 一键脚本安装插件(macOS / Linux),终端执行 /live login 后在网页确认授权,不需要复制密钥。
- 输出
- 助手用一两句话说结论,代码、diff 与日志留在屏幕上不朗读。
- 边界
- 回声消除与真机长时间通话尚未完成验收。
人在手机上说任务,家里或公司的电脑去完成。
- 实现
- 网关在手机会话与电脑执行端之间路由任务;电脑回传任务卡片与进度,越界读取需要手机批准。
- 输出
- 任务卡片:结论、改动文件、步骤和命令输出摘要。
- 边界
- 入口默认隐藏,修复后的卡片逻辑尚未再做线上语音复测。
03
技术栈
- 推理引擎
- PythonPyTorchCUDA GraphCUDA Stream 优先级
- 模型
- 9B ThinkerNemotron 流式识别dots 语音合成
- 网关与接入
- asyncio WebSocketOpus飞书 SSO设备授权码
- 客户端
- 手机网页 PWAAndroid AppPi 插件一键安装
- 运维
- Nginx TLSsystemdSQLite对象存储归档
04
系统架构与部署
推理服务
Python / PyTorch / CUDA Graph批处理多会话引擎,最多 16 个会话一起推理;语音合成在同一进程、低优先级 Stream 运行。
网关
asyncio WebSocket / SQLite鉴权、排队、Opus 转码、记忆、远程任务路由与对话监控;模型端口只在本机监听。
客户端
手机网页 / Android App / Pi 插件网页与 App 直接通话;电脑插件经一键脚本安装,用设备授权码登录。
入口与运维
Nginx TLS / systemd / 对象存储独立子域与证书,服务开机自启;录音按策略归档,索引可从云端重建。
05
容量与成本:人数上限由「同时说话」决定
一张卡能同时听很多人,但能同时说话的路数有限。人数上限按同时说话超过 4 路的概率和实测体验共同确定。
- 6% / 28%
- 超过 4 路同时说话的概率
按每人 30% 时间在听回复估算:8 人约 6%,12 人约 28%。
- ≈ 1 秒
- 满员排队接通
前面有人挂断后自动接通,提速后 3 次实测 0.12、0.98、1.00 秒。
- 67 GB
- 生产进程显存
16 个会话、每会话上下文最长约 27 分钟;同卡其他业务约 4–12 GB。
- ≈ 0.58 元
- 每路每小时
按整卡包月折算、8 人上限;8 个名额全天占满时约 0.01 元/分钟。
继续扩容有两条路:继续优化语音合成,或第二张卡专做语音合成,约多出 7 路同时说话;第一张卡听的一侧能撑 50–64 人。
06
体验指标:语音合成提速前后的回复首句
经公网入口,多个测试客户端按真实节奏通话 10 分钟:提问、听完回复、停顿、按 20% 概率插话。指标为模型决定回复到用户听到第一段声音的时间,提速前后参数相同。
提速前提速后单位:秒8 人 3 秒内开口的比例从 81% 提到 98.8%,最慢 3.3 秒;12 人 3 秒内只有 71%,所以线上保持 8 人。16、32 人压测时听的一侧仍稳定,但回复首句 p50 达到 18–21 秒,只用来测极限。
07
核心业务链路
一步前向推进所有在线会话
- 1各会话音频帧
- 2批量编码
- 3预填充分块
- 4Thinker 批量一步
- 5各会话状态机
- 6合成进程池
每个会话的帧到达时间由客户端决定,相位随机。引擎在「所有在线会话都就绪」或「最早就绪的帧已等够合并窗口」时走一步,负载越高每步越满。不参与本步的行写入空槽、状态保持不变;系统提示词的状态按前缀缓存,接入新会话只是一次拷贝。
手机说一句,电脑完成工作
- 1手机语音
- 2助手判断需要干活
- 3原话下发电脑
- 4编程助手执行
- 5任务卡片与进度
- 6语音回报结论
任务卡片显示结论和改动文件,展开可看每一步和命令输出最后 20 行;绝对路径去掉、密钥打码。改完文件或测试跑完立刻回报,某步 20 秒无进展会说一句「正在……」,两次播报至少间隔 15 秒。读取项目目录以外的文件要在手机上批准;电脑掉线时,运行中的卡片标为失败并自动拒绝待确认操作。
08
关键机制与取舍
01批处理引擎:一张卡服务多路独立会话
- 约束
- 单会话服务的状态散落在模型各层,多路共用时既不能串话,也不能让一路的故障拖垮其他会话。
- 做法
- 每会话一行 KV 缓存(8 个全注意力层)与线性注意力状态(24 层),逐行位置与掩码;按「行数分桶 × 长度分桶」捕获 CUDA Graph。识别编码器的缓存放在池里批量回放;原单会话的步进拆成模型前、模型后两半,回复、工具调用逻辑不变。
- 效果
- 客户端协议不需要修改;8 人真实节奏 10 分钟 0 错误,输入延迟 p99 88 毫秒,单帧耗时最大 20.1 毫秒(预算 80 毫秒)。只听不说时一张卡实测撑住 64 人。
02语音合成:同时说话路数从 2.7 提到 14
- 约束
- 人多时回复首句变慢,瓶颈在「同时说话」而不是「同时在听」。原实现每个合成片段都重新解码 33 帧窗口,一张卡只能实时跟上约 2.7 路。
- 做法
- 声码器改为逐层缓存的流式解码(与原输出 SNR 66 dB),再做跨会话批处理,最后把最耗时的 DiT 与编码器也纳入批处理。合成进程在切换会话时换入换出共享缓存,与单独合成逐采样一致。
- 效果
- 单独跑语音合成时同时说话能力 2.7 → 3.9 → 6 → 14 路;与听的一侧同卡后,8 人回复首句 p95 从 4.5 秒降到 2.4 秒,98.8% 的回复 3 秒内开口。
03容量取值:按「同时说话」的概率定人数上限
- 约束
- 同时说话超过 4 路回复就会变慢,但同时在线人数和同时说话路数不是一回事,直接按最大压测路数定上限会让体验不稳定。
- 做法
- 按每人约 30% 时间在听回复估算同时说话的概率,再用真实节奏客户端(提问、听完、停顿、按比例插话)分别实测 8、10、12 人,以「回复首句 p95 ≤ 3 秒、零错误」为准。
- 效果
- 线上定为 8 人、满员排队,前面有人挂断后约 1 秒内自动接通;10 人 p95 3.45 秒、12 人 7.0 秒未达标,作为临时放宽的依据而不是默认值。
04网关:瓶颈在 GPU,不急着换语言
- 约束
- 多路并发时曾考虑把服务改写成 Rust;需要先确认 Python 网关和服务端开销是否真的是瓶颈。
- 做法
- 分别测原始 PCM 转发与 Opus 转码:100 路 PCM 转发、50 路 Opus 转码,统计增加的延迟和 CPU;服务端 Python 开销对照 GPU 时间。蜂窝网络下自动切到 Opus,每路上行从约 256 kbps 降到约 24 kbps。
- 效果
- PCM 转发 100 路增加延迟 p99 小于 5 毫秒、CPU 18%;服务端 Python 开销约占 GPU 时间 2–3%。保留 Python,等人数超过约 50 且普遍用 Opus 时再改多进程或 Rust 编解码。
05对话监控与录音归档:可查、可追溯、默认不动数据
- 约束
- 管理员需要看到谁在线、在说什么,但不能影响实时性能,也要对用户透明;录音满载一天约 207 GB,磁盘需要可控地腾空间。
- 做法
- 监控只保存文字、在网关内存保留 24 小时,每次查看写审计,登录页说明;录音按会话归档到对象存储,清单记录每个文件摘要,上传后整包下载复核,删除本地前再核对索引、远端与本地三项。
- 效果
- 监控每条文字额外 0.28 微秒,100 路约占单核 0.02%;首批 108 段录音 49 秒全部归档、逐文件校验一致,索引可从云端完整重建。
09
上线与运维
推理服务、网关和网页分开发布。网关重启会断开通话,所以只在线上 0 人通话、0 人排队时操作,模型不跟着重启;上线后用临时账号占一个名额走完整链路,不做压测,结束后停用账号、吊销密钥。
- 1确认空闲0 通话、0 排队
- 2备份网关与网页各留一份
- 3发布重启网关、部署网页
- 4健康检查鉴权、接口与模型就绪
- 5单路实测问答、干活与新功能各走一遍
- 6收尾更新文档,停用临时账号
1.04 / 1.08 秒上线后首包
问答与干活模式各一路实测,0 错误。
51 + 48 项网关 / 网页测试
每次合并后本地全量运行;网页版本号随发布递增,旧缓存自动失效。
49 秒首批录音归档
108 段全部上传并逐文件下载复核,抽 1 段恢复与原目录一致。
评估后没有采用
- 推理服务改写为 Rust服务端 Python 开销只占 GPU 时间 2–3%,瓶颈在 GPU。
- 按压测峰值定人数12 人回复首句 p95 7.0 秒,体验不达标。
- 保存双声道混音录音可由另外两路重新合成,却占约 60% 体积;当前不录音,暂不处理。
11
阶段成果
- 单会话全双工模型改造为一张卡上的多路线上服务,客户端协议不变。
- 手机网页、安卓 App 与电脑插件形成完整入口,邀请、登录、排队、任务确认和监控都端到端可用。
- 容量、延迟和每路成本都有真实节奏的实测依据,人数上限按体验指标而不是压测峰值确定。