避免脏RAG:使用Ollama和LangChain实现检索增强生成

本文详细介绍了检索增强生成(RAG)系统的原理与实现,通过Ollama部署本地大语言模型,结合LangChain构建RAG管道,并利用LangSmith进行全链路监控,最后探讨了RAG系统访问敏感文档的安全风险。

避免脏RAG:使用Ollama和LangChain实现检索增强生成

大语言模型与RAG系统概述

大语言模型(LLMs)通过大规模数据集训练生成概率性响应,但其知识受限于训练数据的时间点。检索增强生成(RAG)通过连接预训练LLMs与实时数据源(如网页、文档)解决时效性问题。RAG系统的工作流程包含以下核心组件:

  1. 嵌入模型:将文本数据转换为向量化格式
  2. 向量数据库:存储向量化数据以供检索
  3. 检索机制:通过相似度搜索匹配用户查询与存储数据
  4. 提示增强:将检索到的上下文数据与原始查询组合后发送给LLM

系统环境配置

硬件要求

  • 推荐配置:Ubuntu 24.04 LTS, 20 CPUs, 240GB RAM, NVIDIA H100 GPU
  • 最低配置:Ubuntu 24.04 LTS, 20 CPUs, 96GB RAM, NVIDIA RTX 3080 GPU
  • 云方案:Digital Ocean节点(约3.50美元/小时)

Ollama安装与模型部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 安装NVIDIA驱动
wget "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb"
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt install -y gcc g++ cuda-toolkit nvidia-open

# 安装Ollama
curl -fsSL https://ollama.com/install.sh | sh

# 下载模型
ollama run BlackHillsInfoSec/llama-3.1-8b-abliterated
ollama pull mxbai-embed-large

LangChain环境搭建

使用conda创建Python 3.11环境并配置poetry依赖管理:

1
2
3
4
5
6
7
conda create -y -n ollama-rag python=3.11
conda activate ollama-rag
pip install poetry
poetry new rag
cd rag
sed -i 's/requires-python = ">=3.11"/requires-python = ">=3.11,<4.0"/' pyproject.toml
poetry add langchain_core langchain_ollama langchain langgraph langchain_community langsmith bs4

LangSmith监控配置

  1. 注册LangSmith账号并创建API密钥
  2. 配置环境变量:
1
2
3
4
5
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
export LANGCHAIN_API_KEY="your_api_key"
export LANGCHAIN_PROJECT="your_project_name"
export USER_AGENT="MyLangchainApp/1.0 (Linux; Python 3.11)"

RAG系统实现代码

核心组件初始化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_ollama.llms import OllamaLLM
from langchain_ollama import OllamaEmbeddings
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langgraph.graph import START, StateGraph
from typing_extensions import List, TypedDict
import bs4
import os

# 模型配置
generativeModelName = "BlackHillsInfoSec/llama-3.1-8b-abliterated"
embeddingsModelName = "mxbai-embed-large"

llm = OllamaLLM(model=generativeModelName)
embeddings = OllamaEmbeddings(model=embeddingsModelName)
vector_store = InMemoryVectorStore(embeddings)

文档加载与处理

1
2
3
4
5
6
7
8
9
# 网页内容加载与分块
loader = WebBaseLoader(
    web_paths=("https://www.blackhillsinfosec.com/using-pyrit-to-assess-large-language-models-llms/",),
    bs_kwargs=dict(parse_only=bs4.SoupStrainer())
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200, add_start_index=True)
all_splits = text_splitter.split_documents(docs)
vector_store.add_documents(documents=all_splits)

RAG工作流定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 状态管理类
class State(TypedDict):
    question: str
    context: List[Document]
    answer: str

# 检索函数
def retrieve(state: State):
    retrieved_docs = vector_store.similarity_search(state["question"])
    return {"context": retrieved_docs}

# 生成函数
def generate(state: State):
    docs_content = "\n\n".join(doc.page_content for doc in state["context"])
    messages = prompt.invoke({"question": state["question"], "context": docs_content})
    response = llm.invoke(messages)
    return {"answer": response}

# 构建执行图
graph_builder = StateGraph(State).add_sequence([retrieve, generate])
graph_builder.add_edge(START, "retrieve")
graph = graph_builder.compile()

查询执行

1
2
response = graph.invoke({"question": "What were the git commands for checking out PyRIT to follow Brian Fehrman's blog?"})
print(response["answer"])

安全风险警示

RAG系统在访问文档时存在严重安全风险:

  1. 权限绕过:用户可通过RAG系统访问未授权敏感文档
  2. 数据泄露:LLM可能返回包含敏感信息的文档内容
  3. 企业防护建议
    • 严格限制RAG系统数据访问权限
    • 实施文档内容过滤机制
    • 监控LLM输出中的敏感信息

性能监控与优化

通过LangSmith可实时监控:

  • 检索步骤的输入输出数据
  • 生成步骤的提示模板和LLM响应
  • 令牌使用情况和执行耗时
  • 向量相似度搜索的相关性评分

结论

本文通过实践演示了RAG系统的完整实现流程,使用Ollama部署本地LLM,利用LangChain构建数据处理管道,并通过LangSmith实现全链路监控。同时强调了RAG系统在文档访问方面的安全风险,为企业部署提供了重要安全考量。


参考文献

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计