一小时会议录音丢前文,通常不是模型“记性差”一句话能解释的:常见原因是上下文窗口被截断、分段摘要丢细节、检索片段没被召回,这几类可能叠在一起。VoxMem 的价值是把“忘了多少”变成可比较的数字——用长音频样本跑评测,看记忆保持率随音频长度怎么变化,并在日志里指出从哪一段开始丢。但它给不出“能不能上线”的结论,要先把音频切成 VoxMem 认的格式,再对着你手头的模型接口跑一遍。
判断方向:先用 VoxMem 把“遗忘”量化,再决定是否换模型或加分块摘要。适用场景是 30 分钟以上连续语音,如会议、访谈、课程录音。操作动作是切分长音频、调用评测脚本、读日志里的遗忘位置标记。验证方式是同一批音频分别按 5/15/30/60 分钟长度跑,看记忆保持曲线是否随长度骤降。风险边界:分数依赖样本构造和模型接口实现,换采样率、切分粒度、提问措辞都可能改变结果,不能直接当线上效果预测,需要用你自己的录音复测。
准备一段超过模型上下文窗口的音频,切成 VoxMem 要求的片段
先估算模型的上下文窗口能装多少秒音频。通常按 token 折算,具体比例取决于编码器和 tokenizer,需要结合你的模型确认。切分前统一格式:16 kHz 单声道 wav 是常见选择,如果模型要求 8 kHz 或 24 kHz,改 -ar 即可。
# 统一为 16kHz 单声道 wav
ffmpeg -i meeting_full.m4a -ac 1 -ar 16000 -vn meeting_16k.wav
# 按 30 秒切片,输出 chunk_000.wav、chunk_001.wav ...
ffmpeg -i meeting_16k.wav -f segment -segment_time 30 -c copy chunk_%03d.wav
# 检查总时长和切片数量是否对得上
ffprobe -v error -show_entries format=duration -of csv=p=0 meeting_16k.wav
ls chunk_*.wav | wc -l
切片粒度建议 20 到 30 秒,太短会让评测请求数暴涨,太长则定位不到具体遗忘位置。VoxMem 一般还需要一个清单文件,把片段和“记忆探针”对应起来。下面给出的是骨架,字段名以你本地仓库的样例清单为准,不要自己造字段:
{"clip":"chunk_000.wav","start":0.0,"end":30.0,"speaker":"spk1"}
{"clip":"chunk_001.wav","start":30.0,"end":60.0,"speaker":"spk2"}
{"probe_id":"p1","ask_after_clip":"chunk_119","question":"第 3 分钟提到的项目代号是什么?","answer":"替换为真实答案"}
探针要覆盖不同距离:把问第 3 分钟内容的问题放到第 60 分钟之后再问,同时混入几条第 55 分钟的内容作为近距离对照。这样跑出来的遗忘位置才有参照,不至于把近处答对、远处答错混成一团。
调用 VoxMem 的评测脚本,指定记忆保持率指标
VoxMem 的具体子命令和参数名以你本地仓库的 `--help` 为准,下面是通用调用骨架,参数按实际替换。关键是让评测脚本知道你用哪个模型接口、按多长切片、要输出哪些指标。
python -m voxmem.eval \
`--manifest` probes.jsonl \
`--audio-dir` ./chunks \
`--model-endpoint` http://127.0.0.1:8000/v1/chat/completions \
`--model-name` your-audio-model \
`--sample-rate` 16000 \
`--chunk-seconds` 30 \
`--metrics` memory_retention,probe_hit,forget_position \
`--output` out/run_60min.json
参数含义:`--model-endpoint` 指向你自己的模型服务地址,本地推理框架通常也暴露 HTTP 接口,填它即可,不要硬编某个官方 SDK;`--model-name` 按服务实际要求传;如果接口需要鉴权,加上 `--auth-token` 或对应的 header 配置。`--metrics` 里 memory_retention 是主指标,probe_hit 表示探针是否答对,forget_position 记录首次丢失的位置。
如果 VoxMem 是以 Python 库形式提供,把命令行换成下面这种接入骨架,模块名和字段名同样按实际替换:
from voxmem import Runner, ProbeSet
probes = ProbeSet.from_jsonl("probes.jsonl")
runner = Runner(
model={"endpoint": "http://127.0.0.1:8000/v1/chat/completions",
"name": "your-audio-model",
"timeout": 60},
chunk_seconds=30,
sample_rate=16000,
)
result = runner.evaluate(probes, metrics=["memory_retention", "forget_position"])
result.save("out/run_60min.json")
先拿 5 分钟音频跑通,确认输出 JSON 里有 memory_retention 字段,再放大到 60 分钟。长音频评测请求多,并发和超时要调低一些,否则请求被模型服务丢掉,看起来就像“遗忘了”,实际是评测侧失败,这种假阴性会误导后面的判断。
在评测日志里找到“遗忘位置”标记
评测日志通常按片段逐条记录,第一次探针答错、并且后面连续答错的位置,才记为遗忘位置。单次答错可能来自 ASR 错字或提问措辞模糊,不要直接下结论。
[ts] INFO chunk=000 t=0.0-30.0 probe=p1 hit=true
[ts] INFO chunk=040 t=1200.0-1230.0 probe=p12 hit=true
[ts] WARN chunk=041 t=1230.0-1260.0 probe=p13 hit=false reason=answer_not_found
[ts] WARN chunk=042 t=1260.0-1290.0 probe=p14 hit=false reason=answer_not_found
[ts] INFO forget_position=chunk=041 t_start=1230.0s first_miss=p13
解析时把 t_start 换算成“分钟:秒”,1230 秒即 20 分 30 秒,说明模型大致从这个位置开始丢掉更早的信息。日志是 JSON 输出时,可以用 jq 或 grep 过滤:
jq -r '.events[] | select(.hit==false) | "\(.chunk) \(.t_start) \(.probe)"' out/run_60min.json
grep -n "forget_position" eval.log
验证方式:随机抽两三个 hit=false 的探针,把对应原始音频回放一遍,确认答案确实在音频里、也不是同音词被听错。确认后再把第一个连续 miss 的时间戳记下来,作为该长度下的遗忘位置。
对比不同音频长度下的记忆保持分数
同一模型、同一批音频,只改总长度,分别跑 5、15、30、60 分钟四档。表格可以先留空,跑完再填,不要拿别人的数字代替自己的结果:
| 音频总长 | memory_retention | probe_hit | forget_position(首次) | 备注 |
|---|---|---|---|---|
| 5 分钟 | 待填 | 待填 | 待填 | 基线档,探针 5 到 10 条 |
| 15 分钟 | 待填 | 待填 | 待填 | 观察是否开始下降 |
| 30 分钟 | 待填 | 待填 | 待填 | 接近真实会议中位长度 |
| 60 分钟 | 待填 | 待填 | 待填 | 与 30 分钟档对比 |
读表时看两件事:一是 60 分钟档相对 30 分钟档掉得多不多,二是遗忘位置有没有随长度明显前移。如果 5 分钟档就已经很低,问题多半不在上下文长度,而在切分、探针表述或接口调用;如果 5 分钟正常、只有长音频掉,才算典型的上下文截断。同一长度建议跑两次,波动大的档次不要拿来下判断。
用 VoxMem 结果判断模型是否适合会议录音场景
会议录音的典型需求是:30 到 90 分钟连续音频,事后能回答“谁在什么时候答应做什么”,并能回溯具体的数字、日期、人名和项目代号。这些需求对记忆保持的要求,比单纯语音转写高得多。可以先用下面这套对照关系,把分数翻译成判断,阈值只作起步参考,需要结合你的录音环境确认:
| 场景需求 | 需要看到的信号 | 读 VoxMem 哪一项 | 不达标时先做什么 |
|---|---|---|---|
| 跨 60 分钟追问 | 60 分钟档保持不明显低于 30 分钟档 | memory_retention 与 forget_position | 先做分块摘要,再让模型在摘要和检索片段上回答 |
| 人名、数字、日期回溯 | 实体类探针命中率接近叙述类探针 | 按探针类型分组的 probe_hit | 加实体索引、热词或专门的抽取步骤 |
| 事后批量处理录音 | 各长度档分数稳定,遗忘位置不飘 | 同一长度重复两次的分数波动 | 固定切分粒度和提示词,再排查服务侧超时 |
保守一点的判断标准:如果 60 分钟档的记忆保持率明显低于 30 分钟档,且遗忘位置落在音频前三分之一,就不建议把整段录音直接喂给模型,改用分块摘要加关键信息抽取的组合;如果只有实体类探针掉得厉害,说明模型对具体名词的跨段保持较弱,补实体索引通常比直接换模型更划算。VoxMem 的分数只代表“这批样本、这套接口配置下”的遗忘情况,换录音设备、换口音、换切分粒度都可能变化,上线前用你自己的会议录音再复测一轮。