Semantic Kernel 向量存储混合搜索(Hybrid Search):从 ADR 架构决策到 .NET / Python 落地实践 📅 发布时间:2026/9/11 18:21:29 👁 浏览次数: Semantic Kernel 向量存储混合搜索Hybrid Search从 ADR 架构决策到 .NET / Python 落地实践【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel导读本文围绕 Semantic Kernel 仓库中的架构决策记录 docs/decisions/0067-hybrid-search.md系统讲解在 VectorStore 抽象层中引入混合搜索Hybrid Search的完整设计过程与最终落地形态。你将掌握混合搜索的两种主流实现原理稠密向量 关键词/全文检索、稠密向量 稀疏向量、主流数据库对混合搜索的支持差异、接口与命名方案的权衡决策以及该设计在 .NET 与 Python 两端 VectorStore 抽象中的真实调用方式与配置项。一、背景与问题为什么 VectorStore 抽象需要混合搜索在 VectorStore 抽象层中单纯的向量搜索Vector Search能力已经覆盖了大多数语义检索场景。但许多数据库在向量搜索之外还支持混合搜索Hybrid Search而混合搜索通常能带来更高的检索质量。原因在于两种检索模式互补稠密向量dense vector检索擅长捕捉语义相似性近义词、同义表达**关键词/全文检索keyword / fulltext search**擅长精确匹配专有名词、编号、缩写等语义模型难以捕捉的硬信号。将两者并行执行并融合排序即可兼顾语义相关性与词面匹配度。因此在 VectorStore 抽象中提供统一的混合搜索能力是 ADR 0067 要解决的核心问题。需要特别说明的是混合搜索的具体实现方式因数据库而异最常见的两种是稠密向量搜索 关键词/全文搜索并行执行再融合结果如 Azure AI Search、PostgreSQL pgvector、CosmosDB NoSQL 等稠密向量搜索 稀疏向量搜索并行执行再融合结果如 Pinecone、Qdrant、Milvus 等。稀疏向量Sparse Vector是什么稀疏向量与稠密向量的区别在于稀疏向量通常拥有多得多的维度但其中大量维度取值为 0。当稀疏向量用于文本搜索时词汇表中每个词/分词对应一个维度维度值表示该词在源文本中的重要程度一个词在特定文本块中出现越频繁同时在整个语料库中出现越不频繁其在稀疏向量中的取值就越高。生成稀疏向量的常见机制包括TF-IDF词频-逆文档频率SPLADEBGE-m3 稀疏嵌入模型pinecone-sparse-english-v0ADR 同时指出一个现实约束稀疏向量生成在 Python 生态支持良好但在 .NET 中支持不足。ML.NET 内置了 TF-IDF 实现可用于在 .NET 中生成稀疏向量但**支持生成稀疏向量本身被明确排除在该 ADR 的范围之外**这直接影响了后续的范围决策详见决策结果一节。二、各数据库混合搜索能力全景对比ADR 0067 对评估集内的 11 种数据库进行了逐项能力盘点这是设计接口时必须对齐的现实基线。下表完整复现该对比Y表示支持N表示不支持n/a表示不适用特性Azure AI SearchWeaviateRedisChromaPineconePostgreSQLQdrantMilvusElasticsearchCosmosDB NoSQLMongoDB混合搜索支持YYN无并行执行融合NYYYYYYY混合搜索定义Vector FullTextVector Keyword (BM25F)--Vector Sparse Vector for keywordsVector KeywordVector SparseVector / KeywordVector SparseVectorVector FullTextVector Fulltext (BM25)Vector FullText融合方法可配置NY--?YYYY但只有一种选项Y但只有一种选项N融合方法RRFRanked/RelativeScore--?自建RRF / DBSFRRF / WeightedRRFRRFRRF混合搜索输入参数Vector stringVector string--Vector SparseVectorVector StringVector SparseVectorVector SparseVectorVector stringVector string 数组Vector string稀疏距离函数n/an/a--dense/sparse 均仅 dotproduct单一设置n/adotproductInner Productn/an/an/a稀疏索引选项n/an/a--与 dense 无独立配置n/aondisk / inmemory IDFSPARSE_INVERTED_INDEX / SPARSE_WANDn/an/an/a稀疏数据模型n/an/a--indices values 数组n/aindices values 数组稀疏矩阵 / dict 列表 / tuple 列表n/an/an/a关键词匹配行为空格分隔SearchModeany 为 ORSearchModeall 为 AND按空格分词影响排序--n/a分词Tokenization无 FTS 索引精确子串匹配有 FTS 索引所有词必须出现n/aAnd/Or 能力-支持多个多词短语 OR单个多词短语内词可 OR 或 AND表中术语解释ADR 提供的词汇表RRF Reciprocal Rank Fusion倒数排名融合DBSF Distribution-Based Score Fusion基于分布的分数融合IDF Inverse Document Frequency逆文档频率关键观察Redis 与 Chroma 不支持混合搜索因此抽象层必须提供能力降级路径见后续运行时能力探测。融合方法五花八门RRF 是覆盖面最广的选项但 PostgreSQL 甚至需要用户自行实现融合逻辑。稀疏向量并非所有数据库的必需输入——Azure AI Search、Weaviate、PostgreSQL、Elasticsearch、CosmosDB、MongoDB 走的是Vector 文本关键词路线。三、全文检索索引配置要求CosmosDB NoSQL 的特殊约束部分数据库要求为混合搜索预先建立全文检索索引其中 CosmosDB NoSQL 是唯一强制要求指定语言的数据库且必须启用全文检索索引才能使用混合搜索特性Azure AI SearchWeaviateRedisChromaPineconePostgreSQLQdrantMilvusElasticsearchCosmosDB NoSQLMongoDB混合搜索需要全文检索索引YYn/an/an/aYN可选n/aYYY必填的全文索引选项无必填可选较多无必填无可选项---语言必填无必填部分可选-无必填可选较多语言必填无必填可选较多这一约束意味着抽象层需要一种机制让用户在建索引时指定语言参数——ADR 给出了两种候选方案详见决策过程一节中全文检索索引必填配置的权衡。四、关键词接口形态兼容性分析混合搜索的关键词输入如何表达直接决定了抽象接口能否覆盖大多数数据库。ADR 对 7 种数据库与 4 种关键词接口形态的兼容性做了逐项核对接口形态Azure AI SearchWeaviatePostgreSQLQdrantElasticsearchCosmosDB NoSQLMongoDBstring[]每元素一词任一匹配词提升排名YY需空格拼接Y需空格拼接Y多个 OR 匹配的 filterYYY需空格拼接string[]每元素一个或多个词单元素内所有词必须同时出现才提升排名YNYYOR filter FTS 索引-NNstring[]每元素一个或多个词单元素内多词需精确短语匹配YNY仅无索引时的 OR filter-NYstring空格分隔任一匹配词提升排名YYYN需自行分词-N需自行分词Y核心结论只有每元素一个词、任一匹配词提升排名这一形态获得全数据库支持。这直接决定了后续接口采用ICollectionstring而非单个字符串的决策方向。五、接口与命名设计多轮方案权衡ADR 记录了接口命名、属性命名、关键词拆分方式、全文索引配置四条设计主线的完整决策过程这是理解最终 API 形态的关键。5.1 接口与方法命名早期提出过三类命名方案核心差异在于方法名与参数类型如何组合方案 A按能力拆分为独立接口 独立方法名接口名方法名参数关键词属性选择器稠密向量属性选择器KeywordVectorizedHybridSearchKeywordVectorizedHybridSearchstring[] 稠密向量FullTextPropertyNameVectorPropertyNameSparseVectorizedHybridSearchSparseVectorizedHybridSearch稀疏向量 稠密向量SparseVectorPropertyNameVectorPropertyNameKeywordVectorizableTextHybridSearchKeywordVectorizableTextHybridSearchstring[] 字符串FullTextPropertyNameVectorPropertyNameSparseVectorizableTextHybridSearchSparseVectorizableTextHybridSearchstring[] 字符串SparseVectorPropertyNameVectorPropertyName方案 B统一方法名HybridSearch能力差异体现在接口与选项上接口名方法名参数选项类关键词属性选择器稠密向量属性选择器HybridSearchWithKeywordsHybridSearchstring[] 稠密向量HybridSearchOptionsFullTextPropertyNameVectorPropertyNameHybridSearchWithSparseVectorHybridSearchWithSparseVector稀疏向量 稠密向量HybridSearchWithSparseVectorOptionsSparseVectorPropertyNameVectorPropertyName方案 C单一接口 未来多参数重载。进一步设想将向量搜索与混合搜索统一为Embedding VectorizableData的北极星形态public Task VectorSearchTRecord(Embedding embedding, VectorSearchOptionsTRecord options null, CancellationToken cancellationToken null); public Task VectorSearchTRecord(VectorizableData vectorizableData, VectorSearchOptionsTRecord options null, CancellationToken cancellationToken null); public Task VectorSearchTRecord(VectorizableData[] vectorizableData, VectorSearchOptionsTRecord options null, CancellationToken cancellationToken null); public Task HybridSearchTRecord, TVectorType(TVector vector, VectorizableData vectorizableData, HybridSearchOptionsTRecord options null, CancellationToken cancellationToken null);ADR 同时以表格形式枚举了向量搜索各形态下方法名与参数的关系检索类型参数形态方法名混合搜索稠密向量 string[]关键词HybridSearch混合搜索vectorizable 字符串 string[]关键词HybridSearch混合搜索稠密向量 稀疏向量HybridSearchWithSparseVector混合搜索vectorizable 字符串 vectorizable 关键词数组HybridSearchWithSparseVector5.2 属性命名显式稠密命名 vs 隐式稠密命名方案 1显式DenseVectorPropertyNameSparseVectorPropertyName或DenseVectorPropertyNameFullTextPropertyName。优点语义更明确考虑到确有稀疏向量参与缺点与非混合向量搜索中的既有命名VectorPropertyName不一致。方案 2隐式VectorPropertyNameSparseVectorPropertyName或VectorPropertyNameFullTextPropertyName。优点与既有向量搜索命名保持一致缺点内部略不统一稠密叫 vector稀疏叫 sparse vector。5.3 关键词拆分方式方案 1接口直接接收已拆分的ICollectionstring另可提供接收单个关键词并转发到集合版本的扩展方法。优点对需要拆分关键词的底层数据库最容易适配且是唯一被数据库广泛支持的形态。方案 2接口接收单个字符串。优点用户无需自行拆分缺点抽象层无法可靠地对字符串做语言适配的清洗如按语言正确分词、剔除填充词。方案 3两种都接收由连接器按底层数据库需要组合或拆分。缺点仍需内部转换且清洗问题依旧存在。方案 4两种都接收但对不支持的形态抛异常。方案 5为集合形态与单字符串形态分别建接口。5.4 全文检索索引必填配置针对 CosmosDB NoSQL 必须指定语言的问题方案 1在 collection 选项类中加语言选项该语言应用于该 collection 创建的所有全文索引。优点实现最简单缺点无法为同一记录的不同字段指定不同语言也未覆盖其他数据库的全文检索选项。方案 2为VectorStoreRecordProperty增加属性包property bag并新增可继承的抽象基类 Attribute各数据库提供自己的 Attribute 来指定语言等设置再转换为属性包。优点支持同一记录多字段多语言且允许各数据库扩展自有设置缺点实现工作量更大。ADR 还就关键词属性选择器的命名征询了候选清单包括HybridSearchPropertyName、AdditionalSearchPropertyName、AdditionalPropertyName、SecondaryPropertyName、HybridSearchSecondaryPropertyName、KeywordsPropertyName、KeywordsSearchPropertyName。六、决策结果Decision Outcome范围决策只做关键词混合搜索在四个候选范围仅关键词混合搜索 / 关键词 稀疏向量混合搜索 / 全部四种 / 泛化混合搜索中最终选择方案 1Keyword Hybrid Search Only。理由企业级数据库对生成稀疏向量的支持较差缺少端到端故事投入价值低泛化混合搜索任意两种检索结果按用户选择的融合方法合并虽强大但在只支持 Vector Keyword 的数据库上根本无法实现。属性命名采用隐式稠密命名选择VectorPropertyNameSparseVectorPropertyName/FullTextPropertyName的组合以与既有向量搜索选项命名保持一致。关键词拆分采用已拆分关键词选择方案 1接口接收ICollectionstring因为它是数据库中支持面最广的形态。最终接口形态当前交付北极星设计方向确认为同时支持Embedding类型与某种 vectorizable data很可能来自 MEAI 的 DataContent作为普通搜索和混合搜索的输入采用单一HybridSearch方法名未来为不同输入增加重载但只保留一个选项类用于选择关键词字段或未来稀疏向量字段的属性选择器定名为AdditionalPropertyName。在正确的数据类型与 Embedding 类型就绪之前先行交付以下接口public Task HybridSearchTVector(TVector vector, ICollectionstring keywords, HybridSearchOptionsTRecord options null, CancellationToken cancellationToken);七、.NET 端落地TextSearchStore 中的混合搜索设计落地后混合搜索在 .NET 端最典型的消费入口是 dotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStore.cs 中的TextSearchStoreTKey——一个面向 RAG 场景的开箱即用文档存储类。运行时能力探测与降级在SearchInternalAsync中搜索逻辑会先探测当前向量存储是否实现了关键词混合搜索接口未实现则自动回退到普通向量搜索// 如果用户未显式关闭混合搜索检查向量存储是否支持它。 var hybridSearchCollection this._options.UseHybridSearch ?? true ? vectorStoreRecordCollection.GetService(typeof(IKeywordHybridSearchableTextRagStorageDocumentTKey)) as IKeywordHybridSearchableTextRagStorageDocumentTKey : null; // 若支持混合搜索则执行混合搜索否则执行常规向量搜索。 var searchResult hybridSearchCollection is null ? vectorStoreRecordCollection.SearchAsync(query, ...) : hybridSearchCollection.HybridSearchAsync( query, this._wordSegmenter(query), // 查询文本被切分为关键词集合 searchOptions?.Top ?? 3, options: new() { Filter filter }, cancellationToken: cancellationToken);这段代码印证了 ADR 的三项决策统一接口名IKeywordHybridSearchable、关键词以ICollectionstring传入、以及用户传入单个查询字符串由框架负责拆分关键词的实践形态默认分词器为\p{L}正则即按非字母字符切分文本。配置项TextSearchStoreOptionsdotnet/src/SemanticKernel.Core/Data/TextSearchStore/TextSearchStoreOptions.cs 提供了与混合搜索相关的两个核心开关配置项类型默认值说明UseHybridSearchbool?true若底层向量存储支持则启用混合搜索置为false可强制只做向量搜索WordSegementerFuncstring, ICollectionstring按非字母字符切分的默认分词器将查询文本拆分为关键词集合供混合搜索使用仅在UseHybridSearch为true时生效此外还有SearchNamespace按命名空间预过滤记录、UseSourceIdAsPrimaryKey用源 ID 作主键与SourceRetrievalCallback未持久化正文时按 source id/link 回调加载正文等通用配置。完整示例Azure AI Search 上的混合搜索仓库示例 dotnet/samples/Concepts/Memory/VectorStore_HybridSearch_Simple_AzureAISearch.cs 演示了从数据摄入到混合搜索的完整链路// 1. 创建 embedding 生成器此处使用 Azure OpenAI Azure CLI 凭据 var embeddingGenerator new AzureOpenAIClient(new Uri(TestConfiguration.AzureOpenAIEmbeddings.Endpoint), new AzureCliCredential()) .GetEmbeddingClient(TestConfiguration.AzureOpenAIEmbeddings.DeploymentName) .AsIEmbeddingGenerator(1536); // 2. 创建 AzureAISearch VectorStore 与 collection var vectorStore new AzureAISearchVectorStore(searchIndexClient); var collection vectorStore.GetCollectionstring, Glossary(skglossary); await collection.EnsureCollectionExistsAsync(); // 3. 将集合转换为混合搜索能力接口 var hybridSearchCollection (IKeywordHybridSearchableGlossary)collection; // 4. 执行混合搜索语义向量 关键词集合 var searchString What is an Application Programming Interface; var searchVector (await embeddingGenerator.GenerateAsync(searchString)).Vector; var resultRecords await hybridSearchCollection.HybridSearchAsync( searchVector, [Application, Programming, Interface], top: 1).ToListAsync(); // 5. 带预过滤filter的混合搜索 resultRecords await hybridSearchCollection.HybridSearchAsync( searchVector, [Retrieval, Augmented, Generation], top: 3, new() { Filter g g.Category External Definitions }).ToListAsync();示例中的数据模型展示了混合搜索对字段级配置的要求——用[VectorStoreData(IsFullTextIndexed true)]声明参与全文检索的字段用[VectorStoreVector(1536)]声明稠密向量字段这正好回应了 ADR 中为 VectorStoreRecordProperty 提供属性包的讨论private sealed class Glossary { [VectorStoreKey] public string Key { get; set; } [VectorStoreData(IsIndexed true)] public string Category { get; set; } [VectorStoreData(IsFullTextIndexed true)] // 参与全文/关键词检索 public string Definition { get; set; } [VectorStoreVector(1536)] public ReadOnlyMemoryfloat DefinitionEmbedding { get; set; } // 稠密向量 }单元测试验证dotnet/src/SemanticKernel.UnitTests/Data/TextSearchStoreTests.cs 中的SearchAsyncWithHybridReturnsSearchResults用例验证了能力探测与调用链先通过GetService(typeof(IKeywordHybridSearchable...))获取混合搜索能力再断言HybridSearchAsync以查询字符串被默认分词器拆分为[query, word, wordtwo]、top 3、HybridSearchOptions选项的方式被调用最终返回记录文本。八、Python 端落地VectorStore 协议中的混合搜索Python 端同样实现了该设计。python/semantic_kernel/data/vector.py 中SearchType枚举定义了KEYWORD_HYBRID keyword_hybrid与VECTOR并列VectorStoreCollection协议声明了hybrid_search抽象方法签名与 ADR 决策一致——统一方法名 additional_property_name作为关键词或未来稀疏向量字段选择器async def hybrid_search( self, values: Any, *, vector: list[float | int] | None None, vector_property_name: str | None None, additional_property_name: str | None None, filter: OptionalOneOrList[Callable | str] None, top: int 3, skip: int 0, include_total_count: bool False, include_vectors: bool False, **kwargs: Any, ) - KernelSearchResults[VectorSearchResult]:create_search_function通过search_type: Literal[vector, keyword_hybrid]参数把搜索能力封装为 KernelFunctionsearch_wrapper内部按SearchType分发到self.search或self.hybrid_search并且会先校验search_type是否在self.supported_search_types内否则抛出VectorStoreOperationNotSupportedException——这与 .NET 端运行时探测能力、不支持则降级的设计互为呼应。Python 侧目前可确认支持该能力的连接器包括 MongoDBpython/semantic_kernel/connectors/mongodb.py相关行为可在单元测试 python/tests/unit/connectors/memory/test_azure_ai_search.py 与示例 python/samples/concepts/memory/complex_memory.py、python/samples/concepts/memory/azure_ai_search_hotel_samples/1_interact_with_the_collection.py 中查看。九、总结与后续演进方向从 ADR 0067 可以看到一次典型的抽象层能力设计流程先盘点 11 种数据库的能力差异再围绕接口命名、参数形态、属性命名、索引配置做多方案权衡最终收敛为一个低门槛、广覆盖的关键词混合搜索接口。当前仓库的落地形态可归纳为三点统一方法名HybridSearchAsync/hybrid_search关键词以集合形式传入与每元素一词、任一匹配词提升排名这一最广泛支持的数据库形态对齐能力探测 自动降级不支持混合搜索的向量存储自动回退到普通向量搜索不破坏既有用户AdditionalPropertyName作为关键词字段选择器为未来引入稀疏向量搜索预留了扩展位。稀疏向量混合搜索HybridSearchWithSparseVector仍留待生成稀疏向量的端到端能力成熟后推进这正是 ADR 文档中Keyword Hybrid Search Only范围决策的前瞻性体现。【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考