本文节选自《DeepSeek本地部署与应用开发:政府与企业级实战案例解析》(北京大学出版社)第8章。若希望深入探讨相关内容,诚挚推荐您购买全书,深入阅读。

8.7 语义向量模型

8.7.1 语义向量模型引擎

语义向量模型引擎是将非结构化数据(如文本、图像、音频)转化为高维稠密向量的技术模块。

其核心原理基于深度学习模型(如Transformer架构),通过嵌入层将离散符号映射为连续向量空间中的数值表示。

在检索增强生成(RAG)系统中,语义向量引擎是核心驱动模块,具体作用如下。

  • 知识库向量化:将文档分块后转化为向量存储,构建可检索的向量索引。
  • 精准语义匹配:通过余弦相似度等算法,将用户查询与知识库向量对比,召回最相关上下文(相比关键词匹配,语义检索准确率提升30%以上)。
  • 动态上下文注入:为生成模型提供精准的参考信息,减少幻觉现象(实验显示RAG系统回答的事实错误率降低58%)。
  • 多语言支持:如BGE-M3模型支持194种语言跨模态对齐,解决跨境电商等多语言场景的检索难题。

Open WebUI 通过模块化架构提供了灵活的语义向量模型引擎集成方案,支持以下三种类型的语义向量模型引擎。

  • Sentence-Transformers:基于PyTorch的轻量级开源框架,与Open WebUI同是Python技术栈,天然适配无缝集成,因此Open WebUI平台默认使用Sentence-Transformers语义向量模型引擎。代表模型有all-MiniLM-L6-v2和paraphrase-MultiLingual-v1。
  • Ollama:支持完全离线运行的本地化部署方案,数据主权自主可控。代表模型有BGE-M3和nomic-embed-text。
  • OpenAI:通过API对接全球领先的预训练模型,持续获取最新算法迭代红利。代表模型有text-embedding-3-large。

8.7.2 语义向量模型对比

表8.3 语义向量模型对比

功能 BGE-M3 all-MiniLM-L6-v2 text-embedding-3-large
支持语言 194种(中/英/日/韩等) 多语言(侧重英文) 多语言(英文最优)
最大文本长度 8192 tokens 256 tokens 8192 tokens
检索功能 稠密+稀疏+多向量混合检索 语义相似度计算 稠密检索(单一模式)
向量维度 1024(可压缩至256) 384 3072(可压缩至256)
模型体积 1.5GB 22MB API调用(无本地部署)
延迟(CPU) 120ms(长文本) 30ms 200ms(API网络延迟)
多模态扩展 支持文本+代码 不支持 不支持

Sentence-Transformers的代表模型all-MiniLM-L6-v2、Ollama的代表模型BGE-M3、以及OpenAI的代表模型text-embedding-3-large,这三者语义向量模型的对比如表8.3所示。

  • BGE-M3:中文检索精度超OpenAI 1.4倍,支持法律/医疗专业术语精准匹配。适用于多语言复杂场景和中文长文档处理。
  • all-MiniLM-L6-v2:移动端问答系统延迟<50ms,资源占用仅为BGE-M3的1/70,适用于实时交互、学术研究、边缘设备和轻量级部署场景。
  • text-embedding-3-large:需要承担API成本,但是性能强大,满足企业级高精度需求,适合全球多语言平台。

综上所述,在企业及政府的本地化部署场景中,推荐使用BGE-M3语义向量模型。

8.7.3 BGE-M3集成

在Open WebUI平台中集成并使用该BGE-M3语义向量模型的详细步骤如下。

  1. 打开 Windows PowerShell或者CMD,在其中输入以下命令,拉取BGE-M3最新模型。
ollama pull bge-m3
  1. 打开Open WebUI平台,如图8.53所示,单击页面左下角管理员账户的头像,依次选择“管理员面板”→“设置”→“文档”即可进入文档设置界面。

  2. 在文档设置设置界面中,调整“语义向量模型引擎”的配置。
     从下拉菜单中选择“Ollama”。
     语义向量模型输入框填:“bge-m3:latest”。
     API密钥输入框不填为空。
     API基础地址输入框填写:“http://host.docker.internal:11434”或者“http://localhost:11434”

  3. 最后,单击界面右下角“保存”按钮,即可完成设置。

图8.53  Open WebUI平台设置语义向量模型

最后,还有需要注意的地方是:如果之前导入的知识库和文档想要用新修改的语义向量模型重新生成向量,则需要重新导入所有文档。否则会报如下错误或者出现其他错误。

open_webui.routers.retrieval:save_docs_to_vector_db:904 - Embedding dimension 1024 does not match collection dimensionality 384

8.8 检索机制

检索的目标是根据输入的内容,检索系统能够从海量的知识库中筛选、识别并提取出与查询最相关的K个知识块。根据所采用的检索策略的不同,检索机制主要可以分为以下三种类型:稀疏检索、稠密检索和混合检索。

  • 稀疏检索
    • 原理:基于关键词匹配,将文本表示为稀疏向量(每个维度对应一个词汇)。通过计算关键词在文档中的出现频率(如TF-IDF、BM25等)来衡量文档与查询的相关性。
    • 优点:简单高效,对关键词匹配非常敏感,适合处理明确的查询需求。
    • 缺点:难以捕捉语义信息,对于语义相关但词汇不匹配的情况表现不佳。
  • 稠密检索
    • 原理:将查询和文档编码为低维稠密向量(通常通过预训练模型如BERT、BGE等)。通过计算向量之间的点积或余弦相似度来衡量相关性。
    • 优点:能够捕捉语义信息,对语义相关性有很好的理解,适合复杂语义查询。
    • 缺点:计算资源需求较高,需要大量的训练数据和计算能力来生成高质量的向量表示。
  • 混合检索
    • 原理:结合稀疏检索和稠密检索的优点。先利用稀疏检索快速筛选出包含关键词的文档,再通过稠密检索对这些文档进行语义重排序,以提高检索的准确性和效率。
    • 优点:综合了两种检索方法的优势,既能够快速筛选关键词匹配的文档,又能通过语义理解进一步优化结果。

Open WebUI默认采用向量检索(即稠密检索)作为其核心检索方式,但同时提供了灵活的混合检索机制。用户可以通过“文档设置”界面中的“混合搜索”按钮,轻松开启或关闭混合检索功能。

在混合检索模式下,Open WebUI首先利用经典的BM25算法进行基础搜索,快速筛选出与查询相关的文档片段。随后,系统借助先进的CrossEncoder技术对这些初步筛选的结果进行深度重排序,以确保最终呈现给用户的文档不仅在关键词匹配上表现出色,更在语义相关性上高度契合。此外,Open WebUI还支持用户自定义相关性分数阈值,用户可以根据自身需求灵活调整检索结果的严格程度,从而获得更精准、更个性化的搜索体验。

8.8.1 向量检索源码解析

Open WebUI平台的向量检索基于query_doc函数实现,query_doc函数的源码路径:open-webui-main\backend\open_webui\retrieval\utils.py

Open WebUI源码Github地址:https://github.com/open-webui/open-webui

代码7-3 query_doc函数(注释说明版)

def query_doc(
    collection_name: str,      		# 目标向量集合名称
    query_embedding: list[float],  	# 查询向量(已编码的文本向量)
    k: int,                    				# 返回结果数量
    user: UserModel = None     		# 用户身份信息(用于权限校验)
):
    try:
        # 执行向量数据库查询(核心操作)
        result = VECTOR_DB_CLIENT.search(
            collection_name=collection_name,  	# 指定查询的集合
            vectors=[query_embedding],        		# 输入查询向量(支持批量查询)
            limit=k,                          				# 限制返回结果数量
        )

        # 记录查询日志(生产环境可添加更多调试信息)
        if result:
            log.info(
                f"query_doc:result {result.ids} {result.metadatas}"  # 记录文档ID和元数据
            )

        return result  # 返回原始结果对象
    
    except Exception as e:
        # 异常处理(包含详细错误上下文)
        log.exception(
            f"Error querying doc {collection_name} with limit {k}: {e}"  # 记录堆栈信息
        )
        raise e  # 向上层抛出异常

query_doc函数源码(注释说明版)如代码7-3所示,该函数用于执行向量数据库的相似性搜索,通过接收查询向量(query_embedding)在指定集合(collection_name)中检索最相似的K个文档(由参数k控制返回数量),核心流程包括调用数据库客户端进行向量匹配、记录返回结果的文档ID和元数据日志,并通过异常处理捕获查询错误(如集合不存在或参数异常),最终返回搜索查询结果。

8.8.2 混合检索源码解析

Open WebUI平台的混合检索功能基于query_doc_with_hybrid_search函数实现,该函数的源码路径:open-webui-main\backend\open_webui\retrieval\utils.py

Open WebUI源码Github地址:https://github.com/open-webui/open-webui

代码7-4 query_doc_with_hybrid_search函数(注释说明版)

def query_doc_with_hybrid_search(
    collection_name: str,     	# 目标文档集合名称(ChromaDB中的集合)
    query: str,                		# 用户输入的查询文本
    embedding_function,        	# 文本编码函数(如BERT模型)
    k: int,                    			# 初步检索数量(召回阶段保留的候选文档数)
    reranking_function,        	# 重排序模型(如CrossEncoder交叉编码器)
    r: float,                  			# 重排序分数阈值(过滤低相关性结果)
):
    try:
        # ========== 数据准备阶段 ==========
        # 从ChromaDB获取指定集合
        collection = CHROMA_CLIENT.get_collection(name=collection_name)
        # 获取集合中所有文档数据(包含文本/元数据等)
        documents = collection.get()

        # ========== 混合检索阶段 ==========
        # BM25检索器(基于关键词匹配的传统检索)
        bm25_retriever = BM25Retriever.from_texts(
            texts=documents.get("documents"),  		# 文档文本列表
            metadatas=documents.get("metadatas"),  	# 文档元数据列表
        )
	# 设置BM25的返回结果数量
        bm25_retriever.k = k  

        # Chroma向量检索器(基于语义相似度的现代检索)
        chroma_retriever = ChromaRetriever(
            collection=collection,             				# Chroma集合对象
            embedding_function=embedding_function,  	# 文本向量化模型
            top_n=k,                          				# 返回结果数量
        )

        # 混合检索器(融合传统与向量检索结果)
        ensemble_retriever = EnsembleRetriever(
            retrievers=[bm25_retriever, chroma_retriever],
            weights=[0.5, 0.5]  # 结果权重:BM25占50%,向量检索占50%
        )

        # ========== 重排序阶段 ==========
        # 创建重排序压缩器
        compressor = RerankCompressor(
            embedding_function=embedding_function,  	# 用于二次编码的模型
            top_n=k,                    					# 最终保留的文档数量
            reranking_function=reranking_function,  	# 交叉编码器模型
            r_score=r                  					# 相关性分数过滤阈值
        )

        # 构建上下文压缩检索器(组合混合检索+重排序)
        compression_retriever = ContextualCompressionRetriever(
            base_compressor=compressor,      	# 重排序组件
            base_retriever=ensemble_retriever 	# 混合检索组件
        )

        # ========== 执行查询 ==========
        # 触发完整检索流程
        result = compression_retriever.invoke(query)
        
        # 格式化输出结果(兼容常见接口格式)
        result = {
            "distances": [[d.metadata.get("score") for d in result]],  	# 相关性分数列表
            "documents": [[d.page_content for d in result]],          	# 文档内容列表
            "metadatas": [[d.metadata for d in result]],              		# 元数据列表
        }

        # 记录日志(生产环境建议添加耗时监控)
        log.info(f"query_doc_with_hybrid_search:result {result}")
        return result
    except Exception as e:
        # 异常处理(建议区分具体错误类型)
        raise e

query_doc_with_hybrid_search函数源码(注释说明版)如代码7-4所示,通过BM25关键词召回+向量语义匹配+交叉编码器重排序的三级架构,实现高精度文档检索,是RAG检索增强的核心模块。流程图如图8.54所示,程序流程说明如下。

  1. 数据获取:从Chroma数据库中获取目标集合数据,该集合数据包含了所有的目标文档和目标元数据。Chroma是一个开源的向量数据库,专为AI和机器学习场景设计,主要用于存储和查询向量数据。
  2. 检索器初始化:基于获取到的目标集合数据,分别初始化 BM25 检索器和向量检索器。BM25 检索器基于关键词匹配的传统检索方式,而向量检索器则利用语义相似度进行现代检索。
  3. 混合检索器构建:将 BM25 检索器和向量检索器的权重均设置为 0.5,然后按照该权重对两个检索器的结果进行合并融合,从而构建出混合检索器。
  4. 重排序压缩器构建:根据预先设定的检索限制数量和重排序分数阈值等参数,使用交叉编码器构建重排序压缩器。该压缩器能够对混合检索的结果进行二次筛选和排序,进一步提高检索结果的相关性。
  5. 完整检索查询执行:启动完整的检索查询流程,该流程包括混合检索和重排序两个关键步骤,确保最终得到的结果既全面又精准。
  6. 结果格式化输出:将检索和重排序后的结果进行格式化处理,使其符合常见的接口格式,方便后续的使用和展示。

图8.54 混合检索程序流程图

8.8.3 Reranker重排序模型

混合检索流程中提到的重排序压缩器的作用是对初步检索得到结果进行重新排序并压缩,其中用到一个关键模型是重排序模型,Reranker重排序模型是对初步检索返回的结果进行重新排序的模型,如图8.55所示。

Reranker重排序模型的工作原理是通过深度学习(如BERT、交叉编码器等)深入分析查询与文档的深层语义关联,解决初步检索中因关键词匹配偏差或语义理解不足导致的排序不合理问题,例如将看似相关但实际无关的文档后置、挖掘同义词或上下文隐含的相关文档前置,最终提升Top-K结果的精准度和相关性,在搜索引擎、问答系统中可使关键指标(如NDCG@10、MRR)提升20%-50%,让用户更快获取高质量信息。
图8.55 重排序模型工作图

在Open WebUI平台中,可以灵活自定义设置重排序模型。当前市面上优秀的重排序模型数量有限,而且不少是闭源模型,不支持本地部署和离线使用。

笔者这边推荐BAAI/bge-reranker-v2-m3模型,是由北京智源研究院推出的高效、开源且支持多语言的重排序模型,是替代Cohere/Jina等闭源方案的理想选择,是构建企业级搜索引擎、多语言知识库问答的首选精排工具。它的核心优势如下。

  • 完全开源免费:Apache-2.0协议,支持本地私有化部署。
  • 动态阈值优化:具备智能的动态阈值调整能力,能够自动精准过滤低相关性内容,有效提升检索结果的精准度与质量。
  • 多语言支持:支持超 100 种语言,在中文及多语言场景表现优异,可满足全球用户的多样化语言需求。
  • 性能强大:在MS MARCO和DuReader等基准测试中NDCG@10指标超越传统模型15%以上,尤其擅长解决同义词替换、语义歧义和跨语言对齐问题。
  • 混合检索适配:可融合文本、图像等多模态特征,支持中、英、日、德等12种语言混合检索。

8.8.4 BAAI/bge-reranker-v2-m3集成

在Open WebUI平台集成BAAI/bge-reranker-v2-m3模型的详细步骤如下。

  1. 打开Open WebUI平台,如图8.41所示,单击页面左下角管理员账户的头像,依次选择“管理员面板”→“设置”→“文”即可进入文档设置界面。
  2. 在文档设置界面中,打开“混合搜索”的开关按钮。
  3. 在“重排模型”的输入框输入:“BAAI/bge-reranker-v2-m3”,然后单击输入框右侧的下载按钮。等待片刻,此时Open WebUI平台从https://huggingface.co网站下载模型。因此,用户需要注意本机电脑是否能够访问https://huggingface.co网站,如果不能,需要合理的进行科学上网。
  4. 最后,单击界面右下角“保存”按钮,即可完成设置。

图8.56  Open WebUI平台设置重排模型

8.9 RAG检索增强生成

篇幅有限,更多精彩,敬请购阅全书。

在这里插入图片描述


本文节选自《DeepSeek本地部署与应用开发:政府与企业级实战案例解析》(北京大学出版社)第8章。若希望深入探讨相关内容,诚挚推荐您购买全书,深入阅读。

【新书推荐】《DeepSeek本地部署与应用开发:政府与企业级实战案例解析》 | 北京大学出版社

若觉得文章对你有帮助,随手『点赞』、『收藏』、『关注』,也是对我的支持。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐