基于 LlaMA 3 + LangGraph 在Windows本地构建RAG智能体(一)
1. 为什么要在Windows本地构建RAG智能体?
最近两年,大语言模型(LLM)的发展速度简直让人眼花缭乱。从最初的ChatGPT到现在的Llama 3,模型的性能越来越强,但同时也带来了一个现实问题:这些模型往往需要强大的云端算力支持。对于很多开发者来说,尤其是个人开发者和小团队,云端API的成本和隐私问题成了拦路虎。
这就是为什么我们要在本地部署大模型。想象一下,你有一个私人助理,它不仅能理解你的问题,还能从你指定的文档中查找答案,而且所有数据都在你的电脑上处理,完全不用担心隐私泄露。这就是RAG(检索增强生成)智能体的魅力所在。
我在实际项目中测试过,使用Llama 3-8B模型在消费级显卡(比如RTX 3060 12GB)上运行完全可行。配合LangGraph的工作流编排能力,你可以构建一个能理解上下文、能自我验证答案准确性的智能系统。最棒的是,整个过程不需要连接任何外部服务器,所有数据处理都在本地完成。
2. 环境准备与依赖安装
2.1 硬件与系统要求
在开始之前,我们先看看需要准备什么。我建议至少满足以下配置:
- 操作系统 :Windows 10/11 64位
- 内存 :16GB以上(32GB更佳)
- 显卡 :NVIDIA显卡,至少8GB显存(RTX 3060及以上)
- 存储空间 :至少20GB可用空间(用于模型和依赖)
如果你没有独立显卡,也可以用纯CPU模式运行,但速度会慢很多。我测试过,在i7-12700K上运行Llama 3-8B,生成速度大约2-3个token/秒,勉强可用但不适合生产环境。
2.2 安装Python和必要工具
首先确保你安装了Python 3.10或更高版本。我强烈建议使用Miniconda创建虚拟环境,避免污染系统Python环境:
conda create -n llama3 python=3.10
conda activate llama3
接下来安装CUDA工具包(如果你有NVIDIA显卡)。到NVIDIA官网下载对应版本的CUDA Toolkit(目前推荐12.1版本),安装时记得勾选"添加到PATH"选项。
2.3 安装核心依赖
现在我们来安装必要的Python包。这里我推荐使用pip的 -q 参数减少输出干扰:
pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -q ollama langchain beautifulsoup4 chromadb gradio unstructured langchain-nomic langchain_community tiktoken langchainhub langgraph gpt4all
这些包包含了我们需要的所有核心功能:
torch:PyTorch深度学习框架ollama:Llama模型的本地运行接口langchain和langgraph:工作流编排的核心chromadb:向量数据库,用于存储文档嵌入gradio:快速构建演示界面
特别提醒:如果你遇到 unstructured 安装问题,可能需要额外安装系统依赖:
pip install "unstructured[all-docs]"
3. 下载并配置Llama 3模型
3.1 获取模型权重
现在我们来下载Llama 3模型。使用ollama可以非常方便地获取官方优化过的模型:
ollama pull llama3
这个命令会自动下载最新的Llama 3-8B模型(约4.7GB)。如果你想使用更大的70B模型(需要32GB以上显存),可以运行:
ollama pull llama3:70b
下载完成后,可以用以下命令验证:
ollama list
你应该能看到类似输出:
NAME ID SIZE MODIFIED
llama3:latest 365c0bd3c000 4.7GB 2 days ago
3.2 模型量化与性能权衡
原始模型对显存要求很高,所以我们通常使用量化版本来降低资源消耗。量化是一种降低模型精度来减少内存占用的技术。ollama默认使用4-bit量化,这是一个很好的平衡点。
我在RTX 3060 12GB上测试过不同量化级别的表现:
- 4-bit:流畅运行,显存占用约8GB
- 8-bit:质量更好,但显存占用约10GB
- 16-bit:接近原始质量,但需要16GB以上显存
对于大多数应用场景,4-bit量化已经足够好了。如果你有更强的显卡,可以尝试更高精度的版本:
ollama pull llama3:8b-instruct-q8_0
4. LangGraph基础与工作流设计
4.1 什么是LangGraph?
LangGraph是LangChain生态系统中的一个新成员,它专门用于构建复杂的AI工作流。你可以把它想象成一个流程图工具,但专门为AI任务设计。它基于"状态图"的概念,允许你定义不同的节点和边,控制信息如何在系统中流动。
我在实际项目中发现,LangGraph特别适合构建需要多步骤决策的AI系统。比如一个问答系统可能需要:
- 理解用户问题
- 决定是否需要检索文档
- 如果需要,从哪些来源检索
- 如何组合检索结果生成最终答案
- 如何验证答案的准确性
4.2 构建第一个状态图
让我们从一个简单的例子开始。创建一个Python文件 basic_graph.py :
from langgraph.graph import StateGraph, END
# 定义状态结构
class AgentState(TypedDict):
input: str
output: str
# 定义节点函数
def node_echo(state: AgentState):
return {"output": f"你说了: {state['input']}"}
# 创建图
workflow = StateGraph(AgentState)
# 添加节点
workflow.add_node("echo", node_echo)
# 设置入口点
workflow.set_entry_point("echo")
# 设置结束点
workflow.add_edge("echo", END)
# 编译图
app = workflow.compile()
这个简单的图只有一个节点,它接收输入并返回一个带前缀的字符串。你可以这样运行它:
result = app.invoke({"input": "你好,世界!"})
print(result["output"]) # 输出: 你说了: 你好,世界!
4.3 添加条件分支
真正的强大之处在于条件分支。让我们扩展上面的例子,添加一个决策节点:
from langgraph.graph import StateGraph, END
from typing import Literal
class AgentState(TypedDict):
input: str
output: str
decision: Literal["echo", "reverse"]
def node_echo(state: AgentState):
return {"output": f"你说了: {state['input']}"}
def node_reverse(state: AgentState):
return {"output": f"反转后: {state['input'][::-1]}"}
def node_decide(state: AgentState):
if len(state["input"]) > 5:
return {"decision": "reverse"}
return {"decision": "echo"}
workflow = StateGraph(AgentState)
workflow.add_node("decide", node_decide)
workflow.add_node("echo", node_echo)
workflow.add_node("reverse", node_reverse)
workflow.set_entry_point("decide")
workflow.add_edge("echo", END)
workflow.add_edge("reverse", END)
workflow.add_conditional_edges(
"decide",
lambda state: state["decision"],
{"echo": "echo", "reverse": "reverse"}
)
app = workflow.compile()
现在这个图会根据输入长度决定是直接回显还是反转字符串。试试看:
print(app.invoke({"input": "hi"})["output"]) # 输出: 你说了: hi
print(app.invoke({"input": "hello world"})["output"]) # 输出: 反转后: dlrow olleh
5. 构建完整的RAG智能体
5.1 文档加载与处理
RAG的核心是从文档中检索相关信息。首先我们需要准备文档并转换为向量存储。创建一个新文件 rag_agent.py :
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
# 加载文档
loader = DirectoryLoader('./docs', glob="**/*.txt")
documents = loader.load()
# 分割文档
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
splits = text_splitter.split_documents(documents)
# 创建向量存储
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OllamaEmbeddings(model="llama3")
)
这段代码会加载 docs 目录下的所有txt文件,将它们分割成小块,然后使用Llama 3的嵌入模型转换为向量存储在Chroma中。
5.2 定义检索节点
现在我们将检索功能集成到LangGraph中:
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# 检索器
retriever = vectorstore.as_retriever()
# 检索节点
def node_retrieve(state: dict):
docs = retriever.invoke(state["question"])
return {"docs": docs}
5.3 定义生成节点
生成节点负责调用Llama 3生成最终答案:
from langchain_community.chat_models import ChatOllama
# LLM实例
llm = ChatOllama(model="llama3")
# 提示模板
template = """基于以下上下文回答问题:
{context}
问题: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
# 生成链
chain = (
{"context": RunnablePassthrough(), "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# 生成节点
def node_generate(state: dict):
answer = chain.invoke({
"context": state["docs"],
"question": state["question"]
})
return {"answer": answer}
5.4 组装完整工作流
现在我们把所有节点组合起来:
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
from langchain.schema import Document
class AgentState(TypedDict):
question: str
docs: List[Document]
answer: str
# 创建图
workflow = StateGraph(AgentState)
# 添加节点
workflow.add_node("retrieve", node_retrieve)
workflow.add_node("generate", node_generate)
# 设置连接
workflow.set_entry_point("retrieve")
workflow.add_edge("retrieve", "generate")
workflow.add_edge("generate", END)
# 编译
app = workflow.compile()
5.5 测试智能体
现在你可以这样使用这个RAG智能体:
result = app.invoke({"question": "文档中提到了哪些关键技术?"})
print(result["answer"])
这个智能体会自动从你的文档中检索相关信息,然后生成基于这些信息的回答,而不是凭空编造答案。
更多推荐


所有评论(0)