入门向从零开始RAG+多模态大模型实战,丝滑简单

NVIDIA AI-AGENT夏季训练营

项目名称:AI-AGENT夏季训练营 — 金融风控垂域RAG + 多模态大模型项目

报告日期:2024年8月18日

项目负责人:Amishor

代码:https://github.com/amishior/LLM/tree/main

项目概述:

金融行业的风险控制对于企业和机构的稳定运行至关重要。传统的风控系统在面对复杂的数据和监管要求时常常显得力不从心。为了让更多人能够轻松上手并理解先进的风控技术,本项目从零开始,通过整合监管文件和统计数据,用户能够快速理解和应用风险管理策略。系统支持文字、图像和语音输入,操作简单,适合入门用户在金融风控领域的学习与应用。

项目亮点:

1.RAG技术的应用: 通过检索增强生成技术,对监管文件进行高效检索,并在此基础上生成智能响应,极大提高了对法规与政策的理解和执行能力。

2.多模态问答大模型: 除了传统的文本问答,系统具备处理文字、图像和语音输入的能力,通过对图像(如统计图表)进行分析,获取详细的数据分析结果。

3.实用性与创新性: 该项目通过融合前沿的 AI 技术和金融风险管理实践,为金融机构提供了一个创新且实用的风控工具,提高决策效率和准确性。

技术方案与实施步骤

模型选择:

项目依托于Nvidia的NIM平台,综合采用了嵌入模型(NV-Embed-QA)和大语言模型(meta/llama-3.1-405b-instruct,microsoft/phi-3-vision-128k-instruct)来构建RAG + 多模态大模型。选择llama-3.1-405b-instruct模型的理由在于其能够高效地从大规模文本库中检索相关信息,以提供更精准和上下文相关的答案。phi-3-vision-128k-instruct的选择是为了增强系统对多种输入形式的处理能力,支持文本、图像,可以帮助用户通过图像轻松查询复杂的统计数据。

数据的构建:

数据构建主要包括对监管文件的收集和向量化处理。采用NV-Embed-QA将文本数据转化为高维向量,使其能够在向量空间中进行高效检索。向量化处理的优势在于能够显著提升检索速度和准确性,并且在面对大规模数据时仍能保持良好的性能。

if not os.environ.get("NVIDIA_API_KEY", "").startswith("nvapi-"):
    os.environ["NVIDIA_API_KEY"] = nvapi_key
### initialize ai-embed-qa-4 model
embedder = NVIDIAEmbeddings(model="NV-Embed-QA")
# Here we read in the text data and prepare them into vectorstore
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']

# Here we create a vector store from the documents and save it to disk.
text_splitter = CharacterTextSplitter(chunk_size=500, 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):

项目整合了语音生成功能,使得用户可以将RAG检索到的信息以语音形式输出。同时,通过多模态模型的集成,系统能够处理用户上传的统计数据图像,并将其转化为可分析的数据信息。

实施步骤

1.环境搭建:

开发环境的搭建包括安装Python及相关库(包括LangChain、Torch等),配置必要的API密钥和数据存储路径。使用Anaconda进行环境隔离,确保不同项目之间的依赖库不产生冲突。

# 在CMD命令执行
conda creat --name ai_endpoint python=3.10
conda activate ai_endpoint
pip install jupyterlab 
pip install langchain-nvidia-ai-endpoints
pip install langchain_core 
pip install langchain matplotlib 
pip install numpy 
pip install faiss-cpu==1.7.2 
pip install langchain-community
pip install torch
pip install openai-whispe
pip install ffmpeg
pip install edge-tts
pip install openai
pip install pydub

设置NVIDIA的API密钥:

def get_nv_api_key():
    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
    return nvapi_key

2.测试与调优

测试部分设计了多种测试用例,涵盖了监管文本文件、文本转语音、统计数据图像输入的场景。通过调优模型、增加数据量等方式,提高了系统的响应速度和准确性。

RAG工作流,通过langchain调度大模型的文献检索:

retriever = store.as_retriever()
nvapi_key = nvapi_key
llm = ChatNVIDIA(model="meta/llama-3.1-405b-instruct", nvidia_api_key=nvapi_key, max_tokens=1024)
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()
)

语音生成模块,通过edge_tts生成语音回答:

if not os.path.exists("./audio"):
    os.mkdir("./audio")

Language = "Chinese" 
voice_name = "zh-CN-XiaoxiaoNeural"
speed = 1

if not os.path.exists("./audio"):
    os.mkdir("./audio")


#@title Edge TTS
def calculate_rate_string(input_value):
    rate = (input_value - 1) * 100
    sign = '+' if input_value >= 1 else '-'
    return f"{sign}{abs(int(rate))}"

def make_chunks(input_text, language):
    language="Chinese"
    if language == "Chinese":
      temp_list = input_text.strip().split(".")
      filtered_list = [element.strip() + '.' for element in temp_list[:-1] if element.strip() and element.strip() != "'" and element.strip() != '"']
      if temp_list[-1].strip():
          filtered_list.append(temp_list[-1].strip())
      return filtered_list

def tts_file_name(text):
    if text.endswith("."):
        text = text[:-1]
    text = text.lower()
    text = text.strip()
    text = text.replace(" ","_")
    truncated_text = text[:25] if len(text) > 25 else text if len(text) > 0 else "empty"
    random_string = uuid.uuid4().hex[:8].upper()
    file_name = f"./audio/{truncated_text}_{random_string}.mp3"
    return file_name

def merge_audio_files(audio_paths, output_path):
    # Initialize an empty AudioSegment
    merged_audio = AudioSegment.silent(duration=0)

    # Iterate through each audio file path
    for audio_path in audio_paths:
        # Load the audio file using Pydub
        audio = AudioSegment.from_file(audio_path)

        # Append the current audio file to the merged_audio
        merged_audio += audio

    # Export the merged audio to the specified output path
    merged_audio.export(output_path, format="mp3")

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("./audio/edge_tts_voice"):
      shutil.rmtree("./audio/edge_tts_voice")
    os.mkdir("./audio/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

def random_audio_name_generate():
  random_uuid = uuid.uuid4()
  audio_extension = ".mp3"
  random_audio_name = str(random_uuid)[:8] + audio_extension
  return random_audio_name

def talk(input_text):
  global translate_text_flag,Language,speed,voice_name
  if len(input_text)>=600:
    long_sentence = True
  else:
    long_sentence = False

  if long_sentence==True and translate_text_flag==True:
    chunks_list=make_chunks(input_text,Language)
  elif long_sentence==True and translate_text_flag==False:
    chunks_list=make_chunks(input_text,"Chinese")
  else:
    chunks_list=[input_text]
  save_path="./audio/"+random_audio_name_generate()
  edge_save_path=edge_free_tts(chunks_list,speed,voice_name,save_path)
  return edge_save_path

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"]

文转语音pipeline,RAG检索监管文件信息,回答生成语音:

def rag_model(question):
    # Load the vectorestore back.
    embedder = NVIDIAEmbeddings(model="NV-Embed-QA")
    store = FAISS.load_local("./zh_data/nv_embedding", embedder,allow_dangerous_deserialization=True)
    retriever = store.as_retriever()
    llm = ChatNVIDIA(model="meta/llama-3.1-405b-instruct", nvidia_api_key=nvapi_key, max_tokens=1024)
    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()
    )
    return chain.invoke(question)

def run_text_prompt(message, chat_history):
    bot_message = rag_model(message)
    edge_save_path=talk(bot_message)
    display(Audio(edge_save_path, autoplay=True))

    chat_history.append((message, bot_message))
    return edge_save_path, chat_history


def run_audio_prompt(audio, chat_history):
    if audio is None:
        return None, chat_history
    message_transcription = convert_to_text(audio)
    edge_save_path, chat_history = run_text_prompt(message_transcription, chat_history)
    return edge_save_path, chat_history

3.集成与部署

各模块的集成通过API的方式实现,最终在本地进行部署,通过调用gradio进行前端展示。部署过程中关注了系统的稳定性。

    multi_modal_chart_agent = gr.Interface(fn=chart_agent_gr,
                    inputs=[gr.Image(label="Upload image", type="filepath"), 'text'],
                    outputs=['image'],
                    title="Multi Modal chat agent",
                    description="Multi Modal chat agent",
                    allow_flagging="never")

项目成果与展示

应用场景展示

该项目在金融风控领域的具体应用场景包监管合规性检查、数据分析支持等。系统能够快速解答用户关于监管要求的疑问进行语音回答:

并通过图像识别技术,将上传的统计图表转化为可用的数据格式进行进一步分析:

问题与解决方案

问题分析

在项目实施过程中,主要遇到的问题包括数据的多样性处理难度、模型集成的复杂性以及多模态输入的响应速度。

解决措施

针对数据多样性的问题,采用了数据增强的策略。通过将RAG和多模态模型进行有效的集成,解决了模型集成的复杂性。

项目总结与展望

项目评估

项目整体表现良好,实现了从零开始搭建一个金融风控系统的目标。项目亮点在于其多模态处理能力和对专业文献的精准检索能力,但在处理更大规模的数据时,仍有进一步优化的空间。

未来方向

未来可以考虑扩展系统的应用场景,如将其应用于其他领域的风控或数据分析。同时,进一步优化多模态处理的性能和扩展系统的实时响应能力,也是未来的发展方向。

附件与参考资料

https://github.com/kinfey/Microsoft-Phi-3-NvidiaNIMWorkshop/tree/main

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值