Chainlit集成LlamaIndex实现知识库高级检索(BM25全文检索器)
检索原理
BM25Retriever类是一个基于BM25算法设计的检索器,它主要用于从一组文档或节点中检索出与查询最相关的文档或节点。这个类的设计目的是为了提高文本检索的效率和准确性,尤其是在处理大量文本数据时。
BM25(Best Matching 25)算法是一种在信息检索领域广泛应用的经典算法,它是对传统的TF-IDF(Term Frequency-Inverse Document Frequency)算法的一种改进。BM25算法的核心思想是利用词频(TF)和逆文档频率(IDF)来衡量文档与查询之间的相关性,同时考虑到文档长度信息对相关性的影响。以下是对BM25算法的一些关键特性和原理的介绍:
原理
BM25算法基于这样一个假设:对于一个特定的查询项,它在相关文档中出现的频率应该高于在非相关文档中的频率。该算法通过结合词项频率(TF)和文档频率(DF)来计算文档的得分。具体来说,BM25算法包括以下几个组成部分:
-
词项频率(TF):词项频率是指一个词项在文档中出现的次数。BM25对传统的TF计算方法进行了调整,引入了饱和度和长度归一化,以防止长文档由于包含更多词项而获得不公平的高评分。
-
逆文档频率(IDF):逆文档频率是衡量词项稀有程度的一个指标。它基于整个文档集合来计算,用来降低常见词项的权重,并提升罕见词项的权重。
-
文档长度信息:BM25算法引入了文档长度信息,以进一步调整相关性的计算。这样可以避免因为文档长度不同而导致的相关性偏差。
计算公式
BM25算法的计算公式可以表述为:

其中:
- ( tf_{t,d} ) 是词项 ( t ) 在文档 ( d ) 中的词频;
- ( IDF(t) ) 是词项 ( t ) 的逆文档频率;
- ( k_1 ) 和 ( b ) 是自由参数,用于调节计算过程中的影响;
- ( |d| ) 是文档 ( d ) 的长度;
- ( avgdl ) 是文档集合中所有文档长度的平均值。
改进与变种
除了标准的BM25算法之外,还有几种重要的变种,如BM25F和BM25L:
BM25F:这是BM25的一个重要扩展,可以在多个文档域上进行计算。BM25L:该变种考虑了文档长度对得分的影响,通过引入文档长度规范化项来平衡不同长度的文档。
应用场景
BM25算法因其在处理词频和相关性之间非线性关系上的优势,被广泛应用于搜索引擎和相关领域。在实际应用中,如Elasticsearch和Lucene这样的全文搜索引擎,默认使用的就是Okapi BM25算法。
总结来说,BM25算法是一种强大而灵活的信息检索算法,它通过对TF-IDF模型的改进,提高了搜索结果的相关性,同时通过引入文档长度因子等改进措施,增强了算法的实用性。
该检索技术的优缺点
LlamaIndex是一个基于语言模型(LLM)的开源信息检索系统,它提供了高效的数据索引和查询功能,适用于大规模文本数据集的快速检索。其中,BM25Retriever是LlamaIndex提供的一个检索器,它基于BM25算法,这是一种广泛使用的信息检索排序函数,专门用于文档检索,尤其擅长处理长文档和短查询。下面将详细探讨BM25Retriever在LlamaIndex中的优缺点。
优点
-
优化的TF-IDF: BM25Retriever是基于TF-IDF(词频-逆文档频率)的改进版本,它解决了标准TF-IDF方法的一些局限性,如长文档可能得到过高评分的问题。BM25通过调整参数k1和b来考虑文档长度的影响,从而使得检索结果更加准确。
-
文档长度的考虑: BM25Retriever的一个关键特性是它考虑了文档长度对评分的影响。对于长文档,BM25Retriever会调整评分,确保不会因为文档较长而产生不公平的优势,这有助于提高检索结果的相关性。
-
灵活性: BM25Retriever可以很容易地与其他检索技术相结合,例如与向量检索混合使用,形成一种称为混合检索的技术。这种组合可以利用各自的优势,提供更加全面的检索服务。
缺点
-
中文支持问题: 默认情况下,BM25Retriever的tokenizer可能不支持中文处理,这意味着在处理中文文本时需要额外的步骤或定制的解决方案,如使用jieba分词器来处理中文文本。
-
计算资源需求: 尽管BM25Retriever在文档检索方面表现优秀,但它需要进行大量的计算来确定文档与查询的相关性得分,尤其是在大型数据集中,这可能会导致较高的计算资源需求。
-
参数调优: BM25算法依赖于一些参数(如k1, b等),这些参数可能需要根据具体的应用场景进行调优才能达到最佳性能。如果不正确地设置这些参数,可能会影响检索结果的质量。
综上所述,BM25Retriever在LlamaIndex中提供了一种强大的检索机制,尤其适用于需要精确排序结果的应用场景。然而,在使用时需要注意其对于特定语言的支持情况以及可能产生的计算开销等问题。在实际应用中,根据具体的业务需求选择合适的检索器,并且合理地调整参数以优化性能是非常重要的。
LlamaIndex官方地址 https://docs.llamaindex.ai/en/stable/
快速上手
创建一个文件,例如“chainlit_chat”
mkdir chainlit_chat
进入 chainlit_chat文件夹下,执行命令创建python 虚拟环境空间(需要提前安装好python sdk。 Chainlit 需要python>=3.8。,具体操作,由于文章长度问题就不在叙述,自行百度),命令如下:
python -m venv .venv
- 这一步是避免python第三方库冲突,省事版可以跳过
.venv是创建的虚拟空间文件夹可以自定义
接下来激活你创建虚拟空间,命令如下:
#linux or mac
source .venv/bin/activate
#windows
.venv\Scripts\activate
在项目根目录下创建requirements.txt,内容如下:
chainlit
llama-index-core
llama-index-llms-dashscope
llama-index-embeddings-dashscope
llama-index-retrievers-bm25~=0.3.0
执行以下命令安装依赖:
pip install -r .\requirements.txt
- 安装后,项目根目录下会多出
.chainlit和.files文件夹和chainlit.md文件
代码创建
只使用通义千问的DashScope模型服务灵积的接口
在项目根目录下创建.env环境变量,配置如下:
DASHSCOPE_API_KEY="sk-api_key"
DASHSCOPE_API_KEY是阿里dashscope的服务的APIkey,代码中使用DashScope的sdk实现,所以不需要配置base_url。默认就是阿里的base_url。- 阿里模型接口地址 https://dashscope.console.aliyun.com/model
在项目根目录下创建app.py文件,代码如下:
import os
import timeimport chainlit as cl
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.retrievers.bm25 import BM25Retriever
from llama_index.core import (Settings,VectorStoreIndex,SimpleDirectoryReader, load_index_from_storage, StorageContext,
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.dashscope import DashScopeEmbedding, DashScopeTextEmbeddingModels, \DashScopeTextEmbeddingType
from llama_index.llms.dashscope import DashScope, DashScopeGenerationModelsSettings.llm = DashScope(model_name=DashScopeGenerationModels.QWEN_TURBO, api_key=os.environ["DASHSCOPE_API_KEY"], max_tokens=512
)
Settings.embed_model = DashScopeEmbedding(model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2,text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT,
)
Settings.node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=20)
Settings.num_output = 512
Settings.context_window = 6000@cl.cache
def get_vector_store_index():storage_dir = "./storage_bm25_512"if os.path.exists(storage_dir):storage_context = StorageContext.from_defaults(persist_dir=storage_dir)index = load_index_from_storage(storage_context)else:documents = SimpleDirectoryReader("./data_file").load_data(show_progress=True)node_parser = SentenceSplitter.from_defaults(chunk_size=512, chunk_overlap=20)nodes = node_parser.get_nodes_from_documents(documents)print(f"nodes: {len(nodes)}")index = VectorStoreIndex(nodes=nodes)index.storage_context.persist(persist_dir=storage_dir)return indexvector_store_index = get_vector_store_index()@cl.on_chat_start
async def start():await cl.Message(author="Assistant", content="你好! 我是泰山AI智能助手. 有什么可以帮助你的吗?").send()@cl.on_message
async def main(message: cl.Message):start_time = time.time()retriever = BM25Retriever.from_defaults(docstore=vector_store_index.docstore, similarity_top_k=5)query_engine = RetrieverQueryEngine.from_args(retriever, streaming=True)msg = cl.Message(content="", author="Assistant")res = await query_engine.aquery(message.content)async for token in res.response_gen:await msg.stream_token(token)print(f"代码执行时间: {time.time() - start_time} 秒")source_names = []for idx, node_with_score in enumerate(res.source_nodes):node = node_with_score.nodesource_name = f"source_{idx}"source_names.append(source_name)msg.elements.append(cl.Text(content=node.get_text(), name=source_name, display="side"))await msg.stream_token(f"\n\n **数据来源**: {', '.join(source_names)}")await msg.send()
- 代码中的
persist_dir=storage_dir不设置的默认是./storage. - 代码中
chunk_size是将长文档分割的文本块的大小,chunk_overlap是和上下文本块的重合文本的大小。 - 代码中
node_parser = HierarchicalNodeParser.from_defaults( node_parser_ids=node_parser_ids, node_parser_map=node_parser_map )可以简写为node_parser = HierarchicalNodeParser.from_defaults()会按照[2048,512,128]三种层次分割,经过我测试不使用默认的效果会更好 similarity_top_k=5返回5条最相关的数据
代码解读
这段代码是一个使用ChainLit框架构建的聊天机器人应用,它集成了向量数据库索引和检索功能,以从文档中检索信息并回答用户的问题。下面是代码的逐部分解释:
-
导入模块:
os和time是标准库模块,分别用于操作系统相关功能和计时功能。chainlit as cl用于创建交互式的Web应用程序。llama_index是一个用于构建索引、检索器和查询引擎的库,帮助处理文本数据并进行问答系统开发。
-
设置环境变量:
- 设置了DashScope的LLM(Language Model)和Embedding模型,并指定了使用的模型类型以及API密钥位置。这些设置是根据环境变量
DASHSCOPE_API_KEY来获取的。
- 设置了DashScope的LLM(Language Model)和Embedding模型,并指定了使用的模型类型以及API密钥位置。这些设置是根据环境变量
-
向量存储索引函数 (
get_vector_store_index):- 这个函数首先检查是否存在一个持久化的存储目录。如果存在,则加载已有的索引;如果不存在,则读取指定目录下的文档,将其分割成节点,创建向量存储索引,并将其持久化到指定目录。
-
聊天开始时的事件处理器 (
start):- 当聊天会话开始时,发送一条消息给用户作为问候。
-
接收消息时的事件处理器 (
main):- 当收到用户的输入消息时,使用BM25检索器来检索最相关的文档,并通过
RetrieverQueryEngine生成答案。 - 使用异步生成器流式传输响应给用户,并记录每个源文档的信息,以便显示数据来源。
- 当收到用户的输入消息时,使用BM25检索器来检索最相关的文档,并通过
这段代码展示了一个基于文档检索的问答系统的实现方式,利用了现代语言模型的能力来生成高质量的回答。注意,在实际部署时需要确保环境变量DASHSCOPE_API_KEY已经正确设置,并且指定的数据文件夹路径是正确的。此外,还需确保所有依赖项已安装,并且与ChainLit框架兼容。
在项目根目录下创建data_file文件夹

将你的文件放到data_file文件夹下。
llama_index 库支持多种文件格式的加载,以便从中提取文本内容用于索引构建和后续的信息检索或问答任务。以下是一些常见的文件格式支持:
- 文本文件 (
.txt):简单的纯文本文件。 - PDF 文件 (
.pdf):便携文档格式,广泛用于书籍、报告等文档。 - Microsoft Word 文档 (
.doc,.docx):Word 文档格式。 - CSV 文件 (
.csv):逗号分隔值文件,常用于表格数据。 - HTML 文件 (
.html,.htm):超文本标记语言文件。 - Markdown 文件 (
.md,.markdown):轻量级标记语言。 - JSON 文件 (
.json):JavaScript 对象表示法,常用于数据交换。 - EPUB 文件 (
.epub):电子书格式。 - PPTX 文件 (
.pptx):PowerPoint 演示文稿。
除了上述文件格式外,llama_index 可能还支持其他一些格式,具体取决于其内部依赖库的支持情况。例如,它可能通过第三方库支持解析像 .xls, .xlsx 这样的 Excel 文件。
为了加载这些不同类型的文件,llama_index 提供了多个不同的读取器(readers),如 SimpleDirectoryReader 可以用来加载一个目录中的多个文件,而针对特定文件格式(如 PDF 或 Word 文档),则有专门的读取器类。
例如,如果你有一个包含多种文件格式的目录,你可以使用 SimpleDirectoryReader 来加载它们。如果你只处理一种类型的文件,比如 PDF 文件,你可以选择使用更具体的读取器,比如 PDFReader。
运行应用程序
要启动 Chainlit 应用程序,请打开终端并导航到包含的目录app.py。然后运行以下命令:
chainlit run app.py -w
- 该
-w标志告知Chainlit启用自动重新加载,因此您无需在每次更改应用程序时重新启动服务器。您的聊天机器人 UI 现在应该可以通过http://localhost:8000访问。 - 自定义端口可以追加
--port 80
启动后界面如下:


BM25Retriever索引器还可以与向量检索器等其他索引器,利用QueryFusionRetriever类将其融合查询。
后续会出更多关于LlamaIndex高级检查的技术文章教程,感兴趣的朋友可以持续关注我的动态!!!
相关文章推荐
《Chainlit快速实现AI对话应用的界面定制化教程》
《Chainlit接入FastGpt接口快速实现自定义用户聊天界面》
《使用 Xinference 部署本地模型》
《Fastgpt接入Whisper本地模型实现语音输入》
《Fastgpt部署和接入使用重排模型bge-reranker》
《Fastgpt部署接入 M3E和chatglm2-m3e文本向量模型》
《Fastgpt 无法启动或启动后无法正常使用的讨论(启动失败、用户未注册等问题这里)》
《vllm推理服务兼容openai服务API》
《vLLM模型推理引擎参数大全》
《解决vllm推理框架内在开启多显卡时报错问题》
《Ollama 在本地快速部署大型语言模型,可进行定制并创建属于您自己的模型》
相关文章:
Chainlit集成LlamaIndex实现知识库高级检索(BM25全文检索器)
检索原理 BM25Retriever类是一个基于BM25算法设计的检索器,它主要用于从一组文档或节点中检索出与查询最相关的文档或节点。这个类的设计目的是为了提高文本检索的效率和准确性,尤其是在处理大量文本数据时。 BM25(Best Matching 25&#x…...
Dubbo入门案例
Dubbo 学习地址:Dubbo3 简介_w3cschool; 01-Dubbo入门案例 我们先来新建一个Dubbo的小案例来体验一下Dubbo的使用,我们先来创建一个springboot的项目。 1.1-zookeeper下载启动 在编写我们的入门案例之前,我们需要先去下…...
android设计模式的建造者模式,请举例
在Android开发中,建造者模式(Builder Pattern)是一种常用的设计模式,它主要用于构建复杂对象。建造者模式通过将复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。这种模式特别适用于那些需要多个…...
【探索智谱AI的CogVideoX:视频生成的新前沿】
2024年8月6日,智谱AI宣布其开源视频生成模型CogVideoX,激发了开发者的创造力和对新技术的期待。 一、CogVideoX模型概述 CogVideoX 是一款先进的视频生成工具,可基于最长 226 个 token 的提示生成视频,时长可达 6 秒,…...
ant design vue做表单验证及form表单外验证、父子嵌套多个表单校验
1、form表单验证(若有时遇到输入框有值但是还是触发验证规则了,请检查form表单绑定正确吗、校验规则正确吗、表格数据字段名正确吗) <a-form:model"formState":label-col"{ span: 8 }":wrapper-col"{ span: 16 }":rules"rul…...
爱速搭百度低代码开发平台
爱速搭介绍 爱速搭是百度智能云推出的低代码开发平台,它灵活性强,对开发者友好,在百度内部大规模使用,有超过 4w 内部页面是基于它制作的,是百度内部中台系统的核心基础设施。 它具备以下功能: 页面制作…...
2024icpc(Ⅱ)网络赛补题E
E. Escape 思路: 可以看成 Sneaker 和杀戮机器人都不能在原地停留,然后杀戮机器人有个活动范围限制。如果 Sneaker 和杀戮机器人可以在原地停留,那么 Sneaker 到达一个点肯定会尽可能早,而且时间必须比杀戮机器人到达这个点短。那…...
mac怎么设置ip地址映射
最近开发的项目分为了两种版本,一个自己用的,一个是卖出去的。 卖出的域名是和自己的不一样的,系统中有一些功能是只有卖出去的版本有的,但我们开发完之后还得测试,那就需要给自己的电脑配置一个IP地址映射了…...
StringReader 使用 JAXB自动将 XML 数据映射到 Java 对象
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import java.io.StringReader; public class JAXBExample { public static void main(String[] args) { try { // 假设这是从某处获取的XML字符串 S…...
【系统架构设计师】专题:系统分析和设计
文章目录 一、处理流程设计1.1 流程表示工具1.2 业务流程重组BPR1.3 业务流程管理BPM二、系统设计三、人机界面设计四、结构化方法4.1 结构化分析(Structured Analysis,SA)。4.2 结构化设计(Structured Design,SD)。4.3 结构化编程(Structured Programming,SP)。4.4 数据库设…...
Lambda表达式(Java)
1.Lambda表达式 Lambda是一个匿名函数,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。 “->”(Lambda操作符)左边:Lambda表达式的所有参数。右边:Lambda体&#x…...
不同的子序列
题目 给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。 字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “…...
CI24R1——精简版Si24R1,高性价比替代XN297开发资料
CI24R1为了减低用户的开发时间,将2.4G芯片开发出2.4G小模块,用户直接贴片调试,大大降低了开发时间跟生产工序。广泛应用在灯控、鼠标、玩具等智能物联网产品。 CI24R1小模块(内置天线) 是 2.4GHz 模块。该模块核心处理…...
MySQL递归查询笔记
目录 一、创建表结构和插入数据 二、查询所有子节点 三、查询所有父节点 四、查询指定节点的根节点 五、查询所有兄弟节点(同级节点) 六、获取祖先节点及其所有子节点 七、查询每个节点之间的层级关系 八、查询指定节点之间的层级关系 一、创建表…...
java中的位运算
位运算是对整数的二进制位进行操作的一种运算。在java中long, int, short, char和byte类型都可以使用位运算。 位运算的过程如下:首先将十进制整数转换成二进制表示形式,然后将位运算符应用于每个二进制数位,并计算结果。最后,将…...
llamafactory0.9.0微调qwen2vl
LLaMA-Factory/data/README_zh.md at main hiyouga/LLaMA-Factory GitHubEfficiently Fine-Tune 100+ LLMs in WebUI (ACL 2024) - LLaMA-Factory/data/README_zh.md at main hiyouga/LLaMA-Factoryhttps://github.com/hiyouga/LLaMA-Factory/blob/main...
Electron 隐藏顶部菜单
隐藏前: 隐藏后: 具体设置代码: 在 main.js 中加入这行即可: // 导入模块 const { app, BrowserWindow ,Menu } require(electron) const path require(path)// 创建主窗口 const createWindow () > {const mainWindow ne…...
软件测试学习笔记丨curl命令发送请求
本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/32332 一、简介 cURL是一个通过URL传输数据的,功能强大的命令行工具。cURL可以与Chrome Devtool工具配合使用,把浏览器发送的真实请求还原出来,附带认证信…...
STM32+PWM+DMA驱动WS2812 —— 2024年9月24日
一、项目简介 采用STM32f103C8t6单片机,使用HAL库编写。项目中针对初学者驱动WS2812时会遇到的一些问题,给出了解决方案。 二、ws2812驱动原理 WS2812采用单线归零码的通讯方式,即利用高低电平的持续时间来确定0和1。这种通信方式优点是只需…...
MMD模型及动作一键完美导入UE5-IVP5U插件方案(二)
1、下载并启用IVP5U插件 1、下载IVP5U插件, IVP5U,点击Latest下载对应引擎版本,将插件放到Plugins目录,同时将.uplugin文件的EnableByDefault改为false 2、然后通过Edit->Plugins启用插件 2、导入pmx模型 1、直接在Content的某个目录拖入pmx模型,选择默认参数 2、…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
