【学习笔记】大模型之美-本地部署RAG
继承LangChain的LLM基类,集成本地部署的ChatGLM-6B-int4模型需要提前加载模型和分词器支持自定义模型参数和类型标识。
代码结构解释
1. 自定义LLM集成:
-
继承LangChain的LLM基类,集成本地部署的ChatGLM-6B-int4模型
-
需要提前加载模型和分词器
-
支持自定义模型参数和类型标识
2. 文档处理流程:
-
使用
CharacterTextSplitter进行文本分块 -
通过
SimpleDirectoryReader加载指定目录的文档 -
将文档解析为可处理的文本节点(nodes)
3. 向量检索系统:
-
使用HuggingFace的多语言句子嵌入模型
-
构建FAISS索引实现高效相似度搜索
-
注意:需要确保嵌入维度(768)与实际模型输出一致
4. 问答系统整合:
-
组合自定义LLM和检索系统创建服务上下文
-
支持自定义问答模板(中文字符需注意编码问题)
-
提供verbose模式查看检索和生成过程
import os # 操作系统接口
import faiss # Facebook的向量相似度搜索库
from transformers import AutoTokenizer, AutoModel
from llama_index import SimpleDirectoryReader, LangchainEmbedding, GPTFaissIndex, ServiceContext
from langchain.embeddings.huggingface import HuggingFaceEmbeddings # HuggingFace嵌入模型
from langchain.text_splitter import CharacterTextSplitter # 文本分割器
from llama_index.node_parser import SimpleNodeParser # 节点解析器
# 自定义LLM类(使用ChatGLM-6B-int4模型)
from langchain.llms.base import LLM
from llama_index import LLMPredictor
from typing import Optional, List, Mapping, Any
# 加载模型和分词器(需要约 8GB GPU 显存)
model_name = "THUDM/chatglm-6b-int4" # HuggingFace 模型ID
# 加载步骤
tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True # 必须开启信任远程代码
)
model = AutoModel.from_pretrained(
model_name,
trust_remote_code=True
).half().cuda() # 转换为半精度并加载到GPU
# -------------------------------
class CustomLLM(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
# 实际调用本地模型进行推理(需要提前加载模型)
# 示例中使用的是ChatGLM的对话接口
response, history = model.chat(tokenizer, prompt, history=[])
return response
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {"name_of_model": "chatglm-6b-int4"} # 模型标识参数
@property
def _llm_type(self) -> str:
return "custom" # 自定义LLM类型
# ----------------- 初始化配置 -----------------
# 文本分割配置(将文档分割为小片段)
text_splitter = CharacterTextSplitter(
separator="\n\n", # 按空行分割
chunk_size=100, # 每个片段最大100字符
chunk_overlap=20 # 片段间重叠20字符
)
parser = SimpleNodeParser(text_splitter=text_splitter)
# 加载文档数据(假设文档存储在指定目录)
documents = SimpleDirectoryReader('./drive/MyDrive/colab_data/faq/').load_data()
# 解析文档为节点(处理后的文本片段)
nodes = parser.get_nodes_from_documents(documents)
# ----------------- 模型与索引配置 -----------------
# 初始化自定义LLM预测器
llm_predictor = LLMPredictor(llm=CustomLLM())
# 配置embedding模型(使用多语言句子嵌入)
embed_model = LangchainEmbedding(
HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
)
)
# 创建服务上下文(组合embedding模型和LLM)
service_context = ServiceContext.from_defaults(
embed_model=embed_model,
llm_predictor=llm_predictor
)
# 初始化FAISS索引(需要与embedding维度匹配)
dimension = 768 # 注意:需要确认实际embedding维度是否匹配
faiss_index = faiss.IndexFlatIP(dimension) # 使用内积作为相似度度量
# 创建GPTFaiss索引(结合文档节点和FAISS索引)
index = GPTFaissIndex(
nodes=nodes,
faiss_index=faiss_index,
service_context=service_context
)
# ----------------- 查询配置 -----------------
# 自定义问答提示模板
from llama_index import QuestionAnswerPrompt, QueryMode
QA_PROMPT_TMPL = (
"{context_str}"
"\n\n"
"根据以上信息,请回答下面的问题:\n"
"Q: {query_str}\n"
)
QA_PROMPT = QuestionAnswerPrompt(QA_PROMPT_TMPL)
# 执行查询示例
response = index.query(
"请问你们海南能发货吗?",
mode=QueryMode.EMBEDDING, # 使用嵌入检索模式
text_qa_template=QA_PROMPT, # 使用自定义提示模板
verbose=True, # 显示详细过程
)
print(response)
📚 代码流程图
-
【书架整理】
SimpleDirectoryReader→ 把文档放进文件夹(就像把书摆上书架)CharacterTextSplitter→ 把长文章撕成小纸片(方便查找) -
【图书编号】
HuggingFaceEmbeddings→ 给每个纸片生成条形码(用数字表示文字含义)Faiss索引→ 把所有条形码贴到检索墙上(按数字顺序排列) -
【训练图书管理员】
CustomLLM→ 雇一个懂中文的AI管理员(用ChatGLM模型)ServiceContext→ 给管理员配发扫码枪(连接检索系统) -
【提问流程】
用户问题 → 生成问题条形码 → 在检索墙上找最相似的3个纸片
→ 管理员阅读相关纸片 → 组织语言回答 -
【核心口诀】
「一问三纸片」:每个问题都通过3个最相关的文档片段生成答案
| 代码组件 | 作用 | 功能 |
|---|---|---|
| SimpleDirectoryReader | 图书搬运工 | 把文档"搬"进系统 |
| Faiss索引 | 图书馆检索机 | 根据条形码闪电查找 |
| ChatGLM | 资深管理员 | 看片段就能编合理答案 |
| QA_PROMPT_TMPL | 回答模板 | "根据这三张纸,应该这样回答..." |
更多推荐
所有评论(0)