【由浅入深探究langchain】第十七集-构建你的首个 RAG 知识库助手(从文档索引到检索增强生成)
前言在大语言模型LLM爆火的今天我们常常会被 GPT 或 Claude 展现出的博学所惊叹。然而当你试着问它“我公司昨晚新发布的财务报表数据是多少”或者“我上周在笔记里写的某个私人计划是什么”时LLM 往往会陷入尴尬的沉默甚至开始一本正经地胡说八道。这种现象被称为模型幻觉Hallucination。究其原因是因为 LLM 的知识库被“冻结”在了训练数据结束的那一刻Knowledge Cut-off它并不具备实时获取外部私有数据的能力。为了填补这一鸿沟RAGRetrieval-Augmented Generation检索增强生成应运而生。简单来说RAG 就像是给大模型配了一本“实时查阅的字典”或“私人图书馆”打破知识边界让模型能够访问实时新闻、企业内网文档或个人笔记。降低幻觉风险强制模型根据检索到的“事实依据”来回答问题知之为知之不知则引用原文。数据隐私保护无需将私有数据送去重新训练模型只需在本地或私有云构建索引即可。具体介绍可以查看前几集的博文。接下来的内容中我将结合实际代码带大家拆解 RAG 的两大核心流程索引阶段和检索生成阶段核心架构RAG 的双螺旋结构Indexing索引阶段 数据如何变成向量并入库。Generation生成阶段 用户提问后如何检索并合成回答。第一阶段建立索引 (Indexing Pipeline)索引阶段的目标是将凌乱的非结构化数据如网页、PDF、文档转化为 LLM 可以理解并快速检索的结构化向量数据。正好最近DOTA2这款游戏更新了新的版本文本内容高达十几万字而大模型不联网搜索的话肯定还没有预训练这部分内容我们就把它拿来做演示。数据加载在代码中我通过设置os.environ[USER_AGENT]和header_template模拟了真实的浏览器行为并利用urllib3.disable_warnings绕过了部分站点的 SSL 验证确保能够稳定抓取数据。虽然我暂时注释掉了bs_kwargs过滤器但在实际应用中利用SoupStrainer针对性地抓取 HTML 中的div.article-content是过滤网页广告、导航栏噪音的关键。page_url https://www.dota2.com.cn/article/details/20260325/220462.html bs4_strainer bs4.SoupStrainer() # 修改 Loader 部分 loader WebBaseLoader( web_paths(page_url,), header_template{User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0}, verify_sslFalse, # 先注释掉特定的过滤器抓取全文看看 # bs_kwargs{parse_only: bs4.SoupStrainer(div, class_article-content)} ) docs loader.load() print(f1. 原始文档数量: {len(docs)}) if len(docs) 0: print(f2. 原始内容预览 (前100字): {docs[0].page_content[:100].strip()}) else: print(错误未能抓取到任何内容请检查 URL 是否有效。) docs loader.load()文本分割text_splitter RecursiveCharacterTextSplitter( chunk_size 300, #每块token/chunk size越小块越多 chunk_overlap 50, #重叠部分 add_start_index True ) all_splitstext_splitter.split_documents(docs)向量化与本地存储embeding OllamaEmbeddings(modelnomic-embed-text:v1.5) from langchain_chroma import Chroma vector_storeChroma( collection_namedota2, embedding_functionembeding, persist_directory./chroma_dota2_db ) ids vector_store.add_documents(documentsall_splits)完整代码如下from langchain_community.document_loaders import WebBaseLoader from langchain_ollama import OllamaEmbeddings from langchain_text_splitters import RecursiveCharacterTextSplitter import bs4 import os import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) os.environ[USER_AGENT] Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 page_url https://www.dota2.com.cn/article/details/20260325/220462.html bs4_strainer bs4.SoupStrainer() # 修改 Loader 部分 loader WebBaseLoader( web_paths(page_url,), header_template{User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0}, verify_sslFalse ) docs loader.load() print(f1. 原始文档数量: {len(docs)}) if len(docs) 0: print(f2. 原始内容预览 (前100字): {docs[0].page_content[:100].strip()}) else: print(错误未能抓取到任何内容请检查 URL 是否有效。) docs loader.load() # print(len(docs)) # 分割文本 text_splitter RecursiveCharacterTextSplitter( chunk_size 300, #每块token/chunk size越小块越多 chunk_overlap 50, #重叠部分 add_start_index True ) all_splitstext_splitter.split_documents(docs) # 向量库存储 embeding OllamaEmbeddings(modelnomic-embed-text:v1.5) from langchain_chroma import Chroma vector_storeChroma( collection_namedota2, embedding_functionembeding, persist_directory./chroma_dota2_db ) ids vector_store.add_documents(documentsall_splits) #add同步 aadd异步当看到项目路径下出现这个chroma_dota2_db说明已经完成的索引的建立第二阶段检索与增强生成 (Retrieval Generation)如果说索引阶段是“存书”那么生成阶段就是“看书考试”。在这一部分我采用了一种比传统 RAG 更灵活的架构基于 Agent 的动态检索。核心利器Tool-Calling (工具调用)传统的 RAG 通常是“先检索、后回答”的线性流程。但在我的代码中我将检索逻辑封装成了一个自定义工具tool这种做法的巧妙之处在于模型Kimi不再是被动接受上下文而是主动思考。如果它判断用户的问题需要外部知识如 DOTA2 魔方的数值改动它会主动调用这个工具去数据库中抓取最相关的 3 条内容。在retrieve_context中我不仅返回了拼接好的字符串还利用了response_formatcontent_and_artifact。这意味着模型在理解内容的同时程序依然能追踪到这些信息是从哪个 URL、哪一页读到的极大地增强了系统的可解释性。tool(response_formatcontent_and_artifact) def retrieve_context(query:str): Retrieve information to help answer a query # 相似度搜索逻辑 retrieve_docs vector_store.similarity_search(query, k3) # ... 格式化输出 ...智能体驱动create_agent通过create_agent我们将模型、工具箱和系统指令绑定在一起。当用户询问“魔方的数值改动”时Agent 会经历接收问题 - 识别意图 - 决定调用检索工具 - 获取 DOTA2 官网数据 - 总结回答这一完整闭环。agent create_agent( modelkimi_model, tools[retrieve_context], system_promptSYSTEM_PROMPT )完整代码from langchain.agents import create_agent from langchain_openai import ChatOpenAI from langchain_ollama import OllamaEmbeddings from langchain_chroma import Chroma from langchain.tools import tool #嵌入模型 embeding OllamaEmbeddings(modelnomic-embed-text:v1.5) #向量库 vector_storeChroma( collection_namedota2, embedding_functionembeding, persist_directory./chroma_dota2_db ) SYSTEM_PROMPT 你可以使用信息检索工具回答用户问题。 tool(response_formatcontent_and_artifact) def retrieve_context(query:str): Retrive information to help answer a query retrieve_docs vector_store.similarity_search(query,k3) content \n\n.join( (fSource:{doc.metadata}\nContent:{doc.page_content}) for doc in retrieve_docs ) return content,retrieve_docs kimi_model ChatOpenAI( modelkimi-k2.5, api_keysk-uQp****, base_urlhttps://api.moonshot.cn/v1, # 重点这里严格对应 Kimi 的 API 结构 extra_body{ thinking: {type: disabled} } ) agent create_agent( modelkimi_model, tools[retrieve_context], system_promptSYSTEM_PROMPT ) results agent.invoke( {messages:[{role:user,content:请告诉我魔方的数值改动?}]} ) messages results[messages] for message in messages : message.pretty_print()效果演示符合官网更新内容中的数据这个运行结果清晰地展示了一个ReActReasoning and Acting模式的智能体是如何工作的Kimi 模型先“思考”需要查资料发起tool_call拿到本地向量库的内容后再进行归纳总结。根据打印输出我们可以将整个黑盒过程拆解为以下 6 步意图识别 (Reasoning)当你输入“请告诉我魔方的数值改动?”时Kimi 模型并没有立即搜索脑海中的旧知识而是识别出这个问题涉及具体的、实时的游戏数值。触发工具 (Action)模型决定调用retrieve_context工具。你会看到日志中出现了Tool Calls这说明 Agent 已经把自然语言转化为了函数调用的参数query: 魔方的数值改动。向量检索 (Retrieval)Python 脚本执行vector_store.similarity_search。由于我们之前建立过索引系统会在本地chroma_dota2_db中寻找与“魔方”向量最接近的 3 个文本块Chunks。知识喂回 (Observation)检索到的原文Source 和 Content被拼接成字符串作为Tool Message返回给 Kimi。这就是你看到的Name: retrieve_context后面那一长串 DOTA2 官网内容。二次推理 (Summarization)Kimi 拿到检索回来的“参考资料”结合最初的问题进行信息提取。它过滤掉了无关的网页导航信息精准锁定了“25%状态抗性”等关键数值。结果输出 (Final Answer)最终Agent 以排版精美的 Markdown 格式回答了你的问题。总结通过这次实战我们深刻体会到RAG 的核心不在于 LLM 本身有多强而在于‘检索质量’和‘Agent 的调度’。当我们利用本地 Embedding 保证了隐私和速度再利用云端大模型保证了逻辑和文笔一个真正实用、专业的 AI 助手才算真正成型。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2462473.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!