当前位置: 首页 > news >正文

Chainlit集成LlamaIndex实现知识库高级检索(组合对象检索)

检索原理

对象组合索引的原理 是利用IndexNode索引节点,将两个不同类型的检索器作为节点对象,使用 SummaryIndex (它可以用来构建一个包含多个索引节点的索引结构。这种索引通常用于从多个不同的数据源或索引方法中汇总信息,并能够基于这些信息进行更复杂的查询操作,如摘要生成。)当查询SummaryIndex时,它会考虑所有包含在内的索引节点,并根据需要综合它们的信息来生成最终的响应或摘要。

组合对象索引检索器的优缺点

结合向量检索(Vector Retrieval)和BM25检索的方式,具有其独特的优点和缺点。下面是对这两种检索方式及其组合使用的优缺点的概述:

向量检索(Vector Retrieval)

优点:
  1. 语义理解:向量检索基于嵌入模型,能够更好地理解文本之间的语义关系,而不仅仅是关键字匹配。
  2. 上下文感知:向量检索可以捕捉句子或段落之间的上下文关系,对于长文本的理解更为有效。
  3. 泛化能力:即使查询词不在文档中出现,只要语义上相关,也可以找到相关的文档。
缺点:
  1. 计算成本:向量检索需要对文档进行嵌入编码,这可能会增加计算资源的需求。
  2. 索引维护:维护一个大型的向量索引可能较为复杂,并且随着文档数量的增加,索引的更新和存储可能变得昂贵。
  3. 精确度依赖于模型质量:向量检索的效果高度依赖于所使用的嵌入模型的质量,如果模型训练不当,效果可能会大打折扣。

BM25 检索

优点:
  1. 简单高效:BM25是一种基于统计的检索模型,不需要复杂的机器学习模型即可实现高效的文档检索。
  2. 可解释性强:因为它是基于关键词频率和文档频率等统计特征,所以结果更容易理解和解释。
  3. 广泛支持:许多搜索引擎和数据库系统已经内置了BM25支持,易于集成。
缺点:
  1. 缺乏语义理解:BM25主要依赖关键词匹配,对于文本的深层语义理解不如向量检索。
  2. 短查询局限性:对于短的或非常特定的查询,BM25可能无法提供最佳的相关性排序。
  3. 忽略上下文:BM25没有考虑到句子或段落之间的上下文关系,这可能导致某些情况下相关性较低。

组合使用的优势

  1. 互补优势:结合两种方法可以在保持简单高效的检索速度的同时,提高检索结果的相关性和准确性。
  2. 灵活性:可以根据具体应用场景灵活调整检索策略,比如对于某些需要强语义理解的任务,可以更依赖向量检索;而对于简单的关键词搜索,可以更多地使用BM25。
  3. 鲁棒性增强:通过融合两种检索方式,可以降低单一方法带来的风险,提高系统的整体性能。

组合使用的挑战

  1. 复杂性增加:维护两种检索机制会增加系统的复杂性,包括数据预处理、索引构建、查询处理等多个环节。
  2. 权衡问题:如何平衡两种检索方法的贡献度是一个需要仔细设计的问题,可能需要通过实验和调参来优化。
  3. 性能开销:虽然理论上可以提高检索质量,但在实际部署中可能需要考虑额外的计算资源消耗。

总的来说,结合向量检索和BM25检索可以利用各自的优势,以期达到更好的检索效果。但在实际应用中,需要根据具体需求和资源条件来进行权衡和选择。

LlamaIndex官方地址 https://docs.llamaindex.ai/en/stable/

LlamaIndex官方地址 https://docs.llamaindex.ai/en/stable/

快速上手

创建一个文件,例如“chainlit_chat”

mkdir chainlit_chat

进入 chainlit_chat文件夹下,执行命令创建python 虚拟环境空间(需要提前安装好python sdkChainlit 需要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文件,代码如下:

  • 此代码使用摘要索引和向量索引,利用RetrieverQueryEngine 路由检索器,根据问题分类提示,选择摘要索引和向量索引进行索引。
import os
import timeimport chainlit as cl
from llama_index.core import (Settings,VectorStoreIndex,load_index_from_storage, StorageContext, SimpleDirectoryReader, SummaryIndex, )
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.schema import IndexNode
from llama_index.embeddings.dashscope import DashScopeEmbedding, DashScopeTextEmbeddingModels, \DashScopeTextEmbeddingType
from llama_index.llms.dashscope import DashScope, DashScopeGenerationModels
from llama_index.retrievers.bm25 import BM25RetrieverSettings.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_obj"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)index = VectorStoreIndex.from_documents(documents)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()vector_retriever = vector_store_index.as_retriever(similarity_top_k=5)bm25_retriever = BM25Retriever.from_defaults(docstore=vector_store_index.docstore, similarity_top_k=5)vector_obj = IndexNode(index_id="vector", obj=vector_retriever, text="Vector Retriever")bm25_obj = IndexNode(index_id="bm25", obj=bm25_retriever, text="BM25 Retriever")summary_index = SummaryIndex(objects=[vector_obj, bm25_obj])query_engine = summary_index.as_query_engine(response_mode="tree_summarize", streaming=True, verbose=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 是和上下文本块的重合文本的大小。
  • 代码中IndexNode是索引节点
    • IndexNode对象
      在代码片段中,vector_obj和bm25_obj都是IndexNode实例。每个IndexNode对象包含了三个主要属性:

      • index_id:索引的唯一标识符。
      • obj:实际的检索对象,这里是指向实际检索逻辑的对象,例如vector_retriever或bm25_retriever。
      • text:描述性文本,用于标识节点的作用

代码解读

这段代码是一个使用Chainlit框架构建的简单聊天机器人应用,它集成了向量检索(Vector Retrieval)和BM25检索机制,并使用了来自DashScope的LLM(Large Language Model)和服务。下面是代码的详细解释:

  1. 导入模块

    • 导入了ostime模块用于操作系统路径和计时。
    • chainlit是一个用于快速构建交互式AI应用的Python库。
    • llama_index提供了一系列工具用于创建和查询知识库索引。
  2. 设置LLM和Embedding模型

    • 设置了DashScope作为默认的LLM和Embedding模型,并指定了API密钥和模型名称。
    • 这些设置影响了如何处理文本输入以及如何生成响应。
  3. 定义获取向量存储索引的函数get_vector_store_index

    • 如果指定的存储目录存在,则从存储加载索引。
    • 否则,从指定的数据目录读取文档来创建一个新的向量存储索引并保存到存储目录中。
  4. 定义聊天开始时触发的函数start

    • 发送一条欢迎消息给用户。
  5. 定义处理用户消息的函数main

    • 创建一个向量检索器和一个BM25检索器,两者都设置为返回前5个最相似的结果。
    • 创建两个IndexNode对象,分别代表向量检索器和BM25检索器。
    • 创建一个SummaryIndex来包含这两个检索器节点。
    • 使用这个总结索引来创建一个查询引擎,该引擎以树状总结模式运行,并且支持流式传输结果。
    • 对于用户的每条消息,使用查询引擎异步查询,并通过流式传输的方式发送每个token给用户。
    • 记录并打印查询所需的时间。
    • 收集并显示源文档的名字作为数据来源。

    代码展示了一个完整的流程,从加载或创建索引,到处理用户输入,再到生成并发送响应。这是一个典型的问答系统的实现方式,特别是当需要从大量的文档中提取信息时。

在项目根目录下创建data_file文件夹

在这里插入图片描述
将你的文件放到data_file文件夹下。
llama_index 库支持多种文件格式的加载,以便从中提取文本内容用于索引构建和后续的信息检索或问答任务。以下是一些常见的文件格式支持:

  1. 文本文件 (.txt):简单的纯文本文件。
  2. PDF 文件 (.pdf):便携文档格式,广泛用于书籍、报告等文档。
  3. Microsoft Word 文档 (.doc, .docx):Word 文档格式。
  4. CSV 文件 (.csv):逗号分隔值文件,常用于表格数据。
  5. HTML 文件 (.html, .htm):超文本标记语言文件。
  6. Markdown 文件 (.md, .markdown):轻量级标记语言。
  7. JSON 文件 (.json):JavaScript 对象表示法,常用于数据交换。
  8. EPUB 文件 (.epub):电子书格式。
  9. 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

启动后界面如下:

在这里插入图片描述
在这里插入图片描述

总结

在chunk_size大小为512,chunk_overlap为20时,整体回复表现良好。但是也有很大的局限性,模型在选择问题时,能否正确选择,这个变得很关键,但实际上往往很难做到正确选择,就比如,我提问2023年的财务报表,模型会倾向于这是一个总结摘要类的问题,会去摘要索引里查找,但是实际上023年的财务报表数据实在向量索引存储的。

相关文章推荐

《Chainlit快速实现AI对话应用的界面定制化教程》
《Chainlit接入FastGpt接口快速实现自定义用户聊天界面》
《使用 Xinference 部署本地模型》
《Fastgpt接入Whisper本地模型实现语音输入》
《Fastgpt部署和接入使用重排模型bge-reranker》
《Fastgpt部署接入 M3E和chatglm2-m3e文本向量模型》
《Fastgpt 无法启动或启动后无法正常使用的讨论(启动失败、用户未注册等问题这里)》
《vllm推理服务兼容openai服务API》
《vLLM模型推理引擎参数大全》
《解决vllm推理框架内在开启多显卡时报错问题》
《Ollama 在本地快速部署大型语言模型,可进行定制并创建属于您自己的模型》

相关文章:

  • 解决 Could not locate zlibwapi.dll. Please make sure it is in your library path
  • Qt获取本机Mac地址、Ip地址
  • iOS OC 底层原理之 category、load、initialize
  • 通过 LabVIEW 正则表达式读取数值(整数或小数)
  • 软件设计之SSM(3)
  • 从《GTA5》的反外挂斗争看网络安全的重要性
  • 高中教辅汇总【35GB】
  • Java:Object操作
  • 【课程总结】day29:大模型之深入了解Retrievers解析器
  • 【C/C++】 秋招常考面试题最全总结(让你有一种相见恨晚的感觉)
  • spring如何解决循环依赖
  • 嵌入式linux裸机调试之windows、linux联合gdb
  • Gromacs——使用过程中暴露问题分析及学习
  • docker-文件复制(docker cp:用于在Docker主机和容器之间拷贝文件或目录)
  • 数学建模研赛总结
  • ES6指北【2】—— 箭头函数
  • (三)从jvm层面了解线程的启动和停止
  • 《深入 React 技术栈》
  • javascript 总结(常用工具类的封装)
  • Javascript设计模式学习之Observer(观察者)模式
  • java取消线程实例
  • JSDuck 与 AngularJS 融合技巧
  • SQLServer之索引简介
  • Tornado学习笔记(1)
  • 闭包--闭包之tab栏切换(四)
  • 关于springcloud Gateway中的限流
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 那些年我们用过的显示性能指标
  • 前端技术周刊 2019-01-14:客户端存储
  • 前端性能优化--懒加载和预加载
  • 前言-如何学习区块链
  • 日剧·日综资源集合(建议收藏)
  • 实战|智能家居行业移动应用性能分析
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 我是如何设计 Upload 上传组件的
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 赢得Docker挑战最佳实践
  • 与 ConTeXt MkIV 官方文档的接驳
  • 交换综合实验一
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (done) Go 语言:三种多文件协作方式
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (五)网络优化与超参数选择--九五小庞
  • .NET Core 成都线下面基会拉开序幕
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET使用存储过程实现对数据库的增删改查
  • .net下的富文本编辑器FCKeditor的配置方法
  • .NET中的十进制浮点类型,徐汇区网站设计
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • @property @synthesize @dynamic 及相关属性作用探究
  • @synthesize和@dynamic分别有什么作用?
  • @Transactional类内部访问失效原因详解