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

news2024/11/14 20:13:57

检索原理

自动合并检索
自动合并检索原理,和我的上一篇文章的检索方案: 将文本分割成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 time

import 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, DashScopeGenerationModels

Settings.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 context
        storage_context = StorageContext.from_defaults(persist_dir=storage_dir)
        # load index
        vector_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 = 10
            else:
                chunk_overlap = 20
            print(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_index


vector_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.node
        source_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.coloradmin.cn/o/2156643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《深度学习》—— 卷积神经网络(CNN)的简单介绍和工作原理

文章目录 一、卷积神经网络的简单介绍二、工作原理(还未写完)1.输入层2.卷积层3.池化层4.全连接层5.输出层 一、卷积神经网络的简单介绍 基本概念 定义:卷积神经网络是一种深度学习模型,通常用于图像、视频、语音等信号数据的分类和识别任务。其核心思想…

如何在Markdown写文章上传到wordpress保证图片不丢失

如何在Markdown写文章上传到wordpress保证图片不丢失 写文日期,2023-11-16 引文 众所周知markdown是一款nb的笔记软件,本篇文章讲解如何在markdown编写文件后上传至wordpress论坛。并且保证图片不丢失(将图片上传至云端而非本地方法) 一&…

通信工程学习:什么是NFVI网络功能虚拟化基础设施层

NFVI:网络功能虚拟化基础设施层 NFVI(Network Functions Virtualization Infrastructure)即网络功能虚拟化基础设施层,是NFV(Network Functions Virtualization,网络功能虚拟化)架构中的一个重要…

精准农业中遥感技术应用(五)- 一站式遥感数据服务平台AIEarth

橙蜂智能公司致力于提供先进的人工智能和物联网解决方案,帮助企业优化运营并实现技术潜能。公司主要服务包括AI数字人、AI翻译、领域知识库、大模型服务等。其核心价值观为创新、客户至上、质量、合作和可持续发展。 橙蜂智农的智慧农业产品涵盖了多方面的功能&…

【LeetCode:116. 填充每个节点的下一个右侧节点指针 + BFS(层次遍历)】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

redis主从复制的理论和实战详细教程

0 前言 就是主从复制,master以写为主,slave以读为主,当master数据变化的时候,自动将新的数据异步同步到其他的slave数据库。也就是redis主从复制异步同步数据的,所以在主从架构中使用分布式锁时,可能会出现…

4--SpringBoot项目中分类管理

目录 新增分类 分类分页查询 启用禁用分类 根据类型查询 修改分类 本文介绍SpringBoot项目中的分类管理,操作类似员工管理模块,具体详解可见以下博客,此处给出各部分代码 2--SpringBoot项目中员工管理 详解(一)-C…

基于51单片机的手环设计仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机,DHT11温湿度采集温湿度,滑动变阻器连接ADC0832数模转换器模拟水位传感器检测水位,通过LCD1602显示信息,然后在程序里设置好是否…

vue3项目中引入词云图

在vue3中的项目引入词云图 前言&#xff1a;先看效果图步骤如下 前言&#xff1a; 公司产品要求项目中使用词云图&#xff0c;我算是第一次用&#xff0c;于是在网上查找资料&#xff0c;最后做出来了。 先看效果图 步骤如下 npm i echarts-wordcloud -S <template> …

恶意AI大模型的兴起将改变网络安全

LLM 的恶意版本&#xff08;如 ChatGPT 的黑暗变体&#xff09;的兴起正在通过使用更复杂和自动化的攻击来升级网络战。 这些模型可以生成令人信服的网络钓鱼电子邮件、传播虚假信息并制作有针对性的社会工程消息。 所有这些非法功能都对在线安全构成了重大威胁&#xff0c;并加…

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

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

[Redis][数据类型]详细讲解

1.Redis 特殊数据结构 1.Streams 应用场景&#xff1a;主要用为队列(阻塞队列) 2.Geospatial 应用场景&#xff1a;用来存储坐标(经纬度) 3.HyperLogLog 应用场景&#xff1a;估算集合中的元素个数注意&#xff1a; HyperLogLog不存储元素的内容&#xff0c;但是能够记录“…

【机器学习】ROC曲线

【机器学习】ROC曲线 1、ROC曲线简介2、ROC曲线和AUC值2.1 ROC曲线2.2 AUC值 3、实验内容3.1 准备数据集3.2 特征提取3.3 数据集划分3.4 模型训练与预测3.5 计算和绘制ROC曲线3.6 绘制混淆矩阵3.7 三分类混淆矩阵 4 源代码4.1 实现ROC二分类4.2 三分类混淆例子 1、ROC曲线简介 …

cnn机器学习时python版本不兼容报错

在使用python执行CNN算法时&#xff0c;发生如下报错&#xff1a; A module that was compiled using NumPy 1.x cannot be run in NumPy 2.1.1 as it may crash. To support both 1.x and 2.x versions of NumPy, modules must be compiled with NumPy 2.0. Some module may …

网络高级day03(Http)

目录 【1】HTTP简介 【2】 HTTP特点 【3】 HTTP协议格式 1》客户端请求消息格式 1> 请求行 2> 请求头 3> 空行 4> 请求数据 2》服务器响应消息格式 【1】HTTP简介 HTTP协议是Hyper Text Transfer Protocol &#xff08;超文本传输协议&#xff09;的缩写&a…

低代码平台:数据筛选功能的全新变革

随着软件开发需求的不断增长&#xff0c;传统的开发方法因其复杂性和耗时性而逐渐无法满足市场对快速交付和迭代的需求。低代码开发平台作为一种新型的软件开发工具&#xff0c;以其高效、易用的特点受到了广泛的关注和应用。 在软件开发领域&#xff0c;数据筛选是一项基础且…

frpc内网穿透

官网地址&#xff1a;frp官网 本次用到的Liunx包&#xff1a; https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.gz下载&#xff1a; wget https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.g…

经典大语言模型解读(3):参数量更大、泛化性能更强的生成式模型GPT-2

概述 在GPT-1的基础上&#xff0c;OpenAI提出了包含15亿参数&#xff08;GPT-1参数量的10倍以上&#xff09;的GPT-2模型。该模型在一个更大规模的文本数据集WebText上进行预训练。与GPT-1依赖特定任务上的有监督微调来提升性能不同&#xff0c;GPT-2具备更强的零样本&#xf…

中小企业体系技术抽象沉淀-异地灾备篇

IT团队内部使用工具 系列文章&#xff1a;https://blog.csdn.net/caicongyang/article/details/136857045 DDL DML管控 https://github.com/hhyo/Archery/ flyway 文档编写 wiki 技术对外输出文档推荐gitbook 同城双活数据同步方案 总览&#xff1a; vivo 系列文章&#x…

脱离枯燥的CRUD,灵活使用Mybatis,根据mybatis动态的xml片段和接口规范动态生成代理类,轻松应付简单业务场景。

需求 需求是这样的&#xff0c;我们有一个数据服务平台的产品&#xff0c;用户先将数据源信息保存到平台上&#xff0c;一个数据源可以提供多个接口服务&#xff0c;而每个接口服务在数据库中存一个具有mybatis语法的sql片段。这样的话&#xff0c;对于一些简单的业务只需要编…