Initial commit
@@ -0,0 +1,232 @@
|
||||
# 第一节 RAG 简介
|
||||
|
||||
## 一、什么是 RAG?
|
||||
|
||||
### 1.1 核心定义
|
||||
|
||||
从本质上讲,RAG(Retrieval-Augmented Generation)是一种旨在解决大语言模型(LLM)“知其然不知其所以然”问题的技术范式。它的核心是将模型内部学到的“**参数化知识**”(模型权重中固化的、模糊的“记忆”),与来自外部知识库的“**非参数化知识**”(精准、可随时更新的外部数据)相结合。其运作逻辑就是在 LLM 生成文本前,先通过检索机制从外部知识库中动态获取相关信息,并将这些“参考资料”融入生成过程,从而提升输出的准确性和时效性 [^1] [^2] [^3]。
|
||||
|
||||
> 💡 **一句话总结**:RAG 就是让 LLM 学会了“开卷考试”,它既能利用自己学到的知识,也能随时查阅外部资料。
|
||||
|
||||
### 1.2 技术原理
|
||||
|
||||
那么,RAG 系统是如何实现“参数化知识”与“非参数化知识”的结合呢?如图 1-1 所示,其架构主要通过两个阶段来完成这一过程:
|
||||
|
||||
(1)**检索阶段:寻找“非参数化知识”**
|
||||
- **知识向量化**:**嵌入模型(Embedding Model)** 充当了“连接器”的角色。它将外部知识库编码为向量索引(Index),存入**向量数据库**。
|
||||
- **语义召回**:当用户发起查询时,检索模块利用同样的嵌入模型将问题向量化,并通过**相似度搜索(Similarity Search)**,从海量数据中精准锁定与问题最相关的文档片段。
|
||||
|
||||
(2)**生成阶段:融合两种知识**
|
||||
- **上下文整合**:**生成模块**接收检索阶段送来的相关文档片段以及用户的原始问题。
|
||||
- **指令引导生成**:该模块会遵循预设的 **Prompt** 指令,将上下文与问题有效整合,并引导 LLM(如 DeepSeek)进行可控的、有理有据的文本生成。
|
||||
|
||||
<div align="center">
|
||||
<img src="./images/1_1_1.svg" width="60%" alt="RAG 双阶段架构示意图">
|
||||
<p>图 1-1 RAG 双阶段架构示意图</p>
|
||||
</div>
|
||||
|
||||
### 1.3 技术演进分类
|
||||
|
||||
RAG 的技术架构经历了从简单到复杂的演进,如图 1-2 大致可分为三个阶段 [^4]。
|
||||
|
||||
<div align="center">
|
||||
<img src="./images/1_1_2.png" width="80%" alt="RAG 技术演进分类">
|
||||
<p>图 1-2 RAG 技术演进分类</p>
|
||||
</div>
|
||||
|
||||
这三个阶段的具体对比如表 1-1 所示。
|
||||
|
||||
<div align="center">
|
||||
<table border="1" style="margin: 0 auto;">
|
||||
<tr>
|
||||
<th style="text-align: center;"></th>
|
||||
<th style="text-align: center;">初级 RAG(Naive RAG)</th>
|
||||
<th style="text-align: center;">高级 RAG(Advanced RAG)</th>
|
||||
<th style="text-align: center;">模块化 RAG(Modular RAG)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>流程</strong></td>
|
||||
<td style="text-align: center;"><strong>离线:</strong> <code>索引</code><br><strong>在线:</strong> <code>检索 → 生成</code></td>
|
||||
<td style="text-align: center;"><strong>离线:</strong> <code>索引</code><br><strong>在线:</strong> <code>...→ 检索前 → ... → 检索后 → ...</code></td>
|
||||
<td style="text-align: center;">积木式可编排流程</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>特点</strong></td>
|
||||
<td style="text-align: center;">基础线性流程</td>
|
||||
<td style="text-align: center;">增加<strong>检索前后</strong>的优化步骤</td>
|
||||
<td style="text-align: center;">模块化、可组合、可动态调整</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>关键技术</strong></td>
|
||||
<td style="text-align: center;">基础向量检索</td>
|
||||
<td style="text-align: center;"><strong>查询重写(Query Rewrite)</strong><br><strong>结果重排(Rerank)</strong></td>
|
||||
<td style="text-align: center;"><strong>动态路由(Routing)</strong><br><strong>查询转换(Query Transformation)</strong><br><strong>多路融合(Fusion)</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>局限性</strong></td>
|
||||
<td style="text-align: center;">效果不稳定,难以优化</td>
|
||||
<td style="text-align: center;">流程相对固定,优化点有限</td>
|
||||
<td style="text-align: center;">系统复杂性高</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><em>表 1-1 RAG 技术演进分类对比</em></p>
|
||||
</div>
|
||||
|
||||
> “离线”指提前完成的数据预处理工作(如索引构建);“在线”指用户发起请求后的实时处理流程。
|
||||
|
||||
## 二、为什么要使用 RAG?
|
||||
|
||||
### 2.1 技术选型:RAG vs. 微调
|
||||
|
||||
在选择具体的技术路径时,一个重要的考量是成本与效益的平衡。通常,我们应优先选择对模型改动最小、成本最低的方案,所以技术选型路径往往遵循的顺序是**提示词工程(Prompt Engineering) -> 检索增强生成 -> 微调(Fine-tuning)**。
|
||||
|
||||
我们可以从两个维度来理解这些技术的区别。如图 1-3 所示,**横轴代表“LLM 优化”**,即对模型本身进行多大程度的修改。从左到右,优化的程度越来越深,其中提示工程和 RAG 完全不改变模型权重,而微调则直接修改模型参数。**纵轴代表“上下文优化”**,是对输入给模型的信息进行多大程度的增强。从下到上,增强的程度越来越高,其中提示工程只是优化提问方式,而 RAG 则通过引入外部知识库,极大地丰富了上下文信息。
|
||||
|
||||
<div align="center">
|
||||
<img src="./images/1_1_3.svg" width="60%" alt="技术选型路径" />
|
||||
<p>图 1-3 选型路径图</p>
|
||||
</div>
|
||||
|
||||
基于此,我们的选择路径就清晰了:
|
||||
- **先尝试提示工程**:通过精心设计提示词来引导模型,适用于任务简单、模型已有相关知识的场景。
|
||||
- **再选择 RAG**:如果模型缺乏特定或实时知识而无法回答,则使用 RAG,通过外挂知识库为其提供上下文信息。
|
||||
- **最后考虑微调**:当目标是改变模型“如何做”(行为/风格/格式)而不是“知道什么”(知识)时,微调是最终且最合适的选择。例如,让模型学会严格遵循某种独特的输出格式、模仿特定人物的对话风格,或者将极其复杂的指令“蒸馏”进模型权重中。
|
||||
|
||||
RAG 的出现填补了通用模型与专业领域之间的鸿沟,它在解决如表 1-2 所示 LLM 局限时尤其有效:
|
||||
|
||||
<div align="center">
|
||||
<table border="1" style="margin: 0 auto;">
|
||||
<tr>
|
||||
<th style="text-align: center;">问题</th>
|
||||
<th style="text-align: center;">RAG的解决方案</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>静态知识局限</strong></td>
|
||||
<td style="text-align: center;">实时检索外部知识库,支持动态更新</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>幻觉(Hallucination)</strong></td>
|
||||
<td style="text-align: center;">基于检索内容生成,错误率降低</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>领域专业性不足</strong></td>
|
||||
<td style="text-align: center;">引入领域特定知识库(如医疗/法律)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>数据隐私风险</strong></td>
|
||||
<td style="text-align: center;">本地化部署知识库,避免敏感数据泄露</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><em>表 1-2 RAG 对 LLM 局限的解决方案</em></p>
|
||||
</div>
|
||||
|
||||
### 2.2 关键优势
|
||||
|
||||
(1)**准确性与可信度的双重提升**
|
||||
|
||||
RAG 最核心的价值在于突破了模型预训练知识的限制。它不仅能**补充专业领域的知识盲区**,还能通过提供具体的参考材料,有效**抑制“一本正经胡说八道”的幻觉现象**。论文研究还表明,RAG 生成的内容在**具体性**和**多样性**上也显著优于纯 LLM。更重要的是,RAG 具备**可溯源性**——每一条回答都能找到对应的原始文档出处,这种“有据可查”的特性极大提高了内容在法律、医疗等严肃场景下的可信度。
|
||||
|
||||
(2)**时效性保障**
|
||||
|
||||
在知识更新方面,RAG 解决了 LLM 固有的**知识时滞问题**(即模型不知道训练截止日期之后发生的事)。RAG 允许知识库独立于模型进行**动态更新**——新政策或新数据一旦入库,立刻就能被检索到。这种能力在论文中被称为**“索引热拔插”(Index Hot-swapping)**——就像给机器人换一张存储卡一样,瞬间切换其世界知识库,而无需重新训练模型,实现了知识的实时在线。
|
||||
|
||||
(3)**显著的综合成本效益**
|
||||
|
||||
从经济角度看,RAG 是一种高性价比的方案。首先,它**避免了高频微调**带来的巨额算力成本;其次,由于有了外部知识的强力辅助,我们在处理特定领域问题时,往往可以使用**参数量更小的基础模型**来达到类似的效果,从而直接降低了推理成本。这种架构也减少了试图将海量知识强行“塞入”模型权重中所需的计算资源消耗。
|
||||
|
||||
(4)**灵活的模块化可扩展性**
|
||||
|
||||
RAG 的架构具备极强的包容性,支持**多源集成**,无论是 PDF、Word 还是网页数据,都能统一构建进知识库中。同时,其**模块化设计**实现了检索与生成的解耦,这意味着我们可以独立优化检索组件(比如更换更好的 Embedding 模型),而不会影响到生成组件的稳定性,便于系统的长期迭代。
|
||||
|
||||
### 2.3 适用场景风险分级
|
||||
|
||||
表 1-3 展示了 RAG 技术在不同风险等级场景中的适用性。
|
||||
|
||||
<div align="center">
|
||||
<table border="1" style="margin: 0 auto;">
|
||||
<tr>
|
||||
<th style="text-align: center;">风险等级</th>
|
||||
<th style="text-align: center;">案例</th>
|
||||
<th style="text-align: center;">RAG适用性</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>低风险</strong></td>
|
||||
<td style="text-align: center;">翻译/语法检查</td>
|
||||
<td style="text-align: center;">高可靠性</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>中风险</strong></td>
|
||||
<td style="text-align: center;">合同起草/法律咨询</td>
|
||||
<td style="text-align: center;">需结合人工审核</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><strong>高风险</strong></td>
|
||||
<td style="text-align: center;">证据分析/签证决策</td>
|
||||
<td style="text-align: center;">需严格质量控制机制</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><em>表 1-3 RAG 适用场景风险分级</em></p>
|
||||
</div>
|
||||
|
||||
## 三、如何上手 RAG?
|
||||
|
||||
### 3.1 基础工具链选择
|
||||
|
||||
构建 RAG 系统通常涉及几个关键环节的选型。在**开发模式**上,我们可以利用 **LangChain** 或 **LlamaIndex** 等成熟框架快速集成,**也可以选择不依赖框架的原生开发**,以获得对系统流程更精细的控制力(在 AI 编程辅助下这并非难事)。而在**记忆载体**(向量数据库)方面,既有 **Milvus**、**Pinecone** 等适合大规模数据的方案,也有 **FAISS**、**Chroma** 等轻量级或本地化的选择,需根据具体业务规模灵活决定。后期为了量化效果,还可以引入 **RAGAS** 或 **TruLens** 等自动化**评估工具**。
|
||||
|
||||
### 3.2 四步构建最小可行系统(MVP)
|
||||
|
||||
(1)**数据准备与清洗**:这是系统的地基。我们需要将 PDF、Word 等多源异构数据标准化,并采用合理的**分块策略**(如按语义段落切分而非固定字符数),避免信息在切割中支离破碎。
|
||||
|
||||
(2)**索引构建**:将切分好的文本通过**嵌入模型**转化为向量,并存入数据库。可以在此阶段关联**元数据**(如来源、页码),这对后续的精确引用很有帮助。
|
||||
|
||||
(3)**检索策略优化**:不要依赖单一的向量搜索。可以采用**混合检索**(向量+关键词)等方式来提升召回率,并引入**重排序**模型对检索结果进行二次精选,确保 LLM 看到的都是精华。
|
||||
|
||||
(4)**生成与提示工程**:最后,设计一套清晰的 **Prompt 模板**,引导 LLM 基于检索到的上下文回答用户问题,并明确要求模型“不知道就说不知道”,防止幻觉。
|
||||
|
||||
### 3.3 新手友好方案
|
||||
|
||||
如果希望快速验证想法而非深耕代码,可以尝试 **FastGPT** 或 **Dify** 这样的可视化知识库平台,它们封装了复杂的 RAG 流程,仅需上传文档即可使用。对于开发者,利用 **LangChain4j Easy RAG** 或 GitHub 上的 **TinyRAG** [^6]等开源模板,也是高效的起手方式。
|
||||
|
||||
### 3.4 进阶与挑战
|
||||
|
||||
当基础的 RAG 系统搭建完成后,下一步的进阶之路便聚焦于如何评估、诊断并突破其固有的瓶颈。
|
||||
|
||||
(1)**评估维度与挑战**
|
||||
|
||||
一套 RAG 系统的好坏,并不能仅凭感觉。业界通常会从几个维度进行量化评估,首先是**检索相关性**(找到的内容是否包含答案),其次是**生成质量**,这又可以细分为**语义准确性**(回答的意思是否正确)和**词汇匹配度**(专业术语是否使用得当)。
|
||||
|
||||
这些评估维度也直接对应了 RAG 当前面临的主要挑战。比如,**检索依赖性**问题——如果检索系统召回了错误信息,再强的 LLM 也会“一本正经地胡说八道”。此外,对于需要跨多个文档进行综合分析的**多跳推理**问题,常见的 RAG 架构也普遍感到吃力。
|
||||
|
||||
(2)**优化方向与架构演进**
|
||||
|
||||
针对上述挑战,社区探索出了多种优化路径。在**性能层面**,可以通过**索引分层**(对高频数据启用缓存)和**多模态扩展**(支持图像/表格检索)来提升效率和能力边界。而在**架构层面**,简单的线性流程正在被更复杂的**设计模式**所取代。例如,系统可以通过**分支模式**并行处理多路检索,或通过**循环模式**进行自我修正,这些灵活的架构是通往更智能 RAG 的必由之路。
|
||||
|
||||
## 四、RAG 已死?
|
||||
|
||||
随着大模型长上下文窗口能力的提升,社区中开始出现“RAG 已死”的声音。这一论调主要来自两个方面,一是认为长上下文已经能暴力“消化”海量文本,不再需要复杂的检索系统;二是批评 RAG 这个术语本身就过于宽泛,模糊了太多技术细节,反而阻碍了理解与优化。
|
||||
|
||||
这些观点忽略了一个技术概念在演进过程中的普遍规律。正如我们可以轻易地为现代复杂的 RAG 系统起一个更精确、更唬人的名字,比如 **“大模型知识管理专家系统”(Large Language Model Knowledge Management Expert System,LKE)**。因为它早已超出了最初“检索-增强-生成”的简单范畴。但这种“换名游戏”,恰恰说明了“RAG 已死”论的表面化——这无异于在用一个新瓶子去装 RAG 这个不断陈化的老酒。
|
||||
|
||||
> 笔者在此并非要创造一个新词,不过为什么要起 LKE 这个名字?它代表了三个核心要素:
|
||||
> - **L(Large Language Model)**:强调系统的驱动力是大语言模型。
|
||||
> - **K(Knowledge Management)**:寓意着系统就像一个知识管理员,精准地为我们找到(**检索**)所需要的知识,辅助我们后续利用大模型进行更高阶应用。
|
||||
> - **E(Expert)**:说明系统能像专家一样,通过路由、分析、融合、修正等一系列步骤,最终给出答案(**生成**)、解决问题。
|
||||
|
||||
可以类比 **Transformer**。今天无论是以 GPT 为代表的 Decoder-only 还是以 BERT 为代表的 Encoder-only,我们都习惯称之为“基于 Transformer 架构”,尽管它们与最初论文中的完整形态差异巨大。但是 Transformer 这个标签抓住了一次技术范式的核心飞跃,并成为了一个技术时代的象征。同理,**RAG 的核心在于“将 LLM 的内在参数化知识与外部非参数化知识相结合”**。只要这个思想或需求不变,无论我们为其增加多少模块——查询转换、多路召回或者自我修正等等,它本质上依然是在这个框架下的演进。
|
||||
|
||||
所以,“RAG 已死”是一个伪命题。相反,**RAG 作为一个概念活得很好**,它正在像 Transformer 一样,成为一个不断吸收新技术、不断进化的基础架构范式。它的生命力,正在于它的“面目全非”和“包罗万象”。而**本教程的目标,就是绘制出这张描绘 RAG 全貌的清晰地图,当我们可以解构它的每一个模块、理解它的每一种可能性时,RAG 也好,LKE 也罢,这些都无关紧要**。我们要做的就是通过 RAG 这道经典例题来学习和拓展(将 LLM 的内在参数化知识与外部非参数化知识相结合)这类题型的解题思路。
|
||||
|
||||
> RAG 技术仍在快速发展中,可以持续关注学术和工业界的最新进展!
|
||||
|
||||
## 参考文献
|
||||
|
||||
[^1]: [Genesis, J. (2025). *Retrieval-Augmented Text Generation: Methods, Challenges, and Applications*](https://www.researchgate.net/publication/391141346_Retrieval-Augmented_Generation_Methods_Applications_and_Challenges).
|
||||
|
||||
[^2]: [Gao et al. (2023). *Retrieval-Augmented Generation for Large Language Models: A Survey*](https://arxiv.org/abs/2312.10997).
|
||||
|
||||
[^3]: [Lewis et al. (2020). *Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks*](https://arxiv.org/abs/2005.11401).
|
||||
|
||||
[^4]: [Gao et al. (2024). *Modular RAG: Transforming RAG Systems into LEGO-like Reconfigurable Frameworks*](https://arxiv.org/abs/2407.21059).
|
||||
|
||||
[^6]: [*TinyRAG: GitHub项目*](https://github.com/KMnO4-zx/TinyRAG).
|
||||
@@ -0,0 +1,487 @@
|
||||
# 第二节 准备工作
|
||||
|
||||
> 本节环境配置方面主推两种基于浏览器的集成开发环境。不管是手机、平板还是电脑,随时都可以上号运行代码。虽然手机平板可能体验不佳,但胜在能用。
|
||||
|
||||
## 一、大模型 API 配置
|
||||
|
||||
### 1.1 AIHubmix API 申请
|
||||
|
||||
AIHubmix 是一个美国平台,公司注册在美国的特拉华州,一站式聚合了全球主流的 AI 模型,最新的模型通常能在发布当天最晚不超过 1 周就会支持。完全对接相关模型的云厂商(OpenAI 对接的是 Azure 云,Gemini 对接的 Google 官方,Claude 对接的是 AWS,其他开源等模型是对接到各大知名云厂商或者推理公司)。AIHubmix 的服务器是在美国谷歌云上采用集群部署,同时因为完全对接云厂商,所以稳定性非常好,有多端点路由机制,可以达到比直连官方更稳定的效果。
|
||||
|
||||
> AIHubmix 提供的免费模型足够我们完成项目的学习。
|
||||
|
||||
1. **访问 AIHubmix 平台**
|
||||
|
||||
打开浏览器,访问 [AIHubmix](https://aihubmix.com/?aff=anNj)。
|
||||
|
||||

|
||||
|
||||
2. **登录或注册账号**
|
||||
|
||||
如果已有账号,可以直接登录。如果没有,请点击页面右上角的注册按钮,使用邮箱或手机号完成注册。
|
||||
|
||||
3. **模型筛选**
|
||||
|
||||
注册完成后,来到[模型页面](https://aihubmix.com/models)。标签选择`免费`,可以看到官方提供了一定数量的免费模型。而且 AIHubmix 还提供了很多嵌入和重排序的国内外模型选择,这些在 RAG 领域都很常用。
|
||||
|
||||

|
||||
|
||||
4. **管理 API 密钥**
|
||||
|
||||
接着进入[密钥管理页面](https://console.aihubmix.com/token),如下图所示,默认已经有了一个密钥可以直接复制使用。当然也可以点击 `创建 Key` 填写名称后重新创建一个。
|
||||
|
||||

|
||||
|
||||
### 1.2 DeepSeek API 申请
|
||||
|
||||
要使用 Deepseek 提供的大语言模型服务,你首先需要一个 API Key。下面是申请步骤:
|
||||
|
||||
1. **访问 Deepseek 开放平台**
|
||||
|
||||
打开浏览器,访问 [Deepseek 开放平台](https://platform.deepseek.com/)。
|
||||
|
||||

|
||||
|
||||
2. **登录或注册账号**
|
||||
|
||||
如果你已有账号,请直接登录。如果没有,请点击页面上的注册按钮,使用邮箱或手机号完成注册。
|
||||
|
||||
3. **创建新的 API 密钥**
|
||||
|
||||
登录成功后,在页面左侧的导航栏中找到并点击 `API Keys`。在 API 管理页面,点击 `创建 API key` 按钮。输入一个跟其他api key不重复的名称后点击创建。
|
||||
|
||||

|
||||
|
||||
4. **保存 API Key**
|
||||
|
||||
系统会为你生成一个新的 API 密钥。请**立即复制**并将其保存在一个安全的地方。
|
||||
|
||||
> 注意:出于安全原因,这个密钥只会完整显示一次,关闭弹窗后就没法再看到了。
|
||||
|
||||

|
||||
|
||||
## 二、GitHub Codespaces 环境配置(推荐)
|
||||
|
||||
> 首先确定是否具有可以流畅访问 GitHub 的网络环境,若无法流畅访问请使用下面的Cloud Studio
|
||||
|
||||
GitHub Codespaces 是 GitHub 提供的一项服务,允许开发者在云端创建、编辑和运行代码。它提供了一个预配置的开发环境,包括代码编辑器、终端、调试工具等,可以直接在浏览器中使用。
|
||||
|
||||
### 2.1 创建Codespaces
|
||||
|
||||
1. **访问项目地址**
|
||||
|
||||
打开浏览器,访问 [all-in-rag](https://github.com/datawhalechina/all-in-rag)
|
||||
|
||||
2. **创建新分支**
|
||||
在项目页面的右上角,点击 `Fork` 按钮,创建一个新的分支。稍等一会儿即可创建成功。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
3. **创建Codespaces**
|
||||
在项目页面的右上角,点击 `Code` 按钮,然后选择 `Codespaces` 选项卡。点击 `New codespace` 按钮,等待新的 Codespaces 环境创建成功。
|
||||
|
||||

|
||||
|
||||
4. **再次进入Codespaces**
|
||||
网页关闭后,找到刚才新建的存储库,点击红框框选内容即可重新进入 codespace 环境。
|
||||
|
||||

|
||||
|
||||
5. **额度设置**
|
||||
找到 GitHub 的账户设置中的 codespace 设置,挂起时间建议根据自己情况调整(时间过长会浪费额度,免费账号提供了单核120小时的额度)
|
||||
|
||||

|
||||
|
||||
### 2.2 python环境配置
|
||||
|
||||
进入 IDE 后先选择下方终端
|
||||
|
||||

|
||||
|
||||
1. **更新系统软件包**
|
||||
|
||||
在终端输入下面指令:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
```
|
||||
|
||||
2. **安装Miniconda**
|
||||
|
||||
```bash
|
||||
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
|
||||
bash ~/miniconda.sh
|
||||
```
|
||||
|
||||
- 按 Enter 阅读许可协议
|
||||
- 输入 `yes` 同意协议
|
||||
- 安装路径提示时直接按 Enter(使用默认路径 /home/ubuntu/miniconda3)
|
||||
- 是否初始化Miniconda:输入 `yes` 将Miniconda添加到您的PATH环境变量中。
|
||||
|
||||
```bash
|
||||
source ~/.bashrc
|
||||
conda --version
|
||||
```
|
||||
|
||||
如果显示版本号,说明安装成功。
|
||||
|
||||
### 2.3 API配置
|
||||
|
||||
1. 使用 `vim` 编辑器打开你的 shell 配置文件。
|
||||
|
||||
```bash
|
||||
vim ~/.bashrc
|
||||
```
|
||||
|
||||
2. 输入 `i` 进入编辑模式,在文件末尾添加以下行,将 `[你的大模型 API 密钥]` 替换为你自己的密钥:
|
||||
|
||||
```bash
|
||||
export DEEPSEEK_API_KEY=[你的大模型 API 密钥]
|
||||
```
|
||||
|
||||
如果选择的是 `AIHubmix` 平台,为了增加辨识度也可以使用:
|
||||
|
||||
```bash
|
||||
export AIHUBMIX_API_KEY=[你的大模型 API 密钥]
|
||||
```
|
||||
|
||||
> 不要带 `[]`
|
||||
|
||||
3. 保存并退出 在 vim 中,按 Esc 键进入命令模式,然后输入 `:wq` 并按 Enter 键保存文件并退出。
|
||||
|
||||
4. 使配置生效 执行以下命令来立即加载更新后的配置,让环境变量生效:
|
||||
|
||||
```bash
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
### 2.4 创建并激活虚拟环境
|
||||
|
||||
1. **创建虚拟环境**
|
||||
|
||||
```bash
|
||||
conda create --name all-in-rag python=3.12.7
|
||||
```
|
||||
|
||||
出现选项直接回车即可。
|
||||
|
||||
2. **激活虚拟环境**
|
||||
|
||||
使用以下命令激活虚拟环境:
|
||||
|
||||
```bash
|
||||
conda activate all-in-rag
|
||||
```
|
||||
|
||||
3. **依赖安装**
|
||||
如果严格安装上述流程当前应该在项目根目录,进入code目录安装依赖库
|
||||
|
||||
```bash
|
||||
cd code
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
> 如果出现关于grpcio的版本错误无需在意。
|
||||
|
||||
## 三、Cloud Studio 环境配置(国内环境推荐)
|
||||
|
||||
Cloud Studio 是腾讯云推出的一款基于浏览器的集成开发环境(IDE)。支持CPU与GPU的访问。
|
||||
|
||||
> 听说一个月是50个小时的免费额度🤔
|
||||
|
||||
### 3.1 应用创建
|
||||
|
||||
1. **访问 Cloud Studio**
|
||||
打开浏览器,访问 [Cloud Studio](https://cloudstudio.net/)。
|
||||
|
||||
2. **登录或注册账号**
|
||||
点击页面右上角的 `注册登录` 按钮,使用微信等方式完成登录。
|
||||
|
||||
3. **创建应用**
|
||||
在页面上方的导航栏中找到并点击 `创建应用`。选择 `从 Git 仓库导入` ,在项目地址栏输入 `https://github.com/datawhalechina/all-in-rag.git` 后回车,将会自动为你创建标题和描述。
|
||||
|
||||

|
||||
|
||||
> 注意描述中不要包含网址
|
||||
|
||||
4. **再次进入**
|
||||
后续在[应用管理页面](https://cloudstudio.net/my-app)找到之前创建的应用,点击后选择右上角编写代码即可再次进入。
|
||||
|
||||

|
||||
|
||||
### 3.2 python环境配置
|
||||
|
||||
进入 IDE 后先选择右侧终端
|
||||
|
||||

|
||||
|
||||
1. **更新系统软件包**
|
||||
|
||||
在终端输入下面指令:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
```
|
||||
|
||||
2. **切换普通用户**
|
||||
|
||||
```bash
|
||||
su ubuntu
|
||||
```
|
||||
|
||||
3. **安装Miniconda**
|
||||
|
||||
```bash
|
||||
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
|
||||
bash ~/miniconda.sh
|
||||
```
|
||||
|
||||
- 按 Enter 阅读许可协议
|
||||
- 输入 `yes` 同意协议
|
||||
- 安装路径提示时直接按 Enter(使用默认路径 /home/ubuntu/miniconda3)
|
||||
- 是否初始化Miniconda:输入 `yes` 将Miniconda添加到您的PATH环境变量中。
|
||||
|
||||
```bash
|
||||
source ~/.bashrc
|
||||
conda --version
|
||||
```
|
||||
|
||||
如果显示版本号,说明安装成功。
|
||||
|
||||
### 3.3 API配置
|
||||
|
||||
1. 使用 `vim` 编辑器打开你的 shell 配置文件。
|
||||
|
||||
```bash
|
||||
vim ~/.bashrc
|
||||
```
|
||||
|
||||
2. 输入 `i` 进入编辑模式,在文件末尾添加以下行,将 `[你的大模型 API 密钥]` 替换为你自己的密钥:
|
||||
|
||||
```bash
|
||||
export DEEPSEEK_API_KEY=[你的大模型 API 密钥]
|
||||
```
|
||||
|
||||
如果选择的是 `AIHubmix` 平台,为了增加辨识度也可以使用:
|
||||
|
||||
```bash
|
||||
export AIHUBMIX_API_KEY=[你的大模型 API 密钥]
|
||||
```
|
||||
|
||||
> 不要带 `[]`
|
||||
|
||||
3. 保存并退出 在 vim 中,按 Esc 键进入命令模式,然后输入 `:wq` 并按 Enter 键保存文件并退出。
|
||||
|
||||
4. 使配置生效 执行以下命令来立即加载更新后的配置,让环境变量生效:
|
||||
|
||||
```bash
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
### 3.4 创建并激活虚拟环境
|
||||
|
||||
1. **创建虚拟环境**
|
||||
|
||||
```bash
|
||||
conda create --name all-in-rag python=3.12.7
|
||||
```
|
||||
|
||||
出现选项直接回车即可。
|
||||
|
||||
2. **配置文件权限**
|
||||
|
||||
```bash
|
||||
sudo chown -R ubuntu:ubuntu code models
|
||||
```
|
||||
|
||||
3. **激活虚拟环境**
|
||||
|
||||
使用以下命令激活虚拟环境:
|
||||
|
||||
```bash
|
||||
conda activate all-in-rag
|
||||
```
|
||||
|
||||
4. **依赖安装**
|
||||
如果严格安装上述流程当前应该在项目根目录,进入code目录安装依赖库
|
||||
|
||||
```bash
|
||||
cd code
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
> 如果出现关于grpcio的版本错误无需在意。
|
||||
|
||||
## 四、windows环境配置(使用Cloud Studio 或 Codespaces 可跳过此步骤)
|
||||
|
||||
### 4.1 API配置
|
||||
|
||||
1. 右键点击 “计算机” 或 “此电脑”,然后点击 “属性”。
|
||||
|
||||
2. 在左侧菜单中,点击 “高级系统设置”。
|
||||
|
||||
3. 在 “系统属性” 对话框中,点击 “高级” 选项卡,然后点击下方的 “环境变量” 按钮。
|
||||
|
||||

|
||||
|
||||
4. 在 “环境变量” 对话框中,点击 “新建”(在 “用户变量” 部分下),然后输入以下信息:
|
||||
- 变量名:DEEPSEEK_API_KEY
|
||||
- 变量值:[你的 Deepseek API 密钥]
|
||||
|
||||

|
||||
|
||||
### 4.2 安装Miniconda
|
||||
|
||||
1. **下载安装程序**
|
||||
|
||||
优先推荐访问[清华大学开源软件镜像站](https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/),以获得更快的下载速度。根据你的系统选择最新的 `.exe` 版本下载。
|
||||
|
||||

|
||||
|
||||
你也可以从 [Miniconda 官方网站](https://docs.conda.io/en/latest/miniconda.html)下载。
|
||||
|
||||
2. **运行安装向导**
|
||||
|
||||
下载完成后,双击 `.exe` 文件启动安装。按照向导提示操作:
|
||||
|
||||
* **Welcome**: 点击 `Next`。
|
||||
|
||||

|
||||
|
||||
* **License Agreement**: 点击 `I Agree`。
|
||||
|
||||

|
||||
|
||||
* **Installation Type**: 选择 `Just Me`,点击 `Next`。
|
||||
|
||||

|
||||
|
||||
* **Choose Install Location**: 建议保持默认路径,或选择一个不含中文和空格的路径。点击 `Next`。
|
||||
|
||||

|
||||
|
||||
* **Advanced Installation Options**: **请不要勾选** “Add Miniconda3 to my PATH environment variable”。我们将稍后手动配置环境变量。点击 `Install`。
|
||||
|
||||

|
||||
|
||||
* **Installation Complete**: 安装完成后,点击 `Next`,然后取消勾选 “Learn more” 并点击 `Finish` 完成安装。
|
||||
|
||||
3. **手动配置环境变量**
|
||||
|
||||
为了能在任意终端窗口使用 `conda` 命令,需要手动配置环境变量。
|
||||
|
||||
* 在Windows搜索栏中搜索“编辑系统环境变量”并打开。
|
||||
|
||||

|
||||
|
||||
* 在“系统属性”窗口中,点击“环境变量”。
|
||||
|
||||

|
||||
|
||||
* 在“环境变量”窗口中,找到“系统变量”下的 `Path` 变量,选中并点击“编辑”。
|
||||
|
||||

|
||||
|
||||
* 在“编辑环境变量”窗口中,新建三个路径,将它们指向你 Miniconda 的安装目录下的相应文件夹。如果你的安装路径是 `D:\Miniconda3`,则需要添加:
|
||||
```
|
||||
D:\Miniconda3
|
||||
D:\Miniconda3\Scripts
|
||||
D:\Miniconda3\Library\bin
|
||||
```
|
||||

|
||||
|
||||
* 完成后,一路点击“确定”保存更改。
|
||||
|
||||
### 4.3 配置 Conda 镜像源
|
||||
|
||||
为了加快后续使用 `conda` 安装包的速度,强烈建议配置国内镜像源。打开一个新的终端或 Anaconda Prompt,运行以下命令:
|
||||
|
||||
```bash
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
|
||||
conda config --set show_channel_urls yes
|
||||
```
|
||||
|
||||
配置完成后,可以通过 `conda config --show channels` 命令查看已添加的源。
|
||||
|
||||
## 五、项目代码拉取(使用Cloud Studio 或 Codespaces 可跳过此步骤)
|
||||
|
||||
### 5.1 安装 Git
|
||||
|
||||
如果你尚未安装 Git,请按照以下步骤安装。
|
||||
|
||||
* **Windows 系统**:访问[Git 官方网站](https://git-scm.com/download/win),下载并运行安装程序,按照默认设置完成安装。
|
||||
* **macOS 系统**:打开终端,输入以下命令安装 Git:
|
||||
|
||||
```bash
|
||||
brew install git
|
||||
```
|
||||
* **Linux 系统(以 Ubuntu 为例)**:打开终端,输入以下命令安装 Git:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install git
|
||||
```
|
||||
|
||||
安装完成后,验证 Git 是否安装成功,输入以下命令:
|
||||
|
||||
```bash
|
||||
git --version
|
||||
```
|
||||
|
||||
如果成功,会显示 Git 的版本号。
|
||||
|
||||
### 5.2 克隆项目代码
|
||||
|
||||
1. **选择存放项目的目录**
|
||||
打开终端(或 Windows 中的 Git Bash),导航到你想存放项目的目录:
|
||||
|
||||
```bash
|
||||
cd [你希望存放项目的路径]
|
||||
```
|
||||
|
||||
2. **克隆仓库**
|
||||
使用以下命令拉取 `all-in-rag` 仓库:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/datawhalechina/all-in-rag.git
|
||||
```
|
||||
|
||||
等待下载完成,项目代码将存放在当前目录下的 `all-in-rag` 文件夹中。
|
||||
|
||||
3. **进入项目目录**
|
||||
拉取代码后,进入项目目录:
|
||||
|
||||
```bash
|
||||
cd all-in-rag
|
||||
```
|
||||
|
||||
### 5.3 创建并激活虚拟环境
|
||||
|
||||
在项目目录下,推荐使用前面配置好的 Miniconda 来创建 Python 虚拟环境。
|
||||
|
||||
1. **创建虚拟环境**
|
||||
|
||||
```bash
|
||||
conda create --name all-in-rag python=3.12.7
|
||||
```
|
||||
|
||||
2. **激活虚拟环境**
|
||||
|
||||
所有系统统一使用以下命令激活虚拟环境:
|
||||
|
||||
```bash
|
||||
conda activate all-in-rag
|
||||
```
|
||||
|
||||
3. **依赖安装**
|
||||
如果严格安装上述流程当前应该在项目根目录,进入code目录安装依赖库
|
||||
|
||||
```bash
|
||||
cd code
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
@@ -0,0 +1,250 @@
|
||||
# 第三节 四步构建RAG
|
||||
|
||||
通过第一节的学习,我们对RAG已经有了基本认识,并且也准备好了虚拟环境和api_key,接下来将尝试使用[**LangChain**](https://python.langchain.com/docs/introduction/)和[**LlamaIndex**](https://docs.llamaindex.ai/en/stable/)框架完成第一个RAG应用的实现与运行。通过一个示例,演示如何加载本地Markdown文档,利用嵌入模型处理文本,并结合大型语言模型(LLM)来回答与文档内容相关的问题。
|
||||
|
||||
## 一、启动虚拟环境
|
||||
|
||||
### 1.1 激活虚拟环境
|
||||
|
||||
假设已经按照前一章节的指导,创建了名为 `all-in-rag` 的 Conda 虚拟环境。在运行脚本前,先激活虚拟环境:
|
||||
|
||||
> 如果使用是Cloud Studio,需要确认当前是否是用户环境,如果不是请运行 `su ubuntu` 切换到用户环境。
|
||||
|
||||
```bash
|
||||
conda activate all-in-rag
|
||||
```
|
||||
|
||||
### 1.2 切换到项目目录
|
||||
|
||||
```bash
|
||||
# 假设当前在 all-in-rag 项目的根目录下
|
||||
cd code/C1
|
||||
```
|
||||
|
||||
每章内容中的代码文件都存放在 `code/Cx` 目录下,其中 `x` 表示章节编号。
|
||||
|
||||
## 二、运行RAG示例代码
|
||||
|
||||
完成上述所有设置后,就可以运行RAG示例了。
|
||||
|
||||
打开终端,确保虚拟环境已激活,然后执行以下命令:
|
||||
|
||||
```bash
|
||||
python 01_langchain_example.py
|
||||
```
|
||||
|
||||
> 若出现nltk相关报错,尝试运行代码路径下[fix_nltk.py](https://github.com/datawhalechina/all-in-rag/blob/main/code/C1/fix_nltk.py)
|
||||
|
||||
代码运行后,可以看到类似下面的输出(格式化后):
|
||||
|
||||
```bash
|
||||
Downloading Model from https://www.modelscope.cn to directory: Path\to\all-in-rag\models\bge-small-zh-v1.5
|
||||
2025-06-08 02:36:19,318 - modelscope - INFO - Target directory already exists, skipping creation.
|
||||
content='
|
||||
文中举了以下例子:
|
||||
|
||||
1. **自然界中的羚羊**:刚出生的羚羊通过试错学习站立和奔跑,适应环境。
|
||||
2. **股票交易**:通过买卖股票并根据市场反馈调整策略,最大化奖励。
|
||||
3. **雅达利游戏(如Breakout和Pong)**:通过不断试错学习如何通关或赢得游戏。
|
||||
4. **选择餐馆**:利用(去已知喜欢的餐馆)与探索(尝试新餐馆)的权衡。
|
||||
5. **做广告**:利用(采取已知最优广告策略)与探索(尝试新广告策略)。
|
||||
6. **挖油**:利用(在已知地点挖油)与探索(在新地点挖油,可能发现大油田)。
|
||||
7. **玩游戏(如《街头霸王》)**:利用(固定策略如蹲角落出脚)与探索(尝试新招式如“大招”)。
|
||||
|
||||
这些例子用于说明强化学习中的核心概念(如探索与利用、延迟奖励等)及其在实际场景中的应用。
|
||||
'
|
||||
additional_kwargs={'refusal': None}
|
||||
response_metadata={
|
||||
'token_usage': {
|
||||
'completion_tokens': 209,
|
||||
'prompt_tokens': 5576,
|
||||
'total_tokens': 5785,
|
||||
'completion_tokens_details': None,
|
||||
'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 5568},
|
||||
'prompt_cache_hit_tokens': 5568,
|
||||
'prompt_cache_miss_tokens': 8
|
||||
},
|
||||
'model_name': 'deepseek-chat',
|
||||
'system_fingerprint': 'fp_8802369eaa_prod0425fp8',
|
||||
'id': '67a0580d-78b1-44d6-bccf-f654ae0e9bba',
|
||||
'service_tier': None,
|
||||
'finish_reason': 'stop',
|
||||
'logprobs': None
|
||||
}
|
||||
id='run--919cedcd-771e-4aed-8dfd-cf436795792e-0'
|
||||
usage_metadata={
|
||||
'input_tokens': 5576,
|
||||
'output_tokens': 209,
|
||||
'total_tokens': 5785,
|
||||
'input_token_details': {'cache_read': 5568},
|
||||
'output_token_details': {}
|
||||
}
|
||||
```
|
||||
|
||||
> 首次运行时,脚本会下载`BAAI/bge-small-zh-v1.5`嵌入模型。
|
||||
|
||||
输出参数解析:
|
||||
- **`content`**: 这是最核心的部分,即大型语言模型(LLM)根据你的问题和提供的上下文生成的具体回答。
|
||||
- **`additional_kwargs`**: 包含一些额外的参数,在这个例子中是 `{'refusal': None}`,表示模型没有拒绝回答。
|
||||
- **`response_metadata`**: 包含了关于LLM响应的元数据。
|
||||
- `token_usage`: 显示了本次调用消耗的token数量,包括完成(completion_tokens)、提示(prompt_tokens)和总量(total_tokens)。
|
||||
- `model_name`: 使用的LLM模型名称,当前是 `deepseek-chat`。
|
||||
- `system_fingerprint`, `id`, `service_tier`, `finish_reason`, `logprobs`: 这些是更详细的API响应信息,例如 `finish_reason: 'stop'` 表示模型正常完成了生成。
|
||||
- **`id`**: 本次运行的唯一标识符。
|
||||
- **`usage_metadata`**: 与 `response_metadata` 中的 `token_usage` 类似,提供了输入和输出token的统计。
|
||||
|
||||
## 三、基于 LangChain 框架的 RAG 实现
|
||||
|
||||
在第一节中,我们提到四步构建最小可行系统分别是数据准备、索引构建、检索优化和生成集成。下面将围绕这四个方面来实现一个基于 LangChain 框架的 RAG 应用。
|
||||
|
||||
> [本节完整代码](https://github.com/datawhalechina/all-in-rag/blob/main/code/C1/01_langchain_example.py)
|
||||
|
||||
### 3.1 初始化设置
|
||||
|
||||
首先进行基础配置,包括导入必要的库、加载环境变量以及下载嵌入模型。
|
||||
|
||||
```python
|
||||
import os
|
||||
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
|
||||
from dotenv import load_dotenv
|
||||
from langchain_community.document_loaders import TextLoader
|
||||
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
||||
from langchain_huggingface import HuggingFaceEmbeddings
|
||||
from langchain_core.vectorstores import InMemoryVectorStore
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_deepseek import ChatOpenAI
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
```
|
||||
|
||||
### 3.2 数据准备
|
||||
|
||||
- **加载原始文档**: 先定义Markdown文件的路径,然后使用`TextLoader`加载该文件作为知识源。
|
||||
```python
|
||||
markdown_path = "../../data/C1/markdown/easy-rl-chapter1.md"
|
||||
loader = TextLoader(markdown_path)
|
||||
docs = loader.load()
|
||||
```
|
||||
- **文本分块 (Chunking)**: 为了便于后续的嵌入和检索,长文档被分割成较小的、可管理的文本块(chunks)。这里采用了递归字符分割策略,使用其默认参数进行分块。当不指定参数初始化 `RecursiveCharacterTextSplitter()` 时,其默认行为旨在最大程度保留文本的语义结构:
|
||||
- **默认分隔符与语义保留**: 按顺序尝试使用一系列预设的分隔符 `["\n\n" (段落), "\n" (行), " " (空格), "" (字符)]` 来递归分割文本。这种策略的目的是尽可能保持段落、句子和单词的完整性,因为它们通常是语义上最相关的文本单元,直到文本块达到目标大小。
|
||||
- **保留分隔符**: 默认情况下 (`keep_separator=True`),分隔符本身会被保留在分割后的文本块中。
|
||||
- **默认块大小与重叠**: 使用其基类 `TextSplitter` 中定义的默认参数 `chunk_size=4000`(块大小)和 `chunk_overlap=200`(块重叠)。这些参数确保文本块符合预定的大小限制,并通过重叠来减少上下文信息的丢失。
|
||||
```python
|
||||
text_splitter = RecursiveCharacterTextSplitter()
|
||||
texts = text_splitter.split_documents(docs)
|
||||
```
|
||||
|
||||
### 3.3 索引构建
|
||||
|
||||
数据准备完成后,接下来构建向量索引:
|
||||
|
||||
- **初始化中文嵌入模型**: 使用`HuggingFaceEmbeddings`加载之前在初始化设置中下载的中文嵌入模型。配置模型在CPU上运行,并启用嵌入归一化 (`normalize_embeddings: True`)。
|
||||
```python
|
||||
embeddings = HuggingFaceEmbeddings(
|
||||
model_name="BAAI/bge-small-zh-v1.5",
|
||||
model_kwargs={'device': 'cpu'},
|
||||
encode_kwargs={'normalize_embeddings': True}
|
||||
)
|
||||
```
|
||||
- **构建向量存储**: 将分割后的文本块 (`texts`) 通过初始化好的嵌入模型转换为向量表示,然后使用`InMemoryVectorStore`将这些向量及其对应的原始文本内容添加进去,从而在内存中构建出一个向量索引。
|
||||
```python
|
||||
vectorstore = InMemoryVectorStore(embeddings)
|
||||
vectorstore.add_documents(texts)
|
||||
```
|
||||
这个过程完成后,便构建了一个可供查询的知识索引。
|
||||
|
||||
### 3.4 查询与检索
|
||||
|
||||
索引构建完毕后,便可以针对用户问题进行查询与检索:
|
||||
|
||||
- **定义用户查询**: 设置一个具体的用户问题字符串。
|
||||
```python
|
||||
question = "文中举了哪些例子?"
|
||||
```
|
||||
- **在向量存储中查询相关文档**: 使用向量存储的`similarity_search`方法,根据用户问题在索引中查找最相关的 `k` (此处示例中 `k=3`) 个文本块。
|
||||
```python
|
||||
retrieved_docs = vectorstore.similarity_search(question, k=3)
|
||||
```
|
||||
- **准备上下文**: 将检索到的多个文本块的页面内容 (`doc.page_content`) 合并成一个单一的字符串,并使用双换行符 (`"\n\n"`) 分隔各个块,形成最终的上下文信息 (`docs_content`) 供大语言模型参考。
|
||||
```python
|
||||
docs_content = "\n\n".join(doc.page_content for doc in retrieved_docs)
|
||||
```
|
||||
> 使用 `"\n\n"` (双换行符) 而不是 `"\n"` (单换行符) 来连接不同的检索文档块,主要是为了在传递给大型语言模型(LLM)时,能够更清晰地在语义上区分这些独立的文本片段。双换行符通常代表段落的结束和新段落的开始,这种格式有助于LLM将每个块视为一个独立的上下文来源,从而更好地理解和利用这些信息来生成回答。
|
||||
|
||||
### 3.5 生成集成
|
||||
|
||||
最后一步是将检索到的上下文与用户问题结合,利用大语言模型(LLM)生成答案:
|
||||
|
||||
- **构建提示词模板**: 使用`ChatPromptTemplate.from_template`创建一个结构化的提示模板。此模板指导LLM根据提供的上下文 (`context`) 回答用户的问题 (`question`),并明确指出在信息不足时应如何回应。
|
||||
```python
|
||||
prompt = ChatPromptTemplate.from_template("""请根据下面提供的上下文信息来回答问题。
|
||||
请确保你的回答完全基于这些上下文。
|
||||
如果上下文中没有足够的信息来回答问题,请直接告知:“抱歉,我无法根据提供的上下文找到相关信息来回答此问题。”
|
||||
|
||||
上下文:
|
||||
{context}
|
||||
|
||||
问题: {question}
|
||||
|
||||
回答:"""
|
||||
)
|
||||
```
|
||||
- **配置大语言模型**: 初始化 `ChatOpenAI` 客户端,配置所用模型(`glm-4.7-flash-free`)、生成答案的温度参数(`temperature=0.7`)、最大Token数 (`max_tokens=2048`) 以及API密钥(从环境变量加载)和 url。
|
||||
```python
|
||||
llm = ChatOpenAI(
|
||||
model="glm-4.7-flash-free",
|
||||
temperature=0.7,
|
||||
max_tokens=2048,
|
||||
api_key=os.getenv("DEEPSEEK_API_KEY")
|
||||
base_url="https://aihubmix.com/v1"
|
||||
)
|
||||
```
|
||||
- **调用LLM生成答案并输出**: 将用户问题 (`question`) 和先前准备好的上下文 (`docs_content`) 格式化到提示模板中,然后调用ChatDeepSeek的`invoke`方法获取生成的答案。
|
||||
```python
|
||||
answer = llm.invoke(prompt.format(question=question, context=docs_content))
|
||||
print(answer)
|
||||
```
|
||||
|
||||
> 老湿老湿,Langchain 很强大但还是太吃操作了,有没有更加简单又好用的框架推荐呢?
|
||||
|
||||
> 有的兄弟,有的!像这样好用的框架还有LlamaIndex😉
|
||||
|
||||
## 四、低代码(基于LlamaIndex)
|
||||
|
||||
在 RAG 方面,LlamaIndex 提供了更多封装好的 API 接口,这无疑降低了上手门槛,下面是一个简单实现:
|
||||
|
||||
```python
|
||||
import os
|
||||
# os.environ['HF_ENDPOINT']='https://hf-mirror.com'
|
||||
from dotenv import load_dotenv
|
||||
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
|
||||
from llama_index.llms.openai_like import OpenAILike
|
||||
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
||||
|
||||
load_dotenv()
|
||||
|
||||
Settings.llm = OpenAILike(
|
||||
model="glm-4.7-flash-free",
|
||||
api_key=os.getenv("DEEPSEEK_API_KEY"),
|
||||
api_base="https://aihubmix.com/v1",
|
||||
is_chat_model=True
|
||||
)
|
||||
Settings.embed_model = HuggingFaceEmbedding("BAAI/bge-small-zh-v1.5")
|
||||
|
||||
documents = SimpleDirectoryReader(input_files=["../../data/C1/markdown/easy-rl-chapter1.md"]).load_data()
|
||||
|
||||
index = VectorStoreIndex.from_documents(documents)
|
||||
|
||||
query_engine = index.as_query_engine()
|
||||
|
||||
print(query_engine.get_prompts())
|
||||
|
||||
print(query_engine.query("文中举了哪些例子?"))
|
||||
```
|
||||
|
||||
## 练习(可利用大模型辅助完成)
|
||||
|
||||
- LangChain代码最终得到的输出携带了各种参数,查询相关资料尝试把这些参数过滤掉得到`content`里的具体回答。
|
||||
- 修改Langchain代码中`RecursiveCharacterTextSplitter()`的参数`chunk_size`和`chunk_overlap`,观察输出结果有什么变化。
|
||||
- 给LlamaIndex代码添加代码注释。
|
||||
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 962 KiB |
|
After Width: | Height: | Size: 237 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 219 KiB |
|
After Width: | Height: | Size: 198 KiB |
@@ -0,0 +1,91 @@
|
||||
# 附:Python虚拟环境部署方案补充
|
||||
|
||||
本项目由于涉及到的包过多,并且**依赖问题**自始至终都是Python的老大难问题,这就造成了 Python 工程化方面生态非常割裂。
|
||||
|
||||
对于这种问题,uv提供了统一的虚拟环境管理入口,同时吸收了 Rust 语言先进的包管理经验,使用它可以减少我们在 Python 工程方面折腾的时间,下面我们使用uv来安装项目的虚拟环境。
|
||||
|
||||
## 1.1 uv 环境管理
|
||||
|
||||
### 1.1.1 Windows 系统
|
||||
|
||||
**使用powershell 安装 uv**
|
||||
|
||||
```bash
|
||||
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||
```
|
||||
|
||||
**安装成功后,按照提示输入以下命令添加环境变量**。这里注意,**不同的人的安装路径不同**,请按照提示自行复制粘贴命令。
|
||||
|
||||
|
||||
```bash
|
||||
$env:Path = "C:\Users\michaelbradley\.local\bin;$env:Path"
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
**输入 uv 命令,如果出现以下提示,说明安装成功**
|
||||
|
||||

|
||||
|
||||
### 1.1.2 Linux / MacOS 系统
|
||||
|
||||
**使用 curl 安装 uv**
|
||||
|
||||
```bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
如果无法使用 curl 命令,**使用 wget 命令**安装 uv
|
||||
|
||||
```bash
|
||||
wget -qO- https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
**输入 uv 命令,如果出现以下提示,说明安装成功**
|
||||
|
||||

|
||||
|
||||
|
||||
## 1.2 创建并激活虚拟环境
|
||||
|
||||
### 1.2.1 **创建虚拟环境**
|
||||
|
||||
```bash
|
||||
uv venv rag --python 3.12.7
|
||||
```
|
||||
|
||||
代码创建的虚拟环境名称为 rag ,使用Python版本为 3.12.7
|
||||
|
||||
Windows 系统创建成功后显示如下信息:
|
||||
|
||||
```bash
|
||||
PS C:\Users\parallel> uv venv rag --python 3.12.7
|
||||
Using CPython 3.12.7
|
||||
Creating virtual environment at: rag
|
||||
Activate with: rag\Scripts\activate
|
||||
```
|
||||
|
||||
Linux / MacOS 系统创建成功后显示如下信息:
|
||||
|
||||
```bash
|
||||
┌──(parallel㉿pacman)-[~/桌面]
|
||||
└─$ uv venv rag -p 3.12.7
|
||||
Using CPython 3.12.7
|
||||
Creating virtual environment at: rag
|
||||
Activate with: source rag/bin/activate
|
||||
```
|
||||
|
||||
### 1.2.2 **激活虚拟环境**
|
||||
|
||||
Windows 系统激活虚拟环境命令为:
|
||||
|
||||
```bash
|
||||
rag\Scripts\activate
|
||||
```
|
||||
|
||||
Linux / MacOS 系统激活虚拟环境命令为:
|
||||
|
||||
```bash
|
||||
source rag/bin/activate
|
||||
```
|
||||