RAG学习-基于 LangChain 框架的 RAG 实现
第三节、四步构建RAG一、启动虚拟环境conda activate all-in-rag# 假设当前在 all-in-rag 项目的根目录下cdcode/C1二、运行RAG示例代码python 01_langchain_example.py代码运行后可以看到类似下面的输出格式化后Downloading Model from https://www.modelscope.cn to directory: Path\to\all-in-rag\models\bge-small-zh-v1.52025-06-08 02:36:19,318 - modelscope - INFO - Target directory already exists, skipping creation.content 文中举了以下例子 1. **自然界中的羚羊**刚出生的羚羊通过试错学习站立和奔跑适应环境。 2. **股票交易**通过买卖股票并根据市场反馈调整策略最大化奖励。 3. **雅达利游戏如Breakout和Pong**通过不断试错学习如何通关或赢得游戏。 4. **选择餐馆**利用去已知喜欢的餐馆与探索尝试新餐馆的权衡。 5. **做广告**利用采取已知最优广告策略与探索尝试新广告策略。 6. **挖油**利用在已知地点挖油与探索在新地点挖油可能发现大油田。 7. **玩游戏如《街头霸王》**利用固定策略如蹲角落出脚与探索尝试新招式如“大招”。 这些例子用于说明强化学习中的核心概念如探索与利用、延迟奖励等及其在实际场景中的应用。 additional_kwargs{refusal:None}response_metadata{token_usage:{completion_tokens:209,prompt_tokens:5576,total_tokens:5785,completion_tokens_details:None,prompt_tokens_details:{audio_tokens:None,cached_tokens:5568},prompt_cache_hit_tokens:5568,prompt_cache_miss_tokens:8},model_name:deepseek-chat,system_fingerprint:fp_8802369eaa_prod0425fp8,id:67a0580d-78b1-44d6-bccf-f654ae0e9bba,service_tier:None,finish_reason:stop,logprobs:None}idrun--919cedcd-771e-4aed-8dfd-cf436795792e-0usage_metadata{input_tokens:5576,output_tokens:209,total_tokens:5785,input_token_details:{cache_read:5568},output_token_details:{}}输出参数解析content: 这是最核心的部分即大型语言模型LLM根据你的问题和提供的上下文生成的具体回答。additional_kwargs: 包含一些额外的参数在这个例子中是{refusal: None}表示模型没有拒绝回答。response_metadata包含了关于LLM响应的元数据。token_usage: 显示了本次调用消耗的token数量包括完成completion_tokens、提示prompt_tokens和总量total_tokens。model_name: 使用的LLM模型名称当前是deepseek-chat。system_fingerprint,id,service_tier,finish_reason,logprobs: 这些是更详细的API响应信息例如finish_reason: stop表示模型正常完成了生成。id: 本次运行的唯一标识符。usage_metadata: 与response_metadata中的token_usage类似提供了输入和输出token的统计。一句话总结这是一个最简 RAG检索增强生成流程加载本地 Markdown 文档 → 分块 → 向量化 → 检索 → 交给 LLM 生成回答用 LangChain 框架实现。三、基于LangChain框架的RAG实现3.1 初始化设置首先进行基础配置包括导入必要的库、加载环境变量以及下载嵌入模型。importos# os.environ[HF_ENDPOINT] https://hf-mirror.comfromdotenvimportload_dotenvfromlangchain_community.document_loadersimportTextLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_huggingfaceimportHuggingFaceEmbeddingsfromlangchain_core.vectorstoresimportInMemoryVectorStorefromlangchain_core.promptsimportChatPromptTemplatefromlangchain_deepseekimportChatOpenAI# 加载环境变量load_dotenv()3.2数据准备加载原始文档: 先定义Markdown文件的路径然后使用TextLoader加载该文件作为知识源。markdown_path../../data/C1/markdown/easy-rl-chapter1.mdloaderTextLoader(markdown_path)docsloader.load()文本分块 (Chunking): 为了便于后续的嵌入和检索长文档被分割成较小的、可管理的文本块chunks。这里采用了递归字符分割策略使用其默认参数进行分块。当不指定参数初始化RecursiveCharacterTextSplitter()时其默认行为旨在最大程度保留文本的语义结构默认分隔符与语义保留: 按顺序尝试使用一系列预设的分隔符[\n\n (段落), \n (行), (空格), (字符)]来递归分割文本。这种策略的目的是尽可能保持段落、句子和单词的完整性因为它们通常是语义上最相关的文本单元直到文本块达到目标大小。保留分隔符: 默认情况下 (keep_separatorTrue)分隔符本身会被保留在分割后的文本块中。默认块大小与重叠: 使用其基类TextSplitter中定义的默认参数chunk_size4000块大小和chunk_overlap200块重叠。这些参数确保文本块符合预定的大小限制并通过重叠来减少上下文信息的丢失。text_splitterRecursiveCharacterTextSplitter()textstext_splitter.split_documents(docs)3.3索引构建数据准备完成后接下来构建向量索引初始化中文嵌入模型: 使用HuggingFaceEmbeddings加载之前在初始化设置中下载的中文嵌入模型。配置模型在CPU上运行并启用嵌入归一化 (normalize_embeddings: True)。embeddingsHuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5,model_kwargs{device:cpu},encode_kwargs{normalize_embeddings:True})构建向量存储: 将分割后的文本块 (texts) 通过初始化好的嵌入模型转换为向量表示然后使用InMemoryVectorStore将这些向量及其对应的原始文本内容添加进去从而在内存中构建出一个向量索引。vectorstoreInMemoryVectorStore(embeddings)vectorstore.add_documents(texts)这个过程完成后便构建了一个可供查询的知识索引。3.4查询与检索索引构建完毕后便可以针对用户问题进行查询与检索定义用户查询: 设置一个具体的用户问题字符串。question文中举了哪些例子在向量存储中查询相关文档: 使用向量存储的similarity_search方法根据用户问题在索引中查找最相关的k(此处示例中k3) 个文本块。retrieved_docsvectorstore.similarity_search(question,k3)准备上下文: 将检索到的多个文本块的页面内容 (doc.page_content) 合并成一个单一的字符串并使用双换行符 (\n\n) 分隔各个块形成最终的上下文信息 (docs_content) 供大语言模型参考。docs_content\n\n.join(doc.page_contentfordocinretrieved_docs)3.5生成集合最后一步是将检索到的上下文与用户问题结合利用大语言模型LLM生成答案构建提示词模板: 使用ChatPromptTemplate.from_template创建一个结构化的提示模板。此模板指导LLM根据提供的上下文 (context) 回答用户的问题 (question)并明确指出在信息不足时应如何回应。promptChatPromptTemplate.from_template(请根据下面提供的上下文信息来回答问题。 请确保你的回答完全基于这些上下文。 如果上下文中没有足够的信息来回答问题请直接告知“抱歉我无法根据提供的上下文找到相关信息来回答此问题。” 上下文: {context} 问题: {question} 回答:)配置大语言模型: 初始化ChatOpenAI客户端配置所用模型glm-4.7-flash-free、生成答案的温度参数temperature0.7、最大Token数 (max_tokens2048) 以及API密钥从环境变量加载和 url。llmChatOpenAI(modelglm-4.7-flash-free,temperature0.7,max_tokens2048,api_keyos.getenv(DEEPSEEK_API_KEY)base_urlhttps://aihubmix.com/v1)调用LLM生成答案并输出: 将用户问题 (question) 和先前准备好的上下文 (docs_content) 格式化到提示模板中然后调用ChatDeepSeek的invoke方法获取生成的答案。answerllm.invoke(prompt.format(questionquestion,contextdocs_content))print(answer)这是一个 Naive RAG 的最小化实现对应 C1 RAG 入门章节使用 LangChain 框架 完整演示了 RAG 的核心流程加载 → 分块 → 嵌入 → 检索 → 生成。逐段功能解析环境准备与导入第1-12行from dotenv import load_dotenvfrom langchain_community.document_loaders import UnstructuredMarkdownLoaderload_dotenv()加载 .env 文件虽然此脚本实际未使用环境变量中的 key引入 LangChain 生态的 6 个核心组件覆盖整个 RAG 流水线文档加载第14-18行markdown_path “…/…/data/C1/markdown/easy-rl-chapter1.md”loader UnstructuredMarkdownLoader(markdown_path)docs loader.load()从项目共享数据目录加载一个 Markdown 文件强化学习教材第一章注意路径 …/…/data/ 是相对路径脚本必须从 code/C1/ 目录运行否则路径错误常见踩坑点文本分块第20-22行text_splitter RecursiveCharacterTextSplitter()chunks text_splitter.split_documents(docs)使用 RecursiveCharacterTextSplitter 将长文档切分成小块默认参数chunk_size1000, chunk_overlap200这是 C2 数据准备 中详细讲解的技术决定了后续检索的粒度中文嵌入模型第24-29行embeddings HuggingFaceEmbeddings(model_name“BAAI/bge-small-zh-v1.5”,model_kwargs{‘device’: ‘cpu’},encode_kwargs{‘normalize_embeddings’: True})加载本项目默认的中文嵌入模型 BAAI/bge-small-zh-v1.5512维CPU推理normalize_embeddingsTrue 启用归一化使余弦相似度等价于内积向量存储第31-33行vectorstore InMemoryVectorStore(embeddings)vectorstore.add_documents(chunks)使用 InMemoryVectorStore内存向量存储适合学习演示生产环境会替换为 FAISS / Chroma / Milvus见 C3 向量数据库章节提示词模板第35-46行prompt ChatPromptTemplate.from_template(“”“请根据下面提供的上下文信息来回答问题。…”“”)构建约束性指令强制 LLM 只基于检索到的上下文回答包含容错机制当上下文不足时LLM 被告知直接说找不到相关信息模板变量{context}检索结果和 {question}用户问题LLM 配置第49-66行llm ChatOpenAI(model“gpt-5.5-free”,api_key“sk-…”,base_url“https://aihubmix.com/v1”)执行查询第68-75行retrieved_docs vectorstore.similarity_search(question, k3)answer llm.invoke(prompt.format(questionquestion, contextdocs_content))print(answer)similarity_search(question, k3)检索与问题最相似的 3 个文档块将检索到的文档拼接为 docs_content填入提示模板调用 LLM 生成最终答案并打印整体流程图Markdown文件 → UnstructuredMarkdownLoader → RecursiveCharacterTextSplitter↓文档块 (chunks)↓HuggingFaceEmbeddings(bge-small-zh-v1.5)↓┌──────────────── InMemoryVectorStore ────────────────┐│ 添加文档块构建向量索引 │└────────────────────┬────────────────────────────────┘↓用户问题 ──────→ similarity_search(k3) ──→ 检索到3个相关块↓拼接 context question 填入模板↓ChatOpenAI(gpt-5.5-free) 生成回答↓打印答案附虚拟环境安装一、powershell-ExecutionPolicyByPass-cirm https://astral.sh/uv/install.ps1 | iex二、安装成功后按照提示输入以下命令添加环境变量。这里注意不同的人的安装路径不同请按照提示自行复制粘贴命令。$env:PathC:\Users\michaelbradley\.local\bin;$env:Path三、uv venv rag--python3.12.7四、rag\Scripts\activate

相关新闻