tools/mtmd · libmtmd audio tokenization
贡献角色参与调查者,非主要负责人;尚未提交实现
调查单采样音频的可恢复错误边界
对 libmtmd 音频边界的一项暂定、非主要调查:结构上合法的单采样 PCM bitmap 会触发进程级断言,把异常请求升级为 server 可用性故障。
- Issue
- #27693
- Pull Request
- 尚未创建
- 所属模块
- tools/mtmd · libmtmd audio tokenization
系统背景
llama.cpp 是一个跨平台 C/C++ 推理项目,涵盖模型加载、本地与 server 推理、CPU/GPU 后端以及多模态输入。问题位于 libmtmd——媒体进入模型前的准备层,不在 backend kernel 或文本生成循环中。
音频路径中,llama-server 接收 OpenAI-compatible 的 input_audio 文件;mtmd_helper 通过 miniaudio 将 WAV/MP3/FLAC 解码成单声道 F32 PCM;libmtmd 创建 audio bitmap,随后 mtmd_tokenize 选择 model-specific preprocessor,将媒体转换成 multimodal chunks 与 audio tokens。
音频输入仍属 experimental,且共享 tokenizer 会选择多种 preprocessor。这意味着共享边界检查不能因为某一模型也许会为超短信号补零,就悄悄扩大所有音频模型的可接受输入域。
触发与影响
Issue 报告描述了 Voxtral 路径上的一个 16 kHz 单声道 WAV,解码后恰好只有一个 sample。一个 mono F32 sample 会形成合法的四字节 buffer:nx == 1、buf.size() == sizeof(float),且 buffer 仍然正确对齐。
当前 tokenizer 已把 nx == 0 作为可恢复的空输入错误,但后面又要求 buf.size() > sizeof(float)。对一个 sample 而言,4 > 4 为假,因此 GGML_ASSERT 会走到 ggml_abort,而不是返回一次请求错误。
上游报告中 CLI 会退出、server 在一次请求后失去 /health;这些运行结果属于作者报告,尚非我的本地复现。我当前参与确认的是静态路径与剩余验收门禁,而不是宣称已在 Windows 复现或已经修复。
根本原因
底层 bitmap 并没有损坏。它的字节数是 nx * sizeof(float),所以单采样对象满足表示与对齐不变量。真正的问题是:一个用户可控的最小长度问题,被写成了会终止整个进程的内部内存断言。
把 > 简单改成 >= 虽能避开这条特定断言,却会把单采样信号送入所有 model-specific preprocessor。Whisper-style 路径可能补零;Conformer、Parakeet、Granite Speech、Qwen3 TTS 等路径则有不同的 frame、normalisation 或最小长度语义。静态证据不足以支持全局放行。
错误边界还必须覆盖 /input_tokens 使用的 placeholder bitmap。若只根据 real buffer 修复,同一个 sample count 可能在 token-count 与正常 completion 路径产生不一致行为。
修复与边界
目前没有源码修改。暂定方向是在共享 audio-tokenization 边界以现有的 LOG_ERR + return-error 契约拒绝 nx < 2,并放在 real-buffer 与 placeholder 分流之前。这样异常输入会变成可恢复的请求失败,而不会继续到 abort。
已有的对齐断言仍保留为内部不变量。正常 nx >= 2 的音频仍进入完全相同的 preprocessor 路径;该方案也避免为所有音频模型定义单采样的数值行为。
这是设计候选,而不是实现完成声明。任何代码之前都需要基线复现、对 zero-sample 错误文案作出明确选择、验证 real-buffer 与 placeholder,并补上一条修复前失败、修复后通过的回归测试。
为什么这样设计
本记录被刻意标为非主要贡献。主要贡献候选已转向 Issue #27697;#27693 保留为有据可查的调查与规划参与,不代表我主导了这个 bug 或未来的 patch。
我没有把方案压缩成一个字符的 >= 修改,因为共享边界服务于语义不同的多个 preprocessor。更安全的范围是让异常外部请求可恢复,而不是为所有模型宣称一个未经验证的最小音频策略。
页面保留“上游报告”“静态源码证据”和“运行时门禁仍开放”的区别。当前没有实现、本地 commit、PR、CI 结果、维护者审查或合并可供宣称。
验证证据
- 01
截至 2026-08-27 11:40 AEST,上游 Issue 为 Open、标签为 bug-unconfirmed,且没有关联的 Development branch 或 PR。macOS abort 属于 Issue 作者的来源报告,并非我的本地复现结果。
- 02
在本地基线 11cd988 上的静态源码核对确认了可达路径:解码后的 mono F32 PCM 形成 audio bitmap;nx == 1 产生四字节;tools/mtmd/mtmd.cpp 在可恢复的 nx == 0 分支之后仍使用严格的 > sizeof(float) 断言。
- 03
本记录没有执行 fetch、构建、模型运行、源码修改、回归测试、commit、push、PR 或 CI。Windows 基线复现、server 存活检查、placeholder 覆盖以及完整 0/1/2/正常音频矩阵仍均为开放门禁。
上游进度
- 静态源码路径
已在本地基线 11cd988 核对
- 本地复现
尚未运行
- 实现与回归测试
仅有候选设计
- Pull Request
尚未创建