一文讲透RAG

8 阅读19分钟

从 RAG 到 Agentic RAG、GraphRAG:一篇讲透企业级知识增强系统的设计、实现与落地

这不是一篇“RAG 是什么”的入门短文,而是一篇面向工程实践的系统化整理。
目标读者:前端 / 后端 / AI 应用开发 / 技术负责人 / 正在做知识库问答、企业 AI 助手、文档检索系统的人。
你可以把它当成:

  • 学习笔记
  • 技术分享底稿
  • 掘金长文
  • 企业内部培训材料

目录


1. 为什么今天还要认真学 RAG

很多人第一次接触大模型,会先经历一个认知阶段:

  • ChatGPT 很聪明
  • Claude 上下文很长
  • 看起来已经什么都能答
  • 那还要不要做知识库?还要不要做 RAG?

这个问题非常常见,而且很容易把人带偏。

因为如果你只是日常聊天,模型确实已经很好用了;但一旦进入企业场景,你会立刻遇到几个现实问题:

  1. 模型不知道你公司的内部知识
  2. 模型不知道训练截止之后的新信息
  3. 模型会幻觉
  4. 模型没有天然的可追溯性
  5. 模型不是数据库,也不是搜索引擎

所以从工程视角看,RAG 之所以重要,不是因为它是一个热门名词,而是因为:

它解决了“大模型无法稳定访问外部知识”这个核心问题。


2. 什么是 RAG:它不是向量库,更不是一个 Prompt 技巧

2.1 定义

RAG,Retrieval-Augmented Generation,中文通常翻译为 检索增强生成

它的核心思想是:

  1. 用户提出问题
  2. 系统先去外部知识库中找相关内容
  3. 再把“问题 + 相关内容”一起交给大模型
  4. 模型基于这些资料生成答案

用一句话概括:

RAG = 检索系统 + 大模型生成系统

2.2 它不是什么

RAG 经常被误解成几种东西:

误解 1:RAG = 向量数据库

不对。
向量数据库只是 RAG 中的一个存储组件。

误解 2:RAG = 给 Prompt 多加一点上下文

也不对。
如果没有检索、没有索引、没有上下文构建,你只是“塞更多文本”,不叫真正的 RAG。

误解 3:RAG = 让模型知道更多

也不准确。
RAG 不是真把知识写进模型参数里,而是让系统在回答问题时临时访问正确知识

2.3 从系统视角重新理解 RAG

从工程视角看,一个完整的 RAG 至少包含四件事:

  • 信息索引系统
  • 检索召回系统
  • 上下文构建系统
  • 生成系统

也就是说,RAG 的本质不是“模型本身变强了”,而是:

系统把“正确知识”送到了模型面前。


3. 为什么 Long Context 不会杀死 RAG

这是现在最常被问到的问题之一。

3.1 表面上的疑问

既然现在模型上下文已经能做到几十万、上百万 token:

  • 我是不是可以把一整本书塞进去?
  • 我是不是可以把所有文档都塞进去?
  • 那我为什么还需要 RAG?

3.2 真正的问题不是“能不能塞”,而是“应不应该塞”

Long Context 解决的是:

  • 一次能读更多材料
  • 更适合跨段落推理
  • 更适合长文精读

但它没有解决:

  • 从海量知识里筛选相关信息
  • 成本控制
  • 首字延迟
  • 脏上下文污染
  • 组织级知识规模远大于单次窗口

3.3 正确结论

RAG 负责广度,Long Context 负责深度。

你可以把它们理解成这样:

  • RAG:先从“整个图书馆”里找出最相关的那一小批书
  • Long Context:再把这些书里的关键内容交给模型精读

这也是为什么未来更合理的方向不是“只有 RAG”或“只有 Long Context”,而是:

Long RAG


4. RAG 的完整系统分层

一个成熟的 RAG 系统,建议至少从四层去理解:

flowchart TD
    A[数据层] --> B[索引层]
    B --> C[检索层]
    C --> D[上下文构建层]
    D --> E[生成层]
    E --> F[评测与监控层]

4.1 数据层

负责文档来源、清洗、解析、更新。

4.2 索引层

负责把文档变成可被高效匹配的数据结构。

4.3 检索层

负责把用户问题映射到最相关的候选知识片段。

4.4 上下文构建层

负责筛选、重排、去重、清洗,形成高质量上下文。

4.5 生成层

负责把问题和证据组织成 Prompt,让模型回答。

4.6 评测与监控层

负责回答一个更现实的问题:

它是不是在真实业务里真的可用?


5. Indexing:知识如何变成“可被检索”的结构

很多初学者对索引阶段理解不深,觉得就是把文件扔进向量库。

其实不是。

5.1 索引链路

原始文档 → 解析 → 分割 → 向量化 → 存储

5.2 文档解析

实际项目里,你的知识来源可能不是纯文本,而是:

  • PDF
  • Word
  • Excel
  • 网页
  • API 文档
  • Markdown
  • 数据库记录
  • 聊天记录
  • 工单系统

所以第一步往往是“解析成统一文本结构”。

5.3 分割(Chunking)

长文档不能直接作为检索单元,因此需要切分。

固定长度切分

优点:

  • 实现简单
  • 处理快

缺点:

  • 容易把语义切碎
递归切分

优点:

  • 更保留语义完整性
  • 通常是最通用方案

缺点:

  • 实现比固定长度更复杂
LLM 辅助切分

优点:

  • 语义边界最好
  • 适合高精度场景

缺点:

  • 成本高
  • 速度慢

5.4 Chunking 的本质不是“切文本”,而是“做信息建模”

这是一个非常重要的判断。

  • 切太小:容易缺上下文
  • 切太大:容易引入噪声

所以 chunk size 不是机械参数,而是召回质量与生成质量的共同上游变量。

5.5 Embedding

Embedding 的作用是把文本映射到向量空间。

要求至少包括:

  • 索引侧和查询侧使用同一 embedding 模型
  • embedding 模型和业务语料相匹配
  • 向量归一化策略清晰统一

5.6 存储

常见选型:

  • Pinecone:托管型
  • Chroma:轻量级,本地/中小型项目友好
  • Milvus:大规模向量检索
  • Weaviate:企业级方案
  • FAISS:本地索引库
  • PGVector:Postgres 扩展

实际项目里,元数据也非常重要,例如:

  • 文档标题
  • 章节
  • 时间
  • 来源
  • 权限
  • 业务线
  • 产品线

很多时候,Metadata Filter 和向量检索同等重要


6. Retrieval:为什么检索质量决定 RAG 上限

RAG 的核心瓶颈,通常不在模型,而在检索。

6.1 语义检索

用户问题也会被 embedding 成向量。
然后系统用它去跟知识库里的向量做相似度比较,找出最相近的片段。

6.2 相似度计算

最常见的是余弦相似度:

cos(θ) = (A · B) / (|A| × |B|)

直觉上可以理解成:

  • 更看方向
  • 不太看长度
  • 适合语义匹配

6.3 Top-K 召回

系统通常先取相似度最高的前 K 条。

但这里一定要注意:

  • K 太小:可能漏掉关键证据
  • K 太大:噪声增加,上下文污染

所以 Top-K 从来不是越大越好,而是 recall 和 precision 的权衡点。

6.4 为什么关键词检索还没有过时

很多人一听到 RAG,就只想到向量检索。

但现实里,很多信息其实更适合 sparse / keyword retrieval:

  • 版本号
  • 编号
  • 产品型号
  • 错误码
  • 专有名词
  • 人名
  • 合同条款编号

所以真实系统里,经常会使用:

Hybrid Search = Dense Retrieval + Sparse Retrieval


7. Rerank:为什么只靠向量检索不够

向量检索更像“粗召回”,它能帮你找到看起来相关的内容,但未必能准确判断:

哪些内容最适合回答当前这个问题

7.1 Rerank 的作用

Rerank 通常用来:

  • 重新排序候选片段
  • 提升上下文精度
  • 去掉弱相关内容
  • 保证最终给模型的是“高密度证据”

7.2 两阶段架构

Recall → Rerank → Context Build

这是非常常见的线上结构。

7.3 上下文构建不仅是“拼接”

还应该做:

  • 去重
  • 清洗噪声
  • 过滤过期内容
  • 控制 token budget
  • 保留高价值事实片段
  • 按回答需要排序

一句话:

高质量 RAG 的关键,不只是找到内容,而是构造高质量上下文。


8. Generation:如何让模型“基于证据回答”

很多人以为检索完成就差不多了,但生成阶段同样决定最终质量。

8.1 一个更稳定的目标

生成阶段应该尽量做到:

  • 基于证据回答
  • 不知道就拒答
  • 输出结构清晰
  • 尽量带引用
  • 不随意扩写证据之外内容

8.2 常见提示约束

例如:

  • 仅依据提供上下文回答
  • 如果证据不足,明确说明
  • 列出引用来源
  • 用结构化格式输出
  • 禁止编造未提供事实

8.3 为什么很多系统“看起来检索对了,回答却还是不稳”

因为生成阶段常见问题包括:

  • Prompt 边界不清晰
  • 引用要求太弱
  • 模型倾向过度总结
  • 证据排序不合理
  • 上下文噪声未清理

9. RAG 的几种主要形态:Basic / Advanced / Modular / Long / Agentic / Graph

这部分是很多文章没讲完整的,但恰恰是工程里最重要的部分之一。

9.1 Basic RAG

最基础的线性形态:

文本分片 → 向量化 → 检索 → 拼接 → 生成
适用场景
  • FAQ
  • 单文档问答
  • 制度说明
  • 产品参数查询
优势
  • 实现快
  • 成本低
  • 非常适合做 MVP
缺点
  • 一旦文档复杂、噪声多、问法不稳定,效果容易下降

9.2 Advanced RAG

它不是换了一个新东西,而是在 Basic RAG 基础上加入一系列增强能力:

  • Query Rewrite
  • Query Decomposition
  • Hybrid Search
  • Metadata Filter
  • Rerank
  • Context Cleaning
本质

让“找到的内容更准”,让“给模型的上下文更干净”

这是现实项目里最常见的形态

因为 Basic RAG 很多时候只能验证方向,而真正上线通常会演进成 Advanced RAG。

9.3 Modular RAG

Modular RAG 的关键不是“更聪明”,而是“更工程化”。

它不再把 RAG 看成一条固定流水线,而是拆成多个可组合模块,例如:

  • Search Module
  • Memory Module
  • Rerank Module
  • Router / Planner
  • Tool Module
  • Database Module
好处
  • 可插拔
  • 易扩展
  • 更适合复杂业务
作用

这是很多系统走向 Agent 化之前的关键过渡阶段。

9.4 Long RAG

Long RAG 是对 “Long Context 不会杀死 RAG” 的一个工程化回答。

它的基本思路是:

海量知识库
  ↓
检索缩小范围
  ↓
重排 + 清洗 + 上下文构建
  ↓
高质量长上下文
  ↓
长窗口模型深度理解
  ↓
答案
它解决什么问题
  • 保留 RAG 的广度筛选能力
  • 利用长上下文增强深度推理能力
特别适合
  • 长 PDF
  • 手册
  • 合同
  • 技术规范
  • 长日志分析

9.5 Agentic RAG(ARAG)

Agentic RAG 的关键不是“换个名字”,而是整个系统开始具备:

  • 任务拆解
  • 多轮检索
  • 工具调用
  • 动态决策
  • 反思与重试
它不再是:

“检索一次 → 回答一次”

而更像: “先想清楚怎么解决,再决定检索什么、查什么、调什么工具”

适用场景
  • 多步骤复杂任务
  • 多轮问答
  • 需要 API / 数据库 / 工具参与
  • 复杂分析类问题
代价
  • 成本更高
  • 延迟更高
  • 不确定性更高
  • 调试更难

9.6 GraphRAG

GraphRAG 更适合关系型知识。

它的核心不是“找最像的文本”,而是:

理解实体之间的关系网络

适用问题
  • 路径推理
  • 多实体关系分析
  • 因果链条梳理
  • 跨文档多跳推理
技术栈通常涉及
  • 实体识别
  • 关系抽取
  • 图数据库(如 Neo4j)
  • 图检索
  • LLM 生成
它特别擅长
  • 谁影响谁
  • 谁依赖谁
  • 沿着什么路径传播

10. 实际项目里哪种用得最多

如果从真实工程落地看,最常见的并不是“纯 Basic RAG”。

一个更接近实际的结论是:

  • Basic RAG:常见于 Demo / MVP
  • Advanced RAG:最主流
  • Long RAG:越来越多
  • Agentic RAG:用于更复杂任务
  • GraphRAG:小众但高价值

可以粗略理解成:

80% 的项目最终都会落在 Advanced RAG / Long RAG 这一带

因为它们在“效果 / 成本 / 稳定性 / 维护成本”之间更平衡。


11. Python 代码:从一个最小 RAG Demo 开始

下面给一个非常简化的本地化 Python 示例,帮助你建立最小闭环。

11.1 依赖

pip install sentence-transformers faiss-cpu numpy

11.2 最小示例

from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

# 1. 准备文档
docs = [
    "公司差旅制度规定:国内出差住宿上限为 500 元/晚。",
    "高级别管理人员住宿上限为 800 元/晚。",
    "餐补标准为 100 元/天。",
    "国外差旅标准另行规定。"
]

# 2. 向量化
model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
doc_embeddings = model.encode(docs, normalize_embeddings=True)

# 3. 建索引
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatIP(dimension)  # 归一化后可用内积近似余弦相似度
index.add(np.array(doc_embeddings, dtype=np.float32))

# 4. 查询
query = "我们公司住宿报销上限是多少?"
query_embedding = model.encode([query], normalize_embeddings=True)

# 5. 检索 Top-K
scores, indices = index.search(np.array(query_embedding, dtype=np.float32), k=2)

hits = [docs[i] for i in indices[0]]
print("Top Hits:")
for h in hits:
    print("-", h)

# 6. 构造上下文(真实项目中这里会接 LLM)
context = "
".join(hits)
prompt = f'''
请仅依据以下资料回答问题。

资料:
{context}

问题:
{query}
'''

print(prompt)

11.3 这个示例说明了什么

它虽然非常简单,但已经具备了最基础的 RAG 主链路:

  • 文档准备
  • embedding
  • 向量索引
  • 检索
  • 构造上下文

真实项目当然会复杂很多,但本质就是这条链路逐步增强。


12. Python 代码:加入 Rerank 与 Metadata Filter 的增强版 RAG

下面给一个更贴近工程的简化版本。

12.1 数据结构

documents = [
    {
        "text": "国内出差住宿上限为 500 元/晚。",
        "meta": {"department": "general", "year": 2026, "source": "差旅制度"}
    },
    {
        "text": "高级别管理人员住宿上限为 800 元/晚。",
        "meta": {"department": "executive", "year": 2026, "source": "差旅制度"}
    },
    {
        "text": "餐补标准为 100 元/天。",
        "meta": {"department": "general", "year": 2026, "source": "差旅制度"}
    },
]

12.2 示例代码

from sentence_transformers import SentenceTransformer, CrossEncoder
import numpy as np
import faiss

embed_model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
rerank_model = CrossEncoder("BAAI/bge-reranker-base")

documents = [
    {
        "text": "国内出差住宿上限为 500 元/晚。",
        "meta": {"department": "general", "year": 2026, "source": "差旅制度"}
    },
    {
        "text": "高级别管理人员住宿上限为 800 元/晚。",
        "meta": {"department": "executive", "year": 2026, "source": "差旅制度"}
    },
    {
        "text": "餐补标准为 100 元/天。",
        "meta": {"department": "general", "year": 2026, "source": "差旅制度"}
    },
]

texts = [d["text"] for d in documents]
doc_embeddings = embed_model.encode(texts, normalize_embeddings=True)

index = faiss.IndexFlatIP(doc_embeddings.shape[1])
index.add(np.array(doc_embeddings, dtype=np.float32))

def metadata_filter(docs, department=None, year=None):
    results = []
    for d in docs:
        if department and d["meta"].get("department") != department:
            continue
        if year and d["meta"].get("year") != year:
            continue
        results.append(d)
    return results

def retrieve(query, top_k=5):
    query_vec = embed_model.encode([query], normalize_embeddings=True)
    scores, indices = index.search(np.array(query_vec, dtype=np.float32), k=top_k)
    return [documents[i] for i in indices[0]]

def rerank(query, candidates, top_n=2):
    pairs = [[query, c["text"]] for c in candidates]
    scores = rerank_model.predict(pairs)
    ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
    return [item[0] for item in ranked[:top_n]]

query = "普通员工住宿报销上限是多少?"

# 1. 粗召回
candidates = retrieve(query, top_k=3)

# 2. 元数据过滤(这里假设只看 general 类)
filtered = metadata_filter(candidates, department="general", year=2026)

# 3. Rerank
final_hits = rerank(query, filtered, top_n=2)

for item in final_hits:
    print(item)

12.3 这个版本比最小 demo 强在哪

它已经出现了真正线上系统的典型组件:

  • embedding recall
  • metadata filter
  • rerank

这就是从 Basic RAG 向 Advanced RAG 演进的最常见路径。


13. Python 代码:Agentic RAG 的一个最小伪实现

Agentic RAG 的重点不在“换模型”,而在“编排方式变化”。

13.1 一个极简伪代码

state = {
    "query": "分析近三个月 A 产品退货率上升原因,并给出建议",
    "context": [],
    "steps": []
}

def planner(state):
    if "sales_data" not in state:
        return {"type": "tool", "tool": "query_sales_db"}
    if "complaints" not in state:
        return {"type": "retrieve", "target": "complaint_docs"}
    return {"type": "final"}

def query_sales_db():
    return {"sales_data": "近三个月退货率从 2% 升到 5%"}

def retrieve_docs():
    return {"complaints": ["物流慢", "包装破损", "屏幕瑕疵"]}

while True:
    action = planner(state)

    if action["type"] == "tool":
        result = query_sales_db()
        state.update(result)
        state["steps"].append(("tool", result))

    elif action["type"] == "retrieve":
        result = retrieve_docs()
        state.update(result)
        state["steps"].append(("retrieve", result))

    elif action["type"] == "final":
        break

print(state)

13.2 为什么这和普通 RAG 差很多

因为它已经不是:

检索一次 → 回答一次

而是:

先规划 → 决定调什么 → 再检索 / 再查工具 → 汇总

这就是 Agentic RAG 与普通 RAG 最大的工程差异。


14. GraphRAG 应该怎么理解

很多人看到 GraphRAG 会以为它只是“把图数据库接上”。

其实它本质上是在回答一个不同类型的问题:

当知识的核心不在文本块,而在实体关系时,普通 RAG 不够用了。

14.1 图谱视角

例如你问:

  • 某政策变化如何影响供应链上的多个公司?
  • 某企业股权变更如何传导到信贷评级?
  • 某设备异常是否可能和上游工序有关?

这类问题的难点不是“找到一段最像的文字”,而是:

  • 找到实体
  • 找到关系
  • 找到路径
  • 推理传播链

14.2 一个简化思路

query = "政策A如何影响企业B和供应商C?"

# 1. 从 query 中抽实体
entities = ["政策A", "企业B", "供应商C"]

# 2. 图数据库查询子图
subgraph = '''
政策A -> 行业补贴变化 -> 企业B成本下降
企业B -> 订单增加 -> 供应商C产能压力上升
'''

# 3. 把关系子图转成可读上下文,再交给 LLM
prompt = f'''
请基于以下关系图回答问题:

{subgraph}

问题:
{query}
'''
print(prompt)

真实 GraphRAG 当然会复杂得多,但你至少可以先记住一句话:

GraphRAG 查的不只是文本,而是关系网络。


15. 工程落地时最容易踩的坑

15.1 以为换更大的模型,RAG 效果就会自动变好

不一定。
很多效果问题根本不在模型,而在:

  • chunk 切法
  • query 改写
  • 检索策略
  • rerank
  • 脏上下文

15.2 以为上下文塞得越多越好

不一定。
很多时候,更少但更干净的上下文,效果更好。

15.3 只做向量检索,不做关键词、过滤与排序

这样很容易在:

  • 错误码
  • 编号
  • 型号
  • 条款号

这类场景翻车。

15.4 一上来就做最复杂架构

很多团队一开始就想上 Agent、Graph、长链路编排,最后把自己复杂死。

更合理的路径通常是:

Basic RAG → Advanced RAG → Long RAG / Agentic RAG / GraphRAG

16. 如何评测一个 RAG 系统是不是“真的可用”

RAG 不能只看“演示时答得像不像”。

16.1 建议至少关注这些指标

检索层
  • 召回率
  • 命中率
  • MRR / NDCG(如果有条件)
  • Top-K 命中情况
生成层
  • 最终答案可用性
  • 引用准确性
  • 拒答准确性
  • 幻觉率
系统层
  • 首字延迟
  • 单次回答成本
  • 吞吐
  • 缓存命中率
用户层
  • 用户追问率
  • 用户修正率
  • 满意度
  • 任务完成率

16.2 为什么评测这么重要

因为没有评测,你就无法知道:

  • query rewrite 是否真的有效
  • rerank 是否真的提升质量
  • top_k 调整有没有帮助
  • 新 embedding 模型是不是更适合你的业务

没有评测,优化基本只能靠感觉。


17. 技术选型建议

如果你是第一次做项目,我建议这样走:

阶段 1:先做可用

  • Basic RAG
  • Chroma / FAISS
  • 一个稳定的 embedding 模型
  • 一个通用 LLM
  • 做最小问答闭环

阶段 2:再做更准

  • Query Rewrite
  • Hybrid Search
  • Rerank
  • Metadata Filter
  • Context Cleaning

阶段 3:再做更复杂

  • Long RAG:长文阅读、手册、合同
  • Agentic RAG:复杂任务、工具调用
  • GraphRAG:关系推理、多跳路径

阶段 4:最后做工程化

  • 评测集
  • 监控
  • 缓存
  • 权限控制
  • 多租户
  • 文档更新机制

18. 一张图总结全文

你可以把整篇文章压缩成下面这张图:

flowchart TD
    A[用户问题] --> B[Query Rewrite / Decompose]
    B --> C[Recall: Dense + Sparse]
    C --> D[Rerank]
    D --> E[Context Build]
    E --> F[LLM Generation]
    F --> G[引用 / 拒答 / 结构化输出]

    H[Basic RAG] --> I[Advanced RAG]
    I --> J[Long RAG]
    I --> K[Agentic RAG]
    I --> L[GraphRAG]

一句话理解就是:

  • Basic RAG:先跑起来
  • Advanced RAG:先把质量做稳
  • Long RAG:处理长文精读
  • Agentic RAG:处理复杂任务链
  • GraphRAG:处理关系网络推理

19. 最后的结论

19.1 关于 Long Context 与 RAG

  • Long Context 不会杀死 RAG
  • RAG 负责从海量知识中缩小范围
  • Long Context 负责对高价值材料做深度阅读
  • 未来主流方向是 Long RAG

19.2 关于架构选择

  • Basic RAG:解决基础知识问答
  • Advanced RAG:解决正式上线的质量问题
  • Long RAG:解决长文精读问题
  • Agentic RAG:解决复杂任务链问题
  • GraphRAG:解决关系型、多跳推理问题

19.3 最值得记住的一句话

RAG 的本质不是“让模型知道更多”,而是“让系统以更低成本、更高可信度访问正确知识”。