1. 项目简介
项目名称:大模型RAG实践操作---一个简单的知识文档助手Demo
报告日期:2024年8月17日
项目负责人:Bruce Xu
2. 项目概述
通过在本地部署JupyterLab环境,使用NVIDIA NIM服务能力,利用Mixtral 8x7B Instruct语言模型和embed-qa-4向量化模型,构建一个采用RAG(检索增强生成)技术实现的知识文档助手Demo。该交互助手能够执行文本生成任务,通过检索相关知识库提升回答的准确性和丰富性。
项目实施过程中,首先进行环境准备,包括硬件配置、软件安装及NVIDIA NIM API Key的获取。随后,利用Python及其相关库,实现数据加载、向量化、索引构建及RAG检索流程。通过langchain框架,结合NVIDIA的混合模型,实现了AI Agent的文档问答功能。最后,利用Gradio构建了一个简单的交互服务界面,方便用户与Agent进行交互。
项目成功展示了RAG技术在提高AI Agent知识问答能力方面的应用潜力,并展望了未来增加多模态能力的方向。
3. 技术方案与实施步骤
3.1 模型选择和技术介绍
文本生成模型:
Mixtral 8x7B Instruct是一种可以遵循指令、完成请求和生成创造性文本格式的语言模型。Mixtral 8x7B是一种高质量的稀疏混合专家模型(SMoE),具有开放权重。该模型已通过监督微调和直接偏好优化(DPO)进行了优化,以确保仔细遵循指令。在MT Bench上,它的得分达到了8.30,使其成为最好的开源模型,性能与GPT3.5相当。Mixtral在大多数基准测试中都优于Llama 2 70B,推理速度快6倍。它是具有许可证的最强开放权重模型,也是成本/性能权衡方面的最佳模型。特别是,在大多数标准基准测试中,它与GPT3.5相匹配或优于GPT3.5。
向量化模型:
embed-qa-4模型是一种针对文本问答检索进行优化的嵌入模型。嵌入模型是文本检索系统的关键组成部分,因为它将文本信息转换为密集的向量表示。它们通常是转换器编码器,处理输入文本的标记(例如问题、段落)以输出嵌入。embed-qa-4模型是NVIDIA NeMo检索器的一部分,它提供最先进的、商业化的模型和微服务,针对最低延迟和最高吞吐量进行了优化。它具有一个具有企业支持的生产就绪信息检索管道。构成此解决方案核心的模型已使用负责任地选择的可审计数据源进行了训练。有了多个预先训练的模型作为起点,开发人员还可以很容易地为他们的特定领域用例进行定制,例如信息技术、人力资源帮助助理和研发研究助理。
使用NIVIDA NIM可以部署大语言模型推理服务。
NVIDIA NIM适用于多个领域,文本、多模态、数字人等等,应用广泛。
3.2 数据的构建
大语言模型中的RAG(Retrieval-Augmented Generation,检索增强生成)技术相对于精调(Fine-tuning)技术,具有如下优势:包括通用性与灵活性、知识与数据需求的降低、成本与效率的提升以及可解释性与安全性的增强。这些优势使得RAG技术在多个领域具有广泛的应用前景,如问答系统、文档生成和自动摘要、智能助手和虚拟代理等。
本次项目直接用互联网公开的相关产品知识链接做为RAG Embedding数据源。
4. 实施步骤
4.1 环境准备
4.1.1 硬件配置
中等配置笔记本电脑一台(内存建议32GB或以上,集成显卡,Windows 10/11操作系统, Chrome或Edge浏览器),能上Internet,网络稳定。
4.1.2 软件准备
Anaconda3,Windows-x86_64
下载网址:Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
可选项:安装轻量级的MiniConda也行,下载网址:Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
4.1.3 NVIDIA NIM API Key获取
1.进入网址Try NVIDIA NIM APIs
点击右上角login
2.填写邮箱
3.如果是全新的邮箱需要创建账户
4.进入邮箱进行验证
5.验证成功全选提交
6 创建用户名
7.第6步完成会自动跳转到主页,可以右上角查看到信息
8 任意点选模型图标,进入模型交互界面后会在右侧看到代码API,然后找到Get API KEY鼠标点击选择生成API KEY并保存好:
KEY的形式类似于这样:
nvapi-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9.温馨提示,可以注意一下NVIDIA赠送的Credits,初始是1000。
4.1.4 本地实验环境安装配置
打开Anaconda Powershell Prompt,按照下面步骤来配置:
创建Python虚拟环境(最低3.8版本,可以用3.10或更新也没问题)
conda create --name ai_endpoint python=3.8 |
进入虚拟环境
conda activate ai_endpoint |
在ai_endpoint虚拟环境下安装包
# 安装nvidia_ai_endpoint工具 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple langchain-nvidia-ai-endpoints # 安装Jupyter Lab pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jupyterlab # 安装langchain_core pip install -i https://pypi.tuna.tsinghua.edu.cn/simple langchain_core # 安装langchain pip install -i https://pypi.tuna.tsinghua.edu.cn/simple langchain # 安装 matplotlib pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib # 安装numpy pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy # 安装faiss,由于Windows下pip没有faiss GPU版本,所以只用CPU版本即可 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple faiss-cpu==1.7.2 # # 安装OPENAI库 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple openai # 安装 langchain_community pip install -i https://pypi.tuna.tsinghua.edu.cn/simple langchain_community # 安装Gradio pip install -i https://pypi.tuna.tsinghua.edu.cn/simple gradio |
4.1.5 打开Jupyter Lab准备实操
在ai_endpoint虚拟环境下,输入以下命令:
jupyter-lab |
稍等片刻,会自动弹出电脑浏览器并打开Jupyter Lab页面:
4.2 代码实现
4.2.1 Step1 载入必要的库模块
from langchain_nvidia_ai_endpoints import ChatNVIDIA from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings from langchain.chains import ConversationalRetrievalChain, LLMChain from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT from langchain.chains.question_answering import load_qa_chain from langchain.memory import ConversationBufferMemory from langchain.vectorstores import FAISS from langchain.text_splitter import RecursiveCharacterTextSplitter |
远程登录访问NVIDIA NIM API
import getpass import os if not os.environ.get("NVIDIA_API_KEY", "").startswith("nvapi-"): nvapi_key = getpass.getpass("Enter your NVIDIA API key: ") assert nvapi_key.startswith("nvapi-"), f"{nvapi_key[:5]}... is not a valid key" os.environ["NVIDIA_API_KEY"] = nvapi_key |
Enter your NVIDIA API key: ········
根据提示输入NVIDIA NIM API KEY,回车,继续下一步。
4.2.2 Step2 定义html_document_loader网络文档数据加载器
定义html_document_loader网络文档数据加载器:进行文档解析返回文档内容。
import re from typing import List, Union import requests from bs4 import BeautifulSoup def html_document_loader(url: Union[str, bytes]) -> str: """ Loads the HTML content of a document from a given URL and return it's content. Args: url: The URL of the document. Returns: The content of the document. Raises: Exception: If there is an error while making the HTTP request. """ try: response = requests.get(url) html_content = response.text except Exception as e: print(f"Failed to load {url} due to exception {e}") return "" try: # 创建Beautiful Soup对象用来解析html soup = BeautifulSoup(html_content, "html.parser") # 删除脚本和样式标签 for script in soup(["script", "style"]): script.extract() # 从 HTML 文档中获取纯文本 text = soup.get_text() # 去除空格换行符 text = re.sub("\s+", " ", text).strip() return text except Exception as e: print(f"Exception {e} while loading document") return "" |
4.2.3 Step3 定义数据向量化工具
def create_embeddings(embedding_path: str = "./embed"): embedding_path = "./embed" print(f"Storing embeddings to {embedding_path}") # 包含Microsoft Phi-3技术文档的网页列表 urls = [ "https://learn.microsoft.com/zh-cn/azure/machine-learning/how-to-deploy-models-phi-3?view=azureml-api-2&tabs=phi-3-mini", "https://azure.microsoft.com/en-us/blog/category/ai-machine-learning/" ] # 使用html_document_loader对Microsoft Phi-3技术文档数据进行加载 documents = [] for url in urls: document = html_document_loader(url) documents.append(document) #进行chunk分词分块处理 text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=0, length_function=len, ) texts = text_splitter.create_documents(documents) index_docs(url, text_splitter, texts, embedding_path) print("Generated embedding successfully") |
4.2.4 Step4 定义index_docs函数作为构建向量储存和文档检索工具
def index_docs(url: Union[str, bytes], splitter, documents: List[str], dest_embed_dir) -> None: """ Split the document into chunks and create embeddings for the document Args: url: Source url for the document. splitter: Splitter used to split the document documents: list of documents whose embeddings needs to be created dest_embed_dir: destination directory for embeddings Returns: None """ # 通过NVIDIAEmbeddings工具类调用NIM中的"ai-embed-qa-4"向量化模型 embeddings = NVIDIAEmbeddings(model="ai-embed-qa-4")
for document in documents: texts = splitter.split_text(document.page_content) # 根据url清洗好的文档内容构建元数据 metadatas = [document.metadata] # 创建embeddings嵌入并通过FAISS进行向量存储 if os.path.exists(dest_embed_dir): update = FAISS.load_local(folder_path=dest_embed_dir, embeddings=embeddings, allow_dangerous_deserialization=True) update.add_texts(texts, metadatas=metadatas) update.save_local(folder_path=dest_embed_dir) else: docsearch = FAISS.from_texts(texts, embedding=embeddings, metadatas=metadatas) docsearch.save_local(folder_path=dest_embed_dir) |
4.2.5 Step5 使用定义好的相关函数和工具执行文档嵌入Embeddings的生成
create_embeddings() embedding_model = NVIDIAEmbeddings(model="ai-embed-qa-4") |
Storing embeddings to ./embed
Generated embedding successfully
# Embed documents embedding_path = "embed/" docsearch = FAISS.load_local(folder_path=embedding_path, embeddings=embedding_model, allow_dangerous_deserialization=True) |
4.2.6 Step6 langchain结合NIM实现LLM-RAG检索
langchain结合NIM实现LLM-RAG检索,并对比未使用RAG的llm输出与使用LLM-RAG的输出效果。
llm = ChatNVIDIA(model="ai-mixtral-8x7b-instruct") result = llm.invoke("什么是Phi-3?用中文回答") print(result.content) |
Phi-3,或称Phillips-3 , 是一种塑料垢合成物,常用于制造塑料垢玩具、浴室用品和其他日用生活用品。它是一种高级聚乙烯 plastic (PP),具有很好的耐用性、chemical resistance 和形状记忆能力。Phi-3 可能也有时被称为 PP-R,表示它是一种聚乙烯碳酸酯 copolymer。
Phi-3 的产品具有出色的 orsion 和 impact resistance,因此它常用于制造需要这些特性的应用,例如玩具、运动用品和 construciton materials。此外,Phi-3 还具有 Excellent chemical resistance,可以抵抗许多常见的 chemicals and solvents,使它成为使用在 harsh 环境中的理想选择。
请注意, producing Phi-3 需要一些特殊的 chemical processes,因此它可能比其他类型的 plastic 更加昂贵。然而, its unique properties make it a valuable material for many applications.
截图:
llm = ChatNVIDIA(model="ai-mixtral-8x7b-instruct") memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT) chat = ChatNVIDIA(model="ai-mixtral-8x7b-instruct", temperature=0.1, max_tokens=1000, top_p=1.0) doc_chain = load_qa_chain(chat , chain_type="stuff", prompt=QA_PROMPT) qa = ConversationalRetrievalChain( retriever=docsearch.as_retriever(), combine_docs_chain=doc_chain, memory=memory, question_generator=question_generator, ) |
query = "什么是Phi-3?用中文回答" result = qa({"question": query}) rag_result = result.get("answer") |
'Phi-3 是一种高性能、高效力的小型自然语言模型(SLM),它在各种语言、处理、编程和数学基础方面都优于同级和下级的模型。Phi-3 系列模型包括 Phi-3-mini 和 Phi-3-medium,其中 Phi-3-mini 是一种基于 Phi-2 数据集(包括聚合数据和选择性网站)构建的 3.8B 参数、高级、开源模型。Phi-3-mini 专注于高容量、高压缩比数据。Phi-3-mini 模型有两个变体:4K 和 128K,分别支持不同长度的上下文(以令牌为单位)。Phi-3-mini-4k-Instruct 和 Phi-3-mini-128k-Instruct 模型经历了多次增强过程,包括校准和直接优化选项,以确保准确地遵循指令并实现可靠的执行过程。'
截图:
4.2.7 Step7 用Gradio实现一个简单交互服务界面
import gradio as gr def techQA(query): result = qa({"question": query}) return result.get("answer") demo = gr.Interface( fn=techQA, inputs=["text"], outputs=["text"], title="Chat Agent Demo", ) demo.launch(debug=True, share=False, show_api=False, server_port=5000, server_name="0.0.0.0") |
5. 项目成果与展示
5.1 应用场景
企业产品智能问答、知识库问答助手等。
5.2 功能演示
目前用Gradio实现一个简单的交互服务UI
6. 问题与解决方案
6.1 问题1及解决思路
在环境准备阶段,由于无法直接访问Conda / PIP Package仓库,所以试图直接用“pip install Package_Name”安装package会报错,所以需要改源。
解决方法一(pip install命令行加清华源):
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Package_Name |
解决方法二(直接改Conda清华源一劳永逸):
Windows 用户无法直接创建名为 .condarc 的文件,需要先执行如下命令,生成该文件后再修改。 conda config --set show_channel_urls yes 在 .condarc 文件中添加清华源: channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2 custom_channels: conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch-lts: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud |
6.2 问题2及解决思路
在Step5执行文档嵌入Embeddings的生成这一步的时候偶尔会遇到报错,查看错误信息主要是:
Exception: [400] Bad Request Inference error RequestID: 84844cdc-a226-4342-8f47-57436cf30b58 |
主要原因是之前Step3定义数据向量化工具中提供的资料数据URL内容访问有问题,有的是需要Token,有的是内容加密等等,最好的办法是多尝试几次找个最合适的资料数据源URL。
解决方法:
def create_embeddings(embedding_path: str = "./embed"): embedding_path = "./embed" print(f"Storing embeddings to {embedding_path}") # 包含 Microsoft Phi-3技术文档的网页列表 urls = [ "https://learn.microsoft.com/zh-cn/azure/machine-learning/how-to-deploy-models-phi-3?view=azureml-api-2&tabs=phi-3-mini", "https://azure.microsoft.com/en-us/blog/category/ai-machine-learning/" ] …以下省略 |
7. 项目总结与展望
- 项目评估
基本达到预想的效果,也全流程操作了一遍langchain相关操作,对大语言模型RAG有了更深的理解。不足的是由于能力有限没有把UI做的更好,另外对于模型输出效果的优化还是有不足,未来需要更多的学习和实践。“路漫漫其修远兮,吾将上下而求索”。
- 未来方向
增加多模态能力,比如说增加语音识别ASR和输出TTS,还可以针对图片等多模态数据识别更多信息用于生成新内容的Prompt。
8. 附件与参考资料
1. NVIDIA AI Endpoint
https://python.langchain.com/v0.1/docs/integrations/chat/nvidia_ai_endpoints/
2. NVIDIA NIM
https://build.nvidia.com/explore/discover
3. NVIDIA mistralai / mixtral-8x7b-instruct-v0.1
NVIDIA NIM | mixtral-8x7b-instruct
4. 全网最详细Gradio教程系列——Gradio的安装与运行