在本博客中,我们将讨论如何构建一个本地RAG(检索增强生成)知识库,既保护隐私又兼顾经济性。所谓”本地”,指的是被分析的文档不会被任何云端大模型处理。这不仅保护了数据隐私,还避免了对OpenAI等服务的API调用,从而节省了成本。
我们将从基于Langchain和开源嵌入模型的基础RAG实现开始。接着,加入Agent支持以提升RAG的智能性。最后,我们会对RAG进行优化以提升性能。
RAG架构概览
检索增强生成(RAG)结合了大语言模型与知识库的能力,能够提供准确且有上下文的回答。架构分解如下:
- 文档处理层
- 支持多种文档类型(PDF、TXT、EPUB)
- 文档存储在可配置的知识库目录
- 针对不同文件类型使用专用加载器(PyPDF2、TextLoader、EbookLib)
- 文本处理层
- 使用RecursiveCharacterTextSplitter将文档切分为可管理的块
- 默认:每块1000字符,重叠200字符
- 保留每块的源元数据
- 嵌入层
- 使用OllamaEmbeddings和”nomic-embed-text”模型
- 将文本块转换为向量表示
- 优化用于语义相似度匹配
- 向量存储层
- 支持多种向量数据库:
- Chroma(默认):持久化存储在”chroma_db”
- FAISS:索引存储在”faiss_index”
- 存储嵌入和元数据
- 支持多种向量数据库:
- 检索与生成层
- 相似度检索找到相关块(默认前4条)
- 本地LLM(通过Ollama的Deepseek)结合上下文处理查询
- 返回带有来源文档的答案
- 实时更新系统
- FileWatcher监控知识库目录
- 文档变更时自动重建索引
- 保证知识库内容实时更新
架构图
下图展示了完整的RAG架构和Agent辅助流程:
六层RAG架构
Agent辅助RAG流程
现在我们了解了RAG系统的架构和流程,下面用LangChain和本地LLM实现细节。
实现细节
让我们看看如何用LangChain和本地LLM实现RAG系统。
什么是LangChain?
LangChain是一个用于开发大语言模型应用的框架。它提供:
- 常用操作的组件(加载文档、切分文本、管理提示)
- 与多种LLM、嵌入模型和向量存储的集成
- 构建链和Agent的工具
有了这些基础,我们可以实现RAG系统,从基础组件到Agent能力。
基础RAG实现(本地LLM)
不使用OpenAI API(需要API密钥且收费),我们可以通过Ollama使用本地模型。以下是用Deepseek模型实现基础RAG的步骤:
- 首先,在Ollama中安装Deepseek:
ollama pull deepseek-coder:1.3b
- 基础LangChain RAG流程:
# 1. 加载文档
from langchain_community.document_loaders import TextLoader
loader = TextLoader("file.txt")
docs = loader.load()
# 2. 文档切分
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_documents(docs)
# 3. 嵌入并存储到向量库
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(chunks, embeddings)
4. 用本地LLM设置检索链
from langchain_community.llms import Ollama
llm = Ollama(model=”deepseek-coder:1.3b”) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type=”stuff”, retriever=vectorstore.as_retriever() )
5. 提问
question = “这份文档讲了什么?” answer = qa_chain.run(question)
此实现:
1. 获取用户问题
2. 用检索器找出最相关的文档块
3. 将这些文档和问题一起"填充"到提示中
4. 通过Ollama将带上下文的提示发送给本地LLM
LangChain的`RetrievalQA`链负责将上下文与问题结合,并管理与LLM的交互。虽然这是基础实现,但它为后续增强提供了基础:
- 自定义提示模板
- 更好的上下文预处理与选择
- 高级检索策略
- 来源验证与引用要求
## 高级Agent-RAG实现
在上述Agent增强方法基础上,下面实现一个综合系统:
### Agent工具与能力
Agent-RAG的强大之处在于能针对不同任务调用不同工具。以下是常见工具的实现方式:
```python
from langchain.tools import BaseTool
from typing import Optional
class LocalKnowledgeBaseTool(BaseTool):
name = "local_kb_search"
description = "在本地知识库中检索相关信息"
def _run(self, query: str) -> str:
results = vectorstore.similarity_search(query, k=4)
return self._format_results(results)
def _format_results(self, results) -> str:
return "\n".join([doc.page_content for doc in results])
class WebSearchTool(BaseTool):
name = "web_search"
description = "检索网络补充信息"
def _run(self, query: str) -> str:
# 实现网络检索逻辑
return web_results
# 工具编排
class ToolOrchestrator:
def __init__(self, tools: List[BaseTool]):
self.tools = {tool.name: tool for tool in tools}
self.fallback_tool = None
def execute_with_fallback(self, tool_name: str, query: str) -> str:
try:
return self.tools[tool_name]._run(query)
except Exception as e:
if self.fallback_tool:
return self.fallback_tool._run(query)
raise e
性能优化
可采用以下优化策略提升RAG性能:
# 1. 并行处理
from concurrent.futures import ThreadPoolExecutor
def parallel_document_processing(documents: List[Document]):
with ThreadPoolExecutor() as executor:
chunks = executor.map(text_splitter.split_text, documents)
return list(chunks)
# 2. 缓存系统
from functools import lru_cache
class CachedVectorStore:
def __init__(self, vectorstore):
self.vectorstore = vectorstore
self.cache = {}
@lru_cache(maxsize=1000)
def similarity_search(self, query: str, k: int = 4):
return self.vectorstore.similarity_search(query, k=k)
# 3. 索引优化
def optimize_index(vectorstore):
if isinstance(vectorstore, FAISS):
vectorstore.index.nprobe = 8 # 根据索引大小调整
return vectorstore
# 4. 查询优化
def refine_query(query: str, context: Optional[str] = None) -> str:
refined = llm(f"""优化此检索查询,同时保持原意。
原始查询: {query}
上下文: {context or '无'}
优化后查询:""")
return refined.strip()
真实场景用法
以下是常见场景的实用模式:
class EnhancedRAGAgent:
def __init__(self, tools, llm, vectorstore):
self.tools = tools
self.llm = llm
self.vectorstore = vectorstore
self.history = []
def process_query(self, query: str) -> str:
# 1. 查询分析
query_type = self.analyze_query_type(query)
# 2. 工具选择
selected_tools = self.select_tools(query_type)
# 3. 并行信息收集
with ThreadPoolExecutor() as executor:
results = list(executor.map(
lambda tool: tool._run(query),
selected_tools
))
# 4. 上下文管理
context = self.merge_results(results)
context = self.filter_relevant_context(context, query)
# 5. 回答生成
response = self.generate_response(query, context)
# 6. 添加引用
final_response = self.add_citations(response, results)
self.history.append((query, final_response))
return final_response
def filter_relevant_context(self, context: str, query: str) -> str:
relevance_scores = self.calculate_relevance(context, query)
return self.select_top_relevant(context, relevance_scores)
def add_citations(self, response: str, results: List[str]) -> str:
sources = self.extract_sources(results)
return f"{response}\n\n来源:\n" + "\n".join(sources)
实际应用示例:
# 初始化增强型RAG系统
agent = EnhancedRAGAgent(
tools=[
LocalKnowledgeBaseTool(),
WebSearchTool(),
ImageAnalysisTool(),
],
llm=Ollama(model="deepseek-coder:1.3b"),
vectorstore=CachedVectorStore(
optimize_index(
Chroma(embedding_function=OllamaEmbeddings())
)
)
)
# 处理复杂查询
response = agent.process_query(
"对比我们公司的病假政策与湾区科技公司的行业标准。"
)
此实现:
- 多工具并行调用
- 错误处理健壮
- 提供来源引用
- 缓存优化性能
- 有效管理上下文
- 生成结构化回答
未来挑战与机遇
- 高级上下文理解
- 处理文档间复杂逻辑关系
- 理解并保留文档层级结构
- 跨文档指代消解
- 针对不同LLM动态调整上下文窗口
- 质量与可信度
- 实时事实核查机制
- 生成回答的置信度评分
- 偏见检测与缓解
- 隐私保护的信息检索
- 多模态支持
- 处理图片、音频、视频内容
- 跨模态推理与检索
- 多模态答案生成
- 结构化数据集成
- 高级交互
- 交互式澄清对话
- 多轮推理能力
- Agent决策过程解释
- 用户偏好学习
这些挑战为RAG系统的未来发展带来机遇。随着领域进步,解决这些问题将推动知识管理系统更智能、更可信、更好地服务用户需求。