基于 LlaMA 3 + LangGraph 在Windows本地构建RAG智能体(一)

📅 2026/7/13 13:20:46 👁️ 阅读次数 📝 编程学习
基于 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模型的本地运行接口
  • langchainlanggraph:工作流编排的核心
  • 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系统。比如一个问答系统可能需要:

  1. 理解用户问题
  2. 决定是否需要检索文档
  3. 如果需要,从哪些来源检索
  4. 如何组合检索结果生成最终答案
  5. 如何验证答案的准确性

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"])

这个智能体会自动从你的文档中检索相关信息,然后生成基于这些信息的回答,而不是凭空编造答案。