项目名称:NVIDIA AI-AGENT夏季训练营——基于RAG的产品参数查询助手
项目负责人:Yuqi An
1.项目概述
该产品参数查询助手旨在帮助用户快速获取和理解产品的详细参数信息,特别是针对技术复杂或多功能产品。助手主要面对各个厂商经常投标的“牛马”售前,帮助他们在投标过程中,快速了解产品的关键特性和参数差异,迅速比对出对应产品是否符合标书要求。用户可以与小助手对话,提出与产品相关的问题,助手将基于LLM(大语言模型)和RAG(检索增强生成)技术,实时提供准确、详细的产品参数对比与差异分析。这不仅能够帮助用户快速完成产品选型,还能提升标书制作的难度与准确性,使用户能在投标过程中鸟枪换炮,完成“牛马”的自我救赎!
2.技术方案与实施步骤
2.1模型选择
选择mistral-nemo-12b-instruct模型,通过NVIDIA NIM API的方式调用;选择该模型的主要原因是:
(1)参数量小,能本地通过ollama等方式部署;
(2)模型能力强,且支持中文,上下文128K,能几乎满足所有产品参数查询的需求。
2.2数据的构建
使用embedding模型:nvidia/nv-embed-v1 对数据进行向量化,通过faiss将数据存入本地向量数据库,随时调用。
2.3功能整合
项目整合了RAG和语音功能,可以让生成结果以语音方式播报出来。
3.实施步骤
3.1环境搭建
可以参考2024 NVIDIA开发者社区夏令营环境配置指南(Win & Mac)_csdn 2024nvidia开发者-CSDN博客
安装好Miniconda,同时创建好自己的conda环境。
3.1.1创建conda,并进入
conda create --name ai-report-new python=3.9
conda activate ai-report-new
3.1.2安装各类环境依赖及工具
pip install langchain-nvidia-ai-endpoints
pip install jupyterlab
pip install langchain_core
pip install langchain
pip install numpy
pip install faiss-cpu==1.7.2
pip install openai
pip install pdfplumber
3.1.3进入jupter-lab
jupyter-lab
3.2代码实现
3.2.1通过NVIDIA NIM API调用mistral-nemo-12b-instruct模型,查询产品参数,作为对照
from openai import OpenAI
client = OpenAI(
base_url = "https://integrate.api.nvidia.com/v1",
api_key = "Your nvidia api"
)
completion = client.chat.completions.create(
model="nv-mistralai/mistral-nemo-12b-instruct",
messages=[{"role":"user","content":"H3C S9820-8C-G交换机的端口形态是什么?"}],
temperature=0.2,
top_p=0.7,
max_tokens=1024,
stream=True
)
for chunk in completion:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")
返回结果:
显然不对,官网参数为:
3.2.2 加载NVIDIA NIM API
import getpass
import os
if os.environ.get("NVIDIA_API_KEY", "").startswith("nvapi-"):
print("Valid NVIDIA_API_KEY already in environment. Delete to reset")
else:
nvapi_key = getpass.getpass("NVAPI Key (starts with nvapi-): ")
assert nvapi_key.startswith("nvapi-"), f"{nvapi_key[:5]}... is not a valid key"
os.environ["NVIDIA_API_KEY"] = nvapi_key
3.2.3解析提前下载好在./test-pdf/文件夹中的官网PDF彩页
import os
from tqdm import tqdm
from pathlib import Path
import pdfplumber
# 指定pdf文件夹中路径并列出所有文件
pdf_dir = "./test-pdf/"
data = []
sources = []
ps = os.listdir("./test-pdf/")
#遍历pdf文件的内容
for p in tqdm(ps, desc="Reading PDFs"):
if p.endswith('.pdf'): # 检查文件扩展名是否为 .pdf
path2file=os.path.join(pdf_dir, p)
# 使用 pdfplumber 打开 PDF 文件
with pdfplumber.open(path2file) as pdf:
for page in pdf.pages:
# 获取页面的文本内容
text=page.extract_text()
if text:
data.append(text)
sources.append(path2file)
此时可以看到,已经读取了文件夹中的PDF文件;
解析好的PDF文件的地址被存在sources中,内容被存在data中。
3.2.4对数据进行简单的整理
documents=[d for d in data if d != '\n']
3.2.5初始化embeding模型,并向量化我们的数据存储在本地数据库中
#初始化embedding模型
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
embedder = NVIDIAEmbeddings(model="nvidia/nv-embed-v1")
#向量化并存储
from operator import itemgetter
from langchain.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain.text_splitter import CharacterTextSplitter
from langchain_nvidia_ai_endpoints import ChatNVIDIA
import faiss
#只需要执行一次,后面可以重读已经保存的向量存储
text_splitter = CharacterTextSplitter(chunk_size=400, separator=" ")
docs = []
metadatas = []
for i, d in enumerate(documents):
splits = text_splitter.split_text(d)
#print(len(splits))
docs.extend(splits)
metadatas.extend([{"source": sources[i]}] * len(splits))
store = FAISS.from_texts(docs, embedder , metadatas=metadatas)
store.save_local('./test-pdf/nv_embedding')
# Load the vectorestore back.
store = FAISS.load_local("./test-pdf/nv_embedding", embedder,allow_dangerous_deserialization=True)
本次设置chunk_size为400,chunk_size的设置,取决于 embeding模型的最大tokens,如:最大tokens 512的话 chunk size 200-400之间尝试,最大tokes 1024的话,chunk size 在500-1000之间尝试。
3.2.6 调用LLM-RAG查询同样的问题,比对返回结果
from langchain_nvidia_ai_endpoints import ChatNVIDIA
llm = ChatNVIDIA(model="nv-mistralai/mistral-nemo-12b-instruct", nvidia_api_key=nvapi_key, max_tokens=1024)
retriever = store.as_retriever()
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Answer solely based on the following context:\n<Documents>\n{context}\n</Documents>",
),
("user", "{question}"),
]
)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
result=chain.invoke("H3C S9820-8C-G交换机的端口形态是什么?")
result2=result.replace('\n','')
print(result)
返回结果完全正确,RAG的确使LLM根据PDF文件中的内容,准确回答了我们的问题!
3.2.7进行语音生成模型环境依赖安装
#安装各类环境依赖、工具和模型
pip install openai-whisper==20231117
pip install ffmpeg==1.4
conda install ffmpeg -y
pip install edge-tts
pip install transformers
edge_command=f'edge-tts --text "{result2}" -v=zh-TW-HsiaoChenNeural --write-media demo.mp3'
使用的是微软的edge-tts 文本转语音,选择语音包是:zh-TW-HsiaoChenNeural
3.2.8生成声音到
import subprocess
subprocess.run(edge_command,shell=False)
from IPython.display import Audio
Audio("./mp3/demo.mp3", autoplay=True)
然后我们就可以听到温柔的台湾妹妹对回答的讲解喽!
4.项目成果与展示
4.1 LLM常规返回与使用了RAG返回的内容和官网正确内容的对比
4.1.1官网正确内容
H3C S9800-G系列数据中心交换机-新华三集团-H3C
4.1.2LLM常规返回内容
可以说是一本正经的胡说八道。。。
4.1.2使用了RAG之后返回的内容
完全正确!
4.2台湾妹子语音朗读
因为音频无法上传,已上传到百度网盘,链接:
通过网盘分享的文件:demo.mp3
链接: https://pan.baidu.com/s/1P-WVTs6OsQUbTnnEA66Plg?pwd=hthi 提取码: hthi
5.问题与解决方案
5.1运行pdfplumber报错
通过AI助手查询分析发现,先前创建的python3.8的环境,不支持pdfplumber工具的部分库,需要python3.9的环境;在原先的conda环境上升级python,并升级所有组件后都无法解决;最终,通过重新创建conda ai-report-new解决。
5.2进行语音合成报错
检查代码后,发现没有安装相关环境依赖导致(环境依赖安装代码详见3.2.7章节),安装好环境依赖,并重启conda,问题解决。
6.项目总结与展望
1.本次项目还是稍有不足,没有形成一个可视化的界面,后续考虑用grdio这样的工具,来做成一个可视化的界面,使交互更好。
2.作为一个之前几乎没有代码基础的小白,通过这几天和各位老师及群里面其他大咖同学的学习,真的是感受到了LLM、RAG及语音生成模型的魅力;感叹这波基于Tansformer架构大模型的爆发真的是在不断的改变我们的生活和工作方式;这样一个简单RAG小助手,就解决了我们在投标过程中的诸多工作量,最后用一句话来勉励自己,也与所有对AI感兴趣的同学共勉:
AI不会替代人,但擅长使用AI的人将会替代不会使用AI的人!
7.附件与参考资料
2024 NVIDIA开发者社区夏令营环境配置指南(Win & Mac)_csdn 2024nvidia开发者-CSDN博客使用AI-Agent的RAG智能对话机器人帮二刺螈角色打赢复活赛-CSDN博客重生之RAG让我变成超级神医-CSDN博客