ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【三个月 AI Agent 实战学习】Day 18:简单的 RAG 实现 —— 本地文档问答机器人

【三个月 AI Agent 实战学习】Day 18:简单的 RAG 实现 —— 本地文档问答机器人 Day 18简单的 RAG 实现 —— 本地文档问答机器人欢迎来到第十八天今天我们将把昨天学习的 Embedding 和向量相似度知识付诸实践使用 LangChain 构建一个完整的本地文档问答机器人。这是 RAG 的最简实现读取几个本地文本文件将其切分成小块存入向量数据库然后根据用户问题检索相关片段并让大模型基于这些片段生成回答。完成这个项目后你将掌握 RAG 的基本流程并为后续构建更复杂的记忆系统打下基础。一、今日学习目标掌握使用 LangChain 的TextLoader加载本地文本文件。学会使用RecursiveCharacterTextSplitter对长文档进行切分。使用Chroma作为本地向量数据库存储文档片段的 Embedding。实现一个完整的 RAG 问答链问题 → 检索 → 拼接上下文 → 生成回答。理解 RAG 与直接 LLM 问答的区别RAG 能基于外部知识回答减少幻觉。二、详细实现步骤步骤 1安装必要的库我们需要安装langchain、langchain-community用于文档加载器、langchain-openai用于 ChatOpenAI 和 Embeddings、chromadb向量数据库以及tiktoken用于 Token 计算可选。如果尚未安装执行pipinstalllangchain langchain-community langchain-openai chromadb步骤 2准备本地文档在你的项目目录下创建一个文件夹例如docs/并在其中放入几个文本文件.txt。内容可以是你感兴趣的任何主题比如人工智能、历史、科技等。为了演示我们创建两个文件docs/ai_intro.txt关于人工智能的简单介绍。docs/ai_ethics.txt关于人工智能伦理的内容。你可以复制一些百科内容或自己编写几段话。确保文件编码为 UTF-8。步骤 3加载文档并切分使用 LangChain 的TextLoader加载docs/目录下的所有文本文件然后使用RecursiveCharacterTextSplitter将文档切分成适当大小的块。新建simple_rag.pyimportosfromdotenvimportload_dotenvfromlangchain_community.document_loadersimportTextLoader,DirectoryLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitter load_dotenv()# 加载 docs 目录下的所有 .txt 文件loaderDirectoryLoader(docs,glob**/*.txt,loader_clsTextLoader,encodingutf-8)documentsloader.load()print(f加载了{len(documents)}个文档)# 文本切分每个块约 500 字符重叠 100 字符text_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap100,separators[\n\n,\n,。,,,, ,])chunkstext_splitter.split_documents(documents)print(f切分为{len(chunks)}个块)注意DirectoryLoader可以批量加载目录中的文件glob参数指定匹配模式。TextLoader需要指定编码否则 Windows 下可能乱码。步骤 4创建向量存储Chroma我们需要一个 Embedding 模型将文本块转换为向量并存入 Chroma 向量数据库。由于 DeepSeek 不提供 Embedding API我们使用智谱 AI 的 Embeddingembedding-2它兼容 OpenAI 格式。在 LangChain 中我们可以使用OpenAIEmbeddings并指定base_url和api_key来适配智谱。fromlangchain_openaiimportOpenAIEmbeddingsfromlangchain_community.vectorstoresimportChroma# 初始化智谱 EmbeddingembeddingsOpenAIEmbeddings(modelembedding-2,api_keyos.getenv(ZHIPU_API_KEY),base_urlhttps://open.bigmodel.cn/api/paas/v4)# 创建向量存储将文本块写入 ChromavectorstoreChroma.from_documents(documentschunks,embeddingembeddings,persist_directory./chroma_db# 持久化目录下次可直接加载)print(向量存储已创建)Chroma 默认会将数据保存在内存中但通过persist_directory可以保存到磁盘避免重复计算 Embedding。下次加载时可以使用Chroma(persist_directory..., embedding_function...)直接加载。步骤 5构建检索器向量存储提供了as_retriever()方法返回一个检索器对象可以根据查询返回最相关的文档片段。retrievervectorstore.as_retriever(search_kwargs{k:3})# 返回最相关的 3 个块步骤 6初始化 LLM 并构建 RAG 链我们将使用 LangChain 的RetrievalQA链或更现代的 LCEL 表达式来构建 RAG 管道。这里展示两种方式方式一使用RetrievalQA简单封装fromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQA llmChatOpenAI(modeldeepseek-chat,api_keyos.getenv(DEEPSEEK_API_KEY),base_urlhttps://api.deepseek.com,temperature0.3)qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,# 将所有检索到的文档拼接到 prompt 中retrieverretriever,return_source_documentsTrue# 返回来源文档便于调试)# 测试query人工智能伦理主要涉及哪些问题resultqa_chain.invoke({query:query})print(回答,result[result])print(来源片段,result[source_documents])方式二使用 LCEL 自定义 RAG 链更灵活fromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnablePassthroughfromlangchain_core.output_parsersimportStrOutputParser# 定义 prompttemplate请根据以下上下文回答问题。如果无法从上下文中找到答案请说“我不知道”。 上下文 {context} 问题{question} 回答promptChatPromptTemplate.from_template(template)# 构建链defformat_docs(docs):return\n\n.join(doc.page_contentfordocindocs)rag_chain({context:retriever|format_docs,question:RunnablePassthrough()}|prompt|llm|StrOutputParser())# 测试answerrag_chain.invoke(query)print(回答,answer)LCEL 方式更透明我们可以自行控制格式化、拼接等逻辑。推荐使用这种方式以便后续扩展。步骤 7运行并测试运行simple_rag.py观察输出。你可以问不同的问题检验检索效果和生成质量。例如“什么是人工智能”“人工智能在医疗领域有哪些应用”“人工智能伦理中算法偏见是怎么产生的”对于知识库中没有的内容模型应该回答“我不知道”从而体现 RAG 的诚实性。三、常见问题与调试Q1加载文档时出现UnicodeDecodeError。→ 在TextLoader中明确指定encodingutf-8。如果文件不是 UTF-8可以尝试gbk等。Q2Chroma 向量数据库保存后下次加载时报错。→ 确保persist_directory路径正确并且加载时使用相同的embedding_function。例如vectorstoreChroma(persist_directory./chroma_db,embedding_functionembeddings)Q3检索结果不相关或质量差。→ 可能原因文档切分不合理尝试调整chunk_size和chunk_overlap。Embedding 模型不适合中文智谱embedding-2对中文支持较好但也可以尝试其他模型。缺少元数据可以在加载文档时添加标题等元数据帮助检索。Q4模型回答时忽略了上下文直接凭记忆回答。→ 在 Prompt 中强调“只根据上下文回答”并降低 temperature。如果仍然如此可以检查检索是否返回了相关片段。Q5如何处理 PDF 或 Word 文档→ 使用相应的加载器PyPDFLoader、Docx2txtLoader等。安装额外的依赖如pypdf、docx2txt后替换TextLoader即可。Q6向量数据库选择 Chroma 还是 FAISS→ Chroma 易于使用支持持久化适合原型开发FAISS 性能更高适合大规模数据。今天选用 Chroma 是因为它开箱即用。四、今日总结与作业今天你完成了✅ 使用 LangChain 加载了本地文本文件并进行了切分。✅ 使用智谱 Embedding 和 Chroma 构建了向量存储。✅ 实现了完整的 RAG 问答链并能返回来源文档。✅ 通过实际测试体会了 RAG 如何让模型基于外部知识回答。今日作业必做在docs/目录下添加至少 5 个不同主题的文本文件每个 200-500 字重新运行 RAG 问答测试 5 个不同问题记录回答质量和检索准确度。将chunk_size分别设置为 200、800、1500对比检索效果和生成回答的质量选择一个你认为最佳的设置并说明理由。修改 Prompt让模型在回答时同时给出引用来源例如标明“根据文档 1 和文档 2”并测试效果。思考题RAG 中的检索器如何与后续的 Agent 记忆模块结合请用 100 字以内描述你的设想。明日预告我们将继续 LangChain 的学习实现第一个真正的 Agent——使用create_react_agent创建一个带工具的数学专家。你将亲眼看到 ReAct 循环是如何工作的。有任何问题欢迎随时提问
返回列表