文档目录

  • 一、总体说明与介绍

  • 二、为什么使用RAG

    • 优点与使用场景
  • 三、环境搭建

    • 环境依赖与安装步骤
    • 模型安装与启动
  • 四、完整的RAG代码示例

    • 代码实现与说明
  • 五、优化建议

    • 性能优化建议
    • 使用技巧提示

一、总体说明与介绍

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合向量检索和生成式语言模型(LLM)的新型技术。它通过实时从外部知识库中检索相关的知识片段作为上下文,增强模型对问题回答的准确性与实时性,广泛应用于企业内部知识库、智能客服、医疗咨询等领域。

本技术文档将指导您如何使用LangChain框架结合Ollama服务,搭建一个本地运行的高效RAG知识库。

二、为什么使用RAG

优点 说明 推荐使用场景
实时更新 无需频繁重新训练模型即可更新知识库内容 企业内部知识库,实时信息更新场景
提升准确性 减少语言模型“幻觉”现象,提高答案准确性 法律咨询、医疗健康
降低成本 维护知识库成本远低于重新训练大型模型 小型公司内部知识库、客服
数据私密性 数据本地存储和处理,保护隐私安全 企业私有数据处理

三、环境搭建

环境依赖与安装步骤

1
2
pip3 install langchain langchain-community chromadb ollama sentence-transformers
pip3 install pypdf "unstructured[all-docs]" python-docx python-pptx lxml openpyxl

包说明:

软件或包名称 安装方式 作用说明
LangChain pip install langchain langchain-community 链式调用AI任务,文档加载
ChromaDB pip install chromadb 本地向量数据库
Ollama 官网安装 本地运行LLM
sentence-transformers pip install sentence-transformers 向量嵌入
文档处理库 pip install pypdf "unstructured[all-docs]" python-docx python-pptx lxml openpyxl 加载多种文档类型,如PDF、Word、Excel等

三、模型安装与启动

操作 命令 说明
启动Ollama ollama serve 启动Ollama本地模型服务
下载DeepSeek模型 ollama pull deepseek-r1:1.5b 下载本地LLM模型用于问答
下载嵌入模型 ollama pull nomic-embed-text:latest 文本转向量的嵌入模型

四、完整的RAG代码示例

以下是完整的Python示例代码,使用LangChain实现基于Ollama的本地RAG知识库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

# pip3 install langchain langchain-community chromadb ollama sentence-transformers
# pip3 install pypdf "unstructured[all-docs]" python-docx python-pptx lxml openpyxl

from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader, PyPDFLoader, UnstructuredWordDocumentLoader, \
UnstructuredPowerPointLoader, UnstructuredHTMLLoader, UnstructuredMarkdownLoader, UnstructuredCSVLoader, \
UnstructuredExcelLoader
from langchain_community.llms.ollama import Ollama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_ollama import OllamaEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. 加载文档
def load_documents(*filepaths): # 修改函数,接收可变数量的文件路径
loaders = []
for filepath in filepaths: # 遍历文件路径列表
if filepath.endswith(".pdf"):
loaders.append(PyPDFLoader(filepath))
elif filepath.endswith(".txt"):
loaders.append(TextLoader(filepath))
elif filepath.endswith(".docx"):
loaders.append(UnstructuredWordDocumentLoader(filepath))
elif filepath.endswith(".pptx"):
loaders.append(UnstructuredPowerPointLoader(filepath))
elif filepath.endswith(".html"):
loaders.append(UnstructuredHTMLLoader(filepath))
elif filepath.endswith(".md"):
loaders.append(UnstructuredMarkdownLoader(filepath))
elif filepath.endswith(".csv"):
loaders.append(UnstructuredCSVLoader(filepath))
elif filepath.endswith(".xlsx"):
loaders.append(UnstructuredExcelLoader(filepath))

documents = []
for loader in loaders:
documents.extend(loader.load())
return documents

# 获取用户输入的文件路径
fileList = []
while True:
inputWord = input("请输入文件全路径,输入q结束:")
if inputWord == "q":
break
else:
fileList.append(inputWord)

# 解包 fileList 并传递给 load_documents
documents = load_documents(*fileList) # 使用 * 解包

# 2. 分割文本
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

# 3. 创建向量数据库
embeddings = OllamaEmbeddings(model="nomic-embed-text:latest")
db = Chroma.from_documents(texts, embeddings)

# 4. 创建检索器
retriever = db.as_retriever()

# 5. 创建问答链
llm = Ollama(model="deepseek-r1:14b")

# 定义 RAG 提示模板
RAG_TEMPLATE = """
You are an assistant for question-answering tasks.

<context>
{context}
</context>

Question: {question}
"""
rag_prompt = ChatPromptTemplate.from_template(RAG_TEMPLATE)

# 格式化文档函数
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)

# 使用管道操作符构建问答链
qa_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| rag_prompt
| llm
| StrOutputParser()
)

# 6. 交互式提问
while True:
query = input("请输入你的问题(输入q退出):")
if query.lower() == "q":
break
result = qa_chain.invoke(query)
print(result)

五、优化建议

  • 调整 chunk_size(如300~1000字符)提高检索的准确性。
  • 根据应用需求调整检索文档数量 k(默认3-5个)提升答案相关度。
  • 使用量化模型(如DeepSeek量化版)减少内存占用,提高响应速度。