当前位置:   article > 正文

【InternLM 实战营笔记】基于 InternLM 和 LangChain 搭建MindSpore知识库

【InternLM 实战营笔记】基于 InternLM 和 LangChain 搭建MindSpore知识库

InternLM 模型部署

准备环境

拷贝环境

/root/share/install_conda_env_internlm_base.sh InternLM

激活环境

conda activate InternLM

安装依赖

  1. # 升级pip
  2. python -m pip install --upgrade pip
  3. pip install modelscope==1.9.5
  4. pip install transformers==4.35.2
  5. pip install streamlit==1.24.0
  6. pip install sentencepiece==0.1.99
  7. pip install accelerate==0.24.1

模型下载

  1. mkdir -p /root/data/model/Shanghai_AI_Laboratory
  2. cp -r /root/share/temp/model_repos/internlm-chat-7b /root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b

LangChain 相关环境配置

  1. pip install langchain==0.0.292
  2. pip install gradio==4.4.0
  3. pip install chromadb==0.4.15
  4. pip install sentence-transformers==2.2.2
  5. pip install unstructured==0.10.30
  6. pip install markdown==3.3.7

同时,我们需要使用到开源词向量模型 Sentence Transformer:(我们也可以选用别的开源词向量模型来进行 Embedding,目前选用这个模型是相对轻量、支持中文且效果较好的,同学们可以自由尝试别的开源词向量模型)

首先需要使用 huggingface 官方提供的 huggingface-cli 命令行工具。安装依赖:

pip install -U huggingface_hub

然后在和 /root/data 目录下新建python文件 download_hf.py,填入以下代码: resume-download:断点续下 local-dir:本地存储路径。(linux环境下需要填写绝对路径)

  1. import os
  2. # 下载模型
  3. os.system('huggingface-cli download --resume-download --local-dir-use-symlinks False sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/data/model/sentence-transformer')

如果下载速度慢可以使用镜像下载将 download_hf.py 中的代码修改为以下代码:

  1. import os
  2. # 设置环境变量
  3. os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
  4. # 下载模型
  5. os.system('huggingface-cli download --resume-download --local-dir-use-symlinks False sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/data/model/sentence-transformer')

执行脚本

python download_hf.py

下载 NLTK 相关资源

下载

  1. cd /root
  2. git clone https://gitee.com/yzy0612/nltk_data.git --branch gh-pages
  3. cd nltk_data
  4. mv packages/* ./
  5. cd tokenizers
  6. unzip punkt.zip
  7. cd ../taggers
  8. unzip averaged_perceptron_tagger.zip

知识库搭建

数据收集

选择mindspre docs代码仓作为语料库来源 地址: https://gitee.com/mindspore/docs

  1. # 进入到数据库盘
  2. cd /root/data
  3. # clone 上述开源仓库
  4. git clone https://gitee.com/mindspore/docs.git

知识库搭建的脚本

  1. # 首先导入所需第三方库
  2. from langchain.document_loaders import UnstructuredFileLoader
  3. from langchain.document_loaders import UnstructuredMarkdownLoader
  4. from langchain.text_splitter import RecursiveCharacterTextSplitter
  5. from langchain.vectorstores import Chroma
  6. from langchain.embeddings.huggingface import HuggingFaceEmbeddings
  7. from tqdm import tqdm
  8. import os
  9. # 获取文件路径函数
  10. def get_files(dir_path):
  11. # args:dir_path,目标文件夹路径
  12. file_list = []
  13. for filepath, dirnames, filenames in os.walk(dir_path):
  14. # os.walk 函数将递归遍历指定文件夹
  15. for filename in filenames:
  16. # 通过后缀名判断文件类型是否满足要求
  17. if filename.endswith("_CN.md"):
  18. # 如果满足要求,将其绝对路径加入到结果列表
  19. file_list.append(os.path.join(filepath, filename))
  20. elif filename.endswith("_CN.txt"):
  21. file_list.append(os.path.join(filepath, filename))
  22. return file_list
  23. # 加载文件函数
  24. def get_text(dir_path):
  25. # args:dir_path,目标文件夹路径
  26. # 首先调用上文定义的函数得到目标文件路径列表
  27. file_lst = get_files(dir_path)
  28. # docs 存放加载之后的纯文本对象
  29. docs = []
  30. # 遍历所有目标文件
  31. for one_file in tqdm(file_lst):
  32. file_type = one_file.split('.')[-1]
  33. if file_type == 'md':
  34. loader = UnstructuredMarkdownLoader(one_file)
  35. elif file_type == 'txt':
  36. loader = UnstructuredFileLoader(one_file)
  37. else:
  38. # 如果是不符合条件的文件,直接跳过
  39. continue
  40. docs.extend(loader.load())
  41. return docs
  42. # 目标文件夹
  43. tar_dir = [
  44. "/root/data/docs"
  45. ]
  46. # 加载目标文件
  47. docs = []
  48. for dir_path in tar_dir:
  49. docs.extend(get_text(dir_path))
  50. # 对文本进行分块
  51. text_splitter = RecursiveCharacterTextSplitter(
  52. chunk_size=500, chunk_overlap=150)
  53. split_docs = text_splitter.split_documents(docs)
  54. # 加载开源词向量模型
  55. embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
  56. # 构建向量数据库
  57. # 定义持久化路径
  58. persist_directory = 'data_base/vector_db/chroma'
  59. # 加载数据库
  60. vectordb = Chroma.from_documents(
  61. documents=split_docs,
  62. embedding=embeddings,
  63. persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上
  64. )
  65. # 将加载的向量数据库持久化到磁盘上
  66. vectordb.persist()

可以在 /root/data 下新建一个 demo目录,将该脚本和后续脚本均放在该目录下运行。运行上述脚本,即可在本地构建已持久化的向量数据库,后续直接导入该数据库即可,无需重复构建。

InternLM 接入 LangChain

脚本

  1. from langchain.llms.base import LLM
  2. from typing import Any, List, Optional
  3. from langchain.callbacks.manager import CallbackManagerForLLMRun
  4. from transformers import AutoTokenizer, AutoModelForCausalLM
  5. import torch
  6. class InternLM_LLM(LLM):
  7. # 基于本地 InternLM 自定义 LLM 类
  8. tokenizer : AutoTokenizer = None
  9. model: AutoModelForCausalLM = None
  10. def __init__(self, model_path :str):
  11. # model_path: InternLM 模型路径
  12. # 从本地初始化模型
  13. super().__init__()
  14. print("正在从本地加载模型...")
  15. self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
  16. self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(torch.bfloat16).cuda()
  17. self.model = self.model.eval()
  18. print("完成本地模型的加载")
  19. def _call(self, prompt : str, stop: Optional[List[str]] = None,
  20. run_manager: Optional[CallbackManagerForLLMRun] = None,
  21. **kwargs: Any):
  22. # 重写调用函数
  23. system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语).
  24. - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless.
  25. - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文.
  26. """
  27. messages = [(system_prompt, '')]
  28. response, history = self.model.chat(self.tokenizer, prompt , history=messages)
  29. return response
  30. @property
  31. def _llm_type(self) -> str:
  32. return "InternLM"

将上述代码封装为 LLM.py,后续将直接从该文件中引入自定义的 LLM 类。

构建检索问答链

整体脚本

  1. from langchain.vectorstores import Chroma
  2. from langchain.embeddings.huggingface import HuggingFaceEmbeddings
  3. import os
  4. # 定义 Embeddings
  5. embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
  6. # 向量数据库持久化路径
  7. persist_directory = 'data_base/vector_db/chroma'
  8. # 加载数据库
  9. vectordb = Chroma(
  10. persist_directory=persist_directory,
  11. embedding_function=embeddings
  12. )
  13. from LLM import InternLM_LLM
  14. llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b")
  15. llm.predict("你是谁")
  16. from langchain.prompts import PromptTemplate
  17. # 我们所构造的 Prompt 模板
  18. template = """使用以下上下文来回答用户的问题。如果你不知道答案,就说你不知道。总是使用中文回答。
  19. 问题: {question}
  20. 可参考的上下文:
  21. ···
  22. {context}
  23. ···
  24. 如果给定的上下文无法让你做出回答,请回答你不知道。
  25. 有用的回答:"""
  26. # 调用 LangChain 的方法来实例化一个 Template 对象,该对象包含了 context 和 question 两个变量,在实际调用时,这两个变量会被检索到的文档片段和用户提问填充
  27. QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template)
  28. from langchain.chains import RetrievalQA
  29. qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
  30. # 检索问答链回答效果
  31. question = "什么是MindSpore"
  32. result = qa_chain({"query": question})
  33. print("检索问答链回答 question 的结果:")
  34. print(result["result"])
  35. # 仅 LLM 回答效果
  36. result_2 = llm(question)
  37. print("大模型回答 question 的结果:")
  38. print(result_2)

部署 Web Demo

  1. from langchain.vectorstores import Chroma
  2. from langchain.embeddings.huggingface import HuggingFaceEmbeddings
  3. import os
  4. from LLM import InternLM_LLM
  5. from langchain.prompts import PromptTemplate
  6. from langchain.chains import RetrievalQA
  7. def load_chain():
  8. # 加载问答链
  9. # 定义 Embeddings
  10. embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
  11. # 向量数据库持久化路径
  12. persist_directory = 'data_base/vector_db/chroma'
  13. # 加载数据库
  14. vectordb = Chroma(
  15. persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上
  16. embedding_function=embeddings
  17. )
  18. # 加载自定义 LLM
  19. llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b")
  20. # 定义一个 Prompt Template
  21. template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
  22. 案。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
  23. {context}
  24. 问题: {question}
  25. 有用的回答:"""
  26. QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template)
  27. # 运行 chain
  28. qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
  29. return qa_chain
  30. class Model_center():
  31. """
  32. 存储检索问答链的对象
  33. """
  34. def __init__(self):
  35. # 构造函数,加载检索问答链
  36. self.chain = load_chain()
  37. def qa_chain_self_answer(self, question: str, chat_history: list = []):
  38. """
  39. 调用问答链进行回答
  40. """
  41. if question == None or len(question) < 1:
  42. return "", chat_history
  43. try:
  44. chat_history.append(
  45. (question, self.chain({"query": question})["result"]))
  46. # 将问答结果直接附加到问答历史中,Gradio 会将其展示出来
  47. return "", chat_history
  48. except Exception as e:
  49. return e, chat_history
  50. import gradio as gr
  51. # 实例化核心功能对象
  52. model_center = Model_center()
  53. # 创建一个 Web 界面
  54. block = gr.Blocks()
  55. with block as demo:
  56. with gr.Row(equal_height=True):
  57. with gr.Column(scale=15):
  58. # 展示的页面标题
  59. gr.Markdown("""<h1><center>InternLM</center></h1>
  60. <center>书生浦语</center>
  61. """)
  62. with gr.Row():
  63. with gr.Column(scale=4):
  64. # 创建一个聊天机器人对象
  65. chatbot = gr.Chatbot(height=450, show_copy_button=True)
  66. # 创建一个文本框组件,用于输入 prompt。
  67. msg = gr.Textbox(label="Prompt/问题")
  68. with gr.Row():
  69. # 创建提交按钮。
  70. db_wo_his_btn = gr.Button("Chat")
  71. with gr.Row():
  72. # 创建一个清除按钮,用于清除聊天机器人组件的内容。
  73. clear = gr.ClearButton(
  74. components=[chatbot], value="Clear console")
  75. # 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
  76. db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[
  77. msg, chatbot], outputs=[msg, chatbot])
  78. gr.Markdown("""提醒:<br>
  79. 1. 初始化数据库时间可能较长,请耐心等待。
  80. 2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。 <br>
  81. """)
  82. gr.close_all()
  83. # 直接启动
  84. demo.launch()

通过将上述代码封装为 run_gradio.py 脚本,直接通过 python 命令运行,即可在本地启动知识库助手的 Web Demo,默认会在 7860 端口运行,接下来将服务器端口映射到本地端口即可访问:

运行效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/389912
推荐阅读
相关标签
  

闽ICP备14008679号