Marqo 语音数据搜索实战:构建“音频转录 → 语义索引 → 智能问答“全流程系统

发布时间:2026/10/13 1:44:47

Marqo 语音数据搜索实战:构建“音频转录 → 语义索引 → 智能问答“全流程系统 搜索引擎AI 应用后端电商NLP【免费下载链接】marqoEcommerce Search and Discovery - marqo.ai项目地址https://gitcode.com/gh_mirrors/ma/marqo点击查看免费下载语音是人类最常见的沟通方式大量有价值的数据以音频形式存储——视频、播客、电话录音、会议纪要等。但音频天然难以检索既不能像文本一样直接建索引也无法靠关键词定位具体内容。本文基于 examples/SpeechProcessing 示例项目完整讲解如何构建一套音频转录 说话人分离 Marqo 语义索引 LLM 问答的端到端系统把音频文件转成带时间戳、说话人标签的转录文本索引进 Marqo 后即可用自然语言查询并返回对应音频片段甚至让大模型基于检索结果回答领域专属问题。读完本文你将掌握一条可直接复用的语音数据检索与问答技术路线。项目概述把不可检索的音频变成可查询的数据库该项目examples/SpeechProcessing的核心思路非常简单但有效Marqo 本身不支持音频只支持文本与图片这一点在配套文章 article.md 中明确说明因此系统在 Marqo 前面加了一层语音处理前端把音频整理成能被索引的文档再交给 Marqo。整体数据处理流程分为四步Ingestion音频采集从 YouTube、网页音频链接或本地文件下载并统一转换为 WAVSpeaker diarisation Speech to Text说话人分离与语音转写识别谁在什么时候说话并转写为文本输出带起止时间和说话人标签的文档Indexing索引将转录文档写入 Marqo 索引只对transcription字段计算向量嵌入Searching QA检索与问答用文本查询检索相关片段再把 Top 命中片段作为上下文交给 LLM 生成自然语言回答。演示数据覆盖三个不同领域以验证系统的跨领域检索能力James Hoffman咖啡主题视频The WAN Show双人科技播客Expert PanelsOpenAI 的多位专家座谈GANs for Good、Optimizing BizOps with AI。将三类数据索引到同一个transcription-index后系统既可以回答萃取浓缩咖啡该用多大压力这样的咖啡领域问题也能回答三星 Space Zoom 争议或GAN 对科研社区的价值等截然不同领域的问题完整问答示例见下文检索增强问答一节。为什么音频搜索如此困难音频在 AI 处理中是出了名的困难介质原因有二高维度人耳可听频率上限约 20,000 Hz按奈奎斯特定理需要约 40,000 Hz 采样率才能完整表示以美国英语使用者平均每秒 2.5 词估算时域上表示一个词平均需要约 16,000 个浮点数特征被掩盖以波形waveform形式存在的时域信号中对人类有意义的语音特征并不直观。实践中通常通过降采样来缓解维度爆炸降到 16,000 Hz 采样率后每个词仍约需 6,400 个浮点数。许多语音 AI 系统不直接操作波形而是把一段波形窗口经快速傅里叶变换FFT转换到频域生成**频谱图spectrogram**再进行处理。这就是为什么直接搜音频几乎不可行——必须先把音频转成文本再借助文本语义搜索引擎如 Marqo来检索。应用场景播客、企业与工业让语音数据可搜索价值远不止演示播客 / 视频平台摆脱对人工元数据标签的依赖搜索结果可直接附带音频片段与时间戳用户无需反复拖动进度条定位内容企业会议索引会议录音后可以检索、追溯和归因决策点。说话人分离在已知说话人数目时效果更好——可通过会议软件集成实时统计并发说话人数并把说话人姓名映射到转录片段工业合规与复盘归档直播通信数据事后可检索导致某个结果事故或成功的关键决策过程用于事后分析。环境准备与快速开始根据 README.md 的 Getting Started 部分按以下步骤准备环境1. 创建虚拟环境并安装依赖python -m venv venv # Linux/Mac source venv/bin/activate # Windows venv\Scripts\activate pip install -r requirements.txt2. 安装并启动 Marqo按 仓库根 README 的 Getting Started 指引安装并运行 Marqo。示例代码默认通过marqo.Client(urlhttp://localhost:8882)连接本地实例见 2. Process.py。3. 安装 FFmpeg用于音频格式转换与提取随平台不同安装方式各异。4. 获取两个 API KeyHugging Face Token登录 Hugging Face 并接受pyannote/speaker-diarization模型的使用条款后获取说话人分离模型需要授权 tokenOpenAI API Key用于问答阶段的 LLM 调用。5. 配置环境变量复制.env_local为.env把两个 Key 填入。示例脚本通过load_dotenv()加载见 2. Process.py转写阶段读取os.environ[HF_TOKEN]2. Process.py。Troubleshooting符号链接权限问题运行2. Process.py时PyAnnote 在无足够权限非管理员/超级用户的情况下可能抛出与符号链接创建相关的错误。解决方式是以管理员/超级用户身份运行脚本。使用流程四步跑通语音搜索完整流程按 README 的 Usage 部分执行# 1. 下载数据按需 python 1. Download.py # 2. 处理并索引数据强烈建议 GPUCPU 会非常慢 python 2. Process.py # 3a. 检索数据交互式提示符返回直接转录片段 python 3a. Search.py # 3b. 问答数据交互式提示符返回自然语言回答 python 3b. chat.py说明当前仓库镜像中保留了 2. Process.py 与 SpeechSearch/chatter.py 两个核心脚本1. Download.py、3a. Search.py以及SpeechSearch包中的transcriber.py、indexer.py模块未包含在仓库内配套文章 article.md 中给出了各模块的完整实现代码与讲解下文的关键实现片段均出自该文。2. Process.py的主流程值得细看它会先删除旧的transcription-index再重新创建保证可重复运行创建时传入自定义的文本预处理设置随后逐个处理audios/目录下的 WAV 文件对每个文件依次执行说话人分离 转写与索引入库并分别打印耗时2. Process.pymq marqo.Client(urlhttp://localhost:8882) index_name transcription-index mq.delete_index(index_name) settings { textPreprocessing: { splitLength: 2, splitOverlap: 0, splitMethod: sentence, }, } response mq.create_index(index_name, settings_dictsettings)如果本机没有 GPU脚本会打印明确的警告CPU 上做说话人标注与转写会非常慢建议只处理少量短视频2. Process.py。音频采集Ingestion的实现细节配套文章中的AudioWrangler类统一封装了三种数据源YouTube 视频用yt_dlp以bestaudio/best格式提取 192 kbps 的 MP3再用 Pydub 转为 WAV文件用hashlib.sha256(url.encode(ascii)).hexdigest()取 URL 哈希作为唯一文件名避免重复下载网页音频文件用urllib.request带User-Agent: Mozilla/5.0请求头下载后同样转 WAV批量文件提供一个每行一条链接的文本文件YouTube 链接或音频链接均可内部用multiprocessing.Pool(os.cpu_count())并行下载大幅缩短批量采集时间。三个演示数据集的链接列表即以这种文本文件形式提供。说话人分离与语音转写Diarisation STT这是整套系统中计算最重的环节由AudioTranscriber类完成两个子任务分别选用说话人分离pyannote/speaker-diarization2.1模型通过Pipeline.from_pretrained(..., use_auth_tokenhf_token)加载。输出是一系列带开始时间、结束时间和说话人标签的片段标签形如SPEAKER_00、SPEAKER_01——因为模型并不知道说话人的真实姓名语音转写fairseq 的 S2TSpeech-to-Text模型家族默认使用facebook/s2t-medium-librispeech-asr_model_size medium配合Speech2TextProcessor做预处理音频统一按 16,000 Hz 采样率加载。说话人分离的标注过程会把过长的连续语音段切成30 秒的块避免出现超长单说话人片段def annotate(self, file: str): diarization self.annotation_pipeline(file) speaker_times [] for t in diarization.get_timeline(): start, end t.start, t.end # reduce to 30 second chunks in case of long segments while end - start 0: speaker_times.append( (start, min(start 30, end), diarization.get_labels(t)) ) start 30 return speaker_times转写阶段会把说话人片段对应的音频切出来按transcription_batch_size默认 4分批喂给预处理器与模型短音频小于 400 个采样点先做零填充补齐再入批def transcribe(self, datas, samplerate16000): batches [] batch [] i 0 for data in datas: if data.shape[0] 400: # pad short audio data np.pad(data, [(0, 400)], modeconstant) batch.append(data) i 1 if i self.transcription_batch_size: batches.append(batch) i 0 batch [] if batch: batches.append(batch) # ... processor(batch) - model.generate(...) - batch_decode(...)最终process_audio把两个结果合并为一条条待索引文档每个文档包含_id由文件名与片段序号生成、speaker、start、end、transcription、samplerate、file七个字段。这些字段正是后续索引与检索的核心数据模型。索引到 Marqo只对转录文本建向量索引阶段是系统与 Marqo 的接合点。Marqo 默认对文档中所有字段计算张量嵌入但这里只有transcription值得向量化speaker、start、end等元数据应保持原样——实现方式是把它们通过non_tensor_fields排除def index_transcriptions(annotated_transcriptions, index, mq, tensor_fields[], devicecpu, batch_size32): # drop short transcriptions and transcriptions that consist of duplicated # repeating character artifacts annotated_transcriptions [ at for at in annotated_transcriptions if len(at[transcription]) 5 or len({*at[transcription]}) 4 ] response mq.index(index).add_documents( annotated_transcriptions, tensor_fieldstensor_fields, devicedevice, client_batch_sizebatch_size ) return response值得注意的实现细节过滤噪声转录丢弃长度 ≤ 5 个字符、或由重复字符伪影构成的转录片段len({*at[transcription]}) 4检查字符去重后的集合大小这是 STT 输出中常见的脏数据索引设置创建索引时设置textPreprocessing.splitMethod sentence、splitLength 2、splitOverlap 0即按句子切分、每 2 句一组、无重叠——这样转录文本会被切成语义完整的短块检索粒度更细。从源码层面看这三项配置的底层定义位于 marqo_index.py 的TextPreProcessing模型split_length: int Field(gt0, aliassplitLength)、split_overlap: int Field(ge0, aliassplitOverlap)、split_method: TextSplitMethod Field(aliassplitMethod)且正是创建索引时的默认配置见 index_settings.py 中splitLength2, splitOverlap0, splitMethodTextSplitMethod.Sentence。也就是说示例中的设置与 Marqo 默认值一致你也可以调整splitLength控制每个文本块的长度或在splitMethod中选择其他切分策略来适配不同语料的粒度需求。add_documents的底层调用链在 document.pyDocument.add_documents根据索引类型Structured / SemiStructured / Unstructured分派给对应的 AddDocumentsHandler再由 handler 完成向量化与入库——示例中未声明索引类型走的是默认的 SemiStructured 路径。检索文本查询返回音频片段索引完成后即可用 Marqo 原生语义搜索直接检索转录片段。搜索入口位于 tensor_search.py 的根级search函数内部会按索引类型分派到 tensor / lexical / hybrid 等具体搜索方法。3a. Search.py提供的交互式检索返回的是直接转录片段含说话人、时间戳等字段适合需要精确原文与定位的场景。配合attributes_to_retrieve等参数你还可以把start、end、file等字段一并取回从而实现搜到片段 → 跳转对应音频位置的完整产品体验。检索增强问答RAG让 LLM 基于转录内容回答3b. chat.py是系统的产品化输出层。正如配套文章中的流程示意图所示问答采用标准的Retrieval-Augmented Generation检索增强生成架构核心实现在 SpeechSearch/chatter.py 中def answer_question(query: str, limit: int, index: str, mq: marqo.Client) - str: print(Searching...) results mq.index(index).search(qquery, limitlimit) print(Done!) context . .join([r[transcription] for r in results[hits]]) prompt PromptTemplate(templateTEMPLATE, input_variables[context, question]) llm OpenAI(temperature0.9) chain_qa LLMChain(llmllm, promptprompt) llm_results chain_qa({context: context, question: query}, return_only_outputsTrue) return llm_results[text]流程是mq.index(index).search(qquery, limitlimit)先检索最相关的转录片段示例中主循环传入limit15见配套文章中的 chat 主函数→ 把所有命中的transcription字段用句号拼接成context→ 交给 LLM 生成回答。这样 LLM 的知识被约束在检索到的真实转录内容内能回答需要读材料才能回答的领域专属问题。Prompt 模板的设计目标非常明确只允许模型回答有据可依的内容You are a question answerer, given the CONTEXT provided you will answer the QUESTION (also provided). If you are not sure of the answer then say I am sorry but I do not know the answer Your answers should two to five sentences in length and only contain information relevant to the question. You should match the tone of the CONTEXT. The beginnings of the CONTEXT should be the most relevant so try and use that wherever possible, it is important that your answers a factual and dont make up information that is not in the CONTEXT. CONTEXT: {context} QUESTION: {question}跨领域问答效果演示将咖啡、科技播客、专家座谈三类数据全部索引进同一 Marqo 索引后README 与配套文章中给出了真实问答记录咖啡领域Q: What pressure should the machine use to extract espresso? A: 机器压力是萃取浓缩咖啡的重要因素。理想情况下机器应设置为 9 bar 压力以获得口感强烈、浓缩、带有浓郁甜味的浓缩咖啡。较低压力可能导致流速变慢和接触时间变长但不一定会提升萃取率。流速过快会导致通道效应channeling降低萃取率并带来苦涩酸味。科技播客领域Q: What is the controversy around Samsungs Space Zoom feature? A: 争议在于该功能暗示手机相机能拍摄月亮等远处物体的高清照片而实际上它只能以较低清晰度放大远处物体。这引发了关于该技术被用于深度伪造视频的担忧以及三星可能故意夸大其手机能力的质疑。专家座谈领域Q: What are some application of GANs that are beneficial to the research community? A: GAN 近年来在科研社区有许多有益应用生成逼真图像、提升安全性、生成音乐等。它们尤其有助于学生和从业者解决日常问题还被用于差分隐私、对抗偏见、医疗领域生成不侵犯患者隐私的假数据、为弱势群体创建数据等。这些回答完全基于被检索到的转录内容生成证明单一索引可以承载多个垂直领域并给出高质量、领域专属的回答。系统局限性与优化方向配套文章对该系统的短板有坦诚的总结语音转写模型是最薄弱环节S2T 模型处理缩写词acronyms的能力不足常产生奇怪伪影换用或针对领域微调其他模型有望改善Whisper 类新模型的取舍OpenAI Whisper 转写质量更好但对重叠说话人片段会习惯性地加引号对本文场景并不理想短查询敏感回答对措辞非常敏感尤其当语料中大量出现相似表达时短查询可能返回更多无关信息进而诱发 LLM 幻觉——这也是 RAG 系统常见的调优难点。总结本文展示了一条完整且可复用的语音数据检索技术路线用说话人分离 语音转写把音频翻译成带时间戳和说话人标签的结构化文本用 Marqo 只对转录字段做语义索引再用检索 LLM实现自然语言问答。从下载音频、切分说话人片段、批量转写到textPreprocessing索引配置、non_tensor_fields字段排除、交互式检索与 RAG 问答每一步都有对应的源码与配置依据可循。即使这套系统实现得很简单它已经能通过文本查询高质量地检索音频片段。对于播客平台、会议归档、工业通信复盘等场景这套音频 → 文本 → 语义索引的范式都可以直接借鉴核心要点是让 Marqo 只对真正需要语义检索的transcription字段建向量同时保留speaker、start、end、file等元数据用于定位与过滤从而把不可检索的音频变成可搜索、可追溯、可问答的结构化知识库。延伸阅读仓库内 SpeechProcessing 目录、配套技术长文 article.md以及 Marqo 索引与搜索的核心实现 marqo_index.py、index_settings.py、tensor_search.py。赞分享搜索引擎AI 应用后端电商NLP【免费下载链接】marqoEcommerce Search and Discovery - marqo.ai项目地址https://gitcode.com/gh_mirrors/ma/marqo点击查看免费下载相关推荐用 Marqo 构建 Simple Wikipedia 语义搜索引擎从数据索引到神经搜索的完整实战用 Marqo 构建 Simple Wikipedia 语义搜索引擎从数据索引到神经搜索的完整实战 导读 本文以仓库中开箱即用的 Simple Wikiped搜索引擎AI 应用后端电商NLPnanoGPT深度解析如何在极简代码中实现GPT模型训练的革命性突破nanoGPT深度解析如何在极简代码中实现GPT模型训练的革命性突破 在大型语言模型 Large Language Models 日益复杂的今天nanoGP人工智能大模型预训练深度学习微调Qwythos-27B-v1量化指南GGUF格式在llama.cpp与Ollama中的应用Qwythos 27B v1量化指南GGUF格式在llama.cpp与Ollama中的应用 Qwythos 27B v1是一款基于Qwen3.5 27B开发的上一篇Rye稳定性长时间运行的可靠性测试终极指南下一篇告别适配烦恼React Native Super Grid 响应式布局完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/13 1:44:47

NSIS+DuiLib自定义安装界面:插件集成与整窗接管实践

简介:NSIS与Duilib结合的自定义安装程序开发素材包,主要面向需要美化Windows安装界面的中高级开发者,解决默认NSIS安装界面样式单一、难以贴合产品品牌视觉的问题。压缩包共451个文件,体积约9.6MB,类型覆盖113个PNG位图…

2026/10/13 1:39:47

AI芯片软硬件协同设计:架构、编译器与联合调优实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 6:50:03

Cortex-M4 三级流水线 BL 带返回跳转指令(PC、LB)

一、行业经典疑点:两段官方描述看似冲突在 Cortex‑M4 汇编体系中,关于 BL 指令存在两段标准描述,是嵌入式学习、面试、考试的核心易错点:硬件流水线描述:BL 执行顺序为先将 PC−4 赋值给 LR,再将目标函数入…

2026/10/13 6:50:03

CentOS 7 NTP精准同步实战:从配置到生产级时间治理

1. 为什么在CentOS 7里搭NTP不是“装个包就完事”——从一次生产环境时间漂移说起去年冬天,某公司一套基于Kubernetes的订单处理系统突然出现大量“时间戳异常”告警。日志里同一笔交易的前端请求时间比后端数据库写入时间早了3.2秒,而MQ消息的消费延迟计…

2026/10/13 6:50:03

AI日报自动化生成实战:从信息采集到深度解读的完整流程

1. 一份AI日报的诞生逻辑:从信息洪流到结构化认知每天早上七点,我的信息采集脚本会准时跑完最后一轮抓取。屏幕上滚动的原始条目大概有三百到五百条,来源横跨论文预印本平台、头部实验室的官方博客、开源社区的提交记录、行业媒体的快讯&…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑