我觉得这个问题其实在问一件事:你建索引的时候,怎么让系统既能快速找到东西,又能找到对的东西。说白了就是'怎么存'和'怎么找'的匹配问题。我一般会从三个维度去考虑:[[分块]]策略、[[Embedding]] 层、还有索引结构本身。
先说分块。很多人上来就固定长度切,比如 512 个 token 一刀切。但这么做有个问题:如果你切的正好断在一个句子的中间,那段向量表达就会很怪,语义不完整,后面召回就容易丢信息。所以我更倾向按语义边界切,比如按句子或段落切。但这里有个前提,就是你的文档结构要比较清晰,比如技术文档、合同条款这种。如果文档特别乱,全是口语对话,那语义边界反而不稳定,这时候固定长度加重叠窗口反而更稳。重叠窗口是否启用、保留多长都应作为候选变量,用同一评测集验证边界证据、召回与冗余成本。举个例子,客服系统里查退款政策,用户问的是'七天无理由',但政策里那句话前面是'本店支持',后面是'但需商品完好',如果切断了,向量可能只匹配到'七天无理由',但丢了'完好'这个条件,召回的结果就不准确。所以我会根据业务场景选:召回不足就扩分块,准确率低就缩分块加过滤。
再一个就是 Embedding 层。模型选型上,通用场景用现成的 BGE 或者 M3E 就够了,但垂域数据,比如金融风控合同、医疗病历,我建议还是微调一下。因为通用模型对行业术语的理解不够。比如合同里'不可抗力'这个词,通用模型可能把它和'自然灾害'关联,但法律场景下它还有具体的免责条款含义。另外我特别推荐 [[Hybrid Search]],就是 [[BM25]] 关键词加 [[Dense Retrieval]] 向量。为什么呢?因为关键词匹配擅长处理长尾词、专有名词,比如订单号、错误码,这种向量很难表达;而向量擅长语义匹配,比如'退货流程'和'退款步骤'。两者互补,能覆盖更多场景。但混合检索有个坑:权重怎么配。如果向量权重太高,关键词结果被淹没,长尾就丢了;反过来关键词权重太高,语义匹配又没了。我一般的做法是先各出一部分结果,再用 [[Rerank]] 模型合并排序。
索引结构上,如果数据量不大,几百万以内,直接暴力搜索加 [[IVF]] 就够了。但上了千万甚至亿级,就得用 [[HNSW]] 图索引,它能做到毫秒级召回。不过图索引有个风险:它建起来慢,而且动态更新困难。如果知识库频繁更新,比如每天加几万条新文档,每次都重建索引成本太高。我的做法是增量写入加双缓冲,一个 base 索引,一个 delta 索引,查询时合并,后台异步重建。还有一个优化是元数据过滤。比如客服场景里,用户问的是'满减政策',但文档里既有今年的也有去年的,如果不过滤时间,去年已经过期的政策也会被召回,造成混淆。所以我会提前把时间、类别这些标签作为过滤器,先筛掉无关数据,再走向量检索,这样准确率能提升不少。
其实还有一个点我没展开,就是分块粒度怎么和检索策略联动。比如你切了句子级和段落级两层索引,什么时候用句子,什么时候用段落?我一般会先做粗召回,用段落级索引把相关的文档块找出来,然后再用句子级索引做精排,这样既快又准。但这也引出一个问题:两层索引的存储和延迟怎么平衡?
所以整体上,我不会一开始就堆所有优化。我会先分析 bad case,看是'召不回'还是'召不准'。召不回,可能分块太大或者 Embedding 模型不够好;召不准,可能元数据过滤没做或者重排不够。我更倾向先定位瓶颈,再针对性优化,而不是一股脑全上。