基于传统信息检索算法 BM25 的检索器 和 基于大语言模型生成的文本嵌入(dense embeddings)来计算相似度的检索器 两者的区别和联系

embedded/2025/2/23 5:53:40/

首先给出示例代码:

python">#### INDEXING ##### Load blog
import bs4
from langchain_community.document_loaders import WebBaseLoader# 设置一个常见的浏览器 User-Agent 字符串
os.environ["USER_AGENT"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"loader = WebBaseLoader(web_paths=("https://www.yixue.com/%E6%80%8E%E6%A0%B7%E7%9C%8B%E8%A1%80%E5%B8%B8%E8%A7%84%E5%8C%96%E9%AA%8C%E5%8D%95",),bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=("mw-body-content"))),
)blog_docs = loader.load()# Split
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=300, chunk_overlap=50)# Make splits
splits = text_splitter.split_documents(blog_docs)
# print(splits)# Index
from langchain_community.embeddings import HuggingFaceBgeEmbeddingsmodel_name = "BAAI/bge-small-zh-v1.5"
model_kwargs = {"device": "cpu"}
encode_kwargs = {"normalize_embeddings": True}
hf_embeddings = HuggingFaceBgeEmbeddings(model_name=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs
)from langchain_community.vectorstores import Chroma
vectorstore = Chroma.from_documents(documents=splits, embedding=hf_embeddings)retriever = vectorstore.as_retriever()dense_retriever = retrieverfrom langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retrieverbm25_retriever = BM25Retriever.from_documents(splits)ensemble_retriever = EnsembleRetriever(retrievers=[bm25_retriever, dense_retriever], weights=[0.5, 0.5]
)question = "血红蛋白(Hb)测定人体正常范围是多少?"
docs = ensemble_retriever.invoke(question)
docs

下面我们一步步解释这段代码的作用和含义。


1. 加载网页内容

python">import bs4
from langchain_community.document_loaders import WebBaseLoaderos.environ["USER_AGENT"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"loader = WebBaseLoader(web_paths=("https://www.yixue.com/%E6%80%8E%E6%A0%B7%E7%9C%8B%E8%A1%80%E5%B8%B8%E8%A7%84%E5%8C%96%E9%AA%8C%E5%8D%95",),bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=("mw-body-content"))),
)blog_docs = loader.load()

解释:

  • 设置 User-Agent: 为了防止网站屏蔽爬虫,这里设置了一个常见浏览器的 User-Agent 字符串。
  • WebBaseLoader: 利用 WebBaseLoader 加载指定 URL(这里是一个医学科普博客页面),并只解析 HTML 中 CSS 类名为 mw-body-content 的部分(通常是页面的主要内容),这样可以过滤掉导航栏、广告等无关信息。
  • 加载文档: loader.load() 将网页内容提取出来,存储在变量 blog_docs 中。

举例说明:
假如你想获取一本在线教程中的正文内容而不包含广告和侧边栏,通过这种方法就能只提取核心内容。


2. 文本分块

python">from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=300, chunk_overlap=50)splits = text_splitter.split_documents(blog_docs)

解释:

  • 文本切分器: 这里使用了 RecursiveCharacterTextSplitter 将加载的长文本分割成更小的块,每块最多 300 个字符,且相邻块有 50 个字符的重叠。
  • 目的: 切分后的文本块更容易生成向量表示,方便后续的检索和匹配,同时重叠部分可以避免信息断裂,保证上下文连续性。

举例说明:
类似于将一本书拆成多个小段,每段之间有部分重叠,这样在搜索时,即使某一段只有部分信息,也能通过重叠部分关联到完整内容。


3. 构建向量索引

python">from langchain_community.embeddings import HuggingFaceBgeEmbeddingsmodel_name = "BAAI/bge-small-zh-v1.5"
model_kwargs = {"device": "cpu"}
encode_kwargs = {"normalize_embeddings": True}
hf_embeddings = HuggingFaceBgeEmbeddings(model_name=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs
)

解释:

  • 生成嵌入: 使用 HuggingFace 上的中文模型 “BAAI/bge-small-zh-v1.5” 将每个文本块转换为数值向量(嵌入)。
  • 归一化: 归一化后的向量在计算相似度时更稳定,适合后续比较。

举例说明:
就像给每一段文字都制作一个数字指纹,这样当你输入查询问题时,可以计算数字指纹之间的相似度,找到最匹配的文本段。


4. 构建向量库并设置检索器

python">from langchain_community.vectorstores import Chroma
vectorstore = Chroma.from_documents(documents=splits, embedding=hf_embeddings)retriever = vectorstore.as_retriever()dense_retriever = retriever

解释:

  • 向量库: 使用 Chroma 将所有文本块及其嵌入向量存入一个向量数据库。
  • 检索器: 通过 as_retriever() 方法,将向量库包装成一个检索器,可以根据查询计算相似度并返回最相关的文本块。
  • dense_retriever: 这里将基于向量相似度的检索器赋值给变量 dense_retriever,表示这是一种基于“密集向量”(dense vector)的检索方法。

举例说明:
类似于在图书馆中给每本书都贴上了一个数字标签,当你搜索某个主题时,可以快速比对这些数字标签,找出最相关的书。


5. 构造 BM25 检索器及集成检索器(Ensemble Retriever)

python">from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retrieverbm25_retriever = BM25Retriever.from_documents(splits)ensemble_retriever = EnsembleRetriever(retrievers=[bm25_retriever, dense_retriever], weights=[0.5, 0.5]
)

解释:

  • BM25Retriever: 这是一个基于 BM25 算法的传统检索器,它利用关键词、词频等统计信息来衡量查询与文档之间的匹配。
  • 集成检索器 EnsembleRetriever: 将两种检索方法组合起来,通过设置相同的权重(各 50%)对查询结果进行综合排序。
  • 目的: 利用传统关键词匹配(BM25)和基于语义的向量匹配(dense_retriever)的优势,互补不足,从而得到更全面、更准确的检索结果。

举例说明:
假设你搜索“血红蛋白正常值”,传统 BM25 检索器会根据关键词“血红蛋白”、“正常值”来查找完全匹配的段落,而 dense_retriever 则能发现语义上相关但词汇不同的内容。将两者融合后,你既不会错过精确匹配的内容,也能捕捉到隐含语义相似的答案。


6. 检索问答示例

python">question = "血红蛋白(Hb)测定人体正常范围是多少?"
docs = ensemble_retriever.invoke(question)
docs

在这里插入图片描述

解释:

  • 输入问题: 设置查询问题:“血红蛋白(Hb)测定人体正常范围是多少?”
  • 调用检索器: 通过 ensemble_retriever.invoke(question) 进行查询,综合 BM25 和 dense 检索器的结果,返回与问题最相关的文本块。
  • 输出结果: 最终返回的 docs 变量中包含了经过排序后认为最能回答这个问题的文本内容。

举例说明:
假设页面中有一段文字写道:“一般来说,男性血红蛋白正常值在13.5至17.5 g/dL之间,女性在12.0至15.5 g/dL之间。”经过检索器处理后,这段内容就可能被排在最前面,作为回答问题的依据。


总结

整段代码的整体流程如下:

  1. 加载网页内容 —— 从指定博客页面中提取核心内容;
  2. 文本分块 —— 将长文档切分成小块,保证后续处理更加高效;
  3. 生成向量嵌入 —— 利用预训练模型将每个文本块转换为数值向量;
  4. 构建向量库 —— 存储所有嵌入并包装成检索器;
  5. 构造两个检索器并集成 —— 使用传统关键词匹配(BM25)和语义匹配(dense 检索器)各自查找相关文档,然后综合排序;
  6. 执行检索问答 —— 输入查询问题,得到与问题最相关的文本块作为答案依据。

通过这种方法,即使面对不同表达方式的查询,也能综合多种检索策略,给出更加准确和全面的答案。

这段代码中用到两个检索器是为了利用各自的优势,从而提高检索结果的全面性和准确性。

  • BM25Retriever:
    这是一个基于传统信息检索算法 BM25 的检索器。BM25 算法利用文档中的关键词、词频和逆文档频率(IDF)等统计信息,来衡量查询和文档之间的匹配程度。它在捕捉精确词汇匹配方面表现很好,适合那些查询中包含明确关键词的场景。

  • dense_retriever:
    这是基于大语言模型生成的文本嵌入(dense embeddings)来计算相似度的检索器。它通过将查询和文档都转换为向量,然后计算它们之间的相似性(例如使用余弦相似度),可以捕捉到更深层次的语义信息。这样,即使查询和文档之间没有完全相同的关键词,也能发现它们在语义上的相似性。

  • 两者的区别和联系:

    • 区别: BM25Retriever 依赖于传统的关键词统计和匹配,注重词汇层面的精确匹配;而 dense_retriever 则依赖于预训练语言模型的语义理解能力,更擅长捕捉隐含语义信息。
    • 联系: 两者都旨在评估查询和文档之间的相关性,但侧重点不同。通过组合它们(例如各占 50% 权重),可以使得检索系统既能利用关键词匹配的精确性,又能发挥语义匹配的广泛覆盖能力,从而提升整体检索效果。

这种集成方法通常能弥补单一方法的不足,使得最终的检索结果既精准又全面。


http://www.ppmy.cn/embedded/164544.html

相关文章

留学辅导机构| 英国商科paper写作技巧

结论是英国商科report正文的最后一部分,主要是对全文总结或者提出展望。商科report初稿结论部分的内容一般包括:重述一下paper的全称,这里并非让你将其中包含的内容事无巨细地都写上去,应当是挑出其中的重点,main poin…

Ubuntu+vscode+CGAL6.0库安装入门教程

Ubuntu下的CGAL6.0.1安装入门教程 CGAL的官方文档 https://doc.cgal.org/latest/Manual/usage.html#title3 https://github.com/CGAL/cgal/ 安装环境如下 Ubuntu 22.04 boost 1.75 cmake 3.22.1一、安装CGAL库 安装CGAL需要预先安装一些基础库Boost、GMP、MPRF等 1、Boost库…

12.Docker 的资源限制

Docker 的资源限制 Docker 的资源限制1. Stress-ng 压力测试工具2. OOM (Out of Memory Exception)3. 容器的内存限制4. 容器的 CPU 限制 Docker 的资源限制 官方文档:https://docs.docker.com/engine/containers/resource_constraints/ 默…

23. AI-大语言模型-DeepSeek简介

文章目录 前言一、DeepSeek是什么1. 简介2. 产品版本1. 类型2. 版本3. 参数规模与模型能力 3. 特征4. 三种访问方式1. 网页端和APP2. DeepSeek API 二、DeepSeek可以做什么1. 应用场景2. 文本生成1. 文本创作2. 摘要与改写3. 结构化生成 3. 自然语言理解与分析1. 语义分析2. 文…

改进收敛因子和比例权重的灰狼优化算法【期刊论文完美复现】(Matlab代码实现)

2 灰狼优化算法 2.1 基本灰狼优化算法 灰狼优化算法是一种模拟灰狼捕猎自然群体行为的社会启发式优化算法,属于一种新型的群体智能优化算法。灰狼优化算法具有高度的灵活性,是当前较为流行的优化算法之一。灰狼优化算法主要分为三个阶段:追…

运维Ansible面试题及参考答案

目录 简述 Ansible 的工作原理,它是如何实现对远程主机管理的? Ansible 是基于什么语言开发的?这门语言的特性对 Ansible 的功能实现有哪些帮助? 解释 Agentless 在 Ansible 中的含义,与基于 Agent 的自动化工具相比,优势体现在哪? Ansible 中的 Inventory 文件是什…

2502C++,C++继承的多态性

构 A{单 向量<串>记;元<类 T>静 空 ff(串&a){清理(记);名向量(a,记);串 b{"---ff---"};打印(b);T::g();} };构 B:公 A{元<类 T>静 空 f(){串 a{"错误.txt"};ff<T>(a);} };构 C:公 A{元<类 T>静 空 f(){串 a{"a12.c…

CloudMounter for Mac v4.11 挂载云盘为本地磁盘 支持M、Intel芯片

CloudMounter 可以把微软 OneDrive, Google Drive, Amazon S3, Dropbox 和远程 FTP/WebDAV 空间加载成 Mac 本地磁盘&#xff0c;方便用户随时存储使用文件的工具。 应用介绍 loudMounter 是一款 macOS 软件&#xff0c;可以将各种云存储服务和远程服务器挂载为本地磁盘。它支…