开发arXiv论文引擎机器人程序 基于RAG+LangChain+Chainlit+ChromaDB
本文将完整粗疏地引见如何经常使用RAG技术与LangChain、Chainlit Copilot组件以及LiteralAI可观测性特色联结开发一款语义论文搜查引擎程序。
简介
在本文中,我将演示如何经常使用检索增强生成(RAG)技术构建语义钻研论文引擎。详细地说,我将经常使用LangChain(作为构建语义引擎的关键框架,以及OpenAI公司的大言语模型和ChromaDB开源向量数据库(。为了构建称号为Copilot的嵌入式Web运行程序,我将经常使用Chainlit中的Copilot插件性能,并结合LiteralAI公司(的可观察性特色。借助于该运行程序,用户可以更容易地查找关系论文,从而促成学术钻研。用户还可以经过征询无关介绍论文的疑问间接与内容互动。最后,咱们将在运行程序中集成可观察性特色,以便跟踪和调试对LLM的调用。整个运行程序的架构如下图所示。
Copilot嵌入式语义钻研论文运行程序全体架构
以下先来看一下咱们将在本教程中引见的一切内容的概览:
Copilot嵌入式语义钻研论文引擎的运转时快照
留意,本教程中的完整示例工程代码可以在GitHub地址处找到:
环境设置
首先,咱们要创立一个新的conda环境:
conda create -n semantic_research_engine python=3.10
而后,经常使用如下命令激活环境:
conda activate semantic_research_engine
最后,经过运转以下命令,在激活的环境中装置一切必需的依赖项:
pip install -r requirements.txt
RAG管道创立
检索增强生成(RAG)是一种盛行的技术,准许你经常使用自己的数据构建自定义的对话式人工智能运行程序。RAG的原理相当便捷:咱们将文本数据转换为向量嵌入,并将其拔出向量数据库;而后将该数据库链接到大型言语模型(LLM)。须要说明的是,咱们将限度LLM从自己的数据库中失掉信息,而不是依赖先验常识来回答用户查问。在接上去的几个步骤中,我将详细引见如何为咱们的语义钻研论文引擎做到这一点。咱们将创立一个名为rag_test.py的测试脚原本了解和构建RAG管道的组件。之后,这些组件将在构建咱们的集成Copilot插件的Chainlit运行程序时重复经常使用。
步骤1:注册账户
须要注册一个账户,以便包全OpenAI API密钥。成功后,在名目目录中创立一个.env文件,并减少该OpenAI API密钥,如下所示:
OPENAI_API_KEY="your_openai_api_key"
在本文运行程序中,咱们将经常使用这个.env文件来存储咱们名目标一切API密钥。
步骤2:输入数据
在这一步中,咱们将创立一个数据库来存储针对用户查问的钻研论文。为此,咱们首先须要从arXivAPI中检索关系论文的列表以启动查问。咱们将经常使用LangChain的ArxivLoader包,由于此包形象了与API的交互,而后检索论文以供进一步解决。咱们可以将这些论文宰割成更小的块,以确保的高效解决和关系信息检索。
为此,咱们将经常使用LangChain中的RecursiveTextSplitter()函数,由于它可以确保在宰割文档时信息的语义保管。接上去,咱们将经常使用HuggingFace(中的sentence-transformers嵌入为这些块创立嵌入。最后,咱们将把这些宰割文档嵌入到ChromaDB数据库中进后退一步查问。
# rag_test.pyfrom langchain_community.document_loaders import ArxivLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import Chromafrom langchain_community.embeddings import HuggingFaceEmbeddingsquery = "lightweight transformer for language tasks"arxiv_docs = ArxivLoader(query=query, load_max_docs=3).load()pdf_data = []for doc in arxiv_docs:text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000,chunk_overlap=100)texts = text_splitter.create_documents([doc.page_content])pdf_data.append(texts)embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-l6-v2")db = Chroma.from_documents(pdf_data[0], embeddings)
步骤3:检索和生成
一旦创立了特定主题的数据库,咱们就可以经常使用该数据库作为检索器,并依据提供的高低文回答用户疑问。LangChain提供了一些不同的检索链,咱们将在本教程中经常使用最便捷的RetrievalQA链。咱们将经常使用from_chain_type()方法设置此链,指定模型和检索器。关于LLM中的文档集成,咱们将经常使用stuff链类型,由于它能够将一切文档填充到一个揭示中。
# rag_test.pyfrom langchain.chains import RetrievalQAfrom langchain_openai import OpenAIfrom dotenv import load_dotenvload_dotenv()llm = OpenAI(model='gpt-3.5-turbo-instruct', temperature=0)qa = RetrievalQA.from_chain_type(llm=llm,chain_type="stuff",retriever=db.as_retriever())question = "how many and which benchmark>
如今,咱们曾经引见了arXiv API的在线检索以及RAG管道的数据输入和检索步骤。接上去,咱们将着手开发语义钻研引擎Web运行程序。
了解Literal AI可观察性特色
LiteralAI(是一个提供可观察性特色并能够启动评价和剖析的平台,用于构建消费级LLM运行程序。演绎起来看,LiteralAI提供的一些关键性能包括:
咱们将经常使用可观察性和揭示迭代性能来评价和调试咱们的语义钻研论文运行程序启动的诸多调用。
经常使用Literal AI揭示词治理
在创立对话式人工智能运行程序时,开发人员须要迭代多个版本的揭示,以取得发生最佳结果的揭示词。揭示工程在大少数LLM义务中起着至关关键的作用,由于庞大的修正就可以清楚扭转言语模型的照应。LiteralAI揭示词治理可以用来简化这个环节。一旦选用了模型提供程序,就可以输入初始揭示模板,减少任何其余信息,偏重复完善揭示以找到最适宜的揭示。在接上去的几个步骤中,咱们将经常使用这特性能为咱们的运行程序找到最佳揭示信息。
步骤1
首先,咱们须要经常使用阅读器关上LiteralAI治理控制台(来创立API密钥。为此,须要注册一个帐户,导航到名目(“projects”)页面,而后创立新名目。每个名目都有其惟一的API密钥。在设置(“Settings”)选项卡上,你将在API密钥局部找到你自己的API密钥。最后,将其减少到.env文件中:
LITERAL_API_KEY="your_literal_api_key"
步骤2
在左侧边栏中,单击“揭示(Prompts)”,而后导航到“新建揭示(New Prompt)”。这将关上一个新的揭示创立会话。
Literal AI平台的揭示面板
进入相应界面后,在左侧边栏的模板(Template)局部减少一条新的系统(System)信息。括号中的任何内容都将被减少到变量(Variables)中,并被视为揭示中的输入:
You are a helpful assistant. Use provided {{context}} to answer user{{question}}. Do not use prior knowledge.Answer:
接上去,在右侧栏中,你可以提供你的OpenAIAPI密钥。选用参数,如“模型(Model)”、“温度(Temperature)”和“最大成功长度(MaximumLength)”等,以便配合揭示词经常使用。
Literal AI揭示词治理界面
对揭示版本感到满意后,单击“保管(Save)”。系统将揭示你输入揭示的称号和可选说明。咱们可以将此版本减少到咱们的代码中。在名为search_engine.py的新脚本中,减少以下代码:
#search_engine.pyfrom literalai import LiteralClientfrom dotenv import load_dotenvload_dotenv()client = LiteralClient()# 上方的代码将会经常使用最新版本,你也可以选用经常使用特定版本prompt = client.api.get_prompt(name="test_prompt")prompt = prompt.to_langchain_chat_prompt_template()prompt.input_variables = ["context", "question"]
LiteralAI准许你保管揭示词对应的不同的运转结果,并具备版本治感性能。你还可以检查每个版本与上一个版本的不同之处。自动状况下,最新版本会被敞开。假设你想将某个版本更改为最新版本,你可以在治理面板上选用它,而后单击“更新(Promote)”。
Literal AI面板揭示词版本治理
减少上述代码后,咱们将能够在Literal AI 控制面板中检查特定揭示的生成结果(稍后将对此启动详细引见)。
了解Chainlit的Copilot组件性能
Chainlit(是一个开源Python包,旨在构建可用于消费级别的对话式人工智能运行程序。这个包能够为几个事情(聊天开局、用户信息、会话复原、会话中止等)提供装璜器支持。你可以检查链接处我撰写的文章,了解更片面的解释。
在本教程中,咱们将重点关注经常使用Chainlit为咱们的RAG运行程序构建软件Copilot。ChainlitCopilot能够在咱们的运行程序中提供高低文指点和智能化用户操作性能。
经常使用关系工具构建的钻研论文运行程序架构
开发Copilot运行程序
在你的运行程序网站中嵌入一个Copilot组件或者很有用。要素有几个:咱们将为咱们的语义钻研论文引擎构建一个便捷的Web界面,并在其中集成一个Copilot组件。这个Copilot组件将提供几项不同的性能,但以下是最突出的几特性能:
在接上去的几个步骤中,我将详细引见如何经常使用Chainlit为咱们的语义钻研引擎创立软件中的Copilot组件。
步骤1
第一步触及为咱们的chailit运行程序编写逻辑。咱们将在本名目中经常使用两个chailit装璜器函数:@cl.on_chat_start和@cl.on_message。咱们将把来自在线搜查和RAG管道的逻辑减少到这些性能中。须要记住的几件事:
咱们将封装从接纳钻研主题到创立数据库以及在@cl.on_chat_start装璜器函数中接纳文档的整个环节。
首先,须要在search_engine.py脚本中,导入一切必要的模块和库:
# search_engine.pyimport chainlit as clfrom langchain_community.document_loaders import ArxivLoaderfrom langchain_community.vectorstores import Chromafrom langchain_community.embeddings import HuggingFaceEmbeddingsfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.chains import RetrievalQAfrom langchain_openai import ChatOpenAIfrom dotenv import load_dotenvload_dotenv()
如今,让咱们减少@cl.on_chat_start装璜器的代码。咱们将使此函数以异步形式口头,以确保多个义务可以同时运转。
# search_engine.py# contd.@cl.on_chat_startasync def retrieve_docs():# QUERY PORTIONarxiv_query = None# 期待用户输入一个题目while arxiv_query is None:arxiv_query = await cl.AskUserMessage(content="Please enter a topic to begin!", timeout=15).send()query = arxiv_query['output']# ARXIV文档局部arxiv_docs = ArxivLoader(query=arxiv_query, load_max_docs=3).load()# 预备arXiv结果,用于显示arxiv_papers = [f"Published: {doc.metadata['Published']} \n "f"Title: {doc.metadata['Title']} \n "f"Authors: {doc.metadata['Authors']} \n "f"Summary: {doc.metadata['Summary'][:50]}... \n---\n"for doc in arxiv_docs]await cl.Message(content=f"{arxiv_papers}").send()await cl.Message(content=f"Downloading and chunking articles for {query} "f"This operation can take a while!").send()#数据库局部pdf_data = []for doc in arxiv_docs:text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)texts = text_splitter.create_documents([doc.page_content])pdf_data.append(texts)llm = ChatOpenAI(model='gpt-3.5-turbo',temperature=0)embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-l6-v2")db = Chroma.from_documents(pdf_data[0], embeddings)# 链局部chain = RetrievalQA.from_chain_type(llm=llm,chain_type="stuff",retriever=db.as_retriever(),chain_type_kwargs={"verbose": True,"prompt": prompt})# 让用户知道管道曾经预备到位await cl.Message(content=f"Database creation for `{query}` complete. "f"You can now ask questions!").send()cl.user_session.set("chain", chain)cl.user_session.set("db", db)
让咱们来看看这个函数中蕴含的代码:
揭示用户查问:咱们首先让用户发送一个钻研主题。在用户提交主题之前,此函数不会继续往下口头。
如今,让咱们定义@cl.on_message函数,并减少RAG管道的生成局部。用户应该能够从失掉的论文中提出疑问,运行程序应该提供关系答案。
@cl.on_messageasync def retrieve_docs(message: cl.Message):question = message.contentchain = cl.user_session.get("chain")db = cl.user_session.get("db")# 为每次调用创立一个新的回调解决程序实例cb = client.langchain_callback()variables = {"context": db.as_retriever(search_kwargs={"k": 1}),"query": question}database_results = await chain.acall(variables,callbacks=[cb])results = [f"Question: {question} "f"\n Answer: {database_results['result']}"]await cl.Message(results).send()
以下是上方函数中代码的各性能说明:
步骤2
第二步是将Copilot组件嵌入到咱们的运行程序网站中。咱们将创立一个便捷的网站启动演示。创立一个index.html文件,并向其中减少以下代码:
<!DOCTYPE html><html><head><title>Semantic Search Engine</title></head> <body><script src="http://localhost:8000/copilot/index.js"></script><script>window.mountChainlitWidget({chainlitServer: "http://localhost:8000",});</script> </body>
在上方的代码中,咱们经过指向托管咱们运行程序的Chainlit主机的位置,将Copilot组件嵌入了咱们的网站中。上述代码中,window.mountChainlitWidget能够在网站的右下角减少一个浮动按钮。点击它将关上Copilot性能。为了确保咱们的Copilot反常上班,咱们须要首先运转Chainlit运行程序。在名目目录中导航到适宜的位置并运转如下命令:
chainlit run search_engine.py -w
这段代码将在地址处运转运行程序。接上去,咱们须要托管咱们的运行程序网站。在阅读器中关上index.html脚本是不起作用的。雷同,咱们须要创立一个HTTPS测试主机。你可以用不同的方法来成功这一点,但一种便捷的方法是经常使用npx工具。npx蕴含在Node.js附带的npm(节点包治理器)中;因此,要取得npx,只要在系统上装置Node.js即可。在名目目录中导航到适宜的位置并运转如下命令:
npx http-server
这段代码将在地址处启动主机程序。导航到该地址,你将能够看到一个嵌入Copilot组件的便捷Web界面。
嵌入Copilot组件的Web界面
由于咱们将经常使用@cl.on_chat_start包装器函数来欢迎用户,因此咱们可以在Chainlit性能中将show_readme_as_default设置为false,以防止界面闪动。你可以在名目目录中的.Chainlit/config.toml中找到你的性能文件。
Copilot组件小窗预览
步骤3
要仅在Copilot组件外部口头代码,咱们可以减少以下内容:
@cl.on_messageasync def retrieve_docs(message: cl.Message):if cl.context.session.client_type == "copilot":# code to be executed only inside the Copilot
只要当你在Copilot组件中与运行程序交互时,才会口头此块中的任何代码。例如,假设在位于地址的Chainlit运行程序接口上运转查问,上方if块中的代码将不会口头,由于它希冀客户端类型为Copilot。这是一个有用的性能,可以用来辨别间接在Chainlit运行程序中口头的操作和经过Copilot界面启动的操作。经过这样做,你可以依据恳求的高低文定制运行程序的行为,从而取得更灵活、更照应的用户体验。
步骤4
Copilot组件可以调用你网站上的函数。这关于代表用户口头操作十分有用,例如关上模态、创立新文档等。咱们将进一步修正Chainlit装璜器函数,使其蕴含两个新的Copilot函数。为此,咱们须要在index.html文件中指定当Chainlit后端运行程序中的Copilot函数被激活时,前端应该如何照应。详细照应状况将依据运行程序的不同而作相应解决。关于咱们的语义钻研论文引擎程序来说,每当须要显示关系论文或数据库答案以响运行户查问时,咱们都会在前端生成弹出通知。
照应Copilot组件中的用户查问而弹出
咱们将在运行程序中创立两个Copilot函数:
首先,让咱们在search_engine.py脚本中设置后端逻辑,并修正@cl.on_chat_start函数:
@cl.on_chat_startasync def retrieve_docs():if cl.context.session.client_type == "copilot":# 代码同上#触发显示arXiv论文结果的弹出窗口fn_arxiv = cl.CopilotFunction(name="showArxivResults",args={"results": "\n".join(arxiv_papers)})await fn_arxiv.acall()# same code as before
在上方的代码中,定义并异步伐用了一个名为showArxivResults的Copilot函数。此函数作用是间接在Copilot界面中显示arXiv论文的格局化列表。函数签名十分便捷:咱们指定函数的称号及其将发送回的参数。咱们将在index.html文件中经常使用这些信息来创立一个弹出窗口。
接上去,咱们须要用第二个Copilot函数修正咱们的@cl.on_message函数,当用户依据失掉的论文提出疑问时,将口头该函数:
@cl.on_messageasync def retrieve_docs(message: cl.Message):if cl.context.session.client_type == "copilot":#代码同上# 激活相应于数据库查问结果的弹出小窗口fn_db = cl.CopilotFunction(name="showDatabaseResults",args={"results": "\n".join(results)})await fn_db.acall()#代码同前
在上方的代码中,咱们定义了要异步伐用的第二个Copilot函数showDatabaseResults。此函数的义务是在Copilot界面中显示从数据库检索到的结果。函数签名指定函数的称号及其将发送回的参数。
步骤5
接上去,咱们将进一步编辑咱们的index.html文件,这包括以下几个方面的更改:
首先,咱们须要为Copilot函数减少事情侦听器。在index.html文件的<script>标志中,减少以下代码:
<script> // 前面的代码 window.addEventListener("chainlit-call-fn", (e) => { const { name, args, callback } = e.detail; if (name === "showArxivResults") {document.getElementById("arxiv-result-text").innerHTML =args.results.replace(/\n/g, "<br>");document.getElementById("popup").style.display = "flex";if (callback) callback(); } else if (name === "showDatabaseResults") {document.getElementById("database-results-text").innerHTML =args.results.replace(/\n/g, "<br>");document.getElementById("popup").style.display = "flex";if (callback) callback(); } });</script>
以下是上述代码的解释:
接上去,咱们须要定义上方指定的弹出窗口。咱们可以经过将以下代码减少到index.html脚本的<body>标志中来成功这一点:
<div> <span>×</span> <div><h1>Arxiv Results</h1><p>Online results will be displayed here.</p> </div> <div><h1>Database Results</h1><p>Database results will be displayed here.</p> </div></div>
让咱们也为弹出窗口减少一些样式。编辑index.html文件的<head>标志:
<style> * {box-sizing: border-box; }body {font-family: sans-serif; }.close-btn {position: absolute;top: 10px;right: 20px;font-size: 24px;cursor: pointer; }.popup {display: none;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);background-color: white;padding: 20px;box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;width: 40%;flex-direction: column;gap: 50px; }p {color: #00000099; }</style>
启动运行程序
至此,咱们曾经将Copilot逻辑减少到Chainlit运行程序中,咱们可以运转运行程序和网站了。要使Copilot上班,咱们的运行程序必定首先运转起来。在名目目录中关上一个终端,而后运转以下命令启动Chainlit主机:
chainlit run search.py -h
在新的终端中,经常使用以下形式启动网站:
npx http-server
Literal AI的LLM可观察性
理论,咱们须要将可观察性特色集成到消费级运行程序中,例如咱们如今开发的集成Copilot组件的语义钻研引擎,以确保运行程序在消费环境中的牢靠性。咱们将在Literal AI框架中经常使用它。
关于任何Chainlit运行程序,Literal AI都会智能启动监控运行程序,并将数据发送到Literal人工智能平台。在search_engine.py脚本中创立揭示时,咱们曾经启动了Literal AI客户端。如今,每次用户与咱们的运行程序交互时,咱们都会在Literal AI面板中看到无关日志信息。
控制面板
导航到Literal AI控制界面(),从左正面板当选用名目,而后单击“可观察性(Observability)”。你将看到针对以下诸性能的日志输入信息。
线程(Threads)
线程示意助理和用户之间的会话。你应该能够看到用户在运行程序中启动的一切对话。
倒退特定的对话将提供关键的细节形容,例如每个步骤所破费的期间、用户信息的细节,以及详细说明一切步骤的基于树的视图。你还可以将对话减少到数据集中。
运转(Runs)
运转是代理或链所口头的一系列步骤。这一局部提供了每次口头链或代理时所采取的一切步骤的详细信息。经过这个选项卡,咱们可以取得每个用户查问的输入和输入。
你可以倒退一个Run,这将提供更多细节信息。雷同,你可以将此信息减少到数据集中。
生成(Generations)
Generations面板蕴含发送到LLM的输入信息及成功信息。这个面板提供的详细信息包括用于成功义务的模型称号,符号计数,以及恳求成功义务的用户(假设你性能了多个用户会话)。
Literal AI揭示评价
自从咱们减少了LangChain集成以来,咱们可以依据运行程序代码中创立和经常使用的每个揭示跟踪生成和线程。因此,每次为用户查问调用链时,都会在Literal AI面板中减少日志信息。这有助于检查特定生成的揭示,并比拟不同版本的性能。
Copilot集成了具备可观察性性能的语义钻研引擎运行程序
论断
在本教程中,我演示了如何经常使用LangChain框架、OpenAI大数据模型和ChromaDB向量数据库并结合RAG性能创立一个语义钻研论文引擎。此外,我还展现了如何为该引擎开发一个Web运行程序,集成了Literal AI的Copilot组件和可观测性特色。为了确保在事实环球的言语模型运行程序中取得最佳性能,往往都须要整合评价和可观察性性能。此外,Copilot关于不同的软件运行程序来说也是一个十分有用的性能;因此,本教程可以成为了解如何为运行程序设置Copilot性能的一个很好的终点。
最后,你可以在我的GitHub()上找到本教程中的一切代码。
译者引见
朱先忠,社区编辑,专家博客、讲师,潍坊一所高校计算机老师,自在编程界老兵一枚。