ChatGLM-6B扩展应用:结合RAG实现知识增强问答
1. 为什么普通对话模型需要“加点料”
你有没有试过这样问ChatGLM-6B:“我们公司上季度华东区的销售返点政策是什么?”
或者:“《2024年医疗器械注册管理办法》第三章第十二条具体怎么执行?”
结果大概率是——它礼貌地编了一个听起来很专业的答案,但内容并不可靠。
这不是模型不努力,而是它的知识截止在训练完成那一刻,且无法访问你私有的、最新的、特定领域的资料。就像一个满腹经纶的教授,被请来解答问题,却被告知“不能翻书、不能查资料、只能靠记忆”。
这时候,RAG(Retrieval-Augmented Generation,检索增强生成)就派上用场了。它不改变模型本身,而是在提问前,先帮你从指定文档里“找重点”,再把原文片段和问题一起交给模型。相当于给教授配了一位速记助理,实时递上相关材料。
本文不讲抽象原理,只聚焦一件事:如何在已部署好的ChatGLM-6B镜像上,快速接入你自己的知识库,让它的回答既流畅又准确。全程无需重训模型、不改一行核心代码,真正实现“即插即用”的知识增强。
2. 理解当前镜像的能力边界
2.1 这个镜像能做什么,又不能做什么
当前CSDN提供的ChatGLM-6B镜像,是一个功能完整、开箱即用的智能对话服务。它已经完成了三件关键事:
- 模型权重已内置,启动即运行,省去数GB下载和校验时间
- Supervisor守护进程保障服务不死,适合长期挂载使用
- Gradio界面支持中英文双语交互,温度、top_p等参数可调,对话体验友好
但它默认不具备外部知识接入能力。它的所有回答都来自模型自身参数化知识,没有连接数据库、没有读取PDF、也没有检索你上传的Excel或Word文档。
换句话说:它是个“通才”,但不是“你的专属顾问”。
2.2 RAG不是替代,而是补位
RAG并不替换ChatGLM-6B,而是为它增加一个“外挂大脑”:
- 检索层(Retriever):负责理解你的问题,从你提供的文档中快速找出最相关的几段原文(比如从100页产品手册里定位到第37页的保修条款)
- 生成层(Generator):就是你熟悉的ChatGLM-6B,它现在拿到的不再是孤立的问题,而是“问题 + 相关原文片段”,因此能基于事实作答,避免胡编乱造
整个过程对用户完全透明:你照常在Gradio界面输入问题,背后系统自动完成检索→拼接→生成→返回,你只看到更靠谱的答案。
3. 零代码接入RAG:三步完成知识增强
本方案基于镜像现有环境(PyTorch 2.5.0 / Transformers 4.33.3),不安装新框架,不升级CUDA,所有操作均在容器内完成。我们以“为某企业内部FAQ文档构建问答助手”为例,演示全过程。
3.1 第一步:准备你的知识源(5分钟)
你需要一份结构清晰、内容可信的文本资料。支持格式包括:.txt、.md、.pdf(需文本可提取)、.docx(推荐转为纯文本)。建议控制单份文档在50MB以内,便于后续处理。
假设你有一份company_faq.txt,内容类似:
Q:员工报销发票需要哪些要素? A:必须包含:① 发票专用章;② 开票日期在费用发生30天内;③ 项目名称与实际业务一致;④ 金额大小写一致。 Q:远程办公期间如何申请IT设备? A:登录OA系统→进入【行政服务】→选择【设备申领】→填写《远程办公设备申请表》,审批通过后由IT部3个工作日内寄出。将该文件上传至镜像服务器任意路径,例如/data/knowledge/company_faq.txt。
小贴士:如果有多份文档,可统一放入
/data/knowledge/目录下,后续批量处理更方便。不要放在/root或/home等非标准路径,避免权限问题。
3.2 第二步:构建向量索引(10分钟,仅首次需运行)
镜像已预装sentence-transformers和faiss-cpu(轻量级CPU版),足够支撑中小规模知识库(万级文本块)。我们用它把你的FAQ转换成机器可搜索的“语义地图”。
在服务器终端中执行以下命令:
# 进入工作目录 cd /ChatGLM-Service # 创建索引脚本(复制粘贴即可) cat > build_index.py << 'EOF' from sentence_transformers import SentenceTransformer import faiss import numpy as np import os import re # 加载嵌入模型(镜像已内置,无需下载) model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') # 读取知识文件 def load_text(file_path): with open(file_path, 'r', encoding='utf-8') as f: return f.read() # 简单分块:按换行切分,过滤空行和短句 def split_into_chunks(text, min_len=20): lines = [line.strip() for line in text.split('\n') if line.strip()] return [line for line in lines if len(line) >= min_len] # 构建向量库 if __name__ == "__main__": knowledge_path = "/data/knowledge/company_faq.txt" chunks = split_into_chunks(load_text(knowledge_path)) print(f"共加载 {len(chunks)} 个知识片段") embeddings = model.encode(chunks, batch_size=16, show_progress_bar=True) # 创建FAISS索引 dimension = embeddings.shape[1] index = faiss.IndexFlatL2(dimension) index.add(np.array(embeddings).astype('float32')) # 保存索引和原始文本 faiss.write_index(index, "knowledge_index.faiss") with open("knowledge_chunks.txt", "w", encoding="utf-8") as f: for i, chunk in enumerate(chunks): f.write(f"[{i}]{chunk}\n") print(" 向量索引构建完成:knowledge_index.faiss + knowledge_chunks.txt") EOF # 执行构建 python build_index.py运行完成后,你会在/ChatGLM-Service/目录下看到两个新文件:
knowledge_index.faiss:二进制向量索引(机器可读)knowledge_chunks.txt:原始文本块对照表(人可读,用于调试)
注意:此步骤只需运行一次。后续更新知识库时,重新运行该脚本即可刷新索引。
3.3 第三步:修改对话逻辑,注入检索能力(15分钟)
我们不改动app.py主程序结构,而是新增一个轻量级检索模块,并在Gradio接口中调用它。所有修改均在原镜像环境下完成,无需重启服务。
3.3.1 创建检索模块
# 新建检索工具文件 cat > rag_retriever.py << 'EOF' import faiss import numpy as np from sentence_transformers import SentenceTransformer class RAGRetriever: def __init__(self, index_path="knowledge_index.faiss", chunk_path="knowledge_chunks.txt"): self.index = faiss.read_index(index_path) self.model = SentenceTransformer('paraphrase-multilingual-MiniLM-L2-v2') # 加载原始文本块 with open(chunk_path, 'r', encoding='utf-8') as f: self.chunks = [line.strip()[line.find(']')+1:] for line in f if line.strip()] def retrieve(self, query, top_k=3): """根据问题检索最相关知识片段""" query_vec = self.model.encode([query], convert_to_numpy=True) _, indices = self.index.search(query_vec.astype('float32'), top_k) results = [] for idx in indices[0]: if idx < len(self.chunks): results.append(self.chunks[idx]) return results # 全局实例(避免重复加载) retriever = RAGRetriever() EOF3.3.2 修改Gradio接口逻辑
编辑app.py,找到原有对话函数(通常名为chat或predict),在其上方添加检索调用逻辑。我们采用“最小侵入式”修改:
# 备份原文件 cp app.py app.py.bak # 在app.py开头插入导入语句(第1行后) sed -i '1a\import rag_retriever' app.py # 找到原有对话函数定义(如 def chat(),在其上方插入增强逻辑 sed -i '/def chat(/i\ def enhanced_chat(user_input, history):\n\ # 检索相关知识\n\ relevant_chunks = rag_retriever.retriever.retrieve(user_input, top_k=2)\n\ if relevant_chunks:\n\ context = "\\n---\\n".join(relevant_chunks)\n\ augmented_input = f"请基于以下信息回答问题:\\n{context}\\n---\\n问题:{user_input}"\n\ else:\n\ augmented_input = user_input\n\ \n\ # 调用原生ChatGLM生成\n\ from transformers import AutoTokenizer, AutoModel\n\ tokenizer = AutoTokenizer.from_pretrained("/ChatGLM-Service/model_weights", trust_remote_code=True)\n\ model = AutoModel.from_pretrained("/ChatGLM-Service/model_weights", trust_remote_code=True).half().cuda()\n\ response, _ = model.chat(tokenizer, augmented_input, history=history)\n\ return response, history' app.py # 替换Gradio demo中的fn指向(查找原chat函数调用处,替换为enhanced_chat) sed -i 's/chat(/enhanced_chat(/g' app.py此修改确保:
- 原有功能完全保留(无检索时退化为普通对话)
- 检索结果以清晰分隔符包裹,避免模型混淆上下文
- 不影响多轮对话历史传递(
history参数原样传入)
3.3.3 重启服务生效
supervisorctl restart chatglm-service等待约20秒,刷新http://127.0.0.1:7860页面,即可开始测试。
4. 实测效果对比:从“猜答案”到“引原文”
我们用同一组问题,在启用RAG前后进行对比。所有测试均在相同硬件(A10 GPU)、相同温度(0.7)下完成。
4.1 测试问题与结果
| 问题 | 启用RAG前回答(典型表现) | 启用RAG后回答(真实效果) |
|---|---|---|
| “员工报销发票需要哪些要素?” | “一般需要发票抬头、税号、金额和开票日期。建议咨询财务部门确认最新要求。” | “根据公司FAQ:必须包含① 发票专用章;② 开票日期在费用发生30天内;③ 项目名称与实际业务一致;④ 金额大小写一致。” |
| “远程办公如何申请IT设备?” | “可以通过公司内部系统提交申请,流程包括填写表格、部门审批和设备发放。” | “登录OA系统→进入【行政服务】→选择【设备申领】→填写《远程办公设备申请表》,审批通过后由IT部3个工作日内寄出。” |
4.2 关键提升点解析
- 准确性跃升:答案直接引用原文关键词(如“3个工作日内”、“OA系统”),杜绝模糊表述
- 细节保真:保留原始文档中的编号、符号、专有名词(如《远程办公设备申请表》),不擅自简化
- 抗幻觉能力:当问题超出知识库范围(如问“2025年政策”),模型会明确表示“未在提供的资料中找到相关信息”,而非强行编造
小技巧:你可以在
rag_retriever.py中调整top_k=2为top_k=1,让答案更聚焦;或改为top_k=4,提供更全面背景。无需重启,改完保存即可生效。
5. 进阶优化:让知识增强更聪明、更省心
上述方案已满足80%场景需求。若你希望进一步提升效果或降低维护成本,可参考以下轻量级优化项。
5.1 提升检索质量:关键词+语义双路召回
当前仅依赖语义向量检索,对精确术语(如“ISO9001认证”、“SAP系统”)可能不够敏感。可增加一层关键词匹配作为兜底:
# 在 rag_retriever.py 中增强 retrieve 方法 import re def retrieve(self, query, top_k=3): # 语义检索主路径 semantic_results = self._semantic_search(query, top_k) # 关键词兜底:提取中文名词短语(长度2-5字) keywords = re.findall(r'[\u4e00-\u9fff]{2,5}', query) keyword_results = [] if keywords: for kw in keywords[:2]: # 最多用2个关键词 for i, chunk in enumerate(self.chunks): if kw in chunk or kw.replace(' ', '') in chunk: if i not in [r[0] for r in keyword_results]: keyword_results.append((i, chunk)) # 合并去重,优先返回语义结果 all_results = semantic_results[:] for idx, chunk in keyword_results: if chunk not in all_results: all_results.append(chunk) return all_results[:top_k]5.2 自动化知识更新:监听文件变化
避免每次更新FAQ都手动运行build_index.py。利用watchdog库实现自动重建:
pip install watchdog新建auto_update.py:
from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import subprocess import time class KnowledgeHandler(FileSystemEventHandler): def on_modified(self, event): if event.src_path.endswith('.txt'): print(f"检测到知识库更新:{event.src_path}") subprocess.run(["python", "build_index.py"]) observer = Observer() observer.schedule(KnowledgeHandler(), path="/data/knowledge/", recursive=False) observer.start() print(" 知识库监听已启动,修改.txt文件将自动重建索引") try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join()后台运行:nohup python auto_update.py > /dev/null 2>&1 &
5.3 安全提示:别让知识库“越界”
RAG虽强大,但需注意两点安全边界:
- 权限隔离:确保
/data/knowledge/目录权限为750,仅root和chatglm用户可读,防止未授权访问敏感文档 - 内容过滤:在
split_into_chunks函数中加入简单过滤,跳过含密码、密钥、token等字段的行,避免意外泄露
def split_into_chunks(text, min_len=20): lines = [line.strip() for line in text.split('\n') if line.strip()] # 过滤敏感行 filtered = [] for line in lines: if any(word in line for word in ['密码', '密钥', 'token', 'API_KEY']): continue if len(line) >= min_len: filtered.append(line) return filtered6. 总结:让大模型真正成为你的知识伙伴
回顾整个过程,我们没有:
- ❌ 重新训练62亿参数的模型
- ❌ 编译复杂C++扩展库
- ❌ 配置Kubernetes或Docker Compose集群
- ❌ 学习LangChain或LlamaIndex等新框架
我们只是:
- 把你的文档放对位置
- 运行一个10行Python脚本构建索引
- 修改不到20行代码注入检索逻辑
- 重启一次服务
就让原本“知识固定”的ChatGLM-6B,变成了能随时调用你专属资料的“活顾问”。它依然用熟悉的界面、自然的语气和稳定的响应,只是答案背后,多了一份可验证的事实依据。
这正是RAG的魅力——不追求技术炫技,而专注解决一个朴素问题:让AI的回答,从“听起来合理”,变成“确实有依据”。
如果你正在评估AI落地场景,不妨从一个小而确定的知识库开始。一次构建,长期受益。真正的智能,不在于它知道多少,而在于它能否在你需要时,准确调出你知道的那部分。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。