代码:

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




 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐