你的RAG系统,是“搭积木”还是“盖房子”?Langchain与纯手搓的抉择,决定了你的AI是“玩具”还是“神器”,细思极恐!

你的RAG系统,是“搭积木”还是“盖房子”?Langchain与纯手搓的抉择,决定了你的AI是“玩具”还是“神器”,细思极恐!

你是否曾为大模型“一本正经地胡说八道”而困扰?或者希望它能回答关于你个人笔记或公司内部文档的问题?今天,我们就来一起动手搭建一个简单 RAG 系统,让你的大模型从“闭卷考试”变成“开卷考试”,大幅提升回答的准确性和实用性。

了解了 RAG 的基本原理后,我们来看看如何动手实现它。

在这里插入图片描述

文章目录

一、什么是 RAG?——让大模型“开卷考试”

1.1 RAG 的核心思想

在这里插入图片描述

想象一下,你正在参加一场考试。如果只能靠记忆答题,遇到不熟悉的知识点就容易答错甚至瞎编——这就像没有 RAG 的传统大语言模型(LLM)。它们的知识被“固化”在训练数据中,无法获取新信息,也容易产生“幻觉”。

而 RAG(Retrieval-Augmented Generation,检索增强生成)技术,就是给大模型发了一本“参考书”。当用户提问时,系统会先从这本“参考书”(你的知识库)里查找相关信息,再把找到的内容和问题一起交给大模型去生成答案。

这种“开卷考试”的方式带来了三大优势:

  • 事实更准确:答案基于真实文档,大幅减少胡编乱造。
  • 知识可更新:只需更新你的知识库文件,就能让大模型掌握最新信息。
  • 支持私有数据:你可以让它读取你的 PDF 报告、Word 文档、网页内容,解答专属问题。

1.2 RAG 的工作流程

在这里插入图片描述

RAG 系统的工作可以分为两个阶段:离线准备在线查询

在你开始使用之前,需要先完成“离线准备”阶段,也就是把你的知识文档处理好,方便后续快速查找。

这个过程包含五个核心步骤:

  1. 用户提问:“阿司匹林的禁忌症是什么?”
  2. 查询向量化:将你的问题转换成一串数字(向量),这是计算机理解语义的方式。
  3. 向量检索:在存储着无数文档片段向量的数据库中,找出与问题向量最相似的几个片段。
  4. 提示增强:把检索到的相关片段和原始问题拼接起来,形成一个新的、信息更丰富的提示词。
  5. 大模型生成:把这个增强后的提示词交给大模型,它就能结合这些参考资料,生成一个有据可依的答案。

整个过程通常在几秒内完成,为你提供精准可靠的信息。

二、两种实现方式对比:Langchain vs 纯手搓

在这里插入图片描述

现在,你已经知道了 RAG 是怎么工作的,接下来就要选择用什么方式来搭建它。主要有两种路径:使用成熟的框架 Langchain,或是从零开始 纯手搓 实现。

2.1 开发效率对比

  • Langchain:这就像使用一套高级乐高积木。它已经为你预制好了“文档加载器”、“文本切分器”、“向量数据库接口”等模块。你只需要像搭积木一样把它们组装起来,几分钟内就能跑通整个流程,非常适合快速验证想法。
  • 纯手搓:这就像是自己烧砖、砍木头,再盖房子。你需要手动调用底层库(如 sentence-transformersfaiss)来实现每一个环节。虽然耗时较长,但你能完全掌控每一个细节。

2.2 代码复杂度与维护成本

维度Langchain 实现纯手搓实现
开发时间~25 分钟~180 分钟
代码行数少(高层 API)多(底层集成)
调试难度
典型应用场景快速原型、企业系统教学演示、边缘设备

总的来说,Langchain 抽象程度高,学习曲线稍陡,但后期扩展和维护非常方便。而纯手搓代码透明可控,适合教学理解底层机制,但在实际项目中维护成本较高。

2.3 适用场景总结表

维度Langchain 实现纯手搓实现
开发时间~25 分钟~180 分钟
代码行数少(高层 API)多(底层集成)
调试难度
典型应用场景快速原型、企业系统、复杂 Agent 编排教学演示、资源受限环境、极致性能优化

通过这个对比,你应该能初步判断哪种方式更适合你当前的需求。接下来,我们将分别用这两种方式,带你一步步实现一个完整的 RAG 系统。

三、Langchain 实现:高效构建你的第一个 RAG 系统

如果你的目标是快速上手并看到效果,那么 Langchain 绝对是首选。让我们开始吧!

3.1 环境准备

首先,你需要安装必要的 Python 包。打开你的命令行工具,执行以下命令:

pip install langchain langchain-openai langchain-text-splitters chromadb faiss-cpu openai python-dotenv 

同时,你需要一个 OpenAI API 密钥来调用 GPT 模型。为了安全起见,建议你创建一个 .env 文件来管理它:

# .env 文件内容 OPENAI_API_KEY=your_actual_api_key_here 

这样,你的密钥就不会硬编码在 Python 脚本里了。

3.2 步骤详解与代码实现

步骤 1:加载文档
from langchain_community.document_loaders import TextLoader ​ # 创建TextLoader实例,加载名为"knowledge.txt"的文本文件 loader = TextLoader("knowledge.txt", encoding="utf-8") documents = loader.load()
  • 功能说明:这一步负责读取你的原始文档。TextLoader 支持 TXT 格式,如果是 PDF,你可以换成 PyPDFLoader
步骤 2:文本切分
from langchain.text_splitter import RecursiveCharacterTextSplitter ​ # 初始化递归字符切分器 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500,# 每个文本块约500个字符 chunk_overlap=50,# 块之间重叠50个字符 separators=["\n\n","\n","。",".","!","?"]# 分割符优先级) chunks = text_splitter.split_documents(documents)
  • 功能说明:将长文档切成小块,便于后续处理。chunk_overlap 的作用就像你读书时前后翻页保持连贯,防止一句话被切断。
  • 💡 小贴士:对于中文文档,确保分割符列表包含了中文句号“。”。
步骤 3:向量化并存入数据库
在这里插入图片描述
from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma ​ # 使用OpenAI的嵌入模型将文本块转为向量 embeddings = OpenAIEmbeddings(model="text-embedding-3-large") vectorstore = Chroma.from_documents( chunks, embedding=embeddings, persist_directory="./chroma_db" # 将数据库持久化保存到本地 ) vectorstore.persist() # 确保数据已写入磁盘 
  • 功能说明embeddings 模型是关键,它能让语义相近的句子(如“猫爱吃鱼”和“猫咪喜欢吃鱼”)拥有相似的向量表示。
  • 替代方案:不想依赖 API?可以换用开源的 HuggingFaceEmbeddingsBAAI/bge-small-zh 模型。
步骤 4:创建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k":3})
  • 功能说明:定义了一个检索策略,每次查询都会返回最相关的 Top-3 结果。
  • 高级选项:可以设置 search_type="mmr" 来使用最大边际相关性算法,避免返回重复冗余的结果。
步骤 5:初始化语言模型
from langchain_openai import ChatOpenAI ​ llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
  • 功能说明:接入 GPT-3.5 模型进行回答生成。temperature=0 表示输出尽可能确定和稳定。
  • 替代建议:国内用户可以尝试接入通义千问、百川等国产大模型的 API。
步骤 6:构建 RAG 生成链
from langchain_core.prompts import ChatPromptTemplate from langchain.schema.runnable import RunnablePassthrough from langchain.schema.output_parser import StrOutputParser ​ # 定义一个提示模板,明确告诉大模型如何利用上下文 prompt = ChatPromptTemplate.from_template("请基于以下上下文回答问题,若无法找到答案请回答‘我不知道’。\n""上下文:{context}\n\n问题:{question}") ​ # 构建核心链条:接收问题 -> 检索相关文档 -> 填充提示模板 -> 调用大模型 -> 解析字符串输出 rag_chain =({"context": retriever,"question": RunnablePassthrough()}| prompt | llm | StrOutputParser()) ​ # 执行查询 result = rag_chain.invoke("阿司匹林的禁忌症是什么?")print("AI回答:", result)
  • 功能说明RunnablePassthrough() 的作用是保留用户的原始问题,并将其传递给下一个组件。
  • ✅ 已完成:恭喜!你已经成功用 Langchain 搭建了一个功能完整的 RAG 系统。

四、纯手搓实现:深入理解 RAG 底层机制

现在,让我们放下高级框架,亲手实现一遍 RAG 的核心逻辑,这能帮助你彻底理解它的本质。

4.1 不依赖框架的意义

通过纯手搓实现,你将清晰地看到数据是如何在各个组件间流动的。这对于学习原理、在资源受限的设备上部署,或者进行极致的性能优化都至关重要。

4.2 步骤详解与代码实现

步骤 1:加载并切分文本
# 手动读取文本文件withopen("knowledge.txt","r", encoding="utf-8")as f: text = f.read()# 使用简单的滑动窗口进行切分 chunk_size =500 overlap =50 chunks =[text[i:i + chunk_size]for i inrange(0,len(text), chunk_size - overlap)]print(f"✅ 切分为 {len(chunks)} 个文本块")
  • 功能说明:这是一种最基础的切分方法,通过固定长度和重叠来生成文本块。
  • 缺陷提醒:这种方法缺乏语义感知,可能会在句子中间切断,导致信息丢失。相比之下,Langchain 的递归切分器要智能得多。
步骤 2:调用嵌入模型生成向量
from sentence_transformers import SentenceTransformer import numpy as np # 加载一个轻量级的开源嵌入模型 embedding_model = SentenceTransformer('all-MiniLM-L6-v2')# 将所有文本块批量编码为向量 chunk_vectors = embedding_model.encode(chunks, show_progress_bar=True) dimension = chunk_vectors.shape[1]# 获取向量维度
  • 功能说明SentenceTransformer 库让本地运行嵌入模型变得非常简单。
  • 推荐模型:对于中文场景,强烈推荐使用 BAAI/bge-small-zh 模型,效果远超通用模型。
步骤 3:构建 Faiss 向量索引
在这里插入图片描述
import faiss # 创建一个基于欧氏距离(L2)的索引 index = faiss.IndexFlatL2(dimension)# 将所有文本块的向量添加到索引中 index.add(np.array(chunk_vectors))# 将索引持久化保存,避免每次启动都重新计算 faiss.write_index(index,"faiss_index.bin")
  • 功能说明:Faiss 是一个高效的向量相似度搜索库,特别适合处理大规模向量数据。
  • 性能优化:对于更大的数据集,可以改用 IndexHNSWFlat 等近似最近邻索引,以换取更快的检索速度。
步骤 4:相似度检索
query ="阿司匹林的禁忌症是什么?"# 将查询问题也编码为向量 query_vector = embedding_model.encode([query])# 在向量库中搜索与查询向量最相似的3个结果 distances, indices = index.search(np.array(query_vector), k=3)# 根据检索到的索引,取出对应的文本块 retrieved_chunks =[chunks[i]for i in indices[0]] context ="\n".join(retrieved_chunks)# 将多个相关片段合并为一段上下文
  • 功能说明index.search() 返回的是距离值(越小越相似)和对应的向量索引。
  • 改进建议:在某些场景下,使用余弦相似度比欧氏距离更能反映语义相关性。
步骤 5:拼接 Prompt 并调用 LLM 生成
from transformers import pipeline # 创建一个文本生成管道,这里使用较小的gpt2模型作为示例 generator = pipeline("text-generation", model="gpt2")# 构造增强提示词 prompt =f"根据以下资料回答问题:\n{context}\n\n问题:{query}\n回答:"# 调用模型生成回答 output = generator(prompt, max_new_tokens=150, do_sample=False)# 提取出模型生成的回答部分,去掉前面的提示词 answer = output[0]['generated_text'][len(prompt):].strip()print("AI回答:", answer)
  • 功能说明:这是整个流程的最后一步,也是最关键的一步。大模型基于你提供的上下文来生成最终答案。
  • 注意事项max_new_tokens 参数控制生成的最大长度,避免模型无限制地生成下去。
  • 步骤 1:加载并切分文本
  • 步骤 2:调用嵌入模型生成向量
  • 步骤 3:构建 Faiss 向量索引
  • 步骤 4:相似度检索
  • 步骤 5:拼接 Prompt 并调用 LLM 生成

✅ 纯手搓 RAG 系统已成功运行!

五、环境配置与新手避坑指南

在这里插入图片描述

为了让你的 RAG 之旅更加顺畅,这里有一份详细的避坑指南。

5.1 推荐开发环境

  • Python 版本:强烈推荐使用 3.9 – 3.11 版本。避免使用 3.12 及以上版本,因为其对 typing 模块的修改可能导致 langchain 等库出现 ImportError: cannot import name 'AsyncGenerator' 的错误。
  • 内存要求:建议 ≥16GB。向量计算和模型加载会消耗大量内存。
  • GPU 建议:如果有 NVIDIA 显卡(显存 ≥8GB),可以显著加速嵌入模型和大模型的推理速度。

5.2 虚拟环境与依赖管理

永远不要在全局环境中安装 Python 包!使用虚拟环境可以避免不同项目间的依赖冲突。

# 创建名为 rag_env 的虚拟环境 python -m venv rag_env # 激活虚拟环境 (Linux/Mac) source rag_env/bin/activate # 激活虚拟环境 (Windows) rag_env\Scripts\activate # 安装依赖 pip install langchain sentence-transformers faiss-cpu openai chromadb PyPDF2 

5.3 新手常见问题与解决方案

问题类型表现解决方案
Python 版本冲突ImportError: cannot import name ‘AsyncGenerator’使用 Python 3.9–3.11
API 密钥未设置AuthenticationError检查 .env 文件中的 OPENAI_API_KEY 是否正确
中文路径报错invalid utf-8 sequence将项目放在纯英文路径下,例如 C:\projects\rag_demo
模型下载失败.model.part 残留检查网络连接,或使用代理;也可尝试离线预载模型

5.4 最佳实践建议

  • 使用 .env 文件:管理 API 密钥等敏感信息,保障安全。
  • 合理设置文本块大小:建议在 200–500 字符之间,并启用 50 字符左右的重叠,以保持语义完整。
  • 约束大模型行为:在提示词中明确指令,如“仅基于以上资料回答,不知道就说‘我不知道’”,有效防止幻觉。
  • 生产环境容器化:使用 Docker 打包应用,保证在任何服务器上都能一致运行。

六、总结与学习建议

通过本文的学习,相信你已经掌握了 RAG 系统的核心概念和两种主流实现方式。

  • 初学者建议:优先使用 Langchain 快速搭建原型,体验 RAG 带来的强大能力。
  • 进阶学习:再通过 纯手搓 的方式,亲手实现一遍,从而深刻理解向量检索、嵌入模型等底层机制。
  • 未来探索:当你熟练掌握基础 RAG 后,可以进一步探索 GraphRAG(利用图结构进行复杂推理)或 多模态 RAG(支持图片、音频等非文本信息的检索)等更高级的形态。

七、转载声明

本文为原创文章,如需转载,请联系作者获得授权,并注明出处。

Read more

5个理由告诉你为什么macOS Web是终极网页操作系统模拟器

5个理由告诉你为什么macOS Web是终极网页操作系统模拟器 【免费下载链接】macos-web 项目地址: https://gitcode.com/gh_mirrors/ma/macos-web 想要在浏览器中体验macOS的优雅界面却苦于没有苹果设备?macOS Web正是你需要的解决方案!这个创新的开源项目利用现代Web技术,将macOS Ventura的桌面体验完整地带到网页端。通过Svelte框架和Vite构建工具,macOS Web为用户提供了一个无需安装、跨平台访问的macOS模拟环境,让你在任何设备上都能享受苹果操作系统的魅力。 🚀 什么是macOS Web? macOS Web是一个完全基于Web技术的开源项目,它精准地复制了macOS操作系统的桌面体验。从经典的菜单栏到Dock栏,从Finder窗口到系统偏好设置,每一个细节都经过精心设计和实现。 💡 为什么选择macOS Web? 1. 跨平台兼容性 无论你使用的是Windows、Linux还是ChromeOS,只要有一个现代浏览器,就能立即体验macOS的界面。这种零安装的特性让mac

SDMatte在智能硬件中应用:带屏音箱UI图标透明底图OTA自动更新

SDMatte在智能硬件中应用:带屏音箱UI图标透明底图OTA自动更新 1. 智能硬件UI更新的挑战与机遇 在智能硬件领域,带屏音箱作为家庭交互中心,其UI界面需要频繁更新以保持新鲜感和功能性。传统UI更新方式面临三大痛点: 1. 资源占用大:完整UI包通常包含大量重复背景元素 2. 更新效率低:每次OTA都需要传输整个UI资源包 3. 设计灵活性差:图标与背景耦合度高,难以动态调整 SDMatte提供的透明底图生成能力,为这些挑战提供了创新解决方案。通过将UI元素与背景分离,可以实现: * 图标资源体积减少60%以上 * OTA更新包大小降低40-70% * 动态主题切换无需重新设计整套UI 2. SDMatte技术原理与优势 2.1 核心算法特点 SDMatte采用改进的Matting网络架构,特别针对硬件UI图标的特性进行了优化: 1. 边缘保留增强:对1-3px细线条的保留率提升至92% 2. 色彩保真技术:确保图标主体颜色与原始设计一致 3. 抗锯齿处理:消除透明边缘的锯齿现象 # 典型UI图标处理流程示例 def process_u

情侣飞行棋前端分享源码,已经网络部署可直接免费访问

情侣飞行棋前端分享源码,已经网络部署可直接免费访问

文章目录 * 情侣飞行棋 * 📋 目录 * 🎮 项目介绍 * 核心玩法 * ✨ 功能特点 * 游戏功能 * 视觉体验 * 技术亮点 * 🛠 技术栈 * 📁 文件结构 * 🎯 游戏规则 * 基本规则 * 回合流程 * 📸 界面预览 * 游戏主界面 * 棋子选中效果 * 任务弹窗 * 游戏结束画面 * 🚀 快速开始 * 环境要求 * 启动方式 * 方式一:直接打开(bug) * 方式二:本地服务器(推荐,并不复杂) * 游戏操作 * 🎨 样式亮点 * 棋子视觉效果 * 配色方案 * 响应式设计 * 🔧 扩展指南 * 添加新任务 * 修改棋子图片 * 自定义样式 * 源码分享 * 注意事项 情侣飞行棋 一款基于 Vue 3 和原生 JavaScript 开发的网页版双人飞行棋

5分钟搞定GPT-OSS部署,WEBUI界面太友好了

5分钟搞定GPT-OSS部署,WEBUI界面太友好了 你是不是也试过:下载模型、配环境、改配置、调端口……折腾两小时,连“你好”都没打出来?这次不一样。用 gpt-oss-20b-WEBUI 镜像,真·5分钟完成部署,打开浏览器就能对话——不用写一行代码,不碰终端命令,连显卡型号都不用查,只要你的算力平台支持双卡4090D(vGPU),点几下鼠标,GPT-OSS就坐在你面前等你提问。 这不是Demo,不是简化版,是基于OpenAI最新开源的 GPT-OSS-20B 模型,搭载 vLLM高性能推理引擎,内置完整WebUI交互界面的真实本地大模型服务。它不依赖云端API,不上传数据,不设token限额,更不让你在config.yaml里找错缩进。它就是为你“开箱即用”而生的。 下面我就带你从零开始,手把手走完全部流程。全程截图式描述,每一步都可验证,每一步都有明确反馈。小白放心跟,老手省时间。 1. 先搞清它到底是什么