前言
前段时间一直准备期末考试,现在有时间更新大模型的文章啦!!!
开始操作
原文章链接【云驻共创】LangChain+ChatGLM3实现本地知识库,转华为云ModelArts,实现大模型AI应用开发-云社区-华为云 (huaweicloud.com),基于LangChain+ChatGLM3的本地知识库问答 (huaweicloud.com)
在进行学习之前需要注册华为云账号,并且需要进行实名认证
进入这个页面后我们点击那个红色的按钮即可“Run in ModelArts”
我们点击这个以后就会进入一个内置jupyter页面,我们等待他初始化,然后我们选择一个免费的环境
下载模型
我们选择这个规格后就可以开始进行操作了
import os
import moxing as mox
work_dir = '/home/ma-user/work'
obs_path = 'obs://dtse-models/tar-models/chatglm3-6b.tar'
ma_path = os.path.join(work_dir, 'chatglm3-6b.tar')
mox.file.copy(obs_path, ma_path)
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/langchain-ChatGLM/file/service','service')
首先我们解析这段代码
import os这个想必都不陌生,处理文件和目录的python标准库
然后这个moxing其实是华为云提供的一个库,用于在ModelArts环境中操作OBS对象存储服务
后面这个work_dir为本地工作目录的路径,obs_path是OBS存储文件的路径,ma_path是将文件从OBS复制到本地工作目录后的目标路径
然后这行代码mox.file.copy(obs_path, ma_path)
将 obs_path 中的文件 chatglm3-6b.tar 复制到本地路径 ma_path
这行代码mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/langchain-ChatGLM/file/service','service')将OBS中 obs://modelarts-labs-bj4-v2/case_zoo/langchain-ChatGLM/file/service 路径下的整个目录复制到本地目录 service
然后我们单击旁边那个运行的按钮即可
os.chdir(work_dir)
!pwd
!tar -xvf chatglm3-6b.tar
这个就是解压到对应目录
import os
import moxing as mox
obs_path = 'obs://dtse-models/tar-models/nltk_data.tar'
ma_path = os.path.join(work_dir, 'nltk_data.tar')
mox.file.copy(obs_path, ma_path)
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/langchain-ChatGLM/file/docs','/home/ma-user/work/docs')
然后我们下载nltk_data数据
nltk_data是一个非常重要的资源库,为Python的自然语言处理(NLP)提供了大量的数据支持。 这些数据资源对于执行各种NLP任务至关重要,包括文本分类、信息提取、机器翻译等
上面这些代码和前面我们具体操作的形式是一样的
os.chdir(work_dir)
!pwd
!tar -xvf nltk_data.tar
这里是将我们这个数据资源库进行解压
然后我们需要下载text2vec-large-chinese模型
这个模型我搜索了一下,ChatGPT给出的解释是这样的
import os
import moxing as mox
obs_path = 'obs://dtse-models/tar-models/text2vec-large-chinese.tar'
ma_path = os.path.join(work_dir, 'text2vec-large-chinese.tar')
mox.file.copy(obs_path, ma_path)
然后又是下载解压,这个操作很系统化
os.chdir(work_dir)
!pwd
!tar -xvf text2vec-large-chinese.tar
配置环境
因为我们依赖的是python3.10.10及以上的环境,所以我们应该先创建虚拟环境
!/home/ma-user/anaconda3/bin/conda create -n python-3.10.10 python=3.10.10 -y --override-channels --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
!/home/ma-user/anaconda3/envs/python-3.10.10/bin/pip install ipykernel
这段代码用于在华为云 ModelArts 环境中创建一个新的 Conda 虚拟环境并安装 ipykernel
-
创建 Conda 虚拟环境:
!/home/ma-user/anaconda3/bin/conda create -n python-3.10.10 python=3.10.10 -y --override-channels --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main- 使用 Conda 创建一个名为
python-3.10.10的虚拟环境,并指定 Python 版本为 3.10.10。 -n python-3.10.10指定虚拟环境的名称。python=3.10.10指定要安装的 Python 版本。-y自动确认所有提示,不需要手动输入。--override-channels指定要覆盖默认的 Conda 渠道。--channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main指定使用清华大学的 Anaconda 镜像源,加快下载速度。
- 使用 Conda 创建一个名为
-
安装
ipykernel:!/home/ma-user/anaconda3/envs/python-3.10.10/bin/pip install ipykernel- 这行代码在新创建的
python-3.10.10虚拟环境中使用pip安装ipykernel包。 ipykernel是 Jupyter 的内核,使得 Jupyter Notebook 可以使用不同的 Python 环境。/home/ma-user/anaconda3/envs/python-3.10.10/bin/pip是指定新创建虚拟环境中的pip执行文件。
- 这行代码在新创建的
import json
import os
data = {
"display_name": "python-3.10.10",
"env": {
"PATH": "/home/ma-user/anaconda3/envs/python-3.10.10/bin:/home/ma-user/anaconda3/envs/python-3.7.10/bin:/modelarts/authoring/notebook-conda/bin:/opt/conda/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/anaconda3/envs/PyTorch-1.8/bin"
},
"language": "python",
"argv": [
"/home/ma-user/anaconda3/envs/python-3.10.10/bin/python",
"-m",
"ipykernel",
"-f",
"{connection_file}"
]
}
if not os.path.exists("/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/"):
os.mkdir("/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/")
with open('/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/kernel.json', 'w') as f:
json.dump(data, f, indent=4)
这段代码的目的是为新创建的 Python 3.10.10 虚拟环境配置一个 Jupyter kernel,使得 Jupyter Notebook 可以使用这个环境
-
定义 kernel 配置数据:
import json import os data = { "display_name": "python-3.10.10", "env": { "PATH": "/home/ma-user/anaconda3/envs/python-3.10.10/bin:/home/ma-user/anaconda3/envs/python-3.7.10/bin:/modelarts/authoring/notebook-conda/bin:/opt/conda/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/anaconda3/envs/PyTorch-1.8/bin" }, "language": "python", "argv": [ "/home/ma-user/anaconda3/envs/python-3.10.10/bin/python", "-m", "ipykernel", "-f", "{connection_file}" ] }- 这里定义了一个
data字典,包含 Jupyter kernel 的配置信息。 "display_name":在 Jupyter Notebook 中显示的内核名称。"env":设置环境变量PATH,包含新虚拟环境的路径及其他必要路径。"language":指定内核语言为 Python。"argv":启动内核的命令和参数,其中{connection_file}是 Jupyter 在运行时替换的占位符。
- 这里定义了一个
-
检查并创建目标目录:
if not os.path.exists("/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/"): os.mkdir("/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/")- 这段代码检查目录
/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/是否存在,如果不存在则创建它。这个目录用于存放新的 Jupyter kernel 配置。
- 这段代码检查目录
-
写入 kernel 配置文件:
with open('/home/ma-user/anaconda3/share/jupyter/kernels/python-3.10.10/kernel.json', 'w') as f: json.dump(data, f, indent=4)- 这段代码将
data字典写入到目标路径下的kernel.json文件中,格式化为 JSON 格式,并设置缩进为 4 个空格,使其易于阅读。 kernel.json文件告诉 Jupyter 如何启动和使用这个新的 Python 3.10.10 环境。
- 这段代码将
运行以后我们就可以开始进行下一步操作
然后我们刷新这个界面
我们将这个python-3.7.10变成python-3.10.10
!pip install transformers==4.30.2
!pip install sentencepiece==0.1.99
!pip install torch==2.0.1 torchvision==0.15.2
!pip install markdown==3.4.3
!pip install faiss-gpu==1.7.2
!pip install langchain==0.0.329 -i https://pypi.tuna.tsinghua.edu.cn/simple
!pip install nltk==3.8.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
!pip install unstructured==0.10.24 -i https://pypi.tuna.tsinghua.edu.cn/simple
!pip install sentence-transformers==2.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
然后安装对应依赖库,当然因为这些库需要进行下载,所以运行时间会有一些些长
具体这些库我在下面写了,如果感兴趣看看就行,不感兴趣直接点旁边菜单栏跳过就行
解释
这些命令用于在当前的 Python 环境中安装指定版本的 Python 库,这些库主要用于自然语言处理(NLP)、深度学习和数据处理。
-
Transformers:
!pip install transformers==4.30.2transformers是由 Hugging Face 提供的一个库,用于访问和使用预训练的 transformer 模型,如 BERT、GPT、T5 等。它支持多种语言模型,并提供了方便的 API 用于模型加载、训练和推理。- 版本 4.30.2 是特定的版本号,确保安装该版本以避免版本兼容性问题。
-
SentencePiece:
!pip install sentencepiece==0.1.99sentencepiece是一个文本分词工具,可以用于无监督文本分词和子词单元(subword units)建模。它常用于处理多语言文本,以提高模型的表现。- 版本 0.1.99 是特定的版本号。
-
PyTorch 和 Torchvision:
!pip install torch==2.0.1 torchvision==0.15.2torch是一个流行的开源深度学习框架,由 Facebook 的 AI 研究实验室开发。它提供了灵活的张量运算和自动微分工具。torchvision是 PyTorch 的一个附加库,提供了常用的计算机视觉数据集、模型和图像变换工具。- 版本 2.0.1 和 0.15.2 是特定的版本号。
-
Markdown:
!pip install markdown==3.4.3markdown是一个用于解析和生成 Markdown 格式文本的库。Markdown 是一种轻量级的标记语言,常用于写作格式化文本。- 版本 3.4.3 是特定的版本号。
-
Faiss-gpu:
!pip install faiss-gpu==1.7.2faiss是一个用于高效相似性搜索和聚类的库,由 Facebook 开发。faiss-gpu版本支持 GPU 加速,可以显著提高大规模数据集的处理速度。- 版本 1.7.2 是特定的版本号。
-
Langchain:
!pip install langchain==0.0.329 -i https://pypi.tuna.tsinghua.edu.cn/simplelangchain是一个用于构建和部署基于自然语言的链式生成模型的库。它帮助开发者将多个 NLP 模型组合成一个工作流。- 版本 0.0.329 是特定的版本号。使用
-i参数指定了清华大学的 PyPI 镜像源,加快安装速度。
-
NLTK(Natural Language Toolkit):
!pip install nltk==3.8.1 -i https://pypi.tuna.tsinghua.edu.cn/simplenltk是一个用于处理和分析人类语言数据的库,提供了丰富的文本处理工具和数据集,常用于 NLP 任务。- 版本 3.8.1 是特定的版本号。使用
-i参数指定了清华大学的 PyPI 镜像源,加快安装速度。
-
Unstructured:
!pip install unstructured==0.10.24 -i https://pypi.tuna.tsinghua.edu.cn/simpleunstructured是一个用于处理非结构化数据的库,支持多种文本处理操作,如分词、词性标注、命名实体识别等。- 版本 0.10.24 是特定的版本号。使用
-i参数指定了清华大学的 PyPI 镜像源,加快安装速度。
-
Sentence-Transformers:
!pip install sentence-transformers==2.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simplesentence-transformers是一个用于生成句子和文本嵌入的库,基于 transformer 模型。它可以用于文本相似度计算、聚类和检索任务。- 版本 2.2.2 是特定的版本号。使用
-i参数指定了清华大学的 PyPI 镜像源,加快安装速度。
代码开发
这里这个解释其实就提到了LangChain这个框架,这个框架学习很重要,后面我们会在写文章仔细讲讲
from langchain.chains import RetrievalQA
from langchain.prompts.prompt import PromptTemplate
from service.config import LangChainCFG
from service.chatglm_service import ChatGLMService
from service.knowledge_service import KnowledgeService
class LangChainApplication(object):
#初始化,加载ChatGLM3模型和本地知识库
def __init__(self, config):
self.config = config
self.llm_service = ChatGLMService()
self.llm_service.load_model(model_name_or_path=self.config.llm_model_path)
self.knowledge_service = KnowledgeService(config)
#获取大语言模型返回的答案(基于本地知识库查询)
def get_knowledge_based_answer(self, query,
history_len=5,
temperature=0.1,
top_p=0.9,
top_k=4,
chat_history=[]):
#定义查询的提示模板格式:
prompt_template = """基于以下已知信息,简洁和专业的来回答用户的问题。
如果无法从中得到答案,请说 "根据已知信息无法回答该问题" 或 "没有提供足够的相关信息",不允许在答案中添加编造成分,答案请使用中文。
已知内容:
{context}
问题:
{question}
"""
prompt = PromptTemplate(template=prompt_template,
input_variables=["context", "question"])
self.llm_service.history = chat_history[-history_len:] if history_len > 0 else []
self.llm_service.temperature = temperature
self.llm_service.top_p = top_p
#利用预先存在的语言模型(llm)、检索器(retriever)、提示(prompt)来创建并初始化BaseRetrievalQA类的实例
knowledge_chain = RetrievalQA.from_llm(
llm=self.llm_service,
#基于本地知识库构建一个检索器,并仅返回top_k的结果
retriever=self.knowledge_service.knowledge_base.as_retriever(
search_kwargs={"k": top_k}),
prompt=prompt)
#combine_documents_chain的作用是将查询返回的文档内容(page_content)合并到一起作为prompt中context的值
#将combine_documents_chain的合并文档内容改为{page_content}(代码默认定义为:Context:\n{page_content}),以适配中文
knowledge_chain.combine_documents_chain.document_prompt = PromptTemplate(
input_variables=["page_content"], template="{page_content}")
#返回结果中是否包含源文档
knowledge_chain.return_source_documents = True
#传入问题内容进行查询
result = knowledge_chain({"query": query})
return result
#获取大语言模型返回的答案(未基于本地知识库查询)
def get_llm_answer(self, query):
result = self.llm_service._call(query)
return result
这段代码定义了一个 LangChainApplication 类,该类使用 LangChain 框架与 ChatGLM 模型进行交互,并利用本地知识库进行查询以提供基于知识的答案
类和方法解释
-
LangChainApplication 类:
- 这个类主要用于初始化和使用大语言模型(ChatGLM3)以及本地知识库,以便提供基于知识库的回答和直接的大语言模型回答。
-
__init__方法:- 参数:
config是配置对象。 - 功能:初始化类实例时加载 ChatGLM3 模型和本地知识库。
- 成员变量:
self.config: 保存传入的配置对象。self.llm_service: ChatGLM 模型服务实例。self.knowledge_service: 知识库服务实例。
- 参数:
-
get_knowledge_based_answer方法:- 参数:
query: 用户查询的问题。history_len: 保存的聊天历史记录的长度。temperature: 生成文本的温度参数。top_p: 生成文本的核采样参数。top_k: 检索器返回的结果数量。chat_history: 聊天历史记录。
- 功能:根据用户查询的问题,利用本地知识库进行检索并生成回答。
- 步骤:
- 定义提示模板,用于指导模型如何回答问题。
- 设置 ChatGLM 模型的历史记录和生成文本的参数。
- 利用本地知识库创建一个检索器,仅返回
top_k个结果。 - 定义如何将检索到的文档内容合并到提示中。
- 设置是否在结果中返回源文档。
- 执行查询并返回结果。
- 参数:
-
get_llm_answer方法:- 参数:
query是用户查询的问题。 - 功能:直接调用大语言模型生成回答,不使用本地知识库。
- 步骤:直接调用
ChatGLMService的_call方法生成回答并返回。
- 参数:
主要模块解释
-
LangChain:
- LangChain 是一个框架,用于构建基于语言模型的应用程序,支持各种 NLP 任务。
-
ChatGLMService:
- 假设这是一个自定义的服务类,用于加载和调用 ChatGLM3 模型。
-
KnowledgeService:
- 假设这是一个自定义的服务类,用于加载和管理本地知识库。
-
RetrievalQA:
- LangChain 中的一个类,用于创建基于检索的问答系统。
-
PromptTemplate:
- 用于定义提示模板,以指导模型如何回答问题。
功能测试
from service.config import LangChainCFG
config = LangChainCFG()
application = LangChainApplication(config)
result = application.get_llm_answer('ModelBox是什么')
print('\nresult of llm:\n')
print(result)
print('\n########################################\n')
application.knowledge_service.init_knowledge_base()
result2 = application.get_knowledge_based_answer('ModelBox是什么')
print('\n########################################\n')
print('\nresult of knowledge base:\n')
print(result2)
在这里华为云给出了这个例子,我们点击运行后就可以看见对应的信息了
至此, 我们这篇文章的学习就完成了,我们可以发现这个其实和我们当时调用api那篇文章很像,但是又有一些不同的地方,我们这里是直接在我们计算机上面下载对应模型,然后进行操作
作业
这个是华为云上面提供的一道题,我们可以直接在jupyter上面直接进行书写
如果这篇文章可以帮助到您,可以点赞加收藏,你们的支持是我滴动力