Initial commit

This commit is contained in:
2026-05-12 09:41:56 +08:00
commit 572283e101
936 changed files with 133949 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
# Chapter 1: Introduction to RAG
## 1. What is RAG?
### 1.1 Core Definition
In essence, RAG (Retrieval-Augmented Generation) is a technical paradigm designed to solve the problem of large language models (LLMs) "knowing things without knowing why." Its core idea is to combine the **"Parametric Knowledge"** learned internally by the model (i.e., the solidified, fuzzy "memory" in its weights) with **"Non-parametric Knowledge"** from external knowledge bases (i.e., precise, externally updatable data).
In plain terms, its operational logic is to dynamically retrieve relevant information from an external knowledge base before the LLM generates text, and integrate these "reference materials" into the generation process, thereby improving the output's accuracy and timeliness [^1] [^2] [^3].
> 💡 **In one sentence**: RAG teaches an LLM to perform an "open-book exam," allowing it to use both what it has learned and what it can look up.
### 1.2 Technical Principles
So, how does a RAG system achieve this combination of "parametric" and "non-parametric" knowledge? As shown in Figure 1-1, its core architecture accomplishes this process through two main phases:
1. **Retrieval Phase: Finding "Non-parametric Knowledge"**
- **Knowledge Vectorization**: The **Embedding Model** acts as a "connector." It first encodes the external knowledge base into a vector index and stores it in a **Vector Database**.
- **Semantic Recall**: When a user makes a query, the retrieval module uses the same embedding model to vectorize the question and, through **Similarity Search**, precisely locates and recalls the most relevant document chunks from the vast data.
2. **Generation Phase: Fusing the Two Types of Knowledge**
- **Context Integration**: The generation module receives the relevant document chunks from the retrieval phase and the user's original query.
- **Instructed Generation**: This module follows a preset **Prompt** to effectively integrate the context with the query and guides an LLM (like DeepSeek) to perform controlled, well-reasoned text generation.
<div align="center">
<img src="./images/1_1_1.svg" width="70%" alt="RAG Two-Stage Architecture Diagram">
<p>Figure 1-1 RAG Two-Stage Architecture Diagram</p>
</div>
### 1.3 Technical Evolution Classification
The technical architecture of RAG has evolved from simple to complex, which can be broadly divided into three stages as shown in Figure 1-2 [^4].
<div align="center">
<img src="./images/1_1_2.png" width="70%" alt="RAG Technical Evolution Classification">
<p>Figure 1-2 RAG Technical Evolution Classification</p>
</div>
| | **Naive RAG** | **Advanced RAG** | **Modular RAG** |
|:---:|:---:|:---:|:---:|
| **Flow** | **Offline:** `Index`<br>**Online:** `Retrieve → Generate` | **Offline:** `Index`<br>**Online:** `...→ Pre-retrieve → ... → Post-retrieve → ...` | "LEGO-like" orchestrable flow |
| **Core Feature** | Basic linear flow | Adds optimization steps **before/after retrieval** | Modular, composable, dynamically adjustable |
| **Key Tech** | Basic vector retrieval | **Query Rewrite**<br>**Rerank** | **Routing**<br>**Query Transformation**<br>**Fusion** |
| **Limitations**| Unstable performance, hard to optimize | Relatively fixed flow, limited optimization points | High system complexity |
> "Offline" refers to pre-processing work done in advance (like index construction); "Online" refers to the real-time processing flow after a user request.
## 2. Why Use RAG?
### 2.1 Technical Selection: RAG vs. Fine-tuning
When choosing a technical path, a key consideration is the balance between cost and benefit. Typically, we should prioritize the solution with the least modification to the model and the lowest cost, so the technical selection path often follows this order:
**Prompt Engineering -> Retrieval-Augmented Generation -> Fine-tuning**.
We can understand the differences between these techniques from two dimensions. As shown in Figure 1-3, the **horizontal axis represents "LLM Optimization"**—the degree to which the model itself is modified. From left to right, the level of optimization deepens; Prompt Engineering and RAG do not change model weights at all, while Fine-tuning directly modifies model parameters. The **vertical axis represents "Context Optimization"**—the degree to which the information provided to the model is enhanced. From bottom to top, the level of enhancement increases; Prompt Engineering only optimizes the way questions are asked, while RAG vastly enriches the context by introducing an external knowledge base.
<div align="center">
<img src="./images/1_1_3.svg" width="70%" alt="Technical Selection Path" />
<p>Figure 1-3 RAG, Fine-tuning, and Prompt Engineering Technical Selection Path</p>
</div>
Based on this framework, our selection path becomes clear:
- **First, try Prompt Engineering**: Guide the model by carefully designing prompts, suitable for simple tasks where the model already has relevant knowledge.
- **Then, choose RAG**: If the model cannot answer due to a lack of specific or real-time knowledge, use RAG to provide contextual information through an external knowledge base.
- **Finally, consider Fine-tuning**: When the goal is to change "how" the model does something (behavior/style/format) rather than "what" it knows (knowledge), Fine-tuning is the ultimate and most appropriate choice. For example, teaching the model to strictly follow a unique output format, mimic a specific character's dialogue style, or "distill" extremely complex instructions into the model weights.
RAG bridges the gap between general-purpose models and specialized domains, and it is particularly effective at addressing the following core limitations of LLMs:
| Problem | RAG Solution |
|---------------------|----------------------------------|
| **Static Knowledge Limitation** | Real-time retrieval from external knowledge bases, supporting dynamic updates |
| **Hallucination** | Generation based on retrieved content, reducing error rates |
| **Lack of Domain Expertise** | Introduction of domain-specific knowledge bases (e.g., medical/legal) |
| **Data Privacy Risks** | Local deployment of knowledge bases, avoiding sensitive data leakage |
### 2.2 Key Advantages
**1. Dual Improvement in Accuracy and Trustworthiness**
The core value of RAG lies in breaking through the limitations of the model's pre-trained knowledge. It not only **fills knowledge gaps in specialized domains** but also effectively **suppresses the "hallucination" phenomenon** by providing concrete reference materials. Research also shows that RAG-generated content is significantly superior in **Specificity** and **Diversity** compared to pure LLMs. More importantly, RAG provides **traceability**—every answer can be traced back to its original source document, which greatly enhances the credibility of the content in serious contexts like law and medicine.
**2. Timeliness Guarantee**
In terms of knowledge updates, RAG solves the inherent **knowledge cutoff problem** of LLMs (i.e., the model is unaware of events after its training date). RAG allows the knowledge base to be **dynamically updated** independently of the model. This capability is referred to in papers as **"Index Hot-swapping"**—like swapping a memory card in a robot, it instantly switches the world knowledge base without retraining the model, enabling real-time knowledge.
**3. Significant Overall Cost-Effectiveness**
From an economic perspective, RAG is a highly cost-effective solution. First, it **avoids the huge computational costs of frequent fine-tuning**. Second, with the powerful assistance of external knowledge, we can often use **smaller base models** to achieve similar results on specific domain problems, directly reducing inference costs. This architecture also reduces the resources needed to forcibly "stuff" massive amounts of knowledge into model weights.
**4. Flexible and Modular Scalability**
The RAG architecture is highly inclusive, supporting **multi-source integration** from data like PDFs, Word documents, or web pages into a unified knowledge base. At the same time, its **modular design** decouples retrieval and generation, meaning we can independently optimize the retrieval component (e.g., by swapping in a better embedding model) without affecting the stability of the generation component, facilitating long-term system iteration.
### 2.3 Risk-Graded Application Scenarios
> The following shows the applicability of RAG technology in scenarios with different risk levels
| Risk Level | Examples | RAG Applicability |
|:--------:|:------------------------------|:--------------------------:|
| **Low Risk** | Translation/Grammar checking | High reliability |
| **Medium Risk** | Contract drafting/Legal consultation | Requires human review |
| **High Risk** | Evidence analysis/Visa decisions | Requires strict quality control mechanisms |
## 3. How to Get Started with RAG?
### 3.1 Basic Toolchain Selection
Building a RAG system typically involves selecting key components. For the **development mode**, you can use established frameworks like **LangChain** or **LlamaIndex** for rapid integration, **or you can opt for native development without a framework** to gain finer control over the system flow (which is not difficult with AI programming assistance). For the **memory carrier** (vector database), choices range from solutions suitable for large-scale data like **Milvus** and **Pinecone** to lightweight or local options like **FAISS** and **Chroma**, depending on the specific business scale. Finally, to quantify performance, you can also introduce automated **evaluation tools** like **RAGAS** or **TruLens**.
### 3.2 Four Steps to Build a Minimum Viable Product (MVP)
1. **Data Preparation and Cleaning**
This is the foundation of the system. You need to standardize heterogeneous data from sources like PDFs and Word documents and adopt a reasonable **chunking strategy** (e.g., splitting by semantic paragraphs rather than fixed character counts) to avoid information fragmentation.
2. **Index Construction**
Convert the chunked text into vectors using an **embedding model** and store them in the database. It is helpful at this stage to associate **metadata** (like source and page number), which is crucial for precise citations later.
3. **Retrieval Strategy Optimization**
Do not rely on a single vector search. Consider using **hybrid retrieval** (vector + keyword) to improve recall, and introduce a **reranking** model to further refine the search results, ensuring the LLM receives high-quality context.
4. **Generation and Prompt Engineering**
Finally, design a clear **Prompt template** to guide the LLM to answer user questions based on the retrieved context, and explicitly require the model to state "I don't know" when it is unsure, to prevent hallucinations.
### 3.3 Beginner-Friendly Solutions
If you want to quickly validate ideas rather than dive deep into code, you can try visual knowledge base platforms like **FastGPT** or **Dify**, which encapsulate complex RAG workflows and allow you to get started just by uploading documents. For developers, using open-source templates like **LangChain4j Easy RAG** or **TinyRAG** [^5] on GitHub is also a highly efficient starting point.
### 3.4 Advanced Topics and Challenges
Once a basic RAG system is built, the next step is to focus on how to evaluate, diagnose, and overcome its inherent bottlenecks.
**1. Evaluation Dimensions & Challenges**
The quality of a RAG system cannot be judged by feeling alone. The industry typically uses several dimensions for quantitative evaluation: first is **retrieval relevance** (does the retrieved content contain the answer?), followed by **generation quality**, which can be subdivided into **semantic faithfulness** (is the meaning of the answer correct?) and **lexical appropriateness** (are technical terms used correctly?).
These evaluation dimensions also directly correspond to the main challenges RAG currently faces. For example, the **retrieval dependency** problem—if the retrieval system recalls incorrect information, even the most powerful LLM will confidently spout nonsense. Additionally, current RAG architectures generally struggle with **multi-hop reasoning** problems that require synthesizing information across multiple documents.
**2. Optimization Directions & Architectural Evolution**
In response to these challenges, the community has explored various optimization paths. At the **performance level**, efficiency and capabilities can be enhanced through **layered indexing** (enabling caching for high-frequency data) and **multimodal extension** (supporting image/table retrieval). At the **architecture level**, simple linear flows are being replaced by more complex **design patterns**. For example, a system can use a **branching pattern** to handle multi-route retrieval in parallel or a **looping pattern** for self-correction. These flexible architectures are the path toward more intelligent RAG systems.
## 4. Is RAG Dead?
With the rise of long context window capabilities in large models, a voice has emerged in the community: "RAG is dead." The core arguments come from two aspects: first, that long context can already "digest" massive texts by brute force, making complex retrieval systems unnecessary; second, a criticism that the term RAG itself is too broad, blurring too many technical details and thus hindering clear understanding and optimization.
These views, however, overlook a common pattern in the evolution of technical concepts. Just as we could easily coin a more precise, impressive name for a modern, complex RAG system—like the **"Large Language Model Knowledge Management Expert System" (LKE)**. It has already far surpassed the simple "retrieve-augment-generate" scope. But this "renaming game" merely illustrates the superficiality of the "RAG is dead" argument—it is tantamount to putting old wine in a new bottle.
> The author does not intend to create a new term here, but why call it LKE? It represents three core elements:
> - **L (Large Language Model)**: Emphasizes that the system's driving force is the large language model.
> - **K (Knowledge Management)**: Signifies that the system acts like a knowledge administrator, precisely **finding** (retrieving) the knowledge we need to assist us in higher-level applications using the large model.
> - **E (Expert)**: Implies that the system can act like an expert, accurately providing answers (generation) and solving problems through a series of steps like routing, analysis, fusion, and correction.
A more fitting analogy is the **Transformer**. Today, whether it's the Decoder-only architecture represented by GPT or the Encoder-only of BERT, we are accustomed to calling them "based on the Transformer architecture," despite their vast differences from the original paper's complete form. The Transformer label captured the core leap of a technical paradigm and became a cultural symbol of an era. By the same token, **the core of RAG lies in "combining the LLM's internal parametric knowledge with external non-parametric knowledge."** As long as this idea holds, no matter how many modules we add—query transformation, multi-route retrieval, or self-correction—it is still an evolution within this framework.
Therefore, "RAG is dead" is a false proposition. On the contrary, **RAG as a concept is very much alive**; like the Transformer, it is becoming a foundational architectural paradigm that continuously absorbs new technologies and evolves. Its vitality lies precisely in its "unrecognizability" and "all-encompassing" nature. And **the goal of this tutorial is to draw a clear map of this RAG landscape. When we can deconstruct its every module and understand its every possibility, the debate over whether "RAG is dead" resolves itself.**
> RAG technology is still rapidly developing, so keep following the latest advances in academia and industry!
## References
[^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).
[^5]: [*TinyRAG: GitHub Project*](https://github.com/KMnO4-zx/TinyRAG).
+421
View File
@@ -0,0 +1,421 @@
# Chapter 2: Preparation
> This section primarily recommends two browser-based integrated development environments for environment configuration. Whether you're using a phone, tablet, or computer, you can log in and run code anytime. Although the experience on phones and tablets might not be ideal, they are still usable.
## 1. Deepseek API Configuration (You can also choose other LLM APIs)
### 1.1 API Application
To use the large language model services provided by Deepseek, you first need an API Key. Here are the application steps:
1. **Visit Deepseek Open Platform**
Open your browser and visit [Deepseek Open Platform](https://platform.deepseek.com/).
![Deepseek Platform Homepage](../images/1_2_1.webp)
2. **Login or Register Account**
If you already have an account, please log in directly. If not, click the register button on the page and complete registration using your email or phone number.
3. **Create New API Key**
After successful login, find and click `API Keys` in the left navigation bar. On the API management page, click the `Create API key` button. Enter a name that doesn't duplicate other API keys and click create.
![Create New Key Button](../images/1_2_2.webp)
4. **Save API Key**
The system will generate a new API key for you. Please **copy immediately** and save it in a secure place.
> Note: For security reasons, this key will only be displayed in full once. You won't be able to see it again after closing the popup.
![Copy and Save Key](../images/1_2_3.webp)
## 2. GitHub Codespaces Environment Configuration (Recommended)
> First, ensure you have a network environment that can smoothly access GitHub. If you cannot access it smoothly, please use Cloud Studio below.
GitHub Codespaces is a service provided by GitHub that allows developers to create, edit, and run code in the cloud. It provides a pre-configured development environment including code editor, terminal, debugging tools, etc., which can be used directly in the browser.
### 2.1 Creating Codespaces
1. **Visit Project Address**
Open your browser and visit [all-in-rag](https://github.com/datawhalechina/all-in-rag)
2. **Create New Fork**
In the upper right corner of the project page, click the `Fork` button to create a new fork. Wait a moment for successful creation.
![Create New Fork 1](../images/1_2_4.webp)
![Create New Fork 2](../images/1_2_5.webp)
3. **Create Codespaces**
In the upper right corner of the project page, click the `Code` button, then select the `Codespaces` tab. Click the `New codespace` button and wait for the new Codespaces environment to be created successfully.
![Create Codespaces](../images/1_2_6.webp)
4. **Re-enter Codespaces**
After closing the webpage, find the newly created repository and click the content in the red box to re-enter the codespace environment.
![Re-enter Codespaces](../images/1_2_7.webp)
5. **Quota Settings**
Find the codespace settings in GitHub's account settings. It's recommended to adjust the suspend time according to your situation (too long will waste quota, free accounts provide 120 hours of single-core quota).
![Quota Settings](../images/1_2_8.webp)
### 2.2 Python Environment Configuration
After entering the IDE, first select the terminal below.
![Enter Terminal](../images/1_2_9.webp)
1. **Update System Packages**
Enter the following command in the terminal:
```bash
sudo apt update
sudo apt upgrade -y
```
2. **Install Miniconda**
```bash
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
bash ~/miniconda.sh
```
- Press Enter to read the license agreement
- Enter `yes` to agree to the agreement
- Press Enter directly when prompted for installation path (use default path /home/ubuntu/miniconda3)
- Whether to initialize Miniconda: Enter `yes` to add Miniconda to your PATH environment variable.
```bash
source ~/.bashrc
conda --version
```
If the version number is displayed, the installation is successful.
### 2.3 API Configuration
1. Use the `vim` editor to open your shell configuration file.
```bash
vim ~/.bashrc
```
2. Enter `i` to enter edit mode, add the following line at the end of the file, replacing `[Your Deepseek API Key]` with your own key:
```bash
export DEEPSEEK_API_KEY=[Your Deepseek API Key]
```
3. Save and exit. In vim, press Esc to enter command mode, then type `:wq` and press Enter to save the file and exit.
4. Make configuration effective. Execute the following command to immediately load the updated configuration and make the environment variable effective:
```bash
source ~/.bashrc
```
### 2.4 Create and Activate Virtual Environment
1. **Create Virtual Environment**
```bash
conda create --name all-in-rag python=3.12.7
```
Press Enter directly when options appear.
2. **Activate Virtual Environment**
Use the following command to activate the virtual environment:
```bash
conda activate all-in-rag
```
3. **Dependency Installation**
If you strictly follow the above process, you should currently be in the project root directory. Enter the code directory to install dependency libraries.
```bash
cd code
pip install -r requirements.txt
```
> If there are version errors about grpcio, you can ignore them.
## 3. Cloud Studio Environment Configuration (Recommended for Domestic Environment)
Cloud Studio is a browser-based integrated development environment (IDE) launched by Tencent Cloud. It supports access to both CPU and GPU.
> I heard there's a free quota of 50 hours per month 🤔
### 3.1 Application Creation
1. **Visit Cloud Studio**
Open your browser and visit [Cloud Studio](https://cloudstudio.net/).
2. **Login or Register Account**
Click the `Register/Login` button in the upper right corner of the page and complete login using WeChat or other methods.
3. **Create Application**
Find and click `Create Application` in the navigation bar at the top of the page. Select `Import from Git Repository`, enter `https://github.com/datawhalechina/all-in-rag.git` in the project address bar and press Enter. It will automatically create a title and description for you.
![Create Application](../images/1_2_10.webp)
4. **Re-enter**
Later, find the previously created application on the [Application Management Page](https://cloudstudio.net/my-app), click on it and select "Write Code" in the upper right corner to re-enter.
![Re-enter Application](../images/1_2_11.webp)
### 3.2 Python Environment Configuration
After entering the IDE, first select the terminal on the right.
![Enter Terminal](../images/1_2_12.webp)
1. **Update System Packages**
Enter the following command in the terminal:
```bash
sudo apt update
sudo apt upgrade -y
```
2. **Switch to Regular User**
```bash
su ubuntu
```
3. **Install Miniconda**
```bash
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
bash ~/miniconda.sh
```
- Press Enter to read the license agreement
- Enter `yes` to agree to the agreement
- Press Enter directly when prompted for installation path (use default path /home/ubuntu/miniconda3)
- Whether to initialize Miniconda: Enter `yes` to add Miniconda to your PATH environment variable.
```bash
source ~/.bashrc
conda --version
```
If the version number is displayed, the installation is successful.
### 3.3 API Configuration
1. Use the `vim` editor to open your shell configuration file.
```bash
vim ~/.bashrc
```
2. Enter `i` to enter edit mode, add the following line at the end of the file, replacing `[Your Deepseek API Key]` with your own key:
```bash
export DEEPSEEK_API_KEY=[Your Deepseek API Key]
```
3. Save and exit. In vim, press Esc to enter command mode, then type `:wq` and press Enter to save the file and exit.
4. Make configuration effective. Execute the following command to immediately load the updated configuration and make the environment variable effective:
```bash
source ~/.bashrc
```
### 3.4 Create and Activate Virtual Environment
1. **Create Virtual Environment**
```bash
conda create --name all-in-rag python=3.12.7
```
Press Enter directly when options appear.
2. **Configure File Permissions**
```bash
sudo chown -R ubuntu:ubuntu code models
```
3. **Activate Virtual Environment**
Use the following command to activate the virtual environment:
```bash
conda activate all-in-rag
```
4. **Dependency Installation**
If you strictly follow the above process, you should currently be in the project root directory. Enter the code directory to install dependency libraries.
```bash
cd code
pip install -r requirements.txt
```
> If there are version errors about grpcio, you can ignore them.
## 4. Windows Environment Configuration (Skip this step if using Cloud Studio or Codespaces)
### 4.1 API Configuration
1. Right-click "Computer" or "This PC", then click "Properties".
2. In the left menu, click "Advanced system settings".
3. In the "System Properties" dialog box, click the "Advanced" tab, then click the "Environment Variables" button below.
![Advanced System Settings](../images/1_2_13.webp)
4. In the "Environment Variables" dialog box, click "New" (under the "User variables" section), then enter the following information:
- Variable name: DEEPSEEK_API_KEY
- Variable value: [Your Deepseek API Key]
![Advanced System Settings](../images/1_2_14.webp)
### 4.2 Install Miniconda
1. **Download Installer**
It's recommended to visit [Tsinghua University Open Source Software Mirror](https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/) for faster download speeds. Choose the latest `Windows-x86_64.exe` version according to your system.
![Select Miniconda Version](images/ch1/miniconda-select-version.png)
You can also download from the [Miniconda Official Website](https://docs.conda.io/en/latest/miniconda.html).
2. **Run Installation Wizard**
After downloading, double-click the `.exe` file to start installation. Follow the wizard prompts:
* **Welcome**: Click `Next`.
![Welcome](../images/)
* **License Agreement**: Click `I Agree`.
![License Agreement](../images/)
* **Installation Type**: Select `Just Me`, click `Next`.
![Installation Type](../images/)
* **Choose Install Location**: It's recommended to keep the default path, or choose a path without Chinese characters and spaces. Click `Next`.
![Install Location](../images/)
* **Advanced Installation Options**: **Do not check** "Add Miniconda3 to my PATH environment variable". We will manually configure environment variables later. Click `Install`.
![Advanced Options](../images/)
* **Installation Complete**: After installation is complete, click `Next`, then uncheck "Learn more" and click `Finish` to complete installation.
![Installation Complete](../images/)
3. **Manually Configure Environment Variables**
To use the `conda` command in any terminal window, you need to manually configure environment variables.
* Search for "Edit the system environment variables" in the Windows search bar and open it.
![Edit System Environment Variables](../images/)
* In the "System Properties" window, click "Environment Variables".
![Environment Variables Button](../images/)
* In the "Environment Variables" window, find the `Path` variable under "System variables", select it and click "Edit".
![Edit Path Variable](../images/)
* In the "Edit Environment Variable" window, create three new paths pointing to the corresponding folders under your Miniconda installation directory. If your installation path is `D:\Miniconda3`, you need to add:
```
D:\Miniconda3
D:\Miniconda3\Scripts
D:\Miniconda3\Library\bin
```
![Add Paths](../images/)
* After completion, click "OK" all the way to save changes.
### 4.3 Configure Conda Mirror Sources
To speed up subsequent package installations using `conda`, it's strongly recommended to configure domestic mirror sources. Open a new terminal or Anaconda Prompt and run the following commands:
```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
```
After configuration, you can view the added sources using the `conda config --show channels` command.
## 5. Project Code Pulling (Skip this step if using Cloud Studio or Codespaces)
### 5.1 Install Git
If you haven't installed Git yet, please follow these steps to install it.
* **Windows System**: Visit the [Git Official Website](https://git-scm.com/download/win), download and run the installer, complete installation with default settings.
* **macOS System**: Open terminal and enter the following command to install Git:
```bash
brew install git
```
* **Linux System (Ubuntu example)**: Open terminal and enter the following commands to install Git:
```bash
sudo apt-get update
sudo apt-get install git
```
After installation, verify that Git is installed successfully by entering the following command:
```bash
git --version
```
If successful, it will display Git's version number.
### 5.2 Clone Project Code
1. **Choose Directory for Project**
Open terminal (or Git Bash in Windows), navigate to the directory where you want to store the project:
```bash
cd [path where you want to store the project]
```
2. **Clone Repository**
Use the following command to pull the `all-in-rag` repository:
```bash
git clone https://github.com/datawhalechina/all-in-rag.git
```
Wait for the download to complete. The project code will be stored in the `all-in-rag` folder in the current directory.
3. **Enter Project Directory**
After pulling the code, enter the project directory:
```bash
cd all-in-rag
```
### 5.3 Create and Activate Virtual Environment
In the project directory, it's recommended to use the previously configured Miniconda to create a Python virtual environment.
1. **Create Virtual Environment**
```bash
conda create --name all-in-rag python=3.12.7
```
2. **Activate Virtual Environment**
All systems use the following command to activate the virtual environment:
```bash
conda activate all-in-rag
```
3. **Dependency Installation**
If you strictly follow the above process, you should currently be in the project root directory. Enter the code directory to install dependency libraries.
```bash
cd code
pip install -r requirements.txt
```
+243
View File
@@ -0,0 +1,243 @@
# Chapter 3: Four Steps to Build RAG
Through the learning in Chapter 1, we have gained a basic understanding of RAG and have prepared the virtual environment and API key. Next, we will try to use the [**LangChain**](https://python.langchain.com/docs/introduction/) and [**LlamaIndex**](https://docs.llamaindex.ai/en/stable/) frameworks to implement and run our first RAG application. Through an example, we will demonstrate how to load local Markdown documents, process text using embedding models, and combine with large language models (LLM) to answer questions related to document content.
## 1. Start Virtual Environment
### 1.1 Activate Virtual Environment
Assuming you have created a Conda virtual environment named `all-in-rag` following the guidance in the previous chapter. Before running the script, first activate the virtual environment:
> If using Cloud Studio, you need to confirm whether you are currently in the user environment. If not, please run `su ubuntu` to switch to the user environment.
```bash
conda activate all-in-rag
```
### 1.2 Switch to Project Directory
```bash
# Assuming currently in the root directory of the all-in-rag project
cd code/C1
```
The code files for each chapter are stored in the `code/Cx` directory, where `x` represents the chapter number.
## 2. Run RAG Example Code
After completing all the above settings, you can run the RAG example.
Open the terminal, ensure the virtual environment is activated, then execute the following command:
```bash
python 01_langchain_example.py
```
> If you encounter nltk-related errors, try running [fix_nltk.py](https://github.com/datawhalechina/all-in-rag/blob/main/code/C1/fix_nltk.py) in the code path.
After the code runs, you can see output similar to the following (formatted):
```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': {}
}
```
> When running for the first time, the script will download the `BAAI/bge-small-zh-v1.5` embedding model.
Output parameter explanation:
- **`content`**: This is the core part, which is the specific answer generated by the large language model (LLM) based on your question and the provided context.
- **`additional_kwargs`**: Contains some additional parameters. In this example, it's `{'refusal': None}`, indicating that the model did not refuse to answer.
- **`response_metadata`**: Contains metadata about the LLM response.
- `token_usage`: Shows the number of tokens consumed in this call, including completion_tokens, prompt_tokens, and total_tokens.
- `model_name`: The name of the LLM model used, currently `deepseek-chat`.
- `system_fingerprint`, `id`, `service_tier`, `finish_reason`, `logprobs`: These are more detailed API response information. For example, `finish_reason: 'stop'` indicates that the model completed generation normally.
- **`id`**: The unique identifier for this run.
- **`usage_metadata`**: Similar to `token_usage` in `response_metadata`, providing statistics on input and output tokens.
## 3. RAG Implementation Based on LangChain Framework
> In Chapter 1, we mentioned that the four steps to build a minimum viable system are data preparation, index construction, retrieval optimization, and generation integration. Next, we will implement a RAG application based on the LangChain framework around these four aspects.
### 3.1 Initial Setup
First, perform basic configuration, including importing necessary libraries, loading environment variables, and downloading embedding models.
```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 ChatDeepSeek
# Load environment variables
load_dotenv()
```
### 3.2 Data Preparation
- **Load raw documents**: First define the path to the Markdown file, then use `TextLoader` to load the file as a knowledge source.
```python
markdown_path = "../../data/C1/markdown/easy-rl-chapter1.md"
loader = TextLoader(markdown_path)
docs = loader.load()
```
- **Text Chunking**: To facilitate subsequent embedding and retrieval, long documents are split into smaller, manageable text chunks. Here we use a recursive character splitting strategy with its default parameters for chunking. When initializing `RecursiveCharacterTextSplitter()` without specifying parameters, its default behavior aims to preserve the semantic structure of the text to the maximum extent:
- **Default separators and semantic preservation**: Try to use a series of preset separators `["\n\n" (paragraphs), "\n" (lines), " " (spaces), "" (characters)]` in order to recursively split the text. The purpose of this strategy is to maintain the integrity of paragraphs, sentences, and words as much as possible, as they are usually the most semantically relevant text units, until the text chunks reach the target size.
- **Preserve separators**: By default (`keep_separator=True`), the separators themselves are preserved in the split text chunks.
- **Default chunk size and overlap**: Use the default parameters `chunk_size=4000` (chunk size) and `chunk_overlap=200` (chunk overlap) defined in its base class `TextSplitter`. These parameters ensure that text chunks meet predetermined size limits and reduce the loss of contextual information through overlap.
```python
text_splitter = RecursiveCharacterTextSplitter()
texts = text_splitter.split_documents(docs)
```
### 3.3 Index Construction
After data preparation is complete, next build the vector index:
- **Initialize Chinese embedding model**: Use `HuggingFaceEmbeddings` to load the Chinese embedding model downloaded in the initial setup. Configure the model to run on CPU and enable embedding normalization (`normalize_embeddings: True`).
```python
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)
```
- **Build vector storage**: Convert the split text chunks (`texts`) into vector representations through the initialized embedding model, then use `InMemoryVectorStore` to add these vectors and their corresponding original text content, thereby building a vector index in memory.
```python
vectorstore = InMemoryVectorStore(embeddings)
vectorstore.add_documents(texts)
```
After this process is completed, a queryable knowledge index is built.
### 3.4 Query and Retrieval
After the index is built, you can query and retrieve based on user questions:
- **Define user query**: Set a specific user question string.
```python
question = "What examples are mentioned in the text?"
```
- **Query relevant documents in vector storage**: Use the `similarity_search` method of vector storage to find the most relevant `k` (in this example `k=3`) text chunks in the index based on user questions.
```python
retrieved_docs = vectorstore.similarity_search(question, k=3)
```
- **Prepare context**: Merge the page content (`doc.page_content`) of multiple retrieved text chunks into a single string, separated by double newlines (`"\n\n"`), forming the final context information (`docs_content`) for the large language model to reference.
```python
docs_content = "\n\n".join(doc.page_content for doc in retrieved_docs)
```
> Using `"\n\n"` (double newlines) instead of `"\n"` (single newlines) to connect different retrieved document chunks is mainly to more clearly distinguish these independent text fragments semantically when passing to large language models (LLM). Double newlines usually represent the end of a paragraph and the beginning of a new paragraph. This format helps LLM treat each chunk as an independent context source, thereby better understanding and utilizing this information to generate answers.
### 3.5 Generation Integration
The final step is to combine the retrieved context with user questions and use large language models (LLM) to generate answers:
- **Build prompt template**: Use `ChatPromptTemplate.from_template` to create a structured prompt template. This template guides the LLM to answer user questions based on the provided context (`context`) and clearly indicates how to respond when information is insufficient.
```python
prompt = ChatPromptTemplate.from_template("""Please answer the question based on the context information provided below.
Please ensure your answer is completely based on this context.
If there is not enough information in the context to answer the question, please directly inform: "Sorry, I cannot find relevant information in the provided context to answer this question."
Context:
{context}
Question: {question}
Answer:"""
)
```
- **Configure large language model**: Initialize the `ChatDeepSeek` client, configure the model used (`deepseek-chat`), temperature parameter for generating answers (`temperature=0.7`), maximum number of tokens (`max_tokens=2048`), and API key (loaded from environment variables).
```python
llm = ChatDeepSeek(
model="deepseek-chat",
temperature=0.7,
max_tokens=2048,
api_key=os.getenv("DEEPSEEK_API_KEY")
)
```
- **Call LLM to generate answer and output**: Format the user question (`question`) and previously prepared context (`docs_content`) into the prompt template, then call ChatDeepSeek's `invoke` method to get the generated answer.
```python
answer = llm.invoke(prompt.format(question=question, context=docs_content))
print(answer)
```
[Complete Code](https://github.com/datawhalechina/all-in-rag/blob/main/code/C1/01_langchain_example.py)
> Teacher, teacher, LangChain is powerful but still requires too much operation. Do you have any simpler and more user-friendly framework recommendations?
> Yes, brother, yes! There are other user-friendly frameworks like LlamaIndex😉
## 4. Low-Code (Based on LlamaIndex)
In terms of RAG, LlamaIndex provides more encapsulated API interfaces, which undoubtedly lowers the barrier to entry. Here's a simple implementation:
```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.deepseek import DeepSeek
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
load_dotenv()
Settings.llm = DeepSeek(model="deepseek-chat", api_key=os.getenv("DEEPSEEK_API_KEY"))
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("What examples are mentioned in the text?"))
```
## Exercises (You can use large models to assist completion)
- Modify the parameters `chunk_size` and `chunk_overlap` of `RecursiveCharacterTextSplitter()` in the LangChain code and observe what changes occur in the output results.
- The final output obtained from LangChain code carries various parameters. Look up relevant materials and try to filter out these parameters to get the specific answer in `content`.
- Add code comments to the LlamaIndex code.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB