1. 从标题拆解 deep-searcher 的真实定位第一次看到zilliztech/deep-searcher这个仓库名很多人会下意识把它归类成又一个 RAG 框架。但把名字拆开看deep和searcher两个词其实已经把它的野心写在脸上了——它要解决的不是能不能检索到而是检索得够不够深。这个区别很关键因为市面上大部分检索增强方案停留在向量相似度 top-k这一层而 deep-searcher 想做的事情是在这个基础之上再叠一层推理式的深度搜索。我最初接触这个项目是因为手上有一个私有文档问答的需求几百份内部技术文档、会议纪要、产品规格书混在一起用户提问往往不是某份文档里写了什么而是我们去年在某个方向上做过哪些尝试结论是什么。这种问题用传统向量检索基本是灾难——单次 top-k 召回拿到的片段要么太碎要么答非所问。deep-searcher 的思路正好切中这个痛点它把搜索从一个单步动作变成了一个可以多轮迭代、自我修正的过程。从定位上说deep-searcher 面向的是这样一类人你手里有一堆非结构化的私有数据PDF、Markdown、网页存档、数据库导出都算你想让大模型基于这些数据回答问题但你发现朴素的 RAG 效果不稳定尤其是遇到需要跨文档、多跳推理的问题时。它适合有一定工程基础的开发者也适合想快速验证深度检索到底能带来多少提升的技术决策者。哪怕你只是想搞明白深度搜索和普通 RAG的差别在哪把这个项目跑一遍也是最快的路径。需要说明的是下面涉及的具体实现细节一部分来自我对该项目的理解一部分是基于同类深度检索系统的常见工程实践做的合理补全。如果你要直接照搬到生产环境建议以仓库最新代码为准我这里更多是讲清楚为什么这么设计以及踩坑时该往哪个方向想。2. 深度搜索到底比普通 RAG 强在哪2.1 普通 RAG 的天花板在哪里要理解 deep-searcher 的价值得先承认普通 RAG 的局限。标准 RAG 流程无非是把文档切块、向量化、存进向量库、查询时把问题向量化、取相似度最高的几块、塞进 prompt 让模型回答。这套流程在答案就藏在某一个 chunk 里的场景下非常好用比如XX 接口的默认超时时间是多少。但一旦问题变成复合型问题就来了。举个例子我们对比过哪几种向量索引方案各自的取舍是什么这个问题的答案可能散落在三份文档里一份讲 HNSW 的参数调优一份讲 IVF 的召回率测试一份是选型会议的纪要。普通 RAG 用问题去检索很可能只召回讲 HNSW 的那份因为向量索引这个词在那份文档里出现频率最高。结果就是模型只答了一半甚至答偏。更麻烦的是多跳问题。A 方案依赖 B 组件B 组件在 C 版本里被替换了那现在 A 方案还能用吗这种问题需要先找到 A 和 B 的关系再找到 B 和 C 的关系最后做推理。单次检索根本覆盖不了这条链路。2.2 deep-searcher 的核心思路把检索变成迭代过程deep-searcher 的核心洞察是既然一次检索不够那就多来几次而且让模型自己决定下一次该搜什么。这听起来简单但工程上要做对并不容易。它大致包含这么几个关键环节查询分解拿到一个复杂问题后先让模型把它拆成若干子问题或子查询。比如上面那个索引选型的问题可能被拆成我们测试过哪些索引每个索引的召回率数据选型时的决策依据。多轮检索针对每个子查询分别去检索拿到各自的候选片段。结果反思与再检索模型看完第一轮结果后判断信息够不够回答原问题如果不够它会生成新的查询继续搜。这一步是deep的精髓所在。证据聚合与作答把多轮检索到的证据汇总去重、排序最后生成带引用的答案。这个流程和人类做深度调研的方式几乎一模一样先粗搜一圈发现线索顺着线索再搜直到信息足够支撑结论。deep-searcher 把这个过程自动化了。2.3 为什么这个设计值得投入有人会问多轮检索不是更慢更贵吗确实token 消耗和延迟都会上去。但这里有个权衡在私有知识库场景下用户要的是答对而不是答得快。一个答错的答案用户还得自己去翻文档验证综合成本反而更高。deep-searcher 把这种人工翻文档的成本前置到了系统里。另外一个容易被忽略的点是可解释性。因为每一轮检索的查询和结果都是显式的你可以清楚地看到模型是怎么一步步逼近答案的。这在企业场景里非常重要——当模型给出一个结论时你能追溯它是基于哪些片段、经过哪些推理步骤得出的。普通 RAG 的黑盒 top-k在这方面就差很多。3. 核心组件与关键技术点解析3.1 文档加载与切分策略深度搜索的效果一半取决于检索算法另一半取决于最前端的文档处理。deep-searcher 支持多种数据源常见的有本地文件PDF、Markdown、TXT、网页内容、以及结构化数据导出。这里第一个坑就是切分粒度。切太碎单个 chunk 语义不完整检索出来的是半句话切太大一个 chunk 里混了好几个主题向量表示被稀释相似度反而不准。我的经验是对于技术文档按标题层级切分H2 或 H3 作为边界通常比固定字符数切分效果好得多。如果文档没有清晰结构那就用带重叠的滑动窗口重叠比例控制在 10% 到 20% 之间。提示切分时一定要保留元数据比如来源文件名、章节标题、页码。deep-searcher 在最终作答时会用到这些信息做引用缺了元数据答案的可信度会大打折扣。3.2 向量化与索引选型向量化模型的选择直接决定检索质量。通用场景下开源的 BGE 系列或者商业的 embedding 接口都能用。但要注意embedding 模型必须和你的数据语言、领域匹配。如果你的文档大量是中文技术内容用一个主要在英文语料上训练的模型效果会明显打折。索引方面deep-searcher 底层通常对接向量数据库这也是 zilliztech 背景的自然选择Milvus 就是他们家的。索引类型的选择要看数据规模数据规模推荐索引理由万级以下暴力检索或 IVF_FLAT数据量小精度优先延迟可接受十万到百万级HNSW召回率和延迟平衡好内存占用可控千万级以上IVF_PQ 或 DiskANN必须考虑内存和磁盘成本接受一定精度损失这里有个实操心得不要一上来就上最复杂的索引。我见过太多人数据才几千条就配了 PQ 量化结果召回率掉得厉害还以为是模型不行。先用简单索引把流程跑通等数据量真的上来了再换。3.3 查询分解与反思机制这是 deep-searcher 区别于普通 RAG 的核心。查询分解通常靠 prompt 工程实现给模型一个复杂问题要求它输出一组子查询。这里的关键是约束输出格式让模型输出结构化的 JSON 或者列表方便程序解析。如果让模型自由发挥它可能给你一段散文解析起来很痛苦。反思机制更微妙。模型需要判断当前证据是否足够。实践中常见两种做法一种是让模型直接回答够/不够另一种是让模型尝试作答如果它自己标注了信息不足或者答案里出现根据现有资料无法确定就触发再检索。第二种更稳因为它把判断和作答合并在一次调用里省了一轮交互。注意反思轮数一定要设上限。我一般设 3 到 5 轮。不设上限的话模型可能陷入永远觉得信息不够的死循环token 烧得飞快问题还答不出来。3.4 证据聚合与答案生成多轮检索下来你手里会有一堆候选片段其中必然有重复和低相关的。聚合阶段要做的是去重按内容哈希或语义相似度、重排可以用 cross-encoder 或者简单的相关性打分、截断控制塞进最终 prompt 的长度。答案生成时强烈建议要求模型逐句标注引用来源。这不仅是给用户看的也是给你自己调试用的。当答案出错时你能快速定位是检索错了还是生成错了。deep-searcher 在这块的设计思路就是让每个结论都能追溯到具体的文档片段。4. 从零跑通 deep-searcher 的实操流程4.1 环境准备与依赖安装假设你已经有一个 Python 环境3.9 以上比较稳妥第一步是把仓库拉下来装依赖。这类项目通常依赖几个大头向量数据库客户端、embedding 模型库、以及大模型的调用 SDK。git clone https://github.com/zilliztech/deep-searcher.git cd deep-searcher pip install -r requirements.txt装依赖时最容易出问题的是版本冲突尤其是 PyTorch 和 CUDA 的匹配。如果你本地没有 GPU或者不想折腾驱动直接用 CPU 版本跑小规模验证完全够用。我建议第一次跑通流程时不要追求性能先确保逻辑正确。4.2 配置数据源与模型接下来要配置两样东西数据在哪模型用哪个。数据源配置一般是个 YAML 或 JSON 文件指定文档目录、文件类型过滤、切分参数。模型配置则包括 embedding 模型和大模型两部分。data_source: type: local path: ./docs file_types: [.pdf, .md, .txt] chunk_size: 512 chunk_overlap: 64 embedding: model: BAAI/bge-large-zh-v1.5 dimension: 1024 llm: provider: openai-compatible model: your-model-name max_tokens: 2048这里chunk_size和chunk_overlap是最需要调的参数。512 是个比较通用的起点但如果你文档里有很多长段落可以适当放大到 800 甚至 1024。overlap 设 64 到 128 之间保证跨 chunk 的语义连续性。4.3 构建索引与首次检索测试配置好之后跑索引构建。这一步会把所有文档切分、向量化、写入向量库。数据量大的话可能要等几分钟到几十分钟取决于你的 embedding 是本地跑还是调 API。python build_index.py --config config.yaml索引建完后先别急着上复杂问题用几个简单查询验证一下基础检索是否正常。比如直接问文档里提到的第一个方案是什么看能不能召回相关片段。这一步是排除数据没进去或向量维度对不上这类低级错误。4.4 运行深度搜索并观察中间过程基础检索没问题后就可以跑完整的深度搜索流程了。deep-searcher 通常会输出中间过程包括每一轮生成的子查询、召回的片段、以及模型的反思结论。一定要把这些中间输出打开看这是理解系统行为的最好方式。python deep_search.py --query 我们对比过哪几种索引方案各自取舍是什么 --max_rounds 3跑的时候重点观察三件事第一子查询拆得合不合理第二每轮召回的内容是不是在逐步逼近答案第三模型是在第几轮决定停止的。如果发现它第一轮就停了但答案明显不全说明反思机制太宽松如果它搜了五轮还在打转说明查询分解有问题可能一直在重复搜同一个方向。4.5 参数调优的实操记录我拿一个约 200 份文档的知识库做过一轮调参记录如下参数初始值调整后效果变化chunk_size256512答案完整度明显提升碎片化减少max_rounds53延迟下降约 40%答案质量基本持平top_k per round105噪声减少但个别问题召回不足最终定在 6overlap096跨段落问题改善明显这轮调参最大的体会是参数没有万能值必须拿你自己的数据去试。别人博客里写的最佳实践只能当起点因为文档结构、问题类型、模型能力都会影响最优参数。5. 常见问题与排查技巧实录5.1 检索召回为空或明显不相关这是最常见的问题原因通常有三类。第一类是数据根本没进库检查索引构建日志有没有报错向量库里 count 一下记录数对不对。第二类是embedding 模型和查询语言不匹配比如文档是中文但用了英文模型这时候查询向量和文档向量根本不在一个语义空间里。第三类是切分把关键信息切断了比如一个表格被从中间切开检索时两边都拿不到完整信息。排查顺序建议从数据量查起再查模型最后查切分。我踩过最坑的一次是切分参数写错了单位以为是字符数结果是 token 数导致 chunk 比预期小了一半检索效果一直上不去查了半天才发现。5.2 多轮检索陷入重复模型反复生成相似的子查询搜来搜去都是那几篇文档。这通常是查询分解的 prompt 没约束好。解决办法是在 prompt 里明确要求新查询必须和之前的查询有实质差异并且把历史查询列表传给模型让它自己避开。另一个技巧是给每轮检索的结果做去重如果新一轮召回的内容和上一轮高度重叠就强制换方向或者直接终止。5.3 答案有引用但引用对不上模型标注了来源但你点进去发现那段话根本不在引用的文档里。这是典型的幻觉引用。根因是生成阶段模型没有严格基于给定片段作答。对策有两个一是把片段编号后在 prompt 里明确要求只能引用编号内的内容二是在后处理阶段做校验把答案里的引用和实际片段做匹配对不上的直接标红或者丢弃。5.4 延迟和成本失控深度搜索天然比普通 RAG 贵但贵到什么程度要心里有数。一个实用的监控方式是记录每次查询的轮数、token 消耗、耗时。如果发现平均轮数超过 4或者单次查询 token 消耗超过某个阈值就该回头看看是不是查询分解太发散或者反思机制太激进。提示生产环境里可以给不同优先级的查询设不同的 max_rounds。实时交互的查询限制在 2 轮后台批处理任务可以放宽到 5 轮这样能在体验和成本之间找到平衡。5.5 常见问题速查表现象可能原因排查方向召回为空数据未入库/模型不匹配查记录数、查 embedding 维度答案不完整轮数不足/切分过碎调大 max_rounds、调大 chunk_size重复检索查询分解无约束加历史查询去重、改 prompt引用错误生成阶段幻觉加编号约束、后处理校验延迟过高轮数过多/片段过长限制轮数、截断上下文6. 深度检索的适用边界与扩展思路6.1 什么场景该用什么场景别硬上deep-searcher 这类深度检索不是银弹。如果你的问题基本都是单点事实查询比如某个配置项的默认值是多少那普通 RAG 又快又准上深度检索纯属浪费。它真正发光的场景是问题需要跨多份文档、需要多跳推理、或者答案本身就是一个需要综合判断的结论。另一个判断维度是数据规模。数据量很小比如就十几份文档的时候你甚至可以把全文塞进长上下文模型里根本不需要检索。深度检索的价值在数据量大到无法全量塞入上下文时才真正体现。6.2 可以往哪些方向扩展跑通基础流程后有几个自然的扩展方向。一是接入更多数据源比如把数据库查询也作为一种检索手段让模型在需要结构化数据时去查库而不是查文档。二是加入重排模型在每轮检索后用一个 cross-encoder 对候选片段精排通常能明显提升最终答案质量。三是做查询缓存把高频问题的检索路径缓存下来既省成本又降延迟。还有一个我觉得很有价值的方向是人工反馈闭环。让用户对答案点赞点踩把踩的案例收集起来分析是检索问题还是生成问题然后针对性地调 prompt 或换模型。深度检索系统因为中间过程透明做这种归因分析比黑盒 RAG 容易得多。6.3 我个人的一点使用体会用下来最深的感受是深度检索系统的效果七分靠数据治理三分靠算法。文档切得干不干净、元数据全不全、embedding 模型选得对不对这些脏活累活决定了上限。算法层面的多轮反思、查询分解更多是在这个上限之内做优化。我见过太多团队一上来就研究怎么改反思 prompt结果文档切分一塌糊涂怎么调都上不去。所以如果你正准备上手 deep-searcher我的建议是先把文档处理这一环做扎实用简单查询验证检索质量确认基础没问题了再去折腾多轮和反思。这个顺序反了后面全是无用功。另外别怕看中间输出那些子查询和召回片段里藏着系统所有的秘密看多了你对模型到底在想什么会有完全不一样的直觉。