Notice: In order to resolve issues efficiently, please follow the template and include reproducible details. (注意:为了更加高效率解决您遇到的问题,请按照模板提问,补充可复现细节。) ## 🐛 Bug <img width="1649" height="672" alt="Image" src="https://github.com/user-attachments/assets/b4e74d2e-84f2-41ff-b768-c3115c5caf73" /> <!-- A clear and concise description of the bug. --> ## To Reproduce Steps to reproduce the behavior. Always include the exact command you ran. 1. Install with: `...` 2. Run: `...` 3. See error: `...` ## Code sample <!-- Paste the smallest code sample that still reproduces the issue. --> ```python ``` ## Expected behavior <!-- A clear and concise description of what you expected to happen. --> ## Error logs <!-- Paste the full traceback or relevant logs. Remove private tokens and paths. --> ```text ``` ## Environment - OS: - Python version: - FunASR version: - ModelScope version: - PyTorch / torchaudio version: - Install method (`pip`, source, Docker): - Device (`cuda`, `cpu`, `mps`): - GPU model: - CUDA/cuDNN version: - Docker image tag, if used: ## Audio details If the audio cannot be shared, please describe: - Duration: - Sample rate: - Format: - Language/dialect: - Speaker count: - Background noise/music:
Activity
andyuan1000 commentedon Nov 10, 2026
请大神给点思路...
[-]识别中的文字,比较全,一旦确定后,会发现丢文字;这个一般怎么姐姐姐[/-][+]识别中的文字,比较全,一旦确定后,会发现丢文字;这个一般怎么解决[/+]LauraGPT commentedon Nov 10, 2026
目前只有截图,无法区分这是流式中间结果被正常修订,还是最终结果在 VAD/标点/ITN 阶段丢失。请补充以下可复现信息:
收到这些信息后才能判断应在流式解码、VAD 合并还是后处理路径复现。请勿包含私有路径、令牌或敏感音频。
[-]识别中的文字,比较全,一旦确定后,会发现丢文字;这个一般怎么解决[/-][+]正在识别的文字,显示的文字比较全,但是确定后,会发现丢文字;这个一般怎么解决[/+]andyuan1000 commentedon Nov 11, 2026
@LauraGPT 老师,帮忙排查下
andyuan1000 commentedon Nov 11, 2026
【复现补充】流式中间结果较全、确定后丢文字 —— 以
meeting测试重复.wav为例1. 环境信息
1.4.15(pip 安装,conda 环境)v40-1(无 git 仓库,无法提供 commit)iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404(SeACo-Paraformer-Large)iic/speech_fsmn_vad_zh-cn-16k-common-pytorchiic/punc_ct-transformer_cn-en-common-vocab471067-largeiic/speech_campplus_sv_zh-cn_16k-commonllm.isOpen: false),排除后处理改写文本的可能关键配置(
config_online.yml)调用方式:WebSocket 流式推 16kHz / mono / 16-bit PCM,每 60ms 一帧喂
DynamicStreamingVAD.feed(..., is_final=False);VAD 确认段后走
_decode_segment()整段重解码 →_reconcile_completed_segment_text()→_append_completed_segment()。2. 复现音频
meeting测试重复.wav开头的能量分布(这是"开头丢字"的诱因)
即:一句很短的话(约 0.6 s)后面紧跟 6 秒静音,然后才开始正文。VAD 在 t≈2.70s 才确认第一段
[0-980ms]。3. VAD 分段结果(完整音频,生产配置,60ms 逐帧喂入 +
finalize())确定Locked记录逐段吻合;4. 逐次中间输出 与 最终输出原文(核心复现数据)
以下均在容器里用同一份 Paraformer 权重、
generate()直接解码得到。PARTIAL= 按生产get_partial_decode_audio()的规则取窗口(从vad.current_speech_start到当前时刻,上限 15s);FINAL= VAD 确认段后_decode_segment()实际解码的段区间。4.1 第一段
[0-980ms](开头那句短话)[0, 0.5][0, 1.0][0, 1.5][0, 2.0][0, 2.5][0, 2.6][0, 0.98]现象:同一句开头,在后续长静音里被反复重解码,结果在「星期几啊」和「你几啊 / 你几呀」之间来回跳,首字「星」会丢。这就是"开头丢文字"的直接体现——开头短语音后面跟长静音时,中间结果不稳定。
4.2 第二段
[7090-22100ms](15 秒长段,问题最明显)[7.09, 8.0][7.09, 10.0][7.09, 12.0][7.09, 15.0][7.09, 18.0][7.09, 20.0][7.09, 21.0][7.09, 22.0][7.90, 22.9][7.09, 22.10]两个关键差异:
partial_window_sec=15.0,窗口起点从 7.09s 右移到 7.90s,开头的「这个事还」(4 字)在中间结果里消失。段越长越容易发生。两两个人、现他他们俩、城城区区、副副局、一一个、政政府办),并把「我们根据你」变成「我们会根据你」。前端把流畅的 partial 替换成这个版本,观感就是"确定后文字变差/丢了"。5. 机理分析(对应代码)
get_partial_decode_audio(),partial_window_sec=15.0min_start = total_samples - partial_window_samples会把长段段首截掉_decode_segment()generate(max_new_tokens=512),Paraformer 出现重复字_reconcile_completed_segment_text()catastrophically_short/tail_regressed/truncated_prefix时保留 partial,三者都基于长度,未检测"重复字激增/质量退化",故 FINAL 被直接采纳detect_and_fix_hallucination()两两个人、城城区区这类单字重复_clean_asr_text()ct-punc,。?、,不删字,排除 ITN/标点丢字补充:
_finalize_speakers → HybridSpeakerTracker._try_split()会按说话人重切段,但本次复现未启用该路径即已出现差异,故不是主因。6. 最小复现步骤
repro_03_seg2_15s.wav(7.09–22.10s,16kHz/mono/16-bit,15.01s);partial_window_sec=15.0;partial文本(应为流畅长句);is_final),记录sentences中该段的最终文本;若只需复现"开头丢字",用
repro_01_head_2s.wav(0–2s):把这段反复重解码(模拟长静音期间的 partial 刷新),观察「星期几啊」退化为「你几啊」。7. 附件(均为 16kHz / mono / 16-bit PCM WAV,另附 44.1kHz mp3 便于试听)
repro_01_head_2s.wav/.mp3repro_02_head_12s.wav/.mp3repro_03_seg2_15s.wav/.mp3音频内容为影视剧对白,无真实人名、无内部业务信息、无令牌与私有路径,可公开用于复现。
8. 想请教的问题
两两个人、城城区区),是否属于预期行为?是否有推荐的段长上限或解码参数?partial_window_sec这类窗口上限导致段首文字丢失,是否有推荐做法(例如窗口起点固定在 VAD 段起点、只在尾部截断)?andyuan1000 commentedon Nov 11, 2026
repro_01_head_2s.mp3
repro_03_seg2_15s.wav
repro_03_seg2_15s.mp3
repro_02_head_12s.wav
repro_02_head_12s.mp3
repro_01_head_2s.wav
LauraGPT commentedon Nov 11, 2026
补充信息已读,模型 ID、参数、逐次结果和音频链接不需要重发。目前尚未完成这组音频的独立 GPU 复现;下面是对代码和你提供的时间轴的定位,不是“已解决”的结论。
get_partial_decode_audio()的取窗规则一致。该次 partial 的输入已不含段首,不能直接把它当作覆盖整段的替代文本。repro_03_seg2_15s.wav按说明对应原录音 7.09–22.10s,因此原录音 t=20.0s 对应裁剪文件 12.91s,t=22.0s 对应 14.91s;这份 15.01s 的裁剪本身不包含 t=22.9s 的后续音频。复现脚本应分别标明原录音时间与裁剪内时间,避免比较不同输入却归因于同一解码。目前主线已经有保留对齐 partial 的启发式逻辑,但它不是模型置信度保证。你报告的是 SeACo-Paraformer,而所引用的主线
_decode_segment()调用的是传入的vllm_engine.generate(inputs=...)。下一步需要补齐的是:把config_online.yml、该会话包装器和 ParaformerAutoModel.generate()连起来的最小调用脚本,以及模型 revision/快照版本。尤其请保留输入切片、实际传参和_reconcile_completed_segment_text()前后的原始文本;不需要提供生产配置中的私密字段。先以同一权重、同一段 PCM 和明确的 12.91s/14.91s/15.01s 输入核对模型原始输出,再区分窗口展示、整段推理和 reconcile 的影响。目前不把调整段长或
max_new_tokens当作已验证修复,issue 保持打开。andyuan1000 commentedon Nov 12, 2026
感谢逐条定位。我们按你要求做了控制变量复现,先更正两处我们之前给错的前提,再补齐你要的证据。这不是"已解决"的结论,issue 继续保持 open;本轮未改任何业务代码/配置。
1. 两处更正(重要,会影响后续推算)
1.1 partial 窗口实际是 8.0s,不是 15s
你按 15s 推出的
[7.90, 22.90]、晚 810ms,结论方向没错,但前提是我们给错的:之前文档把vad.max_single_segment_time: 15000当成了 partial 取窗长度,那是 VAD 单段上限。realtime_ws.py里partial_window_sec=8.0(__init__默认值 /--partial-window-sec默认值 / 会话构造处,三处一致),生产启动命令未传--partial-window-sec,故实际窗口为 8.0s:get_partial_decode_audio()取窗:decode_start = max(current_speech_start, total_samples - partial_window_samples)。所以 t=22.9s、段起点 7.09s 时:[7.90, 22.90][14.90, 22.90]实测裸模型输出:8s 窗口 35 字、15s 窗口 70 字、VAD 整段
[7.09,22.10]71 字。段首「这个事你还可以找那个谭秘书和张明他们两个人现在他们俩一个是在这个城关区域当副局长」整段都没进入 8s 窗口的解码输入。窗口缺字属输入切片层,与模型退化分开追踪,这一点完全接受。1.2 "第二段整段 FINAL 的重复字"不是确定性的 final 退化
我们之前把某一次带重复字的输出标为
FINAL/LOCKED并据此断言整段重解码退化,这是采样偏差,需要撤回。补做了字节比对 + 重复调用(同一权重、同一
AutoModel实例、同一数组、同一调用形式,CPU fp32):其中第 2 次几乎完全流畅(仅「这个事儿」「那谭秘秘书」两处),第 3/5 次带明显重复字。另有一处旁证:
M-15.01与W-SEG是同一段 240160 samples 的 PCM,两次direct输出也不同。因此更准确的表述是:重复字是同一段 PCM 上模型输出的波动,在流式里表现为"确定后变差",而不是一次稳定可复现的 final 退化。你提醒的"不能仅凭更长或更流畅的 partial 判断它一定更准确"在这里得到直接支持。非确定性来源我们尚未定位。
2. 其余几点的确认
"第一段 FINAL 没丢『星期几啊』":接受,不再主张第一段丢字,追加静音后的 partial 不稳定另行看待。
"不宜统一删除重复汉字":接受,也不提出该改法。包装层
POST_PROCESS_CONFIG的max_char_repeat=5/max_2gram_repeat=3阈值远高于本例的"2 字重复 2 次",下调会伤及「刚刚 / 看看 / 渐渐」等正常叠词。双时间轴:已按要求分别标注。
repro_03_seg2_15s.wav= 原录音7.09–22.10s:窗口右移实验只用全量音频,未在裁剪文件上比较,避免把不同输入归因于同一解码。音频链接沿用之前提供的,不重发。
3. 环境与模型 revision / 快照版本
fun-asr-nano-realtime:v40-1iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404AutoModel(model_path=...),以本地为准)iic/speech_fsmn_vad_zh-cn-16k-common-pytorch/iic/punc_ct-transformer_cn-en-common-vocab471067-large--device cuda)本地权重目录
.mv:.msc文件级 revision(ModelScope blob hash):model.pt/config.yaml/configuration.json/tokens.jsonff922d0e9af830cee4d1ec9b57b193196941efd8am.mvn/seg_dict/fig/struct.pngb0bf20ac984e61faae6d997e1c9af20c9b1b48d5README.md6059253cbfda9ea43d6c6f198d38854f09adb298example/asr_example.wav17d593c496945f14a7ac387dc47e20a3333a7f9fMD5:
model.pt=da55f0cb422ac0c1a32d1a7a0a295c92(880,502,012 bytes)、tokens.json=2d505fc2487d5acbc5e8d71f9c30d9b7。config_online.yml相关项(已脱敏,不含地址/账号/密钥):4. 最小调用链路:
vllm_engine不是 vLLMconfig_online.yml: asr.engine = paraformer→load_models()走 paraformer 分支 →ParaformerEngineWrapper(AutoModel(...), punc_model)→ 包进RealtimeBatchingEngine→ 赋给模块级_vllm_engine(变量名沿用,实际不是 vLLM)→RealtimeASRSession._decode_segment(seg):ParaformerEngineWrapper.generate()内部是self._asr_model.generate(input=audios, disable_pbar=True),其中input是 list of tensor;之后_normalize_output()→_apply_punc()→_post_process_text();回到_decode_segment()再走_clean_asr_text()→_reconcile_completed_segment_text()→ (条件满足时)边界 retry →_postprocess_result_text()。本轮三种调用形式都测了,实际传参逐条记录:
directAutoModel.generate(input=torch.Tensor[N], disable_pbar=True)batchAutoModel.generate(input=[torch.Tensor[N]], disable_pbar=True)(生产包装层形式)wrapperParaformerEngineWrapper.generate(inputs=[Tensor], hotwords=None, language=None, max_new_tokens=512)均无 hotword、无 language;paraformer 路径忽略
max_new_tokens。包装层函数用 AST 从源码抽到隔离命名空间执行,未 import 业务模块、未启动服务。4.1 可独立运行的最小脚本(L0 裸模型,含双时间轴与重复调用)
把
input=torch.from_numpy(x).float()换成input=[torch.from_numpy(x).float()]即对应生产包装层形式。完整分层脚本、10 组 case 的原始结果与 reconcile before/after 原文我们可以按需要附上。5. 同一权重、同一段 PCM 的模型原始输出(12.91 / 14.91 / 15.01s)
均为裁剪文件内时间,
direct形式(未过任何后处理):12.91s(原
[7.09,20.00],65 字,流畅)14.91s(原
[7.09,22.00],70 字,流畅)15.01s(原
[7.09,22.10],71 字,出现重复字)同一 15.01s 输入的三种形式字数都 71,但重复位置不同:
batch为「张明明们们…这城城区区当当副局长」,wrapper为「两个个人现他他们俩…城城区域当副副长…政政府办」。结合第 1.2 节的重复调用结果,差异更可能来自解码非确定性,而非调用形式。结论 A:重复字在裸模型
direct输出里就已存在,不是包装层 / 标点 / ITN /_post_process_text()引入;_normalize_output()(去中文间空格)与max_char_repeat=5/max_2gram_repeat=3也都不会削掉"2 字重复 2 次"这种模式。6. 窗口展示 / 整段推理 / reconcile 三层分离
6.1 输入切片(原录音时间轴,裸模型字数
direct/batch/wrapper)[14.90,22.90]实际 8s 窗口[7.90,22.90]文档 15s 窗口[7.09,22.10]VAD 整段6.2
_reconcile_completed_segment_text()前后原文输入
seg=[7090,22100]、decode_succeeded=True、segment_partial_stable_count=3、last_partial_eligible=True:before_decoded_text(= 15.01s 整段batch输出,71 字,带重复字;四种场景相同):before_partial_text(= 12.91sbatch输出,65 字,流畅;四种场景相同):adopted_partial即使构造了首尾完全对齐、观察 3 次、eligible 的理想条件,启发式仍直接返回
final_text。逐条判据:final_hallucinated未触发(本例是 2 字重复 2 次);truncated_prefix不满足(partial 65 字 < final 71 字);catastrophically_short不满足(65 ≥ 213 不成立);tail_regressed不满足(65 − 71 = −6)。此外_partial_fallback_candidate还要求start_ms == seg[0]且|end_ms − seg[1]| <= 100,窗口一旦右移就进一步失效。结论 B:该启发式的判据只覆盖"变短 / 尾部回退 / 明显幻听",对"等长或略长、但重复字激增"这类退化没有判据。这具体印证了你说的"保留对齐 partial 的启发式不是模型置信度保证"。reconcile 层既没有制造也没有修复重复字。
6.3 另一个音频上的旁证(不作 VAD 归因)
另取一段 1h 会议音频的前 120s 转 16kHz mono:
[0,7s]输出「我」、[0,15s]输出「嗯」、[0,30s]才输出完整 28 字句子;[7,15s]近静音窗口出现the the the…幻听(三种形式 19/35/27 字)。即高能量开头段未产生可识别文本,与"开头丢字"同构。本组未跑 VAD 段边界,只作旁证。7. 新增一处想请你判断的不一致
磁盘快照的
configuration.json:即快照来自普通
paraformer-large仓库(无 seaco),而代码LOCAL_PARA_NAME传的是 SeACo-Paraformer ID;config.yaml里也是model: Paraformer/predictor: CifPredictorV2,未见 hotword/bias 相关配置。由于AutoModel(model=..., model_path=...)在model_path存在时以本地目录为准,实际加载权重可能是普通 Paraformer。我们不做结论,想确认这一组合是否为预期、是否与重复字 / 非确定性相关。本轮所有测试都使用这一份磁盘权重,因此"同一权重"在本次测试内部成立。8. 仍未验证(不作为结论)
--device cuda,本轮 CPU fp32,未在 GPU 上重复第 1 步核对。decoded_text是同一权重下按 VAD 段边界直接调用AutoModel.generate()得到的复现值。同意不把「调整段长 /
max_new_tokens/ 统一删除重复汉字」当作已验证修复,issue 保持打开。上述材料不含生产配置中的私密字段,转写原文来自测试用对白音频。如果你希望下一步优先做某一项(例如在同一段 PCM 上做 CUDA 复现,或提供完整分层脚本与原始结果 JSON),请指明,我们按该方向补。
老师 这是AI回复的,我真不知道下一步如何解决,给点思路吧
LauraGPT commentedon Nov 12, 2026
先别改生产,也别继续调去重阈值。现在建议按这个顺序做两件小事:
m = AutoModel(...)后加print(type(m.model).__name__)。你提供的本地配置写的是Paraformer / CifPredictorV2,不能因为传入了 SeACo 的字符串 ID 就把本地权重当作 SeACo;当前加载代码会采用本地目录里的模型配置。先把这条事实固定下来,不要同时换模型。m.kwargs["frontend"].dither;若非零,只在离线复现脚本中将这个 frontend 的dither改为0.0,仍用同一份 15.01s PCM、同一实例、相同参数各调用五次,保留全部输出。当前WavFrontend会把该值传给 fbank;这是一个值得单独排除的随机扰动来源,还不是已确认的根因或识别质量修复。若本来就是零,不要改其他参数,先补上实际模型类和这个值即可。8s 窗口不包含前面 7.81s 的语音,不能靠去重或把这段 partial 直接覆盖整段 final 找回。窗口展示与模型输出波动分开处理。本轮你补的是 CPU 结果,不能据此断言生产 CUDA 同样表现;我也尚未完成你的本地权重在 GPU 上的复现,issue 保持打开。
代码依据:本地模型配置加载、frontend 的 dither 传递。这些是当前主线的代码定位,不把你镜像里的实现视为已独立核验。