Chainlit集成LlamaIndex实现知识库高级检索(自动合并检索)

检索原理

自动合并检索
自动合并检索原理,和我的上一篇文章的检索方案: 将文本分割成512大小(一般对应段落大小)和128(一般对句子大小不是严格的句子长度)大小两种分别存储到索引库,再用llama_index的简单融合寻回器,分别从这里个向量库查询。将查询结果融合排序后交给LLM的方式十分类似,不同点是检索能将子小块的内容合成大块文本返回。上一篇文章《Chainlit集成LlamaIndex实现知识库高级检索(简单融合寻回器)》
自动合并检索主要是将文档按照块大小拆分成不同层级的节点,这些节点包括父节点和子节点,然后在检索过程中找到相似度高的叶子节点,如果一个父节点中有多个子节点被检索到,那么这个父节点就会被自动合并,最终将父节点的所有文档都作为上下文发送给 LLM(大语言模型),下面是自动合并检索的示意图:

在这里插入图片描述

该检索技术的优缺点

LlamaIndex是一个用于将大型语言模型(LLMs)与外部数据连接的工具,它提供了一系列的功能,使得从外部数据源检索信息变得更加容易和高效。其中,自动合并检索(Auto-merging Retrieval)是LlamaIndex的一项重要功能,它能够在检索过程中自动合并相关的小文本片段,形成更大的上下文,以便更好地服务于后续的信息合成或问题回答任务。以下是关于LlamaIndex自动合并检索的一些优缺点分析:

优点

提高检索质量
自动合并检索能够递归地“合并”引用父节点超过给定阈值的叶节点子集,从而将潜在不同的、较小的上下文合并成一个较大的上下文。这意味着,当用户提出一个问题或者需要获取相关信息时,系统不仅仅提供孤立的信息片段,而是将相关的信息整合起来,形成更加完整和连贯的答案,提高了检索结果的相关性和质量。

优化文本合成
自动合并检索不仅有助于提高检索的准确性,还可以优化文本的合成过程。通过合并相关的上下文,系统可以更好地理解用户的需求,并且在合成信息时考虑到更多的背景信息,使得最终生成的文本更加符合用户的预期。

灵活性和高效性
LlamaIndex作为一个文本检索工具,以其灵活性和高效性著称。自动合并检索作为其一部分,同样继承了这些特点,使得用户可以在不同的应用场景下灵活地调整检索参数,以达到最佳的检索效果。

缺点

可能增加计算成本
虽然自动合并检索提高了检索质量,但是由于需要合并多个相关片段,可能会导致计算资源的消耗增加。特别是在处理大量数据的情况下,如果不对合并的阈值和策略进行合理的设定,可能会导致不必要的计算开销。

复杂性提升
相比于简单的检索方式,自动合并检索增加了系统的复杂性。为了实现高效的合并,需要设计合理的层次结构和切割策略,这对于用户来说意味着更高的学习成本和技术门槛。同时,这也要求系统设计者需要对数据结构有深入的理解。

潜在的信息冗余
尽管自动合并检索旨在提供更完整的上下文,但是在某些情况下,这种合并可能会引入不必要的信息冗余。如果合并策略不够精确,可能会导致检索结果中包含过多无关紧要的细节,反而影响了信息的清晰度和可读性。

综上所述,LlamaIndex的自动合并检索功能为提高检索质量和文本合成提供了强大的支持,但在实际应用中也需要考虑其可能带来的额外开销和复杂性。正确地配置和使用这一功能,对于最大化其优势同时减轻潜在的缺点至关重要。总体来看,只要文档切割分块的每个块的内容完整,使用自动合并检索的这种方式优于 我上一篇写的文章《Chainlit集成LlamaIndex实现知识库高级检索(简单融合寻回器)》 的方案,当然你也可以使用 简单融合寻回器和自动合并检索结合,利用QueryFusionRetrievernum_queries参数来生成多个相似问题,使用retrievers参数设置,自动合并检索器和其他检索器整合,提高检索精度。

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

执行以下命令安装依赖:

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 import (Settings,VectorStoreIndex,SimpleDirectoryReader, StorageContext, load_index_from_storage, )
from llama_index.core.node_parser import SentenceSplitter, HierarchicalNodeParser, get_leaf_nodes, get_root_nodes, \get_child_nodes
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import AutoMergingRetriever
from llama_index.core.storage.docstore import SimpleDocumentStore
from llama_index.embeddings.dashscope import DashScopeEmbedding, DashScopeTextEmbeddingModels, \DashScopeTextEmbeddingType
from llama_index.llms.dashscope import DashScope, DashScopeGenerationModelsSettings.llm = DashScope(model_name=DashScopeGenerationModels.QWEN_MAX, max_tokens=512, api_key=os.environ["DASHSCOPE_API_KEY"]
)
Settings.embed_model = DashScopeEmbedding(model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2,text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT,
)@cl.cache
def get_vector_store_index():storage_dir = "./storage_auto"if os.path.exists(storage_dir):# rebuild storage contextstorage_context = StorageContext.from_defaults(persist_dir=storage_dir)# load indexvector_store_index = load_index_from_storage(storage_context)else:documents = SimpleDirectoryReader("./data_file").load_data(show_progress=True)print(f"documents: {len(documents)}")chunk_sizes = [512, 128]node_parser_ids = [f"chunk_size_{chunk_size}" for chunk_size in chunk_sizes]node_parser_map = {}for chunk_size, node_parser_id in zip(chunk_sizes, node_parser_ids):if chunk_size == 128:chunk_overlap = 10else:chunk_overlap = 20print(chunk_size, chunk_overlap)node_parser_map[node_parser_id] = SentenceSplitter(chunk_size=chunk_size,chunk_overlap=chunk_overlap,)node_parser = HierarchicalNodeParser.from_defaults(node_parser_ids=node_parser_ids, node_parser_map=node_parser_map)nodes = node_parser.get_nodes_from_documents(documents)print(f"nodes: {len(nodes)}")root_nodes = get_root_nodes(nodes)print(f"root_nodes: {len(root_nodes)}")middle_nodes = get_child_nodes(root_nodes, all_nodes=nodes)print(f"middle_nodes: {len(middle_nodes)}")leaf_nodes = get_leaf_nodes(nodes)print(f"leaf_nodes: {len(leaf_nodes)}")doc_store = SimpleDocumentStore()doc_store.add_documents(nodes)storage_context = StorageContext.from_defaults(docstore=doc_store)vector_store_index = VectorStoreIndex(nodes=leaf_nodes, storage_context=storage_context)vector_store_index.storage_context.persist(persist_dir=storage_dir)return vector_store_indexvector_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_index.as_retriever(similarity_top_k=20)retriever = AutoMergingRetriever(vector_retriever=vector_retriever, storage_context=vector_index.storage_context,simple_ratio_thresh=0.4,verbose=True)query_engine = RetrieverQueryEngine.from_args(retriever, streaming=True,)print(f"代码执行时间1: {time.time() - start_time} 秒")msg = cl.Message(content="", author="Assistant")res = await query_engine.aquery(message.content)print(f"代码执行时间1: {time.time() - start_time} 秒")async for token in res.response_gen:await msg.stream_token(token)print(f"代码执行时间3: {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=20 返回20条最相关的数据
  • simple_ratio_thresh,它的默认值是 0.5,表示自动合并文档的阀值,如果在一个父节点中,子节点被检索到的比例小于这个阀值,那么自动合并功能将不会生效,这样提交给 LLM 的上下文就只会包含检索到的叶子节点。反之如果大于这个阀值,文档就会自动合并,最终提交给 LLM 的上下文就会包含这个父节点的内容。比如父节点有 4 个子节点,检索时发现只有 1 个子节点,那么子节点被检索到的比例就是 0.25(1/4),小于阀值 0.5,所以自动合并功能不会生效,最终提交给 LLM 的上下文就只会包含那个检索到的子节点。

代码解读

这段代码展示了一个使用 chainlitllama_index 库来创建一个基于向量存储索引的问答系统的过程。下面是对这段代码的关键部分进行的解读:

  1. 导入必要的库

    • 导入了 ostime 这两个Python标准库。
    • 导入了来自 llama_index 库的核心组件,如设置、向量存储索引、文档读取器等。
    • 导入了 chainlit 库用于构建交互式聊天应用。
  2. 初始化LLM(Large Language Model)和嵌入模型

    • 设置了使用的LLM为 DashScope 提供的 Qwen Max 模型,并配置了API密钥等参数。
    • 嵌入模型也选择了 DashScopeTEXT_EMBEDDING_V2 模型。
  3. 定义获取向量存储索引的方法

    • 如果存储目录存在,则加载已有的索引;否则,从文档中创建新的索引。
    • 使用 HierarchicalNodeParser 来处理文档,将其拆分为不同粒度的节点,并构建层次结构。
    • 创建 SimpleDocumentStore 并将所有节点存储进去。
    • 创建并保存向量存储索引。
  4. 定义聊天启动函数

    • 使用 chainliton_chat_start 装饰器来定义当聊天开始时发送的消息。
  5. 定义消息处理函数

    • 使用 chainliton_message 装饰器来定义接收用户输入后执行的操作。
    • 创建一个向量检索器,并基于此创建一个自动合并检索器。
    • 创建一个查询引擎来处理检索到的信息,并通过流式传输的方式返回结果。
    • 处理查询引擎返回的结果,并通过 chainlit 发送回给用户。

这段代码主要展示了如何构建一个基于文档知识库的问答系统,并且利用 chainlit 来提供用户界面进行交互。它包括了从文档加载到索引构建,再到查询处理和结果展示的整个流程。需要注意的是,为了使这段代码运行,你需要确保安装了所有必要的依赖库,并且拥有正确的API密钥。此外,代码中的路径(例如 ./data_file./storage_auto)需要根据实际情况调整。

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

在这里插入图片描述
将你的文件放到这里,代码中设置的支持,pdf、doc、csv 、txt格式的文件,后续可以根据自己的需求增加更多,langchain带有很多格式文件的加载器,可以自行修改代码。

运行应用程序

要启动 Chainlit 应用程序,请打开终端并导航到包含的目录app.py。然后运行以下命令:

 chainlit run app.py -w   
  • -w标志告知 Chainlit 启用自动重新加载,因此您无需在每次更改应用程序时重新启动服务器。您的聊天机器人 UI 现在应该可以通过http://localhost:8000访问。
  • 自定义端口可以追加--port 80

启动后界面如下:

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

后续会出关于LlamaIndex高级检查的技术文章教程,感兴趣的朋友可以持续关注我的动态!!!

相关文章推荐

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/429901.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NoSql数据库Redis知识点

数据库的分类 关系型数据库 ,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL 、 Oracle 、 MS SQL Server 和 DB2 都属于这类传统数据库。 NoSQL 数据库 ,全称为 Not Only SQL &a…

[uni-app]小兔鲜-01项目起步

项目介绍 效果演示 技术架构 创建项目 HBuilderX创建 下载HBuilderX编辑器 HBuilderX/创建项目: 选择模板/选择Vue版本/创建 安装插件: 工具/插件安装/uni-app(Vue3)编译器 vue代码不能直接运行在小程序环境, 编译插件帮助我们进行代码转换 绑定微信开发者工具: 指定微信开…

2024年最新前端工程师 TypeScript 基础知识点详细教程(更新中)

1. TypeScript 概述 TypeScript 是由微软开发的、基于 JavaScript 的一种强类型编程语言。它是在 JavaScript 的基础上添加了静态类型检查、面向对象编程等功能的超集,最终会被编译为纯 JavaScript 代码。由于其扩展了 JavaScript 的功能,TypeScript 特…

解锁亚马逊测评自养号防关联新技术

解锁亚马逊测评自养号防关联的新技术主要包括以下几个方面,这些技术旨在提高测评过程的安全性,降低账号被关联的风险: 1. 独立纯净IP技术 独立纯净IP:采用独立、纯净且未受污染的国外IP地址,确保这些IP未被标记或列入…

240922-MacOS终端访问硬盘

A. 最终效果 B. 操作步骤 在macOS中,可以通过命令行使用Terminal访问硬盘的不同位置。你可以按照以下步骤操作: 打开终端(Terminal): 在应用程序中打开终端,或者使用 Spotlight 搜索“Terminal”来启动。 …

初学者的鸿蒙多线程并发之 TaskPool 踩坑之旅

1. 背景 目标群体:鸿蒙初学者 版本:HarmonyOS 3.1/4.0 背景:鸿蒙 App 的全局路由管理功能,需要在 App 启动时初始化对 raw 下的相关配置文件进行读取、解析并缓存。App 启动时涉及到了大量模块的初始化,好多模块都涉…

巨潮股票爬虫逆向

目标网站 aHR0cDovL3dlYmFwaS5jbmluZm8uY29tLmNuLyMvSVBPTGlzdD9tYXJrZXQ9c3o 一、抓包分析 请求头参数加密 二、逆向分析 下xhr断点 参数生成位置 发现是AES加密,不过是混淆的,但并不影响咱们扣代码 文章仅提供技术交流学习,不可对目标服…

Vue3+Element Plus:使用el-dialog,对话框可拖动,且对话框弹出时仍然能够在背景页(对话框外部的页面部分)上进行滚动以及输入框输入信息

【需求】 使用Element Plus中的el-dialog默认是模态的(即它会阻止用户与对话框外部的元素进行交互),对话框弹出时仍然能够在背景页(对话框外部的页面部分)上进行滚动以及输入框输入信息,且对话框可拖动 【…

react hooks--React.memo

基本语法 React.memo 高阶组件的使用场景说明: React 组件更新机制:只要父组件状态更新,子组件就会无条件的一起更新。 子组件 props 变化时更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)-> 渲…

STM32精确控制步进电机

目的:学习使用STM32电机驱动器步进电机,进行电机运动精确控制。 测试环境: MCU主控芯片STM32F103RCT6 ;A4988步进电机驱动器模块;微型2相4线步进电机10mm丝杆滑台,金属丝杆安装有滑块。 10mm二相四线微型…

NtripShare测量机器人自动化监测系统测站更换仪器后重新设站

NtripShare测量机器人自动化监测系统投入商业运营已经很久了,在MosBox与自动优化网平差技术的加持下,精度并不让人担心,最近基于客户需求处理了两个比较大的问题。 1、增加对反射片和免棱镜的支持。 2、进一步优化测站更换仪器或重新整平后重…

Qemu开发ARM篇-5、buildroot制作根文件系统并在qemu中进行挂载启动

文章目录 1、 buildroot源码获取2、buildroot配置3、buildroot编译4、挂载根文件系统 在上一篇 Qemu开发ARM篇-4、kernel交叉编译运行演示中,我们编译了kernel,并在qemu上进行了运行,但到最后,在挂载根文件系统时候,挂…

[数据集][目标检测]文本表格检测数据集VOC+YOLO格式6688张5类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):6688 标注数量(xml文件个数):6688 标注数量(txt文件个数):6688 标注…

Fyne ( go跨平台GUI )中文文档-绘图和动画(三)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章: Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…

Easy Excel从入门到精通!!!

目录 1.文件导入 1.1基本方式读取excel文件内容 1.2注解模型映射器读取excel 1.3多行表头读取 1.4文件上传读取 2.文件导出 2.1基本方式导出 2.2模型映射导出 2.3设置行高、列宽等内容 2.4合并单元格 2.5导出设置超链接、批注、公式 2.6模板填充对象导出 2.7模板填…

Mybatis 返回 Map 对象

一、场景介绍 假设有如下一张学生表: CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…

【C++篇】引领C++模板初体验:泛型编程的力量与妙用

文章目录 C模板编程前言第一章: 初始模板与函数模版1.1 什么是泛型编程?1.1.1 为什么要有泛型编程?1.1.1 泛型编程的优势 1.2 函数模板的基础1.2.1 什么是函数模板?1.2.2 函数模板的定义格式1.2.3 示例:通用的交换函数输出示例&am…

华为HarmonyOS地图服务 11 - 如何在地图上增加点注释?

场景介绍 本章节将向您介绍如何在地图的指定位置添加点注释以标识位置、商家、建筑等,并可以通过信息窗口展示详细信息。 点注释支持功能: 支持设置图标、文字、碰撞规则等。支持添加点击事件。 PointAnnotation有默认风格,同时也支持自定…

文献阅读(220)MRCN

题目:MRCN: Throughput-Oriented Multicast Routing for Customized Network-on-Chips时间:2023期刊:TPDS研究机构:韩国成均馆大学 这篇论文探讨的问题是多播死锁问题,下图中Packet A分成两条路径,但在rou…

Leetcode—1014. 最佳观光组合【中等】

2024每日刷题&#xff08;164&#xff09; Leetcode—1014. 最佳观光组合 实现代码 class Solution { public:int maxScoreSightseeingPair(vector<int>& values) {int mxPre values[0] 0;int ans 0;for(int i 1; i < values.size(); i) {ans max(ans, mxP…