
做语音相关项目有一段时间了我一直对“按住说话”这个交互模式有执念。手机屏幕上那么多按钮唯独PTTPush-to-Talk这个动作最简单按下、开口、松开。过去它只出现在对讲机和语音消息里但在信息真假难辨的今天我总觉得它能干一件更重要的事——变成一个随身的“真相机器”。于是我把“按住说话”和“事实核查”接到了一起做出一个叫 The Truth Machine 的原型按住按钮随口说一句“这种药是不是真的不能空腹吃”松手之后系统用语音识别、信源检索和证据交叉验证在几秒钟内播报一句“此说法存疑目前没有权威指南支持建议空腹服用已找到3条相反依据”。这篇文章就把原型的完整搭建思路、系统架构、核心逻辑和实际踩坑记录都整理出来。整个项目适合两类人看一类是正在做语音助手、访谈记录、会议纪要这类工具的产品或研发想给语音链路加一层“可信度判断”另一类是纯技术爱好者想了解一个多模块系统怎么用最短路径串起来。不懂RAG、向量检索、流式ASR也没关系我会把每个环节都拆到“直接照着配置就能跑”的程度。1. 这个项目到底在做什么从Push-to-Talk说起1.1 为什么是“按住说话”Push-to-Talk这个词最早来自通信行业英文全称就是Push-to-Talk直译是“按下即通话”国内更习惯叫“按键通话”或“按住说话”。通信时代它是半双工对讲的核心同一时间只有一个人能说话按住就是占用信道松开就是释放。到了智能设备上PTT变成了一个更轻量的交互原语微信语音条、对讲机App、车载蓝牙按键都在用。真正让我觉得PTT适合做事实核查入口的原因有三个。第一是低门槛不用唤醒词、不用打字、不用面对一个复杂的搜索框按住说话是绝大多数人已经形成肌肉记忆的动作。第二是边界明确按下代表“我要开始说话”松开代表“我说完了”这个天然的起止信号可以直接变成语音识别系统的触发条件比一直监听麦克风要省电、省算力也更保护隐私。第三是符合“即时求证”的场景人在对话中听到一个拿不准的说法最自然的反应不是掏出键盘敲字而是下意识想反驳或追问如果这时候手边有个按键能马上“开口核实”认知摩擦会小很多。所以我在这个项目里把PTT定义为整个系统的交互骨架而不是一个简单的录音按钮。按住到松开这段时间系统只做一件事采集干净、完整、带明确边界的语音。松开之后所有重活才正式开始。这个设计让后面的语音识别、检索、推理都能在边界清晰的情况下工作避免了很多“语音助手一直在监听结果却不知道怎么触发”的问题。1.2 “真相机器”要解决的真实痛点为什么需要一台“真相机器”我自己在日常工作中有一个很直接的体感群聊、会议、短视频评论区里随口断言出现的频率远高于严谨陈述。比如“这种保健品能降压”“油价马上要大涨”“某手机续航比某品牌好一大截”这些话被反复传播但很少有人会当场停下来验证。等到想验证的时候又往往要打开浏览器、输入关键词、翻十几个网页这个成本太高了高到多数人会放弃。The Truth Machine想解决的并不是“替代搜索引擎”而是把“快速求证”塞进正在发生的对话里。它要回答三个问题这句话有没有可靠信源支持支持到什么程度如果不可靠靠得住的替代说法是什么输出也不是一篇长文而是一个“可信度标签 置信度分数 一句话证据摘要 信源名称”的极简结论让人在放松按键后几秒内就能决定要不要信这句话。这个定位和常见的语音助手有明显区别。语音助手擅长的是“天气怎么样”“帮我设个闹钟”本质是单轮问答事实核查则是面向不确定断言的证据检索与推理它需要的不是百科式回答而是“证据支持度评估”。这也是为什么系统里不能只放一个通用大模型完事必须有检索和交叉验证来做底层兜底。2. 整体技术方案怎么搭架构与关键技术选型2.1 端到端流程从按下按钮到播报结论整个系统跑通后是这样的流程用户按下按键音频数据进入录音缓冲用户松开按键系统先做端点检测VAD把意外停顿、环境底噪、尾音切掉接着把干净音频送给自动语音识别模型转成文本文本经过规整后进入“断言拆分”模块因为一句话里很可能包含多个待核实点拆分后的每个子断言分别触发检索检索来源包括预设白名单站点、新闻搜索、垂直数据库检索命中的文档经过相关性过滤后进入大模型做证据交叉验证输出结构化判断最后用语音合成把结论播出来同时如果有屏幕就把来源列表展示出来。这个流程看起来长但实际交互里用户只感知到一个动作按住、说话、松开、听结果。为了压低延迟我做了两个关键设计。一是“录音缓冲”和“语音识别启动”解耦按下时就开始写环形缓冲区松开后立刻把缓冲尾部的音频补齐而不是等整段语音全部落盘这样可以省掉几百毫秒的录音落盘时间。二是“检索预触发”在语音识别还在进行的时候先用已识别出的前几个词发起一次粗检索把可能命中的文档提前拉进缓存等完整文本出来后直接精排。这套并行策略在后面实测部分会给出具体提速数据。2.2 核心组件选型为什么是这个组合组件选型是整个项目里最费时间的地方。我先把每个模块的选择和理由列出来方便你直接抄作业。模块推荐选择理由替代方案音频采集PyAudio webrtcvad跨平台、社区成熟、能拿到16kHz单声道PCMsounddevice、miniaudio按键监听pynput 键盘/GPIO按键原型阶段可以用电脑键盘或蓝牙按键模拟PTTesp32 物理按键 串口语音识别whisper.cpp 的 small 模型本地推理、隐私可控、中文识别够用FunASR、Paraformer、云端ASR接口端点检测webrtcvad 模式3 能量门限轻量、实时性好适合松键后的尾音切除silero-vad精度更高但重一点文本检索向量库Chroma/FAISS 搜索API混合向量检索适合语义模糊查询搜索API适合时效性断言纯BM25、Tavily/博查API证据交叉验证Claude/GPT/本地Qwen 等 LLM用结构化JSON输出判断结果强制模型引用证据训练小型判别模型语音合成edge-tts 或 PaddleTTS中文自然度足够支持流式播放云端TTS、Azure TTS这里有一个容易被忽略的坑语音识别引擎的选型直接决定了后面所有环节的数据质量。我一开始用云端ASR接口识别准确率确实高但每段音频都要上传等结果返回时延迟已经占了总耗时的一半而且在网络差的环境下会直接卡死。后来切成本地whisper.cpp的small模型虽然在专业术语上偶尔会出错但胜在稳定、可控、离线可用。对于事实核查场景我宁可选“稍微笨一点但老实”的识别模型也不选“聪明但需要网络且时不时超时”的方案。另一个关键判断是事实核查不能只靠大模型的“记忆”。直接问大模型“咖啡会导致骨质疏松吗”它通常能给出一个像模像样的回答但这是语言模型根据训练语料做的概率推理不是基于实时证据的验证。如果某个说法涉及最新研究、新政策、刚发生的事件模型记忆基本不可靠。所以必须走“检索增强生成”路线也就是先检索再判断让模型基于检索到的证据文本输出结论。后面3.2节会具体解释怎么设计证据交叉验证才能让模型不“睁眼说瞎话”。3. 核心环节的实现细节从原型到可用版本3.1 按键触发与语音采集的工程细节先说按键和采集。我的第一个原型用的是电脑键盘上的空格键按住空格开始录音松开空格结束。这样做的好处是开发快pynput一个监听就能搞定坏处是键盘按键和真实使用场景有差距后来我换成了蓝牙自拍杆上的音量键再通过一个简单的串口协议把按键状态发给电脑体验才接近真正的“PTT设备”。音频采集部分用PyAudio打开输入流参数固定为16kHz、单声道、16bit PCM。采样率这里不能偷懒语音识别模型大多是用16kHz音频训练的如果你用44.1kHz的高采样率不仅浪费存储还会影响识别效果所以我第一件事就是把所有音频统一转成16kHz单声道。录音缓冲是实现“按下即开始、松开即结束”的关键。我用一个deque实现环形缓冲区容量设为300ms音频数据。按下的瞬间开始写入松开的时候把缓冲里最后300ms的音频和松开后继续采集的50ms拼到一起这样能保证语音尾音不丢。实际测试中如果不用这个缓冲说话速度稍微快一点、尾音稍微轻一点识别结果就会缺字比如“不能空腹吃”被听成“不能空”。录音结束后先插一个轻量VAD。我用webrtcvad配合音频能量门限做两段式判断第一段用能量门限过滤明显静音第二段用webrtc的VAD把中间的非语音段落识别出来。参数上有个经验值webrtcvad的模式建议直接设成3最高灵敏度因为事实核查场景里人说话通常比较清晰模式3能有效抓住轻音和尾音。但模式3在环境噪声音乐下容易误判所以还要叠加一个短期能量均值的下限低于这个下限的音频直接当静音处理。一个容易踩的坑是“电平削波”。很多麦克风输入增益默认拉得很高说话稍微大点声波形就顶到天花板了识别出来的文字经常出现吞字。我在采集端加了一个峰值检测如果发现连续多个样本绝对值超过0.95就自动把输入增益降6dB追回来。实测下来这个处理比在识别后再修复要有效得多。3.2 事实核查逻辑怎么判断一句话“可信”“存疑”“不实”这是整个项目最核心的部分。一套靠谱的事实核查逻辑不能只靠“感觉”。我把它拆成三级决策先检索再证据抽取最后结构化判断。三级决策的第一步是检索。用户松开按键后ASR输出的文本先经过一个“断言改写”模块把口语变成适合检索的查询。比如用户说“我听说吃这个药的时候不能喝牛奶”改写模块会抽出核心断言“服用该药物期间不宜饮用牛奶”再拆出关键词“药物 牛奶 相互作用”。这里不建议直接用原始文本检索因为口语里的冗余词会严重拉低向量检索的准确率。我给检索系统配了一个双通道向量库负责语义相似搜索API负责时效性。向量库里预置了百科条目、医学公开资料、科普文章、新闻语料搜索API负责实时抓取最近一周的内容。两个通道的结果合并后用归一化的BM25分数和向量余弦相似度做加权排序权重各占一半。排序后取top5文档进入证据抽取。这里有一个我踩过的坑如果只取top1文档就下判断几乎必然被单一信源的立场带偏尤其当这个话题本身有争议的时候取top5并强制要求来自不同主办方才能让后面的交叉验证不至于太偏。第二步是证据抽取。top5文档仍然太长不能全塞给大模型否则上下文爆炸而且费用很高。我先把文档切成句子级的chunk然后对每个chunk做embedding和用户断言计算相似度筛出和断言最相关的支持句、反对句、中性句各若干条。筛选时我还加了一个“内容同质化惩罚”如果5个证据句子虽然来自不同文档但其实是同一篇原始报道的转载那么只算一个独立信源避免一家之言被加权成“多方证实”。第三步是结构化判断。我设计了一个固定的prompt模板要求模型必须输出JSON格式不要输出任何多余解释。模板核心内容大致是这样你是一个事实核查助手。用户提出了一个断言“{user_claim}”。 下面是检索到的证据列表每条都标注了来源域名和发布时间 {evidence_list} 任务要求 1. 只依据上方证据进行判断禁止使用你自己的常识。 2. 判断结果限定为可信、基本可信、存疑、不实 四选一。 3. 输出严格的JSON格式为 { judgment: 可信, confidence: 0-100的整数, summary: 一句话结论摘要不超过30个字, sources: [来源域名1, 来源域名2] } 4. 如果证据中既没有明确支持也没有明确反对只能判“存疑”。这个prompt看起来简单但实际跑下来有几个细节直接影响准确率。一是“禁止使用你自己的常识”这句不能删一旦删掉模型就会拿训练时的记忆补齐证据缺失的部分导致错误判断。二是confidence分数模型常常虚高我后来在得到分数后做了一次“信源交叉率”校正如果支持证据来自2个以上不同主办方的域名confidence加5分如果所有证据来自同一个域名减15分如果没有找到任何独立支持信源强制confidence不高于50。这个校正规则没法让系统完美但能明显压住模型的自嗨倾向。举一个实际跑通过的例子。用户按住说话“咖啡会导致骨质疏松吗”。ASR识别很正断言拆分也没出问题。检索结果里有几篇科普文章给出“每日适量咖啡不影响骨密度”的结论且来源包含医学媒体和营养学会转载同时有一篇来源不明的帖子声称“咖啡因会增加尿钙排出所以导致骨质疏松”。证据抽取后支持句来自前两篇反对句来自那篇帖子。经过交叉验证模型输出“基本可信confidence 71summary为常规剂量咖啡未见明确致骨质疏松证据来源含医学媒体和营养学会”。帖子由于主办方不明且为转载内容权重低被压下去了。这种判断质量已经可以给普通用户一个靠谱的参考。3.3 反馈设计把结论“说”回来事实核查的结果不能跟写论文一样直接念出来。用户在松开按键的时候带着一个明确的期待我立刻想知道答案。所以反馈设计我走了“极简语音播报 可选屏幕卡片”的双通道。语音播报的文案控制在三句以内核心信息只有三个判断词、置信度、一条最短证据。比如“这个说法不可信。现有证据指向相反结论支持度约七成。”如果判断是“存疑”文案变成“暂无法判断。证据不足建议继续查证。”这种短文案用TTS播出来大概2秒用户不需要费劲听细节。另外我还加了一个“核查中”的反馈音。搜索和LLM推理加起来要几秒钟这段时间用户如果什么反馈都听不到会以为系统坏了。我在松开按键后立即播一个很短的“滴”声表示已经开始处理处理完成后直接播报结论。这个设计跟对讲机的“松键提示音”一个逻辑让交互有明确的节奏感。屏幕卡片则是语音播报的补充。有屏幕的设备上我会把结构化JSON渲染成三块顶部是判断标签和置信度条中间是结论摘要底部是来源列表只显示域名不显示全文。来源列表做成可点开的形式让想深究的人能自己去验证。卡片的颜色也做了语义化处理蓝色表示“可信”黄色表示“存疑”红色表示“不实”。这样即使用户没听清播报扫一眼卡片也能快速抓到重点。4. 实测中的常见问题与排查记录4.1 语音识别在强噪音环境下突然“变聋”第一个严重问题是噪音。我在一个开着风扇和净化器的房间里测试whisper small的识别准确率直接从安静环境下的96%掉到了80%出头最典型的现象是“不”字被吞掉比如“不是空腹吃”识别成“是空腹吃”事实核查结论直接反转。这是最危险的一类错误。排查过程分两步。第一步我看波形发现环境底噪把语音的轻音部分完全盖住了VAD切出来的音频段很多是非语音。第二步我加了RNNoise降噪库先把音频过一遍降噪再送进ASR。实测降噪后识别准确率回到了91%左右但随之而来一个新问题RNNoise在音乐场景下会把低频声部削掉识别结果变得很怪。所以我在前端又加了一个音频类型粗判用短期过零率方差和频谱熵判断当前音频更可能是“说话”还是“音乐/噪音”。过零率方差高、频谱熵高的判为音乐此时跳过降噪直接识别其他情况才启用降噪。这套规则谈不上高级但在原型阶段足够解决问题。这里有一个经验不要迷信某一个降噪库的参数默认值。RNNoise默认针对语音电话优化对室内噪声处理还行一旦到户外风声、车辆声占主导还是得回到“硬件层面解决”——用更接近嘴边的麦克风、开降噪耳机模式比任何后处理都靠谱。4.2 一句话里包含多个断言时怎么拆第二个高频问题是一句话里藏着好几个断言。比如“这款手机拍照比某品牌好而且续航一天都没问题”这其实是两个断言一个是“拍照更好”一个是“续航一整天”。如果整体拿去做检索和判断检索结果往往顾此失彼最后模型在两个话题的证据里打转输出一个莫名其妙的“存疑”。解决办法是加一个“断言拆分”模块。这个模块用LLM来做给它的指令很简单把用户输入拆分为多个独立的事实断言每个断言只包含一个可验证的信息点如果某个信息点包含比较关系或具体数字把它单独标出来。LLM拆分后的结果我测试了约200条真实口语输入准确率在82%左右剩下的主要问题是把“我觉得某手机好用”这种主观评价也拆成了断言但主观评价本就不该进入事实核查流程所以我加了一道过滤器包含“我觉得”“我认为”“我感觉”的句子直接标记为“观点”不参与核查。拆分之后每个子断言独立走一遍检索和交叉验证最后把多个结论合并播报。比如上例最终会输出“关于续航的说法基本可信有测评数据支持关于拍照的说法存疑缺少可比较的客观评测。”这样的结果比硬着头皮整体回答要准确得多。需要注意的是拆出来的子断言如果超过4个我会直接丢弃扩展性不强的只保留包含明确可验证信息的前两个否则延迟会成倍增加。4.3 事实核查的时效性与来源偏差事实核查最怕的其实是“旧闻当新闻”。有一次用户问“现在是不是可以随便买退烧药了”我的检索结果混杂了几年前的政策新闻LLM被旧闻带跑给出了完全错误的结论。这个问题本质上不是模型能力问题而是检索系统的时效性权重没做好。解决办法是在排序阶段加入时间衰减因子。我给每条检索文档加了一个“发布时间新鲜度”分数近7天的权重为1.030天内的0.8590天内的0.7超过一年的降到0.3。这个权重和相关性分数相乘后再排序。同时对涉及政策、药品、价格、安全类的断言我会强制要求检索结果必须包含近6个月内的内容否则不进证据池。还有一条严格规则如果支持某一结论的文档全部来自同一个域名不论多相关系统都把这个结论降级为“存疑”因为单一主办方信源不足以证明一个断言是可信的。来源偏差还体现在白名单维护上。我建了一个小型白名单库包含医学、法律、经济、教育等领域的权威站点检索时白名单位置加权。但白名单也不是一劳永逸的有些站点虽然域名正统内容却经常做商业推广这种站点如果被检索到我会通过它的页面特征广告占比、署名缺失给它打低分。说白了信源判断不能只看域名长得正不正还得看页面本身的专业度痕迹。4.4 延迟过高导致交互不自然最后一个大问题是延迟。刚开始整个流程是串行的录音结束 - 识别 - 检索 - LLM推理 - TTS播报。我实测了一段3秒语音总耗时居然到了10秒以上用户早就不耐烦了。我拆开看各环节耗时环节耗时3秒语音本地CPUWhisper small 转写1.8~2.5秒检索向量库 搜索API2~4秒LLM 证据交叉验证2~3秒TTS 语音合成1~2秒降低延迟我做了三件事。第一是把“录音结束再识别”改成“边录边识别”。按下说话的过程中ASR就开始对前1秒音频做初步转写虽然不完整但能先提取出前几个关键词触发预检索。等松键语音补齐后只对剩余部分做增量识别合并不完整文本。这个改动把识别加检索的总时间从6秒压到了3秒左右。第二是加了一个短断言缓存。如果用户在短时间10分钟内重复说了一句意思相近的话系统直接返回上次的核查结果不再重新检索。我在测试脚本里模拟了日常使用缓存命中率大概15%别小看这15%一旦命中整个响应时间直接变成1秒以内。第三是把LLM推理放到最后并限制上下文长度。证据只取top5的句子级片段把上下文控制在1500字以内。实际测试中发现把证据从3000字减到1500字LLM输出质量几乎不下降但推理时间能减少1秒左右。这个取舍在交互场景里非常划算。关于延迟还有一条额外经验TTS不要在全部文本生成后再播而是做成流式。比如30字的结论模型生成第一个分句就立刻合成播报后面的在缓冲里继续生成这样用户感觉响应更快比死死板板等全部合成完再播放体验好了不止一个档次。最后再说点个人体会做完这个原型我最大的感受是真正的“真相机器”并不在于机器本身有多聪明而在于它能不能在用户还愿意听的时候给出判断。很多事实核查系统想做“绝对严谨”结果输出一大堆限定语和来源列表用户根本来不及看。我做这版时一直在做减法宁可置信度不是那么精确也要保证用户能在五秒内收到一个能指导行动的信号。如果你也想自己搭一套我的建议是先别碰大而全的框架把链路跑通再说。第一步用电脑键盘按键加whisper和任意一个LLM接口做出一个能响应的Demo第二步再慢慢加检索、加白名单、加断言拆分。每加一个模块都会引入新的延迟和新的错误预期跑通之后你会发现真正的难度全在边界条件噪音、多断言、时效性、单一信源这些东西比模型选型更值得花时间。下一步我准备把医疗、金融、教育这几个垂直领域的白名单拆开做细粒度适配配合领域词典让ASR先纠正专业术语再把判断规则按领域分开让事实核查的颗粒度再细一个级别。这个方向值得继续深挖。