LLM漫谈(三)| 使用Chainlit和LangChain构建文档问答的LLM应用程序

一、Chainlit介绍

     Chainlit是一个开源Python包,旨在彻底改变构建和共享语言模型(LM)应用程序的方式。Chainlit可以创建用户界面(UI),类似于由OpenAI开发的ChatGPT用户界面,Chainlit可以开发类似streamlit的web界面。

1.1 Chainlit的主要特点

  • 可视化中间步骤:Chainlit可以可视化大语言模型管道中的每个步骤;
  • Chainlit与Python代码轻松集成,可以快速释放LM应用程序的潜力;
  • 快速响应的UI开发:使用Chainlit可以利用其直观的框架来设计和实现类似于ChatGPT的迷人UI。

1.2 Chainlit装饰器功能

on_message

      与框架的装饰器,用于对来自UI的消息作出反应。每次收到新消息时,都会调用装饰函数。

on_chat_start

       Decorator对用户websocket连接事件作出反应。

1.3 概念

User Session

      user_session是一个存储用户会话数据的字典,idenv键分别保持会话id和环境变量。用户会话其他数据存储在其他key中。

Streaming

Chainlit支持两种类型的流:

Python Streaming(https://docs.chainlit.io/concepts/streaming/python)

Langchain Streaming(https://docs.chainlit.io/concepts/streaming/langchain)

二、实施步骤

1.开始上传PDF格式文件,确保其正确提交;

2.随后,使用PyPDF2从上传的PDF文档中提取文本内容;

3.利用OpenAIEmbeddings将提取的文本内容转换为矢量化嵌入;

4.将这些矢量化嵌入保存在指定的向量库中,比如Chromadb;

5.当用户查询时,通过应用OpenAIEmbeddings将查询转换为相应的矢量嵌入,将查询的语义结构对齐到矢量化域中;

6.调用查询的矢量化嵌入有效地检索上下文相关的文档和文档上下文的相关元数据;

7.将检索到的相关文档及其附带的元数据传递给LLM,从而生成响应。

三、代码实施

3.1 安装所需的包

pip install -qU langchain openai tiktoken pyPDF2 chainlitconda install -c conda-forge chromadb

3.2 代码实施

#import required librariesfrom langchain.embeddings import OpenAIEmbeddingsfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.vectorstores  import Chromafrom langchain.chains import RetrievalQAWithSourcesChainfrom langchain.chat_models import ChatOpenAIfrom langchain.prompts.chat import (ChatPromptTemplate,                                    SystemMessagePromptTemplate,                                    HumanMessagePromptTemplate)#import chainlit as climport PyPDF2from io import BytesIOfrom getpass import getpass#import osfrom configparser import ConfigParserenv_config =  ConfigParser()# Retrieve the openai key from the environmental variablesdef read_config(parser: ConfigParser, location: str) -> None:    assert parser.read(location), f"Could not read config {location}"#CONFIG_FILE = os.path.join("./env", "env.conf")read_config(env_config, CONFIG_FILE)api_key = env_config.get("openai", "api_key").strip()#os.environ["OPENAI_API_KEY"] = api_key# Chunking the texttext_splitter = RecursiveCharacterTextSplitter(chunk_size=1000,chunk_overlap=100)##system templatesystem_template = """Use the following pieces of context to answer the user's question.If you don't know the answer, just say that you don't know, don't try to make up an answer.ALWAYS return a "SOURCES" part in your answer.The "SOURCES" part should be a reference to the source of the document from which you got your answer.Begin!----------------{summaries}"""messages = [SystemMessagePromptTemplate.from_template(system_template),HumanMessagePromptTemplate.from_template("{question}"),]prompt = ChatPromptTemplate.from_messages(messages)chain_type_kwargs = {"prompt": prompt}#Decorator to react to the user websocket connection event. @cl.on_chat_startasync def init():    files = None    # Wait for the user to upload a PDF file    while files is None:        files = await cl.AskFileMessage(            content="Please upload a PDF file to begin!",            accept=["application/pdf"],        ).send()    file = files[0]    msg = cl.Message(content=f"Processing `{file.name}`...")    await msg.send()    # Read the PDF file    pdf_stream = BytesIO(file.content)    pdf = PyPDF2.PdfReader(pdf_stream)    pdf_text = ""    for page in pdf.pages:        pdf_text += page.extract_text()    # Split the text into chunks    texts = text_splitter.split_text(pdf_text)    # Create metadata for each chunk    metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))]    # Create a Chroma vector store    embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))    docsearch = await cl.make_async(Chroma.from_texts)(        texts, embeddings, metadatas=metadatas    )    # Create a chain that uses the Chroma vector store    chain = RetrievalQAWithSourcesChain.from_chain_type(        ChatOpenAI(temperature=0,                    openai_api_key=os.environ["OPENAI_API_KEY"]),        chain_type="stuff",        retriever=docsearch.as_retriever(),    )    # Save the metadata and texts in the user session    cl.user_session.set("metadatas", metadatas)    cl.user_session.set("texts", texts)    # Let the user know that the system is ready    msg.content = f"`{file.name}` processed. You can now ask questions!"    await msg.update()    cl.user_session.set("chain", chain)# react to messages coming from the UI@cl.on_messageasync def process_response(res):    chain = cl.user_session.get("chain")  # type: RetrievalQAWithSourcesChain    cb = cl.AsyncLangchainCallbackHandler(        stream_final_answer=True, answer_prefix_tokens=["FINAL", "ANSWER"])    cb.answer_reached = True    res = await chain.acall(res, callbacks=[cb])    print(f"response: {res}")    answer = res["answer"]    sources = res["sources"].strip()    source_elements = []    # Get the metadata and texts from the user session    metadatas = cl.user_session.get("metadatas")    all_sources = [m["source"] for m in metadatas]    texts = cl.user_session.get("texts")    if sources:        found_sources = []        # Add the sources to the message        for source in sources.split(","):            source_name = source.strip().replace(".", "")            # Get the index of the source            try:                index = all_sources.index(source_name)            except ValueError:                continue            text = texts[index]            found_sources.append(source_name)            # Create the text element referenced in the message            source_elements.append(cl.Text(content=text, name=source_name))        if found_sources:            answer += f"\nSources: {', '.join(found_sources)}"        else:            answer += "\nNo sources found"    if cb.has_streamed_final_answer:        cb.final_stream.elements = source_elements        await cb.final_stream.update()    else:        await cl.Message(content=answer, elements=source_elements).send()

3.3 运行应用程序

chainlit run <name of the python script>

3.4 Chainlit UI

点击返回的页码,详细说明所引用的文档内容。

我们也可以更改设置。

参考文献:

[1] https://medium.aiplanet.com/building-llm-application-for-document-question-answering-using-chainlit-d15d10469069

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

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

相关文章

5 个适用的免费数据恢复软件【2024 年 版本】

互联网上有许多免费的数据恢复软件产品。有些产品是免费软件&#xff0c;而其他产品则提供该工具的免费试用下载以进行评估。我们列出了2024 年 5 款最佳数据恢复工具 &#xff0c;可以免费下载和试用。 5 个适用的免费数据恢复软件 1.奇客数据恢复&#xff08;Windows和Mac&am…

Apache-Common-Pool2中对象池的使用方式

最近在工作中&#xff0c;对几个产品的技术落地进行梳理。这个过程中发现一些朋友对如何使用Apache的对象池存在一些误解。所以在写作“业务抽象”专题的空闲时间里&#xff0c;本人觉得有必要做一个关于对象池的知识点和坑点讲解。Apache Common-Pool2 组件最重要的功能&#…

中仕公考:2024年上半年中小学教师资格考试(笔试)报名已开始

2024年上半年中小学教师资格考试(笔试)报名工作于1月12日开始&#xff0c;此次笔试在31个省(自治区、直辖市)举办&#xff0c;各省(自治区、直辖市)的报名公告将陆续上网。 个别地区报名截止时间有所差异&#xff0c;上海1月13日报名截止&#xff0c;浙江、天津、河南1月14日截…

负荷预测 | Python基于CEEMDAN-VMD-BiGRU的短期电力负荷时间序列预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 提出一种分解去噪、重构分解的 CEEMDAN-VMD-BiGRU组合预测方法&#xff1a; 1 采用CEEMDAN将原始电力负荷数据分解成一组比较稳定的子序列&#xff0c;联合 小波阈值法将含有噪声的高频分量去噪&#xff0c;保留含有信…

微服务技术要点

一、服务注册到nacos 1.下载nacos&#xff0c;修改nacos启动模式为单机模式&#xff0c;另外需要在环境变量配置JAVA_HOME,否则启动不起来。 2.启动类加注解EnableDiscoveryClient 3.application.yml配置nacos地址 spring:cloud:nacos:discovery:server-addr: 127.0.0.1:884…

springboot怎样设置全局的traceId(包括MQ)

一、Controller打印TraceId 1、拦截所有的controller&#xff0c;输入输出将traceId放入MDC中&#xff1a; package com.perkins.ebicycle.mobile.trace;import java.util.Arrays; import java.util.List; import java.util.UUID; import java.util.stream.Collectors;import…

华为设备登录安全配置案例

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

Python+甘特图及标签设置

图示 甘特图代码 import matplotlib.pyplot as plt import numpy as npclass ProjectEmement:def __init__(self, name_, starttime_: float, endtime_: float, fact_endtime_: float, grade_, rootlist_: list, keylist_: list, isover_=-1):self.name = name_self.starttime…

开发你的第一个 Python3 程序

简介 “Hello, World!” 程序是一个经典的&#xff0c;确立已久的传统电脑程序。"Hello, World!"因为能展示一个语言的基本句法&#xff0c;因此常被用作初学者的第一个"简单但完整"的程序&#xff0c;并可以被用来测试编程环境。 这个教程将指导你写出第…

宝塔nginx部署前端页面刷新报404

问题&#xff1a; 当我们使用脚手架打包前端项目的时候&#xff0c;如果前端项目并没有静态化的配置&#xff0c;如以下 当我们刷新页面&#xff0c;或进行路由配置访问的时候就会报404的错误 原因&#xff1a; 这是因为通常我们做的vue项目属于单页面开发。所以只有index.html…

【教程】华为数据恢复的5个简单方法

您刚刚不小心从华为手机中删除了一些重要文件&#xff0c;现在您迫切希望将它们找回来。如果是这样&#xff0c;那么您现在可能会感到沮丧和无助。您可能已向您的朋友寻求帮助或在互联网上搜索答案&#xff0c;但似乎无济于事。 华为数据恢复的5个简单方法 好吧&#xff0c;别…

MyBatis第二课,灰度发布,@Results注解,使用xml书写mysql

目录 打印MyBatis的日志配置&#xff1a; 灰度发布:指发布环境&#xff0c;比如发布环境有200台机器&#xff0c;发布的时候是一批一批的机器的发布 2.删除与修改 使用Results注解&#xff0c;这样就和上面的别名一个意思&#xff0c;column是数据库的列 自动转驼峰&#…

学习资料: uni-app HBuilderX

编译器&#xff1a;HBuilderX HBuilderX-高效极客技巧 uni-app介绍&#xff1a;uni-app官网 uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;开发者编写一套代码&#xff0c;可发布到iOS、Android、Web&#xff08;响应式&#xff09;、以及各种小程序&#…

根据gbt81702008数值修约的C#函数

#region 修约函数/// </summary>/// <param name"data_val">输入数值</param>/// <param name"len">保留几位小数</param>/// <returns></returns>public static decimal round_gbt8170(decimal data_val,int l…

投手最核心的能力是什么?

巨量广告的本质是用户体验和流量成本 广告投放系统升级的越智能说明三点&#xff1a; 1: 流量顶到天了 2: 系统对用户人群价值计算的准确度提高 3&#xff1a;素材越来越卷 而对于投手来说&#xff1a; 入行门槛降低&#xff0c;操作层面简单&#xff0c;系统能用算法集合…

Unity组件开发--UI管理器

1.Canvas组件&#xff1a; 注意属性&#xff1a; &#xff08;1&#xff09;渲染模式是&#xff1a;屏幕空间相机 &#xff08;2&#xff09;创建一个UICamera节点&#xff0c;管理相机 &#xff08;3&#xff09;屏幕画布缩放模式 &#xff08;4&#xff09;画布下挂载两…

Android-基础

Activity生命周期 1.启动Activity&#xff1a;系统会先调用onCreate方法&#xff0c;然后调用onStart方法&#xff0c;最后调用onResume&#xff0c;Activity进入运行状态。 2.当前Activity被其他Activity覆盖其上或被锁屏&#xff1a;系统会调用onPause方法&#xff0c;暂停当…

linux批量查杀进程

linux批量查杀进程 方案1&#xff1a;killall killall 命令来杀掉所有指定名称的进程。 killall -9 uwsgi这将会杀掉所有名称为 uwsgi 的进程&#xff0c;包括在后台运行的进程。 注意&#xff0c;使用 killall 命令要小心&#xff0c;因为它可能会误杀其他不相关的进程。在…

WiFi7: MLO操作之AP MLD的发现—AP的行为

原文:如果AP是AP MLD的transmitted BSSID,那么Beacon帧和Probe Response 帧必须在Reduced Neighbor Report element中包含对应各AP的TBTT Information域,并将TBTT Information Length域设置为16或者更高(见9.4.2.169.2(Neighbor AP Information field))。FILS Discovery帧…

华为HCIE课堂笔记第十五章 IPv6过渡技术

第十五章 IPv6过渡技术 15.1 简介 1、隧道技术 2、双栈技术 3、地址转换技术 15.2 隧道技术 15.2.1 ipv6 over ipv4 隧道 手工隧道&#xff1a;IPv6 Over IPv4隧道 Ipv6 Over IPv4&#xff1a;IPv6孤岛通过IPv4网络之间进行通信&#xff0c;IPv6的报文封装IPv4报文之上…