
RAG 的本质是给大模型“开卷考试”先把你的文档切成小块存进向量库用户提问时检索出最相关的几块连同问题一起交给模型生成答案。下面从零开始用最少的依赖跑通完整流程。第一步理解 RAG 的两个阶段在动手之前先明确你在做什么阶段一离线把你的文档加载 → 切分 → 向量化 → 存入向量数据库。这步只需要跑一次。阶段二在线用户提问 → 把问题向量化 → 在库里搜索最相似的 N 个文本块 → 拼成提示词 → 交给大模型生成答案-1。第二步安装依赖只需要四个核心库。建议用清华镜像加速pip install langchain langchain-openai langchain-community langchain-text-splitters chromadb -i https://pypi.tuna.tsinghua.edu.cn/simple这些库的分工langchain负责串联流程langchain-openai提供嵌入和对话模型接口chromadb是向量数据库langchain-text-splitters负责文档切分-7。第三步准备你的知识库文档创建一个简单的文本文件作为知识库。比如knowledge.txtRAG 是检索增强生成的缩写。 它的核心思想是在回答问题前先从外部知识库检索相关信息。 向量数据库用于存储文本的向量表示。 ChromaDB 是一个轻量级的向量数据库适合本地开发。 嵌入模型负责把文本转换成高维向量。第四步编写完整代码创建一个rag_demo.py文件把下面的代码复制进去。每一步我都加了注释你可以直接运行。import os from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser # 0. 配置 API Key # 你需要一个支持 OpenAI 接口的 API Key # 如果使用阿里云百炼把 base_url 改成 dashscope 的地址 os.environ[OPENAI_API_KEY] 你的 API Key os.environ[OPENAI_BASE_URL] https://api.openai.com/v1 # 或替换为你的代理地址 # 1. 加载文档 loader TextLoader(knowledge.txt, encodingutf-8) docs loader.load() print(f加载了 {len(docs)} 个文档) # 2. 切分文档 # chunk_size200 表示每个文本块约 200 个字符 # chunk_overlap50 表示相邻块之间有 50 字符重叠避免语义断裂 text_splitter RecursiveCharacterTextSplitter( chunk_size200, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) splits text_splitter.split_documents(docs) print(f切分成了 {len(splits)} 个块) for i, split in enumerate(splits): print(f 块 {i}: {split.page_content[:50]}...) # 3. 向量化并存入向量库 # 使用 OpenAI 的嵌入模型将文本块转为向量存入 Chroma embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentssplits, embeddingembeddings, persist_directory./chroma_db # 持久化下次不用重新嵌入 ) print(f向量库构建完成共 {vectorstore._collection.count()} 条向量) # 4. 创建检索器 # 搜索时返回最相似的 2 个文本块 retriever vectorstore.as_retriever(search_kwargs{k: 2}) # 5. 构建 RAG 提示词 # 核心规则只允许基于提供的上下文回答不能编造 prompt_template 仅根据以下提供的上下文回答问题。如果上下文不包含答案请直接说“提供的文档不包含足够的信息来回答此问题”。 上下文 {context} 问题{question} 答案 prompt ChatPromptTemplate.from_template(prompt_template) # 6. 初始化大模型 llm ChatOpenAI(modelgpt-4o-mini, temperature0) # 7. 串联成 RAG 链 def format_docs(docs): return \n\n.join(doc.page_content for doc in docs) rag_chain ( {context: retriever | format_docs, question: RunnablePassthrough()} | prompt | llm | StrOutputParser() ) # 8. 测试 questions [ RAG 是什么, ChromaDB 是什么, 今天天气怎么样 # 这个问题知识库里没有测试模型的边界处理 ] for q in questions: print(f\n问题{q}) answer rag_chain.invoke(q) print(f答案{answer})第五步理解每个关键环节的“为什么”文档切分chunk_size 和 chunk_overlap 怎么定切分是 RAG 中最容易被忽视但影响巨大的环节。块太小检索到的片段缺乏上下文块太大嵌入向量会“稀释”关键信息检索精度下降-3-13。经验起点chunk_size512tokenschunk_overlap10%-15%约 50-80 tokens-8。中文场景下可以先用chunk_size200-300字符因为中文字符的信息密度更高。RecursiveCharacterTextSplitter的聪明之处在于它按优先级尝试分割符先段落、再换行、再句号尽量保证每个块在语义边界处断开-7。嵌入模型选哪个中文场景首选bge-large-zh-v1.5它在 MTEB 中文榜单上表现最好开源可本地部署1024 维的向量维度是性价比最优的选择-4-9。如果追求便捷text-embedding-3-small的 1536 维英文效果够用成本也低-4。关键认知Embedding 模型决定了检索的“天花板”。换一个更好的嵌入模型往往是投入产出比最高的优化手段-9。提示词防止幻觉的核心规则RAG 提示词必须包含基础约束明确声明模型只能使用提供的上下文并定义“不知道”时的回退行为-5。上面的模板用了最直接的表达“仅根据以下提供的上下文回答问题。如果上下文不包含答案请直接说……”这种命令式语言比“可以考虑使用上下文”有效得多-10。第六步跑起来然后观察输出运行python rag_demo.py。你应该看到切分结果5 句话被切成了 3-5 个块取决于你的文本长度和分割符前两个问题模型从知识库中检索到了相关片段并给出了正确答案第三个问题“今天天气怎么样”模型应该返回“不包含足够的信息”而不是编造天气如果第三个问题模型还是编造了答案说明提示词约束不够强。把“如果上下文不包含答案”改成“禁止使用你训练数据中的任何信息”再试-5。下一步可以做什么跑通这个 Demo 后你可以按需扩展支持 PDF/网页把TextLoader换成PyPDFLoader或WebBaseLoader换向量库Chroma 适合本地FAISS 更快Milvus/Weaviate 适合生产增加对话记忆让模型能理解“他/她/它”指代的是谁-2加 Reranker先用向量检索召回 10 条再用交叉编码器精排能显著提升第一屏答案的质量-9但不要一开始就搞这些。先把最小闭环跑通确认检索到的内容确实和问题相关再逐步优化。