代码:
https://github.com/aakaking/LLM-Learning/tree/master/chatbot
项目概述:
多模态大模型RAG入门项目,适合初学者和小白,快速搭建垂直领域多模态大模型,通过添加私域数据解答针对性问题,例如添加企业管理制度,即辅助企业内部的hr或者行政人员回答咨询,添加学校管理制度,可辅助学校的助教或辅导员回答咨询,还有各类客服。相比于已经有的智能客服,大模型的优势在于超强的理解能力,回答问题更加专业准确智能。本项目示例为保险客服机器人,所用数据为网上下载的一份保险条款,可以通过替换数据来简单实现不同应用场景的机器人。
技术方案:
模型选择
为快速搭建项目,选择调用NIM的api,提供多种模型,根据需求选择。
RAG
大模型不胡言乱语的关键,这里我们可以根据业务需求添加一些特有数据。
数据的构建
数据是非标注的文本,选择一个embedding模型对数据进行向量化,使用 faiss将embedding数据保存到磁盘。数据向量化只需要处理一次,存入向量数据库,之后使用的时候读取即可。
功能整合
为了更好的互动,这里加入语音功能,tts和asr通过whisper实现。
实施步骤:
环境搭建
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
代码实现
文档向量化
初始化embedding模型
embedder = NVIDIAEmbeddings(model="NV-Embed-QA")
数据准备
ps = os.listdir("./zh_data/")
data = []
sources = []
for p in ps:
content = ""
if p.endswith('.txt'):
path2file="./zh_data/"+p
with open(path2file,encoding="utf-8") as f:
lines=f.readlines()
for line in lines:
content += line
if len(content)>=1:
data.append(content)
sources.append(path2file)
documents=[d for d in data if d != '\n']
存储向量数据
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('./zh_data/nv_embedding')
RAG
加载向量数据
embedder = NVIDIAEmbeddings(model="NV-Embed-QA")
store = FAISS.load_local("./zh_data/nv_embedding", embedder,allow_dangerous_deserialization=True)
RAG检索
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()
)
语音模态
ASR
def convert_to_text(audio_path):
import whisper
select_model ="base" # ['tiny', 'base']
whisper_model = whisper.load_model(select_model)
result = whisper_model.transcribe(audio_path,word_timestamps=True,fp16=False,language='Chinese')
with open('scan.txt', 'w') as file:
file.write(str(result))
return result["text"]
TTS
def edge_free_tts(chunks_list,speed,voice_name,save_path):
# print(chunks_list)
if len(chunks_list)>1:
chunk_audio_list=[]
if os.path.exists("./content/edge_tts_voice"):
shutil.rmtree("./content/edge_tts_voice")
os.mkdir("./content/edge_tts_voice")
k=1
for i in chunks_list:
print(i)
edge_command=f'edge-tts --rate={calculate_rate_string(speed)}% --voice {voice_name} --text "{i}" --write-media ./content/edge_tts_voice/{k}.mp3'
print(edge_command)
var1=os.system(edge_command)
if var1==0:
pass
else:
print(f"Failed: {i}")
chunk_audio_list.append(f"./content/edge_tts_voice/{k}.mp3")
k+=1
# print(chunk_audio_list)
merge_audio_files(chunk_audio_list, save_path)
else:
edge_command=f'edge-tts --rate={calculate_rate_string(speed)}% --voice {voice_name} --text "{chunks_list[0]}" --write-media {save_path}'
print(edge_command)
var2=os.system(edge_command)
if var2==0:
pass
else:
print(f"Failed: {chunks_list[0]}")
return save_path
测试与调优
尝试了phi-3-small-128k-instruct、llama3-70b-instruct,其中llama3-70b完全可以从未经处理的文档中提取需要信息作出准确回答,phi-3-small表现不是很好,但是可以通过优化数据得到一定提升,在对资源要求高的情况下可以考虑phi-3-small。
集成与部署
使用gradio实现了ui,直接运行部署。
结果展示:
用场景展示: 保险语音客服
功能演示: 可以通话语音互动,得到准确回复。(gradio刚接触,生成了回复的语音,但还没在页面上加上播放功能)
总结与展望:
项目评估:这是一个面向新手的入门级demo,旨在快速搭建多模态大模型应用,熟悉流程,了解工作,是一个简单但完成的项目,具体在业务中使用还有诸多需要优化的点,需要深入了解。
未来方向:大模型的小型化。
参考资料
https://github.com/kinfey/Microsoft-Phi-3-NvidiaNIMWorkshop/tree/main