LangChain 入门学习第四篇-基于本地 Markdown 的 RAG 问答

💡 原文中文,约3400字,阅读约需8分钟。
📝

内容提要

本文介绍了一个基于本地Markdown文件的最小RAG(检索增强生成)问答系统实现。系统通过读取Hugo博客文章、去除front matter、切分文本,利用关键词检索相关片段,并组装Prompt让模型基于上下文回答。代码结构包括配置、模型、文档加载和检索问答模块。该方法不依赖向量数据库,逻辑透明,适合理解RAG基本流程,但存在关键词匹配敏感、无索引持久化等限制,后续将逐步优化。

🔎

延伸解读

为何先不用向量检索

本文刻意不引入向量数据库和 embedding 模型,而是用关键词匹配跑通 RAG 流程。这样做的目的是让读者先看清 RAG 的核心链路:检索资料、构造上下文、约束模型回答。关键词检索虽然简单,但逻辑透明、易于调试,能直观看到检索结果对最终回答的影响,为后续引入更复杂的检索方式打下基础。

元数据在 RAG 中的重要性

代码在将文章转换为 Document 时,不仅保存了正文,还保留了来源路径和标题等元数据。这提醒我们,RAG 不只是把文本喂给模型,还要保留来源信息,否则模型回答后无法追溯答案出处。在真实应用中,元数据还能用于过滤、排序和引用,是构建可靠问答系统不可忽视的一环。

提示词对 RAG 效果的约束

本文的 system prompt 明确要求模型只根据给定上下文回答,上下文不足时需说明。这体现了 RAG 中提示词设计的关键作用:即使检索结果相关,如果提示词不加以约束,模型仍可能自由发挥。因此,RAG 的效果不仅取决于检索质量,也取决于提示词能否有效限制模型的输出范围。

当前实现的局限与改进方向

作者坦诚指出当前版本存在关键词匹配敏感、中文分词简单、无索引持久化等局限。这些限制会导致用户提问与文章用词不一致时检索不到,且每次运行都需重新读取文章。文章预告了后续改进:第五篇引入向量检索,第六篇持久化索引,第七篇调优检索质量,为读者指明了学习路径。

Q&A

什么是RAG?

RAG全称是Retrieval-Augmented Generation,即检索增强生成。它不是让大模型凭空回答,而是先从本地资料中检索相关内容,再将这些内容作为上下文交给模型,让模型基于这些上下文进行回答。

如何实现一个不依赖向量数据库的RAG系统?

可以通过关键词检索实现。具体步骤包括:读取本地Markdown文章,去除front matter,切分文本为小块,然后根据用户问题中的关键词对每个块进行打分(标题权重更高),选出相关片段,最后组装成Prompt交给模型回答。

在RAG中,为什么需要保留文档的metadata?

因为RAG不仅要给模型提供文本内容,还要保留来源信息。这样模型回答后,可以知道答案来自哪篇文章,便于追溯和引用。

RAG中文本切分的chunk_size和chunk_overlap参数有什么作用?

chunk_size控制每个片段的大致长度,chunk_overlap保留片段之间的重叠,避免一句话被切断后上下文丢失。

在RAG的Prompt设计中,system prompt应该包含什么关键指令?

system prompt应该明确告诉模型只能根据给定上下文回答,如果上下文不足,就说明没有找到足够信息,不要硬编。这样可以约束模型基于检索到的内容回答,提高回答的准确性。

基于关键词检索的RAG有哪些局限性?

局限性包括:对表达方式敏感,用户问题和文章用词不一致时可能检索不到;中文分词只是简单切片,不适合复杂搜索场景;没有保存索引,每次运行都重新读取文章。

如何运行这个RAG demo?

在code/langchain-demo目录下运行命令:uv run python -m chapter04.simple_rag "Python 函数式编程讲了什么?"。如果当前shell有其他项目设置的PYTHONPATH,可以运行:env -u PYTHONPATH .venv/bin/python -m chapter04.simple_rag "Python 函数式编程讲了什么?"。

🏷️

标签

➡️

继续阅读