Qwen-Audio-3.0-Realtime 接进语音客服,先核对采样率和分包大小

文章导读
语音客服接实时音频模型时,“能连上”和“听清楚”是两件事。如果一通通话里转写结果断续、句子被切在半句上,先不要急着调模型参数,按顺序核对三处:采集端送上来的采样率和声道是否规整、分片时长是否大到让一句话横跨两个包、时间戳是否连续。这三处都能从配置、日志和录音文件里查出来,不需要靠反复试。下面的处理顺序适合在测试线路或单条通话上先走一遍,确认无误后再放到正式客服链路上。
📋 目录
  1. 壹 在通话记录里找出被切碎的句子位置
  2. 贰 核对采集端的采样率与声道配置
  3. 叁 把音频按固定时长分包再送
  4. 肆 把上行和下行音频各存一份复听
  5. 伍 记录首包返回时间作为后续基线
A A

语音客服接实时音频模型时,“能连上”和“听清楚”是两件事。如果一通通话里转写结果断续、句子被切在半句上,先不要急着调模型参数,按顺序核对三处:采集端送上来的采样率和声道是否规整、分片时长是否大到让一句话横跨两个包、时间戳是否连续。这三处都能从配置、日志和录音文件里查出来,不需要靠反复试。下面的处理顺序适合在测试线路或单条通话上先走一遍,确认无误后再放到正式客服链路上。

遇到“连得上但听不清”,建议先把异常断句定位到具体秒数,再核对采集端采样率与声道配置,然后统一分片时长并用连续时间戳验证分包没有断档。每一步都用原始音频、转写文本或打点日志来验证,不靠听感判断。采样率不匹配和分包过大都会造成断句,两者常同时存在,需要分开验证;具体取值要结合浏览器录音约束、服务端接收能力和模型输入要求确认,不要直接照搬他人配置。

在通话记录里找出被切碎的句子位置

先把“听不清”落到时间点上。把通话的原始上行音频和转写文本放到同一时间轴上看:音频用播放器打开,记录每一处明显停顿或被截断的秒数;转写文本按句读出,对照播放位置标出对应秒数。建议列一张三列小表,左列是异常秒数,中列是原文听到的内容,右列是转写出来的内容。

异常秒数 | 原始音频听到的内容 | 转写文本内容
00:03.2  | “我想查一下上个月的……” | “我想查一下上”
00:03.8  | “……账单明细” | “个月的账单”

如果断句位置在时间上大致等距,比如每隔固定几秒就断一次,优先怀疑分片时长;如果断句出现在音量较低、语速较快或多人同时说话的位置,优先怀疑采集端格式和降噪处理。这一步只记录位置,不改任何参数。

核对采集端的采样率与声道配置

确认送进模型的音频本身是否规整。在浏览器端,检查录音约束里显式声明的字段:sampleRate、channelCount、echoCancellation、noiseSuppression、autoGainControl。如果不声明采样率,浏览器通常会按设备默认值给,不同机器可能不一致,建议显式写死并在日志里打印最终生效值。

navigator.mediaDevices.getUserMedia({
  audio: {
    sampleRate: 16000,
    channelCount: 1,
    echoCancellation: true,
    noiseSuppression: true
  }
});
// 拿到 track 后再读一次实际值,写入日志
const s = track.getSettings();
console.log(s.sampleRate, s.channelCount);

系统侧录音或网关侧转码也要一起查:录音文件属性里能看到实际采样率和声道数,命令行可以用 ffprobe 反查,确认文件本身是不是单声道、是不是期望的采样率。

Qwen-Audio-3.0-Realtime 接进语音客服,先核对采样率和分包大小
ffprobe -v error -select_streams a:0 \
  -show_entries stream=sample_rate,channels,codec_name \
  -of default=noprint_wrappers=1 call_uplink.wav

反查结果与代码里声明的值不一致时,问题在采集或转码环节,先修这里再谈模型侧。双声道混成立体声再送单声道模型,也常表现为能量被削一半、转写丢字,需要结合环境确认。

把音频按固定时长分包再送

让分包大小成为一个可比较的量,而不是随手定。分片时长太短,请求次数变多;太长,一句话跨包会让模型在片尾截断。建议先固定一个片长并写进配置,例如 200ms 到 500ms 之间取一个值,同时给缓冲区设上限,避免上行拥塞时无限堆积。

SLICE_MS = 300
BUFFER_MAX_MS = 2000
seq = 0
t0 = now_ms()
while (audio = read(SLICE_MS)):
    ts = now_ms() - t0
    send({seq: seq, ts_ms: ts, pcm: audio})
    seq += 1
    if (now_ms() - t0 - last_sent_ts) > BUFFER_MAX_MS:
        log_warn("uplink buffer over limit")
        drop_oldest()

每片带上递增序号和相对起始时间戳,服务端按 ts_ms 是否连续来判断有没有断档:相邻两片的 ts_ms 差值应接近片长,明显偏大说明中间丢片或采集卡顿。把序号和差值写进日志,出问题时直接看这一段,不必重放整通电话。

Qwen-Audio-3.0-Realtime 接进语音客服,先核对采样率和分包大小

把上行和下行音频各存一份复听

分不清是采集失真还是播放侧问题时,两边各留一份。上行存采集端送出的原始 PCM 或 WAV,下行存模型返回的音频,放在同一个通话目录下,文件名带上通话 ID、方向和时间范围,例如 20240601-153012_uplink_0-4200ms.wav、20240601-153012_downlink_0-3800ms.wav。目录按日期分层,便于按通话 ID 定位。

复听时对比三个点:一是音量是否忽大忽小,突然变小的段落往往对应转写丢字;二是背景杂音,键盘声、风扇声在抑制后残留多少;三是断续位置是否与前面标出的异常秒数吻合。上行本身就断,问题在采集;上行完整但下行播放断,问题在返回链路或播放缓冲。

记录首包返回时间作为后续基线

调参之前先留一个能复测的参照值。在客户端打两个点:发出首片的时间、收到第一帧返回音频或首段转写的时间,两者相减记为首包返回时间。打点位置写在日志里,附上本次的采样率、声道、片长,便于条件一致时再比。

通话ID | 采样率 | 声道 | 片长 | 首包(ms) | 备注
C-001  | 16000  | 1    | 300  | 待填     | 测试线路
C-002  | 16000  | 1    | 300  | 待填     | 测试线路
C-003  | 16000  | 1    | 300  | 待填     | 测试线路

建议同一配置连测三轮取平均,避免单次抖动误导判断。后续改片长或换网络环境时,用同一张表复测,比较的是自己前后的记录,不引用外部数据。首包时间明显偏大时,先回到分包大小和上行缓冲去查,再看网络往返。