news 2026/9/23 23:40:12

all-in-rag 实战解析:从“太阳蛋“食谱看 RAG 知识库的构建与智能问答全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
all-in-rag 实战解析:从“太阳蛋“食谱看 RAG 知识库的构建与智能问答全流程

all-in-rag 实战解析:从"太阳蛋"食谱看 RAG 知识库的构建与智能问答全流程

【免费下载链接】all-in-rag🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/项目地址: https://gitcode.com/datawhalechina/all-in-rag

本篇文章以 all-in-rag 仓库 C8 食谱 RAG 系统知识库中的一份真实数据源——太阳蛋.md——为主线,完整复现其食谱内容,并深入剖析这份 Markdown 文档在 code/C8 完整 RAG 流水线中"如何被加载、如何被元数据增强、如何被结构分块、如何被检索、如何被生成回答"的全过程。读完本文,你既能照做一份零失败的微波炉太阳蛋,也能掌握一套可直接复用的"Markdown 结构化知识库 → 向量索引 → 混合检索 → 多模式生成"的 RAG 工程实现。


一、太阳蛋食谱:一份典型的 Markdown 结构化数据源

在 all-in-rag 的 C8 食谱 RAG 系统中,data/C8/cook 是整个知识库的原始数据目录,按分类/菜品/的目录层级组织(如breakfast/太阳蛋.mdmeat_dish/红烧肉.md)。太阳蛋.md 就是其中一份标准的"早餐"分类食谱,其内容结构完整、难度标识规范,非常适合作为理解 RAG 数据准备的样例。原文内容如下:

1.1 必备原料和工具

  • 鸡蛋
  • 分可控火候微波炉或不可控火候微波炉(定义和分辨方式请见附加内容)
  • 筷子或牙签

1.2 用量计算

  • 鸡蛋的用量为 1 个。
  • 盐的用量为 1 g 每个鸡蛋。
  • 油的用量为 5 mL 每个鸡蛋。

使用上述条件,计算出计划使用的原材料比例(即按份数线性缩放即可:做 N 份,则鸡蛋 N 个、盐 N g、油 5N mL)。

1.3 操作步骤

可控火候微波炉:

  • 准备一个小碗,倒入在上一步计算好的油,撒盐,搅拌均匀。倾斜碗使油沾在碗表面。
  • 取出一个鸡蛋,打入小碗。
  • 蛋黄表面戳孔。牙签戳 5 个或筷子戳 1 个。
  • 放入微波炉,中火 3 分钟。

不可控火候微波炉:

  • 准备一个小碗,倒入在上一步计算好的油,撒盐,搅拌均匀。倾斜碗使油沾在碗表面。
  • 取出一个鸡蛋,打入小碗。
  • 蛋黄表面戳孔。牙签戳 5 个或筷子戳 1 个。
  • 放入微波炉,1 分钟。
  • 循环执行:只要太阳蛋还未大面积呈固体状,就继续用微波炉加热 30 秒。

1.4 附加内容

循环执行:只要太阳蛋的熟度不符合个人口味,就继续用微波炉加热 1 分钟。

  • 不可控火候微波炉
    • 定义:即无法控制火候、仅能控制时长的微波炉。
    • 辨别方法:若在微波炉操作面板上无法找到小火、中火、大火等字样,即为不可控火候微波炉。
  • 可控火候微波炉
    • 定义:即既能控制火候又能控制时长的微波炉。
    • 辨别方法:若在微波炉操作面板上能找到小火、中火、大火等字样,即为可控火候微波炉。

关键技巧提示:蛋黄表面戳孔是防爆核心——蛋黄在微波加热时内部水分汽化会产生高压,若不戳孔极易炸开;同时先让油盐在碗壁形成薄油层,能有效避免鸡蛋粘碗。这两条经验正是食谱中可被检索模块精确命中的"制作技巧"型内容。


二、食谱文档如何进入 RAG 知识库:数据准备模块

在 all-in-rag 的 code/C8/rag_modules/data_preparation.py 中,DataPreparationModule负责将data/C8/cook下数百份食谱文档(含太阳蛋.md)转化为带丰富元数据的父子文档结构。

2.1 批量加载 Markdown 文件

load_documents()通过Path(data_path).rglob("*.md")递归扫描整个知识库目录,直接以 UTF-8 读取原文并保持 Markdown 格式,为每份父文档生成确定性的parent_id(基于相对路径的 MD5),同时记录sourcedoc_type: "parent"标记。

2.2 元数据增强:太阳蛋的"身份证"

_enhance_metadata()会为太阳蛋文档自动补全三类核心元数据:

元数据字段提取逻辑太阳蛋文档的取值
category从文件路径匹配CATEGORY_MAPPING(如breakfast→ 早餐)早餐
dish_name直接取文件名 stem太阳蛋
difficulty用正则★+统计连续星号数量,映射 1~5 星难度简单(文档标记为 ★★)

其中难度映射表定义在源码中:{5: '非常困难', 4: '困难', 3: '中等', 2: '简单', 1: '非常简单'}。太阳蛋文档头部"预估烹饪难度:★★"正是这条规则的数据来源,也就是说——即使不改动任何代码,只要在食谱里按规范标注星号,系统就能自动识别难度

2.3 Markdown 结构感知分块

_markdown_header_split()使用 LangChain 的MarkdownHeaderTextSplitter,按#(主标题)、##(二级标题)、###(三级标题)三级结构对文档分块,并设置strip_headers=False保留标题上下文。太阳蛋文档经此流程会被拆分为典型的父子结构:

太阳蛋.md(父文档,parent_id 唯一标识) ├── 子块1:# 太阳蛋的做法 + 难度评级 ├── 子块2:## 必备原料和工具 ├── 子块3:## 计算(用量配比) ├── 子块4:## 操作(可控火候/不可控火候分支) └── 子块5:## 附加内容(微波炉类型定义)

每个子块都会继承父文档的categorydifficultydish_name,并新增chunk_idparent_iddoc_type: "child"chunk_index等字段,同时写入parent_child_map维护父子映射——这正是"小块检索、大块生成"架构的基础。

分块的价值在于:用户问"做太阳蛋需要什么食材"时,可精确命中"子块2";而生成回答时再通过get_parent_documents()将命中子块对应的完整父文档(含全部操作步骤)交给 LLM,保证上下文不残缺。


三、索引构建与混合检索:让"太阳蛋"被精确召回

3.1 向量化与 FAISS 索引

code/C8/rag_modules/index_construction.py 中的IndexConstructionModule使用HuggingFaceEmbeddings(默认模型BAAI/bge-small-zh-v1.5normalize_embeddings=True)将每个子块编码为向量,并构建 FAISS 索引;save_index()/load_index()实现了索引缓存机制,首次构建后后续启动可直接秒级加载。

3.2 双路混合检索与 RRF 重排

code/C8/rag_modules/retrieval_optimization.py 的RetrievalOptimizationModule同时设置了两路检索器:

  • 向量检索vectorstore.as_retrieverk=5):基于语义相似度,能理解"微波炉做早餐""怎么煎个蛋"等同义表达;
  • BM25 检索BM25Retriever.from_documentsk=5):基于关键词精确匹配,能稳定命中"太阳蛋""戳孔"等专名。

hybrid_search()调用_rrf_rerank()用 RRF(Reciprocal Rank Fusion)融合两路结果,每个文档得分 =Σ 1 / (k + rank + 1)(默认k=60),综合排名后取top_k(配置文件默认 3)。此外,metadata_filtered_search()支持按categorydifficulty元数据过滤——例如查询"推荐几道简单的早餐"时,系统会自动从问题中提取过滤条件(见 main.py 的_extract_filters_from_query),只检索早餐+简单的文档块,太阳蛋正是此类场景的理想命中对象。


四、生成集成:从检索结果到结构化回答

code/C8/rag_modules/generation_integration.py 的GenerationIntegrationModule负责"最后一公里"。

  1. 查询路由query_router()用 LLM 将问题分类为list(要菜名推荐)、detail(要具体做法)、general(一般性问题)三类;
  2. 查询重写:对非list类查询,query_rewrite()会智能改写模糊表达(如"想做个蛋"→更利于检索的表达),明确查询则保持原样;
  3. 父子文档聚合get_parent_documents()按子块命中次数统计父文档相关性并智能去重;
  4. 多模式生成
    • detail类问题走generate_step_by_step_answer(),按"菜品介绍/所需食材/制作步骤/制作技巧"的结构化提示词输出分步指导;
    • general类问题走generate_basic_answer()输出常规回答;
    • list类问题由generate_list_answer()直接返回去重后的菜名列表;
  5. 流式输出generate_step_by_step_answer_stream()/generate_basic_answer_stream()基于 LCEL 的chain.stream()实现逐字输出,配合 main.py 中print(chunk, end="", flush=True)呈现打字机效果。

若用户问"太阳蛋怎么做",链路将呈现为:查询路由判定detail→ 重写后混合检索命中太阳蛋相关子块 → 聚合完整父文档 → 分步指导模式生成包含原料配比与双火候操作分支的详细回答。


五、一键运行:把太阳蛋"喂"给 RAG 系统

完整系统由 code/C8/main.py 的RecipeRAGSystem协调:initialize_system()按依赖顺序初始化数据准备、索引构建、生成集成模块;build_knowledge_base()优先加载已保存索引;run_interactive()提供命令行交互问答。

运行前提

  1. 按 code/C8/requirements.txt 安装依赖(langchain==0.3.26、faiss-cpu、sentence-transformers、rank_bm25 等);
  2. 设置环境变量MOONSHOT_API_KEY(默认 LLM 为kimi-k2-0711-preview,见 code/C8/config.py);
  3. 默认数据路径../../data/C8/cook与嵌入模型BAAI/bge-small-zh-v1.5均已在 code/C8/config.py 中配置好,top_k=3temperature=0.1max_tokens=2048可按需调整。
# 在 code/C8 目录下 export MOONSHOT_API_KEY="your_api_key" python main.py

启动后即可交互提问,例如:"太阳蛋怎么做"(detail 分步指导)、"推荐几道简单的早餐"(list + 元数据过滤)。整体架构与运行说明还可参考 docs/chapter8/01_env_architecture.md,各模块实现细节见 docs/chapter8/02_data_preparation.md、docs/chapter8/03_index_retrieval.md、docs/chapter8/04_generation_sys.md。


六、小结

一份看似简单的"太阳蛋"食谱,在 all-in-rag 的 C8 系统中完整经历了 RAG 的四大环节:数据准备(目录路径推断分类、星号正则识别难度、三级标题结构分块)→索引构建(BGE 向量化 + FAISS 缓存)→混合检索(向量语义 + BM25 关键词 + RRF 融合 + 元数据过滤)→生成集成(查询路由、智能重写、父子文档聚合、多模式与流式输出)。掌握这条链路,你就能将任何规范化的 Markdown 文档集快速改造为可问答、可推荐的领域知识库——这也正是 all-in-rag 项目"从文档到生产级 RAG"的核心工程价值所在。

【免费下载链接】all-in-rag🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/项目地址: https://gitcode.com/datawhalechina/all-in-rag

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 23:37:59

巴菲特经济护城河:企业竞争优势的本质与评估

1. 巴菲特经济护城河的本质理解我第一次接触"经济护城河"这个概念是在2008年金融危机期间。当时市场一片恐慌,但伯克希尔哈撒韦公司却在大举投资。巴菲特在致股东信中解释:"我们只投资那些拥有持久竞争优势的企业——那些被宽阔护城河保护…

作者头像 李华
网站建设 2026/9/23 23:36:48

Java课程设计:基于Swing的俄罗斯方块完整实现与避坑指南

简介:一套基于 Java GUI Swing 的俄罗斯方块项目资料,适合毕业设计、课程设计、大作业或工程实训,面向需要从零完成 Swing 游戏开发的学习者。项目功能完整,包含游戏主界面、画布与方块显示、移动旋转控制、颜色切换、等级与进度…

作者头像 李华
网站建设 2026/9/23 23:34:42

华为路由器交换机VLAN配置实战:从端口类型到跨交换机互通

简介:面向网络运维与数通初学者的华为VLAN配置实战文档,以华为路由器R2621与交换机S3026e为核心设备,通过4台PC搭建小型组网环境,演示VLAN划分、虚拟网与物理网互通、防火墙默认策略及ACL访问控制的完整过程。文档从IP地址与网关规…

作者头像 李华