从零到一构建企业级 RAG 问答系统:一个完整的模块化实践指南

写在前面

在人工智能技术飞速发展的今天,大语言模型(LLM)展现出了惊人的能力。然而,如何让 LLM 真正落地到垂直领域,解决实际问题,仍然是一个值得深入探讨的课题。RAG(Retrieval-Augmented Generation,检索增强生成)作为目前最成熟的解决方案之一,通过将外部知识库与 LLM 结合,有效解决了模型知识更新滞后、幻觉等问题。

本文将带你完整走一遍我最近实现的一个企业级模块化 RAG 问答系统。这不是一个简单的 Demo,而是一个集成了多种检索策略、支持多轮对话、具有流式输出能力的生产级系统。我会详细拆解系统的每一个模块,分享设计思路,并附上完整的架构图和流程图。

无论你是正准备上手 RAG 项目的开发者,还是希望深入理解 RAG 内部机制的学习者,希望这篇文章能给你带来一些启发。


一、项目概述:我们要解决什么问题?

1.1 业务背景

假设你正在为一个在线教育平台构建智能问答助手。平台有海量的课程资料(PDF、PPT、Word、图片),学生经常询问课程内容、知识点细节、学习路径等问题。传统的做法是:

  • 纯 LLM 方案:模型可能不了解平台特有的课程内容,容易产生幻觉

  • 关键词检索方案:只能匹配精确词汇,无法理解语义相似的问题

RAG 方案的优势在于:既能利用 LLM 的强大生成能力,又能基于实际文档内容进行回答,保证答案的准确性和可追溯性。

1.2 核心需求

需求 描述
多格式文档支持 PDF、Word、PPT、图片、Markdown
智能检索 语义理解 + 关键词匹配
多轮对话 记住上下文,连续问答
高性能 毫秒级响应,支持流式输出
可扩展 模块化设计,易于新增功能

二、系统架构:一张图看懂全貌

python 复制代码
"""
┌─────────────────────────────────────────────────────────────────────────────┐
│                              用户交互层                                      │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐  │
│  │   Web 前端   │    │  API 接口   │    │ WebSocket  │    │   命令行    │  │
│  │  (HTML/JS)  │    │  (RESTful)  │    │  (流式)     │    │   (CLI)     │  │
│  └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              API 网关层                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  FastAPI 服务                                                       │    │
│  │  • CORS 跨域支持  • 会话管理  • 历史记录  • 健康检查  • 静态文件      │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           集成问答系统层                                     │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    IntegratedQASystem                               │    │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐ │    │
│  │  │ 会话管理    │  │ 历史存储    │  │ 流程编排    │  │ 流式输出    │ │    │
│  │  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘ │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘
                                       │
              ┌────────────────────────┼────────────────────────┐
              │                        │                        │
              ▼                        ▼                        ▼
┌─────────────────────┐  ┌─────────────────────┐  ┌─────────────────────┐
│     一级检索        │  │     二级检索        │  │     三级检索        │
│   (BM25 + MySQL)    │  │   (Milvus + BGE)    │  │   (Reranker)        │
│                     │  │                     │  │                     │
│  • 关键词匹配       │  │  • 稠密向量检索     │  │  • Cross-Encoder    │
│  • 精确问答         │  │  • 稀疏向量检索     │  │  • 精排优化         │
│  • 毫秒级响应       │  │  • 语义理解         │  │  • 相关性打分       │
└─────────────────────┘  └─────────────────────┘  └─────────────────────┘
              │                        │                        │
              └────────────────────────┼────────────────────────┘
                                       ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              数据存储层                                      │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐  │
│  │   MySQL     │    │   Redis     │    │   Milvus    │    │  本地模型    │  │
│  │  • 知识库   │    │  • 缓存     │    │  • 向量库   │    │  • BERT     │  │
│  │  • 会话历史 │    │  • BM25索引 │    │  • 父子文档 │    │  • BGE-M3   │  │
│  └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
"""

三、核心模块详解

3.1 文档加载器:多源异构文档的统一处理

这是系统的"输入"环节。用户的资料可能是 PDF、Word、PPT,甚至是一张截图。我们需要一个统一的加载框架来应对这种多样性。

设计思路
python 复制代码
# 工厂模式 + 策略模式
document_loaders = {
    ".pdf": OCRPDFLoader,      # PDF 加载器(支持 OCR)
    ".docx": OCRDOCLoader,     # Word 加载器(支持图片 OCR)
    ".pptx": OCRPPTLoader,     # PPT 加载器(支持组合图形)
    ".jpg": OCRIMGLoader,      # 图片加载器(纯 OCR)
    ".png": OCRIMGLoader,
    ".md": UnstructuredMarkdownLoader,  # Markdown 加载器
}
关键实现

1. PDF 加载器(OCRPDFLoader)

python 复制代码
class OCRPDFLoader(BaseLoader):
    def pdf2text(self):
        ocr = get_ocr()  # 获取 OCR 实例
        doc = fitz.open(self.file_path)
        
        for page in doc:
            # 提取文本层
            text = page.get_text("text")
            resp += text + "\n"
            
            # 提取图片层(智能过滤)
            for img in page.get_image_info():
                # 只 OCR 占据页面 60% 以上的大图
                if self._is_large_image(img, page):
                    pix = fitz.Pixmap(doc, img["xref"])
                    result, _ = ocr(np.array(pix))
                    resp += "\n".join([line[1] for line in result])

设计亮点

  • 双通道提取:同时提取文本层和图片层

  • 智能过滤:只对占据页面 60% 以上的大图进行 OCR,避免对 logo、图标等小图的无效处理

  • 旋转校正:处理扫描件时自动校正页面旋转

2. Word 加载器(OCRDOCLoader)

Word 文档的结构比 PDF 更复杂,需要处理段落、表格、内嵌图片。

python 复制代码
def doc2text(self, filepath):
    doc = Document(filepath)
    
    for block in iter_block_items(doc):
        if isinstance(block, Paragraph):
            # 提取段落文本
            resp += block.text.strip() + "\n"
            # 提取段落中的图片
            for image in self._extract_images(block):
                resp += self._ocr_image(image)
                
        elif isinstance(block, Table):
            # 提取表格内容
            for row in block.rows:
                for cell in row.cells:
                    resp += cell.text.strip() + "\n"

3. PPT 加载器(OCRPPTLoader)

PPT 有特殊的"组合形状"概念,需要递归处理。

python 复制代码
def extract_text(self, shape):
    if shape.has_text_frame:
        resp += shape.text.strip() + "\n"
    elif shape.has_table:
        # 提取表格
        for row in shape.table.rows:
            for cell in row.cells:
                resp += cell.text.strip() + "\n"
    elif shape.shape_type == 13:  # 图片类型
        result, _ = ocr(np.array(Image.open(BytesIO(shape.image.blob))))
        resp += "\n".join([line[1] for line in result])
    elif shape.shape_type == 6:   # 组合类型(递归处理)
        for child in shape.shapes:
            self.extract_text(child)

4. 图片加载器(OCRIMGLoader)

最简洁的加载器,直接进行 OCR 识别。

python 复制代码
def img2text(self):
    ocr = get_ocr()
    result, _ = ocr(self.img_path)
    return "\n".join([line[1] for line in result])

3.2 文本切分器:中文语义的精准分割

文档加载后得到的是原始文本,但直接存入向量库会有问题:

  • 文本太长,检索精度下降

  • 文本太短,上下文不完整

解决方案是父子文档切分策略

父子文档策略
python 复制代码
"""
原始文档 (3000字)
        │
        ▼ parent_splitter (chunk_size=1200)
┌─────────────────────────────────────────────────────────────┐
│  Parent Chunk 0 (1200字)              parent_id: doc_0_parent_0 │
│        │                                                      │
│        ▼ child_splitter (chunk_size=300)                     │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│  │ Child 0_0    │ │ Child 0_1    │ │ Child 0_2    │ │ Child 0_3  │ │
│  │ parent_id    │ │ parent_id    │ │ parent_id    │ │ parent_id  │ │
│  │ parent_      │ │ parent_      │ │ parent_      │ │ parent_    │ │
│  │ content      │ │ content      │ │ content      │ │ content    │ │
│  └──────────────┘ └──────────────┘ └──────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
"""

设计思想

  • 子块入库:用于检索,粒度小,匹配精准

  • 父块输出:作为 LLM 上下文,内容完整,语义连贯

这样,当用户问"什么是神经网络"时,系统可以在子块中精准匹配到相关段落,然后返回完整的父块给 LLM,保证答案的完整性。

中文优化切分器
python 复制代码
class ChineseRecursiveTextSplitter(RecursiveCharacterTextSplitter):
    def __init__(self):
        self._separators = [
            "\n\n",           # 段落分隔
            "\n",             # 换行
            "。|!|?",       # 中文句尾标点(正则支持多匹配)
            "\.\s|\!\s|\?\s", # 英文句尾+空格
            ";|;\s",         # 分号
            ",|,\s"          # 逗号
        ]

相比 LangChain 原生切分器,这个版本对中文更友好,能够按语义边界进行切分。

3.3 向量存储:Milvus 的高效检索

Schema 设计
python 复制代码
schema.add_field("id", VARCHAR, is_primary=True)      # MD5 哈希作为主键
schema.add_field("text", VARCHAR)                     # 子块文本内容
schema.add_field("dense_vector", FLOAT_VECTOR, dim=1024)  # 稠密向量
schema.add_field("sparse_vector", SPARSE_FLOAT_VECTOR)     # 稀疏向量
schema.add_field("parent_id", VARCHAR)                # 父块 ID(溯源)
schema.add_field("parent_content", VARCHAR)           # 父块内容(避免二次查询)
schema.add_field("source", VARCHAR)                   # 学科过滤字段
混合检索原理

稠密向量:由 BGE-M3 模型生成,捕获语义相似性。例如:"汽车"和"轿车"在语义空间中是接近的。

稀疏向量:也是由 BGE-M3 生成,但本质上是学习出来的关键词权重分布。例如:每个 token 对应一个权重分数,表示该词在文档中的重要性。

python 复制代码
# 稀疏向量示例(概念示意)
sparse_vector = {
    token_id_1: 0.85,  # "人工智能" 的权重
    token_id_2: 0.62,  # "课程" 的权重
    token_id_3: 0.31,  # "介绍" 的权重
}
两阶段排序
python 复制代码
"""
用户 Query
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ 第一阶段:混合检索 + 加权合并                                 │
│                                                            │
│  稠密向量检索 (权重 1.0)  ─────┐                            │
│                              ├── WeightedRanker ──► 粗排   │
│  稀疏向量检索 (权重 0.7)  ─────┘                            │
└─────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ 第二阶段:Cross-Encoder 重排序                              │
│                                                            │
│  BGE-Reranker-Large 对候选文档逐一打分                       │
│  按相关性得分重新排序 ──► 最终结果                           │
└─────────────────────────────────────────────────────────────┘
"""

什么需要两阶段?

方法 速度 精度 适用
加权合并 快(毫秒级) 一般 初筛,从百万级降到百级
Reranker 慢(秒级) 精排,从百级降到最终 K 个

3.4 查询分类器:BERT 微调实现意图识别

并不是所有问题都需要走 RAG 流程。像"今天天气怎么样"这类通用问题,直接让 LLM 回答即可,既能节省成本,又能提升响应速度。

python 复制代码
class QueryClassifier:
    def __init__(self):
        self.model = BertForSequenceClassification.from_pretrained(
            "bert-base-chinese", 
            num_labels=2  # 二分类:通用知识 vs 专业咨询
        )
        
    def predict_category(self, query):
        encoding = self.tokenizer(query, return_tensors="pt")
        outputs = self.model(**encoding)
        prediction = torch.argmax(outputs.logits, dim=1).item()
        return "专业咨询" if prediction == 1 else "通用知识"

训练数据示例

python 复制代码
{"query": "AI 课程学什么?", "label": "专业咨询"}
{"query": "今天天气怎么样?", "label": "通用知识"}
{"query": "JAVA 的学费是多少?", "label": "专业咨询"}

通过 5000 条标注数据微调,分类准确率可达 90% 以上。

3.5 策略选择器:LLM 即路由器

这是项目中一个创新的设计------用 LLM 来决定使用哪种检索策略。

python 复制代码
class StrategySelector:
    def select_strategy(self, query):
        prompt = f"""
        从以下策略中选择最适合的:
        1. 直接检索:适用于意图明确的问题
        2. 子查询检索:适用于涉及多个实体的问题
        3. 假设问题检索(HyDE):适用于抽象问题
        4. 回溯问题检索:适用于复杂问题
        
        用户查询:{query}
        策略:
        """
        return self.llm(prompt).strip()
策略 适用场景 示例
直接检索 意图明确 "AI 学科学费是多少?"
子查询检索 涉及多个实体 "比较 Milvus 和 Zilliz Cloud 的优缺点"
HyDE 抽象问题 "人工智能在教育领域的应用"
回溯问题 复杂问题 "100亿条数据存 Milvus 可以吗?"

3.6 BM25 检索:快速降级方案

RAG 虽然强大,但每次都要调用 LLM,成本和延迟都较高。因此,我们设计了一级快速检索:BM25 + MySQL。

python 复制代码
class BM25Search:
    def search(self, query, threshold=0.85):
        # 1. 查 Redis 缓存
        cached = self.redis_client.get_answer(query)
        if cached:
            return cached, False
            
        # 2. BM25 打分
        scores = self.bm25.get_scores(query_tokens)
        softmax_scores = self._softmax(scores)
        best_score = softmax_scores.max()
        
        # 3. 阈值判断
        if best_score >= threshold:
            answer = self.mysql_client.fetch_answer(best_question)
            self.redis_client.set_data(f"answer:{query}", answer)
            return answer, False
        
        # 4. 降级到 RAG
        return None, True

设计亮点

  • 两级缓存:答案缓存 + BM25 索引缓存

  • Softmax 归一化:将 BM25 原始分数映射到 [0,1] 区间

  • 阈值降级:低于 0.85 的查询自动降级到 RAG

3.7 多轮对话管理:会话隔离 + 历史记忆

python 复制代码
# 会话表结构
CREATE TABLE conversations (
    id INT AUTO_INCREMENT PRIMARY KEY,
    session_id VARCHAR(36) NOT NULL,     -- 会话隔离
    question TEXT NOT NULL,
    answer TEXT NOT NULL,
    timestamp DATETIME NOT NULL,
    INDEX idx_session_id (session_id)    -- 加速查询
);

# 获取最近5轮对话(最新在前)
SELECT question, answer FROM conversations
WHERE session_id = %s
ORDER BY timestamp DESC LIMIT 5

历史格式转换

python 复制代码
# SQL 返回(最新 → 最旧)
history = [Q5, Q4, Q3, Q2, Q1]

# 反转后(最旧 → 最新)
history = history[::-1]  # [Q1, Q2, Q3, Q4, Q5]

# 格式化为 LLM 可理解的字符串
history_text = "\n".join([f"Q:{h['question']}\nA:{h['answer']}" for h in history])

3.8 流式输出:提升用户体验

python 复制代码
def call_llm_stream(self, prompt):
    response = ollama.chat(model='qwen2.5:7b', stream=True)
    for chunk in response:
        yield chunk['message']['content']

# 使用
for token in self.llm_stream(prompt):
    yield token, False  # False 表示未完成
yield "", True          # True 表示完成

效果:用户不用等待完整回答,可以逐字看到生成过程,体验大幅提升。


四、完整问答流程

python 复制代码
"""
用户: "AI 课程学什么?" + session_id="001" + source_filter="ai"
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 1: 获取历史对话                                         │
│ SELECT * FROM conversations WHERE session_id='001'         │
│ ORDER BY timestamp DESC LIMIT 5                            │
│ → 反转后得到 [Q1,A1, Q2,A2, Q3,A3, Q4,A4, Q5,A5]           │
└─────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 2: BM25 快速检索                                       │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2.1 查 Redis 缓存                                        │ │
│ │     key = "answer:AI 课程学什么?"                       │ │
│ │     → 未命中                                            │ │
│ └─────────────────────────────────────────────────────────┘ │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2.2 BM25 打分                                           │ │
│ │     query_tokens = ["AI", "课程", "学什么"]              │ │
│ │     scores = bm25.get_scores()                          │ │
│ │     softmax_scores = softmax(scores)                    │ │
│ │     best_score = 0.32 (< 0.85)                          │ │
│ │     → 需要降级到 RAG                                     │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 3: RAG 深度检索                                        │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3.1 BERT 分类                                           │ │
│ │     "AI 课程学什么?" → "专业咨询"                        │ │
│ └─────────────────────────────────────────────────────────┘ │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3.2 策略选择 (LLM 路由)                                  │ │
│ │     → "直接检索"                                         │ │
│ └─────────────────────────────────────────────────────────┘ │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3.3 混合检索 (Milvus)                                    │ │
│ │     • 稠密向量检索 (语义)                                 │ │
│ │     • 稀疏向量检索 (关键词)                               │ │
│ │     • WeightedRanker 加权合并                            │ │
│ │     • 提取父块去重                                        │ │
│ │     • BGE-Reranker 精排                                  │ │
│ │     → 返回 2 个父块                                      │ │
│ └─────────────────────────────────────────────────────────┘ │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3.4 构建 Prompt                                          │ │
│ │     context = 父块1 + 父块2                              │ │
│ │     history = 最近5轮对话                                 │ │
│ │     prompt = format(context, history, query)            │ │
│ └─────────────────────────────────────────────────────────┘ │
│                                                              │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3.5 流式生成答案                                          │ │
│ │     for token in llm_stream(prompt):                    │ │
│ │         yield token, False                              │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│ Step 4: 更新历史                                            │
│                                                              │
│ • INSERT INTO conversations (session_id, question, answer) │
│ • DELETE 超出5轮的旧记录                                     │
│ • 缓存答案到 Redis                                          │
└─────────────────────────────────────────────────────────────┘
    │
    ▼
用户收到流式答案
"""

五、关键技术选型

组件 技术选型 选型理由
向量数据库 Milvus 支持混合检索、高性能、云原生
嵌入模型 BGE-M3 同时支持稠密+稀疏向量,中文效果好
重排序模型 BGE-Reranker-Large Cross-Encoder 架构,精排精度高
LLM DeepSeek-V3 (via SiliconFlow) 中文能力强,性价比高
分类模型 BERT-base-chinese 轻量级,微调后效果好
文档加载 PyMuPDF + python-docx + python-pptx 成熟稳定,支持 OCR
文本切分 自定义中文递归切分器 对中文语义边界更友好
数据库 MySQL 结构化数据存储
缓存 Redis 高性能缓存
API 框架 FastAPI 高性能、异步支持、自动文档
OCR RapidOCR (Paddle/ONNX) 自动降级,支持 GPU/CPU

六、项目亮点总结

6.1 架构设计亮点

  1. 模块化设计:每个组件职责单一,可独立替换和升级

  2. 三级检索降级:Redis 缓存 → BM25 关键词 → Milvus 向量,层层递进

  3. 父子文档策略:子块精准检索 + 父块完整上下文,兼顾精度和完整性

  4. 会话隔离:支持多用户、多会话独立对话历史

6.2 检索策略亮点

  1. 混合检索:稠密向量(语义)+ 稀疏向量(关键词),互补优势

  2. 两阶段排序:加权合并快速初筛 + Cross-Encoder 精排

  3. LLM 路由:用 LLM 智能选择检索策略,而非硬编码规则

  4. BERT 分类器:快速识别通用问题,避免不必要的 RAG 调用

6.3 工程实现亮点

  1. 多格式文档加载:PDF/Word/PPT/图片,统一接口

  2. 智能 OCR:只对大图进行 OCR,避免性能浪费

  3. 流式输出:逐字返回,用户体验好

  4. 自动历史清理:只保留最近 5 轮,控制上下文长度

  5. 两级缓存:Redis 缓存答案和 BM25 索引

6.4 用户体验亮点

  1. WebSocket 流式:实时反馈,无等待感

  2. 多会话支持:用户可创建多个独立对话

  3. 学科过滤:可按学科限定检索范围

  4. 历史追溯:所有问答都有记录


七、运行效果

命令行模式

python 复制代码
$ python new_main.py

欢迎使用集成问答系统!
支持的来源: ['ai', 'java', 'test', 'ops', 'bigdata']

请您输入对话ID: 001

输入查询: AI 课程学什么?

输入来源过滤 (ai/java/test/ops/bigdata) (按 Enter 跳过): ai

根据提供的文档,AI 课程主要包括以下几个模块:
1. 人工智能导论
2. 机器学习基础
3. 深度学习框架
4. 自然语言处理
5. 计算机视觉
...

API 模式

python 复制代码
# 启动服务
$ python app.py

# 调用接口
$ curl -X POST http://localhost:8001/api/query \
  -H "Content-Type: application/json" \
  -d '{"query": "AI 课程学什么?", "source_filter": "ai"}'

# 响应
{
  "answer": "根据提供的文档,AI 课程主要包括...",
  "is_streaming": false,
  "session_id": "xxx",
  "processing_time": 1.23
}

WebSocket 流式

python 复制代码
const ws = new WebSocket("ws://localhost:8001/api/stream");
ws.send(JSON.stringify({
    query: "AI 课程学什么?",
    source_filter: "ai",
    session_id: "001"
}));

ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    if (data.type === "token") {
        console.print(data.token);  // 逐字打印
    } else if (data.type === "end") {
        console.log("\n生成完成,耗时:", data.processing_time);
    }
};

八、踩坑与优化

8.1 遇到的问题

问题 解决方案
ModelScope 依赖冲突 降级 setuptools 到 65.5.0
BERT 路径错误 使用绝对路径替代相对路径
流式输出换行符过多 过滤 \n token 或使用 .strip()
WebSocket 循环提前退出 移除 break,使用 continue
混合检索精度不足 增加 Reranker 精排阶段

8.2 性能优化建议

  1. 批量插入:Milvus 插入时使用批量操作

  2. 连接池:数据库和 Redis 使用连接池

  3. 异步处理:API 层使用异步 IO

  4. 模型预热:启动时预加载模型到内存


九、扩展方向

  1. 多模态支持:增加图像、音频理解能力

  2. Agent 模式:让 LLM 自主选择工具和策略

  3. 知识图谱:引入结构化知识增强推理

  4. 评估体系:建立 RAG 评估指标(忠实度、答案相关性等)

  5. A/B 测试:支持多版本模型对比


写在最后

这个 RAG 项目从文档加载到向量检索,从 BM25 降级到多轮对话,从流式输出到 API 封装,覆盖了一个完整问答系统的所有环节。

回顾整个开发过程,最大的体会是:RAG 不是一个单一的技术,而是一套系统工程。它需要你综合考虑文档处理、向量检索、模型选型、系统架构、用户体验等多个维度。

希望这篇文章能帮助你理解 RAG 系统的内部机制,也希望能给你在自己的项目中落地 RAG 提供一些参考。

如果你有任何问题或建议,欢迎留言交流!

参考资源


可以的话加个好友,互相学习,感谢阅读。

相关推荐
UXbot1 小时前
如何用 AI 生成产品原型:从需求描述到可交互界面的完整 5 步流程
前端·人工智能·ui·交互·ai编程
hbstream1 小时前
Hermes Agent 一周暴涨五万 Star,但我劝你别急着追
前端·人工智能
货拉拉技术1 小时前
# AI翻译:出海企业如何跨越“语言鸿沟”?
人工智能
2402_854808371 小时前
Golang数组和切片有什么区别_Golang数组切片对比教程【通俗】
jvm·数据库·python
2401_865439631 小时前
如何在 Go 中精确安装指定版本的模块
jvm·数据库·python
小菜同学爱学习1 小时前
进阶实操!MySQL常用查询技巧(多场景案例+优化思路)
数据库·mysql
IT科技那点事儿1 小时前
Fortinet 全面升级安全运营平台:全面整合云 SOC、智能体 AI、托管检测与响应及端点安全防护
人工智能·安全
Java面试题总结1 小时前
Spring AI 核心架构、抽象模型与四大核心组件设计精髓
人工智能·spring·架构
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【20】MessagesAgentHook 、MessagesModelHook 相关实现类
java·人工智能·spring