几乎所有情况下,检索增强生成(RAG)的开发都涉及创建一个或多个应用程序,简称为“应用”。在最初编写RAG应用程序时,通常会在代码中创建一个变量,表示一个提示(prompt)或其他类型的输入,这些输入会代表RAG管道要处理的内容。但用户未来如何使用你正在构建的应用程序呢?你如何使用这些代码测试这些用户?你需要一个界面!
在本章中,我们将提供一个实用的指南,教你如何使用Gradio作为用户界面(UI)来使你的应用程序与RAG进行交互。内容包括设置Gradio环境、集成RAG模型、创建一个用户友好的界面,让用户像使用典型的Web应用程序一样使用你的RAG系统,以及将其托管在一个永久且免费的在线空间中。你将学习如何快速原型化和部署RAG驱动的应用程序,使最终用户能够与AI模型进行实时交互。
有关于如何构建界面的一整本书籍,而且有很多地方可以提供界面,比如Web浏览器或移动应用。但幸运的是,使用Gradio,我们可以为你提供一个简单的方式来为你的RAG应用程序提供一个界面,而不需要进行广泛的Web或移动开发。这使得分享和展示模型变得更加容易。
本章将特别涵盖以下主题:
- 为什么选择Gradio?
- 使用Gradio的好处
- 使用Gradio的局限性
- 代码实验 – 添加Gradio界面
首先,让我们讨论为什么Gradio是你RAG开发工作的重要组成部分。
技术要求
本章的代码可以在此找到:GitHub链接
为什么选择Gradio?
到目前为止,我们关注的主题通常属于数据科学领域。机器学习、自然语言处理(NLP)、生成式人工智能(Generative AI)、大语言模型(LLMs)和RAG等技术都需要深厚的专业知识,往往需要大量时间投入,因此我们没有足够的时间在其他技术领域,例如Web技术和构建Web前端方面积累经验。Web开发本身就是一个高度技术化的领域,需要丰富的经验和专业知识才能成功实施。
然而,在RAG中,拥有一个UI(用户界面)是非常有帮助的,尤其是当你想测试或向潜在用户展示时。如果我们没有时间去学习Web开发,我们该如何提供界面呢?
这正是许多数据科学家,包括我自己,选择使用Gradio的原因。它允许你非常快速地(相对于构建Web前端)在可共享的格式中启动一个UI,甚至包括一些基本的认证功能。这并不会让Web开发人员失业,因为如果你想将RAG应用程序转变为一个完整的、健壮的网站,Gradio并不是一个理想的选择。但它可以让你在有限的时间内,以非常适合RAG应用的UI启动一个应用,这对很多没有时间学习Web开发的开发者来说非常有用!
我们的目标是让你将更多的精力集中在RAG开发上,而不是Web开发,因此我们将简化关于Gradio的讨论,只关注帮助你将RAG应用程序部署到Web并能共享的组件。然而,随着你的RAG开发继续进行,我们鼓励你进一步探索Gradio的功能,看看它是否能为你的具体工作提供更多帮助!
接下来,让我们讨论一下在构建RAG应用程序时,Gradio的主要优点。
使用Gradio的好处
除了对非Web开发者来说非常易用之外,Gradio还有许多优点。Gradio的核心库是开源的,这意味着开发者可以自由使用、修改和贡献项目代码。Gradio与流行的机器学习框架(如TensorFlow、PyTorch和Keras)集成良好。除了开源库外,Gradio还提供了一个托管平台,开发者可以在上面部署自己的模型界面并管理访问权限。Gradio还包括一些功能,方便团队间的协作,比如共享界面和收集反馈。
Gradio的另一个令人兴奋的功能是它与Hugging Face的集成。Hugging Face由前OpenAI员工创建,拥有许多支持生成式AI社区的资源,如模型共享和数据集托管。其中一个资源是能够使用Hugging Face Spaces为你的Gradio演示创建一个永久的互联网链接。Hugging Face Spaces为你永久托管机器学习模型提供免费的基础设施!你可以访问Hugging Face官网了解更多有关Spaces的信息。
但是,使用Gradio在构建RAG应用时也存在一些局限性,了解这些局限性非常重要。
使用Gradio的局限性
使用Gradio时,最重要的一点是它不适合用于构建一个将与成百上千甚至数百万用户交互的生产级应用。在这种情况下,你可能需要雇佣一个具有大规模生产级应用前端开发经验的开发人员。但对于我们所称的概念验证(POC)类型的应用,或者构建一个允许你测试应用并提供基本交互性和功能的应用,Gradio做得非常出色。
当你使用Gradio构建RAG应用时,可能会遇到的另一个限制是它在构建内容上的灵活性不足。对于许多RAG应用,特别是在构建POC时,这并不成问题。但如果你或你的用户开始要求更多复杂的UI功能,Gradio的功能就会远不如一个完整的Web开发框架强大。不仅如此,理解这一点对你来说是有益的,而且与用户设定预期也是很重要的,帮助他们理解Gradio仅适用于简单的演示应用。
接下来,让我们直接进入代码,演示Gradio如何为你的RAG应用提供应有的界面。
代码实验 – 添加Gradio界面
这段代码与我们在第5章结束时的代码相接,只是最后一部分代码是关于提示探测攻击(prompt probe attack)。正如我们在所有代码实验开始时所做的,我们将首先安装一个新的包——Gradio!同时,我们将卸载uvloop包,因为它与其他包存在冲突:
%pip install gradio
%pip uninstall uvloop -y
这将安装Gradio包并移除冲突的uvloop包。
接下来,我们将把多个包添加到导入列表中:
import asyncio
import nest_asyncio
asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
nest_asyncio.apply()
import gradio as gr
这些代码导入了asyncio和nest_asyncio库,并设置了事件循环策略。asyncio是一个用于编写并发代码的库,基于协程和事件循环,nest_asyncio是一个允许在Jupyter notebook中嵌套事件循环的库。asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())这一行设置事件循环策略为默认策略,nest_asyncio.apply()应用必要的补丁来启用嵌套事件循环。最后,我们导入Gradio包,并为方便起见将其别名为gr。
添加导入后,我们只需要在现有代码的末尾添加以下代码来设置Gradio界面:
def process_question(question):
result = rag_chain_with_source.invoke(question)
relevance_score = result['answer']['relevance_score']
final_answer = result['answer']['final_answer']
sources = [doc.metadata['source'] for doc in result['context']]
source_list = ", ".join(sources)
return relevance_score, final_answer, source_list
process_question函数是在你点击“提交”按钮时调用的函数。你将在gr.Interface代码中定义这个调用,但实际执行的就是这个函数。process_question函数接受你作为用户提交的问题作为输入,并使用RAG管道处理它。它调用rag_chain_with_source对象并传入问题,获取相关性得分、最终答案和源文档列表。然后,函数将源文档连接成一个以逗号分隔的字符串,并返回相关性得分、最终答案和源文档列表。
接下来,我们将设置Gradio界面的实例:
demo = gr.Interface(
fn=process_question,
inputs=gr.Textbox(label="Enter your question",
value="What are the Advantages of using RAG?"),
outputs=[
gr.Textbox(label="Relevance Score"),
gr.Textbox(label="Final Answer"),
gr.Textbox(label="Sources")
],
title="RAG Question Answering",
description="Enter a question about RAG and get an answer, a relevancy score, and sources."
)
demo = gr.Interface(...)这一行是Gradio“魔法”发生的地方。它使用gr.Interface函数创建了一个Gradio界面。fn参数指定了在用户与界面交互时调用的函数,这里我们提到的就是调用process_question并启动RAG管道。inputs参数定义了界面的输入组件,这里是一个gr.Textbox组件用于输入问题。outputs参数定义了界面的输出组件,这里有三个gr.Textbox组件,用于显示相关性得分、最终答案和源文档。title和description参数设置了界面的标题和描述。
接下来只需要启动界面:
demo.launch(share=True, debug=True)
demo.launch(share=True, debug=True)这一行启动了Gradio界面。share=True参数启用了Gradio的共享功能,它会生成一个公开可访问的URL,你可以将该URL分享给他人,以便他们访问你的界面。Gradio通过一个隧道服务提供此功能,允许任何拥有该URL的人在不需要本地运行代码的情况下与界面进行交互。debug=True参数启用调试模式,提供额外的信息和调试工具。在调试模式下,如果process_question函数在执行过程中发生错误,Gradio会在浏览器控制台显示详细的错误信息。
我认为demo.launch(share=True, debug=True)这一行代码在所有代码中是特别的,因为它做了你之前未见过的事情;它调用Gradio启动本地Web服务器来托管由gr.Interface(...)定义的界面。当你运行这段代码时,你会发现它会一直运行,直到你停止它。你还会注意到,在停止它之前,不能运行其他代码单元。
还有一个可选参数是auth参数,你可以像下面这样将它添加到demo.launch函数中:
demo.launch(share=True, debug=True, auth=("admin", "pass1234"))
这将添加一个简单的认证层,万一你需要公开分享你的应用时。它会生成一个额外的界面,要求输入用户名(admin)和密码(pass1234)。你可以根据需要更改admin/pass1234,但一定要更改!并且只与需要访问你RAG应用的用户共享这些凭证。请记住,这不是非常安全,但至少能提供基本的访问控制。
现在,你已经有了一个活跃的Web服务器,它接受输入、处理数据,并根据你为Gradio界面编写的代码返回新的界面元素。这曾经需要大量的Web开发专业知识,但现在你可以在几分钟内完成!这让你可以专注于你真正想要做的事:编写你的RAG应用代码!
一旦你运行了包含Gradio代码的单元,界面将变得交互式,允许用户在输入框中输入问题。正如之前描述的,当用户提交一个问题时,process_question函数会被调用,并将用户的问题作为输入。该函数调用RAG管道rag_chain_with_source,传入问题,并从结果中获取相关性得分、最终答案和源文档。然后,它将相关性得分、最终答案和源文档列表返回给Gradio,Gradio会更新输出框,显示这些值。
界面将保持活跃和响应,直到单元执行完成或调用gr.close_all()关闭所有活动的Gradio界面。
最终,当你运行这段Gradio代码时,你将得到一个类似于图6.1的界面。你可以在你的笔记本中直接显示Gradio界面,也可以通过运行该单元生成的链接在完整的网页上显示界面。
我们已预填了这个问题:What are the advantages of using RAG? 。不过,你可以更改这个问题,提问其他内容。正如我们在上一章中讨论的,如果问题与数据库中的内容不相关,LLM应该回应“我不知道”。我们鼓励你尝试相关和不相关的问题!看看你能否找到一个正常工作的情况,帮助你提升调试技巧。
在你的笔记本界面上方,你可能会看到类似下面的文本:
Colab notebook detected. This cell will run indefinitely so that you can see errors and logs. To turn off, set debug=False in launch().
Running on public URL: https://pl09q9e4g8989braee.gradio.live
This share link expires in 72 hours.
点击该链接后,你应该可以在一个新的浏览器窗口中看到界面!它看起来就像图6.1那样,但会占据整个浏览器窗口。
点击提交按钮会启动你代码中的RAG过程,将你输入的问题传递给LangChain链(通过 result = rag_chain_with_source.invoke(question)),并在等待几秒钟后返回一个响应。最终的界面应该看起来类似于图6.2:
让我们来聊聊当LLM返回响应时,界面中发生的几件事。首先是相关性得分,这是我们在第5章中添加的,用于通过LLM确定问题的相关性,作为一种安全措施来防止提示注入。在你展示给用户的应用程序中,这个得分可能不会显示,但在这里作为附加信息与LLM响应一起显示,目的是提供更多的背景信息。
说到LLM的响应,来自ChatGPT 4的最终答案已经按标记格式进行了排版。Gradio会自动使用这些标记中的换行符,并据此显示文本,在这种情况下,文本会分成几个段落。
最后,来源是一个包含四个来源的列表,表示检索器返回了四个来源。这来自我们在第3章中设置的代码,当时我们添加了将检索结果的来源信息带到元数据中的功能,以便可以在UI中显示。现在在第6章中,随着我们拥有了UI界面,终于可以看到这一努力的成果!你可能注意到所有四个来源都是相同的。这是因为这是一个小示例,只拉取了一个数据源。
在大多数应用中,你可能会引入更多的数据来源,那个列表中会显示更多的来源。如果你在代码中添加了更多与所问问题相关的数据来源,它们应该会出现在这个来源列表中。
总结
在本章中,我们通过实用的指南介绍了如何使用RAG和Gradio作为UI创建交互式应用程序。我们涵盖了Gradio环境的设置、RAG模型的集成,以及创建一个用户友好的界面,允许用户像典型的Web应用一样与RAG系统进行交互。开发人员可以快速原型化并部署基于RAG的应用程序,使最终用户能够实时与RAG管道互动。
我们还讨论了使用Gradio的好处,如其开源特性、与流行机器学习框架的集成以及协作功能,此外Gradio还与Hugging Face集成,为生成性AI社区提供资源,包括使用Hugging Face Spaces免费永久托管Gradio演示的能力。
通过代码实验,我们学习了如何为RAG应用程序添加Gradio界面。我们使用gr.Interface创建了Gradio界面,指定了输入和输出组件、标题和描述。我们通过demo.launch()启动了界面,这会启动一个本地Web服务器来托管界面。这包括创建一个process_question函数,该函数调用RAG管道处理用户问题,并从结果中获取相关性得分、最终答案和来源。这个过程反映在Gradio界面上,允许用户输入问题,并接收RAG系统返回的相关性得分、最终答案和来源。
本章还讨论了如何将来源信息从检索器带到UI,并在界面中显示,展示了我们在前几章中添加此功能的努力。
然而,这仅仅是Gradio的入门介绍。我们鼓励你访问Gradio网站(www.gradio.app/),并通过他们的快速入门指南和文档来了解该平台提供的其他重要功能。
在下一章中,我们将探讨向量和向量存储在增强RAG系统中的关键作用。