- 教程
- 人工智能
- 大模型
- RAG
【免费下载链接】all-in-rag
🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/
这是一篇以 data/C8/cook/dishes/meat_dish/白菜猪肉炖粉条.md 菜谱为标本的实战解析文章。读者一方面能照单学会这道东北家常菜的标准做法(从原料计算到出锅收汁),另一方面能透过这份菜谱,理解 all-in-rag 项目第 8 章"尝尝咸淡 RAG 系统"是如何把这类高度规整的 Markdown 菜谱,改造成"小块检索、大块生成"的知识库,进而支撑"今天吃什么"这类智能问答的。读完本文,你将同时掌握一份可下厨复现的菜谱,以及一条可运行的菜谱 RAG 流水线(数据加载 → 元数据增强 → 结构分块 → 混合检索 → 生成回答)。
一、菜谱档案:一道简单上乘的东北家常菜
白菜猪肉炖粉条是一道简单易做的传统东北家常菜,以做法简单、味道上乘的特点在广大东北人民群众中备受喜爱。原菜谱文档给出的预估烹饪难度为★★★(中等),属于典型的"一锅炖"家常菜:食材常见、火候宽容、容错率高,非常适合作为 RAG 菜谱知识库的入门语料来观察整个处理链路。
从数据视角看,这份菜谱文件本身就是一份"教科书级"的结构化 Markdown:它严格遵循# 标题+ 简介 + 难度评级 +## 必备原料和工具+## 计算+## 操作+## 附加内容的固定骨架。这一点在 docs/chapter8/01_env_architecture.md 中被明确点出——HowToCook 风格菜谱"结构高度规整、篇幅较短",几乎不需要额外清洗就能直接用于 RAG 构建。
二、必备原料与工具
制作这道菜需要的原料清单(对应菜谱文档的"必备原料和工具"小节):
| 原料/工具 | 说明 |
|---|---|
| 五花肉 | 带皮三层五花为佳,肥瘦相间,炖煮后油脂融入汤汁 |
| 白菜 | 大白菜,需将嫩叶与白菜帮子分开处理 |
| 土豆干粉条 | 建议使用土豆淀粉干粉条,耐煮、久炖不烂 |
| 十三香 | 中式复合香料,提供炖菜底味 |
| 鸡精 | 提鲜 |
| 食用盐 | 基础调味 |
| 老抽 | 给肉上色 |
| 生抽 | 提鲜调味 |
无需特殊厨具,一口炒锅/炖锅、一把菜刀即可完成全部操作。
三、用量计算:每份的标准配比
菜谱文档明确给出了"每份"的精确配比,这是该文档"计算"小节的核心内容,也是 RAG 系统回答"需要什么食材""放多少量"类问题时被检索到的关键信息:
| 原料 | 用量(每份) |
|---|---|
| 五花肉 | 300g |
| 大白菜 | 500g |
| 土豆干粉条 | 50g |
| 十三香 | 10g |
| 鸡精 | 5g |
| 食用盐 | 15g |
| 老抽 | 5ml |
| 生抽 | 5ml |
从烹饪原理看,这份配比遵循了"肉 3 : 菜 5 : 粉条 0.5"的东北炖菜黄金比例:五花肉提供油脂与肉香,白菜量大且炖后大幅出水缩水,粉条吸水膨胀,三者成菜后体积与味道恰好平衡。老抽与生抽各 5ml 的分工明确——老抽负责上色、生抽负责提鲜,二者不可互相替代。
四、操作步骤:九步做出地道东北味
以下是菜谱文档"操作"小节的完整步骤,我按执行时序重新组织了编号,并补充了每一步的原理说明,方便下厨复现:
第 1 步(最先做):泡发粉条锅内烧水,水开后放入干粉条,煮 5 分钟后连同水一起倒入容器中,盖上盖子继续浸泡备用。原文档特别强调"第一步先做这个",因为土豆干粉条煮制时间长,先泡上可以利用等待时间并行推进后续步骤,这是全流程的时间管理关键。
第 2 步:切肉五花肉切成 3mm 的肉片备用。3mm 是兼顾"快速炒熟上色"与"久炖不柴"的折中厚度:太薄炖后易碎,太厚则油脂难以析出。
第 3 步:切菜大白菜嫩叶与白菜帮子分开,切成 2 份菜片备用。帮子与嫩叶熟成时间差异大,分开处理是保证"帮子软烂、叶子不烂"的关键技巧。
第 4 步:热锅下油热锅,锅内放入 10ml~15ml 食用油,等待 10 秒让油温升高。热锅凉油有利于后续肉片不粘锅。
第 5 步:煸炒五花肉放入五花肉,保持翻炒至肉变色。此步将肉中的油脂逼出,是整道菜香气的根基。
第 6 步:老抽上色加入老抽,炒1 分钟,给肉上色。老抽需在肉片表面裹匀并炒出焦香,才能形成红亮色泽。
第 7 步:炒白菜帮加入白菜帮子,加入食用盐、生抽,炒一分钟;如果粘锅,烹入 10ml 水。先加盐有助于白菜帮快速出水,避免干烧粘锅。
第 8 步:加水炖煮(20 分钟)加水没过所有食材,加入鸡精、十三香,沸腾后将火调小,然后等待 20 分钟。这一阶段是味道融合的核心:肉香、菜甜、料香在慢火中互相渗透。
第 9 步:粉条入锅(5 分钟)粉条滤水切成小段放入碗中备用;加入白菜嫩叶,炒匀后将粉条放在菜上方,加盖再煮5 分钟。粉条放在菜上方而不是埋进汤底,可避免粉条沉底粘锅糊底。
第 10 步:收汁出锅尝味、关火、收汁。原文档的附加内容强调:最后一步务必尝味,如果发现味道偏淡或未熟,继续加盖煮一段时间即可,这是一道"容错率"极高的菜。
五、实操技巧与注意事项
菜谱文档"附加内容"小节给出的两条经验,值得单独展开:
- 粉条先行:土豆干粉条煮制时间长,放在第一步操作,期间可并行切肉、切菜,整体耗时可压缩到 30 分钟内。
- 尝味兜底:最后一步"尝味"是出锅前的质量闸门——味道淡继续加盐,未熟继续加盖炖,无需担心过火,因为白菜与粉条在余温下依然会继续熟成。
补充两条从步骤中可推出的要点:一是老抽与生抽 5:5 的比例使成品颜色红亮而不发黑;二是"粉条置于菜上"的摆法有效避免了粉条与锅底直接接触导致的糊底问题。
六、进阶视角:这道菜在"尝尝咸淡 RAG 系统"中的全生命周期
本仓库的 C8 章节构建了一个名为"尝尝咸淡"的食谱问答 RAG 系统(背景见 docs/chapter8/01_env_architecture.md),其数据目录正是 data/C8/cook,白菜猪肉炖粉条这道菜就是其中荤菜类(meat_dish)知识库的一份语料。结合 code/C8 源码,可以完整还原这道菜从 Markdown 文件到可被问答的检索单元的处理过程。
6.1 文档加载与元数据增强
在 code/C8/rag_modules/data_preparation.py 的load_documents()中,系统通过rglob("*.md")递归扫描数据目录读取所有菜谱,随后调用_enhance_metadata()对每个文档做元数据增强。以本菜谱为例:
- 菜品分类(category):通过
CATEGORY_MAPPING将路径中的目录名映射为中文分类,meat_dish→荤菜; - 菜品名称(dish_name):直接取文件名主干,即
白菜猪肉炖粉条; - 难度等级(difficulty):用正则
r'★+'精确匹配连续星号数量,本菜谱★★★映射为中等。
值得注意的实现细节是:源码中的难度映射表为{5: '非常困难', 4: '困难', 3: '中等', 2: '简单', 1: '非常简单'},与菜谱文档顶部的星级评级一一对应;而parent_id通过数据根目录相对路径的 MD5 哈希生成,保证同一份菜谱多次加载时 ID 确定不变(见 data_preparation.py)。
6.2 Markdown 结构分块:一份菜谱切成五个子块
chunk_documents()使用 LangChain 的MarkdownHeaderTextSplitter,按#、##、###三级标题进行结构感知分块(strip_headers=False保留标题以便理解上下文)。按照这个逻辑,本菜谱会被切分为如下父子结构(映射关系存储于parent_child_map,子块通过parent_id关联父文档):
父文档:白菜猪肉炖粉条.md(完整菜谱,doc_type=parent) ├── 子块1:# 白菜猪肉炖粉条的做法 + 简介 + 难度评级 ├── 子块2:## 必备原料和工具 + 食材清单 ├── 子块3:## 计算 + 用量配比 ├── 子块4:## 操作 + 详细制作步骤 └── 子块5:## 附加内容 + 技巧这种"小块检索、大块生成"的设计(架构说明见 docs/chapter8/02_data_preparation.md)解决了一个关键矛盾:如果整篇菜谱作为一个向量块,用户问"白菜猪肉炖粉条需要什么食材"时,该问题在整篇文档中占比太小,可能检索不到;而按标题分块后,"必备原料和工具"子块能精确命中食材类问题,生成阶段再通过get_parent_documents()取回完整父文档,保证 LLM 拿到全部上下文。
6.3 智能去重:检索多块合并为完整菜谱
用户若问"白菜猪肉炖粉条怎么做",混合检索可能同时命中"操作"与"计算"等多个子块。get_parent_documents()(data_preparation.py)会统计每个父文档被命中的子块数量作为相关性指标,按命中次数降序去重输出父文档——同一道菜只出现一次,且命中子块越多的菜谱排名越靠前。
6.4 检索与生成链路
在 code/C8/main.py 的ask_question()中,问题会依次经过:
- 查询路由(
query_router):将问题分为list(推荐菜品)、detail(具体做法)、general(一般知识)三类; - 查询重写(
query_rewrite):对模糊查询(如"想做点简单的荤菜")补充烹饪术语,对明确包含菜名的查询保持原样; - 混合检索:向量检索(FAISS + BGE 中文嵌入模型)与 BM25 关键词检索双路召回,经RRF(Reciprocal Rank Fusion)重排融合(见 retrieval_optimization.py);
- 元数据过滤:
_extract_filters_from_query()会从问题中提取"荤菜""中等"等关键词作为过滤条件; - 生成:
detail类问题走generate_step_by_step_answer()分步指导模式,以"菜品介绍 → 所需食材 → 制作步骤 → 制作技巧"的结构输出——这正是本菜谱从 Markdown 分块到自然语言问答的最终呈现形态。
其中嵌入模型、LLM 模型、检索数量、生成参数等均可在 code/C8/config.py 的RAGConfig数据类中配置(默认embedding_model="BAAI/bge-small-zh-v1.5"、llm_model="kimi-k2-0711-preview"、top_k=3、temperature=0.1),索引会持久化到./vector_index目录实现秒级重启加载。
七、运行与复现
在仓库根目录下按以下方式即可运行这套菜谱 RAG 系统(详见 docs/chapter8/01_env_architecture.md):
# 创建并激活虚拟环境(示例使用 conda) conda create -n cook-rag-1 python=3.12.7 conda activate cook-rag-1 # 安装依赖 cd code/C8 pip install -r requirements.txt # 配置 MOONSHOT_API_KEY 环境变量后启动 python main.py启动后进入交互式问答,可以尝试提问"白菜猪肉炖粉条怎么做""推荐几道简单的荤菜""白菜猪肉炖粉条需要什么食材"——前者会命中"操作"子块并展开分步指导,后者会精确命中"必备原料和工具"子块,而推荐类问题则会走list路由返回菜品名称列表,直观验证本文所述的分块与检索链路。
结语
白菜猪肉炖粉条这道菜,烹饪上讲究"粉条先行、帮叶分离、慢火 20 分钟";在 all-in-rag 的 RAG 体系中,它则示范了一类典型语料的标准处理范式——目录路径映射为分类元数据、星级标记解析为难度字段、标题结构切分为父子子块、RRF 混合检索保证召回精度、父子回溯保证生成上下文完整。掌握了这道菜的两种"做法",你既能端出一锅热气腾腾的东北炖菜,也能照此范式把任何一批结构化 Markdown 文档快速改造成可问答的 RAG 知识库。
- 教程
- 人工智能
- 大模型
- RAG
【免费下载链接】all-in-rag
🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/
相关推荐
Roo Code v2.2.29 发布解析:为自动写入增加可配置延迟,让诊断与 Linter 从容跟上
Roo Code v2.2.29 发布解析:为自动写入增加可配置延迟,让诊断与 Linter 从容跟上 Roo Code 2.2.29 引入了一项直接影响开发体
教程人工智能大模型RAG包菜炒鸡蛋粉丝烹饪全解:一道家常菜的结构化菜谱与 RAG 知识库实践(all-in-rag)
包菜炒鸡蛋粉丝烹饪全解:一道家常菜的结构化菜谱与 RAG 知识库实践(all in rag) 本篇以 all in rag 项目 C8 章节 https://l
教程人工智能大模型RAG小龙虾菜谱的结构化数据与 RAG 智能问答:all-in-rag 菜品知识库实战剖析
小龙虾菜谱的结构化数据与 RAG 智能问答:all in rag 菜品知识库实战剖析 本篇技术指南以 小龙虾菜谱 https://link.gitcode.co
教程人工智能大模型RAG
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考