从数据类型出发理解RAG

RAG 基础:从数据类型出发理解RAG

写给第一次接触 RAG 的你。读完本文,你不仅能说出 RAG 是什么,更能在面对自己的真实数据时,知道该选哪条技术路线。


目录

  1. 从一个例子说起
  2. [为什么需要 RAG](#为什么需要 RAG "#2-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-rag")
  3. [RAG 的核心思想:先查资料,再回答](#RAG 的核心思想:先查资料,再回答 "#3-rag-%E7%9A%84%E6%A0%B8%E5%BF%83%E6%80%9D%E6%83%B3%E5%85%88%E6%9F%A5%E8%B5%84%E6%96%99%E5%86%8D%E5%9B%9E%E7%AD%94")
  4. [RAG 的通用流水线](#RAG 的通用流水线 "#4-rag-%E7%9A%84%E9%80%9A%E7%94%A8%E6%B5%81%E6%B0%B4%E7%BA%BF")
  5. [核心:按数据类型选择 RAG 策略](#核心:按数据类型选择 RAG 策略 "#5-%E6%A0%B8%E5%BF%83%E6%8C%89%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E9%80%89%E6%8B%A9-rag-%E7%AD%96%E7%95%A5")
  6. [数据混杂怎么办:路由、质检纠错与 Agentic RAG](#数据混杂怎么办:路由、质检纠错与 Agentic RAG "#6-%E6%95%B0%E6%8D%AE%E6%B7%B7%E6%9D%82%E6%80%8E%E4%B9%88%E5%8A%9E%E8%B7%AF%E7%94%B1%E8%B4%A8%E6%A3%80%E7%BA%A0%E9%94%99%E4%B8%8E-agentic-rag")
  7. 选型决策速查表
  8. [如何评估一个 RAG 系统](#如何评估一个 RAG 系统 "#8-%E5%A6%82%E4%BD%95%E8%AF%84%E4%BC%B0%E4%B8%80%E4%B8%AA-rag-%E7%B3%BB%E7%BB%9F")
  9. 五个常见误区
  10. 小结与学习路线

1. 从一个例子说起

假设你在一家公司负责搭建内部智能助手"小智"。员工会问它各种问题:

员工的问题 答案藏在哪
"差旅报销的流程是什么?" PDF 制度文档、Wiki 页面
"上个季度华东区的销售额是多少?" 关系型数据库里的订单表
"帮我找找和'轻量化运动水壶'描述相似的商品" 商品库(JSON 文档)
"支付网关这个项目,前后参与过哪些人、依赖哪些系统?" 人员/项目关系网络(图数据)
"这张架构图里,网关上游接的是什么服务?" 一张图片
"上周客户投诉电话里,大家主要在抱怨什么?" 客服录音(音频)

你会发现:问题的本质都是"回答问题",但答案存放的"容器"完全不同

这就是本文想传达的核心观点------很多人学 RAG 时一上来就背各种技术名词(向量、Embedding、GraphRAG......),但其实更好的入门方式是:

先看你的数据长什么样,再决定用什么方法去检索它。

数据类型决定了钥匙的形状。接下来我们就沿着这条主线,把 RAG 讲清楚。


2. 为什么需要 RAG

大语言模型(LLM)很聪明,但它有几个天生的局限:

  1. 知识有截止日期。模型的训练数据停留在某个时间点,之后发生的事情它一无所知。
  2. 会产生幻觉。当它不知道答案时,有时不会说"不知道",而是自信地编一个听起来很像真的答案。
  3. 看不到私有数据。你公司的制度文档、数据库、内部代码,从来没有出现在它的训练集中。

你可能会想:现在的模型上下文窗口不是已经能塞几十万 token 了吗?把所有资料都塞进去不就行了?

不太行,原因有三:

  • 。每次提问都塞几十万字,token 费用很高,响应也慢。
  • 注意力会稀释。上下文越长,模型对中间内容的关注度越低(业内常说的 "Lost in the Middle" 现象),关键信息可能被忽略。
  • 装不下。一个中型企业的全部数据,早就超过了任何模型的上下文上限。

所以我们需要一种机制:回答时只把"真正相关的少数资料"送给模型。这就是 RAG。

顺带说明:RAG 和长上下文不是二选一的关系。常见的最佳实践是先用 RAG 捞出精准的资料,再用长上下文对这批资料做深入的分析推理------两者互补,各司其职。


3. RAG 的核心思想:先查资料,再回答

RAG 全称 Retrieval-Augmented Generation(检索增强生成)。名字有点拗口,思想却很朴素:

在让模型回答之前,先去资料库里检索相关内容,把检索结果和问题一起交给模型,让它"有据可依"地作答。

可以把它类比成一场开卷考试

  • 闭卷考试(纯 LLM):全凭记忆答题,记不清就现编。
  • 开卷考试(RAG):允许翻书。先翻到相关的那几页,再照着书写答案------准确率自然高得多。

注意一个关键细节:模型并不是把资料原样抄一遍 ,而是阅读理解后用自己的话组织答案。所以资料的质量直接决定答案的质量------检索环节做得好不好,比提示词写得漂不漂亮重要得多。这是初学者最容易忽略的一点。


4. RAG 的通用流水线

无论数据是文档、数据库还是图片,一个 RAG 系统都可以拆成两个阶段、七个步骤:

markdown 复制代码
【离线 · 索引阶段】(数据入库时做一次)

    加载/解析 ──→ 切块/结构化 ──→ 向量化/建索引 ──→ 存储
                                                    │
【在线 · 查询阶段】(每次提问都执行)               │
                                                    │
    问题理解 ──→ 检索 ←─────────────────────────────┘
                    │
                    ▼
                重排/过滤 ──→ 生成答案

离线索引阶段(数据进入系统时做一次,之后增量更新):

  1. 加载解析:把 PDF、网页、数据库表、音频等原始数据读进来,转成可处理的格式。
  2. 切块 / 结构化:把长内容拆成合适大小的单元;或者把数据整理成便于检索的结构。
  3. 向量化 / 建索引:把内容转成向量(Embedding),或建立其他形式的索引(全文索引、图索引等)。
  4. 存储:存入向量数据库、搜索引擎或图数据库。

在线查询阶段(每次提问都执行):

  1. 问题理解:理解用户意图,必要时改写问题。
  2. 检索:用合适的钥匙去开对应的锁,找出最相关的候选内容。
  3. 生成:把检索到的内容作为参考资料,连同问题一起交给 LLM,生成最终答案。

记住这个骨架。接下来所有内容,讲的都是不同数据类型如何影响第 2、3、6 步的做法

关于示例代码 :本文示例基于 LangChain 1.0(Python),先安装核心依赖:

bash 复制代码
pip install -U langchain langchain-openai langchain-community langchain-text-splitters pypdf

示例中的模型字符串(如 openai:gpt-5.5)可替换为任意 LangChain 支持的模型;Embedding 服务同理,代码结构不变。


5. 核心:按数据类型选择 RAG 策略

这是全文的重点。我们先建立一个判断原则:

检索的本质是匹配。数据是模糊的语义,就用语义匹配(向量);数据是精确的结构,就用结构匹配(查询语言)。

带着这个原则,我们逐类来看。


5.1 非结构化文本

典型来源:PDF、Word、Markdown、网页、Wiki、邮件、会议纪要、工单。

这是最经典、也是你最先会遇到的 RAG 场景。

难点在哪?

一段长文档没法整段塞给模型,必须切块(chunk);而切块会带来两个问题:

  • 切断了语义:一刀切在第 500 字,可能正好把一句话腰斩。
  • 语义鸿沟:用户问"钱花超了怎么找公司要回来",文档里写的却是"费用报销申请流程"------字面不同,意思相同。关键词搜索在这里会失效。

再加上第三个短板:搜到的资料不行,也照样拿去生成。切块粗暴、语义鸿沟、来者不拒------这就是最朴素的 Naive RAG 的三大经典短板。本节的增强技术和第 6 节的质检纠错,都是围绕它们展开的。

标准做法:向量检索

用 Embedding 模型把文字变成一串数字(向量)。语义相近的文本,向量在空间中的距离也近。于是"怎么要回钱"和"报销流程"虽然字面不同,向量却很接近------语义鸿沟就此填平

直观感受一下(数字为示意,真实向量有上千维):

文本 向量(示意)
钱花超了怎么找公司要回来 0.21, 0.85, 0.13, ...
费用报销申请流程 0.23, 0.82, 0.15, ...
今天中午吃什么 0.87, 0.11, 0.44, ...

前两句话面完全不同,向量却挨得很近;和第三句就离得远了。

进阶增强(生产环境几乎必备):

技术 解决什么问题 一句话原理
混合检索(向量 + BM25 关键词) 编号、型号、专有名词搜不到 向量管"意思相近",关键词管"字面精确",两路结果用 RRF 等算法融合成统一排序;生产环境几乎都应以它取代纯向量检索
重排(Reranker) 检索结果里混着噪声 Embedding 模型分别给问题和文档算向量,快但糙;Reranker 把"问题+文档"成对送进模型精打分,慢但准。生产上常做级联:先粗筛一两百条,再逐级精排到 5 条左右
查询改写(Multi-Query) 用户问法千奇百怪 让 LLM 把问题改写成多个表述,分别检索再合并去重;代价是多一次改写调用和多路检索,改写跑偏还会引入无关文档
HyDE 问题很短、文档很长,向量空间里对不上 让 LLM 先凭空写一段"假答案"(不必准确),用假答案的向量去检索------它的文体和真文档更接近。适合 LLM 有基本领域认知的场景;冷门领域或私有术语慎用,编跑偏了反而更糟

这四招分别解决"搜得到、搜得准、问得清"。还有一类问题是"搜到的全是垃圾,模型还硬答"------它的解法(检索质检与自我纠错)与数据类型无关,统一放在第 6 节讲。

最小可运行示例(LangChain 1.0)

二十来行代码,就是一个能跑通的文本 RAG,每一步都对应第 4 节的骨架:

python 复制代码
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_core.vectorstores import InMemoryVectorStore

# ---------- 离线索引:加载 → 切块 → 向量化 → 入库 ----------
docs = PyPDFLoader("差旅报销制度.pdf").load()        # 1. 加载解析
chunks = RecursiveCharacterTextSplitter(             # 2. 切块
    chunk_size=500, chunk_overlap=80
).split_documents(docs)

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = InMemoryVectorStore(embeddings)       # 3+4. 向量化并入库
vector_store.add_documents(chunks)                   #(生产环境可换 Chroma / Milvus / Qdrant)

# ---------- 在线查询:检索 → 生成 ----------
retriever = vector_store.as_retriever(search_kwargs={"k": 5})
question = "钱花超了怎么找公司要回来?"
context = "\n\n".join(d.page_content for d in retriever.invoke(question))

llm = ChatOpenAI(model="gpt-5.5")                    # 模型可按需替换
answer = llm.invoke(
    f"请仅依据以下资料回答问题,资料中没有的信息请直接说明。\n\n"
    f"资料:\n{context}\n\n问题:{question}"
)
print(answer.text)

切块策略怎么选?

  • 按结构切(优先考虑):文档本身有清晰标题层级(如产品手册)时,直接按章节、标题切块,便宜且效果好。
  • 固定长度切:每块 300~800 字、相邻块保留 10%~20% 重叠。简单通用,适合起步。
  • 语义切:计算相邻句子的相似度,在"话题转折处"下刀。适合话题跳来跳去的会议记录、访谈稿,但成本更高、阈值难调。
  • 父子块技巧:用小块做检索(精准),命中后返回它所在的大块(上下文完整)。兼顾两头,长文档推荐。

什么时候文本 RAG 不够用? 当答案不落在任何"一段话"里,而是散落在多个实体、多条记录之间的关系中时------请往下看。


5.2 关系型数据库

典型来源:MySQL / PostgreSQL 里的订单表、用户表、财务流水。

先做一个思想实验:员工问小智------

"上季度华东区销售额最高的三个产品是什么?"

这个问题能用向量检索解决吗?不能。 因为答案不在某段文字里,而是需要对成千上万行数据做过滤、聚合、排序。你就算把所有订单行都向量化了,也"搜"不出一个 SUM 结果。

这印证了我们的判断原则:结构化的精确问题,要用结构化的查询语言来答。

标准做法:Text-to-SQL

流程只有四步:

  1. 把数据库的表结构(有哪些表、字段、含义、示例值)写进提示词;
  2. 让 LLM 把自然语言问题翻译成 SQL
  3. 执行这条 SQL;
  4. 把查询结果交回给 LLM,用自然语言组织成答案
sql 复制代码
-- 第 2 步的产物示例:LLM 把上面的中文问题翻译成了这样一条 SQL
SELECT product_name, SUM(amount) AS total
FROM orders
WHERE quarter = '2026Q2' AND region = '华东'
GROUP BY product_name
ORDER BY total DESC
LIMIT 3;

用 LangChain 1.0 实现,核心思路是把"执行 SQL"包装成一个带安全约束的工具

python 复制代码
import sqlite3
from langchain.agents import create_agent
from langchain.tools import tool

@tool
def query_orders(sql: str) -> str:
    """对订单库执行只读 SQL 并返回结果。仅支持 SELECT。
    表结构:orders(id, product_name, amount, region, quarter)。"""
    if not sql.strip().lower().startswith("select"):
        raise ValueError("只允许 SELECT 查询")                 # 语法白名单
    conn = sqlite3.connect("file:orders.db?mode=ro", uri=True)  # 只读模式打开
    try:
        rows = conn.execute(sql).fetchmany(50)                  # 行数上限,防慢查询
        return str(rows)
    finally:
        conn.close()

agent = create_agent(
    model="openai:gpt-5.5",
    tools=[query_orders],
    system_prompt="你是数据分析助手。回答数值问题前,必须先通过 query_orders 工具查询数据库。",
)

result = agent.invoke({"messages": [
    {"role": "user", "content": "上季度华东区销售额最高的三个产品是什么?"}
]})
print(result["messages"][-1].text)

注意 @tool 函数的文档字符串(docstring)------它会成为工具的"说明书",模型靠它判断什么时候该用这个工具、怎么传参数。写得越清楚,调用越准确。

安全红线(务必重视)

生产环境绝不能把 LLM 生成的 SQL 直接丢给数据库执行。最低限度的防护:

  • 使用只读账号,并限制可访问的表;
  • SQL 审计:解析语句,只放行 SELECT,拦截任何写操作和危险函数;
  • 设置超时和行数上限,防止一条慢查询拖垮业务库;
  • 高危场景增加人工确认环节。

一个容易被忽略的高级技巧:结构化与语义检索混用

很多真实问题一半精确、一半模糊。比如:

"找出去年退货率超过 10% 的商品里,用户评论主要在抱怨什么。"

最好的做法是两步走 :先用 SQL 查出符合数值条件的商品 ID 列表,再拿这些 ID 作为过滤条件,去文本库中语义检索相关评论。SQL 负责算数,向量负责理解语义,两者是搭档,不是对手。


5.3 JSON / 文档型数据库

典型来源:MongoDB 集合、Elasticsearch 文档、商品 SKU、配置信息、用户画像。

这类数据介于前两类之间,是半结构化的:

  • 固定字段price: 299category: "运动户外" ------适合精确过滤;
  • 也有自由长文本description: "轻量便携,适合徒步和日常通勤......" ------适合语义检索。

标准做法:过滤 + 向量检索(Filtered Vector Search)

核心思路一句话:数值和枚举字段做前置过滤,自由文本字段做语义搜索。

举个例子,用户问小智:

"有没有 300 元以内、适合新手徒步的登山鞋?"

拆解一下这个问题:

部分 性质 处理方式
"300 元以内" 精确条件 过滤:price <= 300
"登山鞋" 枚举类别 过滤:category = "登山鞋"
"适合新手、徒步" 模糊语义 向量检索

执行顺序上,先过滤、后向量搜索能同时拿到"算得对"和"搜得准":

ini 复制代码
候选集 = 文档库.filter(price <= 300, category == "登山鞋")
结果   = 向量库.search(embed("适合新手 徒步 舒适"), filter=候选集, top_k=5)

用 LangChain 1.0 实现:入库时把结构化字段放进 metadata,查询时用 filter 先收窄再搜:

python 复制代码
from langchain_core.documents import Document

# 入库:自由文本做语义检索,结构化字段放 metadata 做过滤
docs = [
    Document(
        page_content="轻量防水,鞋底抓地力强,适合新手徒步和日常通勤。",
        metadata={"category": "登山鞋", "price": 268},
    ),
    # ... 更多商品
]
vector_store.add_documents(docs)

# 查询:精确条件交给 filter,模糊语义交给向量
results = vector_store.similarity_search(
    "轻便舒适,适合新手",
    k=5,
    # Chroma 写法:多个条件必须用 $and 显式连接;不同向量库的语法差异较大,用前查文档
    filter={"$and": [
        {"category": {"$eq": "登山鞋"}},
        {"price": {"$lte": 300}},
    ]},
)

实践建议

  • 索引设计时就想清楚:哪些字段进过滤索引,哪些字段做 Embedding,不要把整份 JSON 无脑向量化------数字和日期本身没有"语义",向量化它们纯属浪费。
  • 字段较多的文档,可以只把"标题 + 描述 + 标签"拼接后做 Embedding,把结构化字段留给过滤层。
  • JSON 数据库(如 Elasticsearch 8.x、MongoDB Atlas)现在大多原生支持向量字段,一个库就能同时完成过滤和语义检索,架构可以很简单。

5.4 图数据库与知识图谱

典型来源:Neo4j 等图数据库,或散落在文档中、尚未成图的实体关系(人员↔项目↔系统↔部门)。

向量检索的盲区:多跳问题

回到开头的例子:

"支付网关这个项目,前后参与过哪些人、依赖哪些系统?"

假设语料里有这些零散的信息:

  • 文档 A:"老张是支付网关项目的第一任负责人。"
  • 文档 B:"支付网关上线后由小李接手维护。"
  • 文档 C:"支付网关依赖风控服务和账务系统。"

答案不在任何单独一段话里 ,而是要把三条信息沿着关系串起来。向量检索只能分别找到它们,拼装推理则全靠模型临场发挥,容易漏、容易错。

标准做法:GraphRAG

分两步:

  1. 建图(离线):用 LLM 阅读原始文档,抽取实体(人、项目、系统、部门)和它们之间的关系,存入图数据库。这一步成本较高------每篇文档都要过一遍 LLM。
  2. 查图(在线) :从问题中定位起始实体 → 在图上沿关系扩展一到两跳,取回一张子图 → 把子图序列化成文字(如 老张 ---负责→ 支付网关 ←维护--- 小李)→ 交给 LLM 作答。
  3. 全局问题的秘密武器:社区摘要 。微软提出的 GraphRAG 还会用 Leiden 算法把图聚成一个个联系紧密的"社区",并让 LLM 为每个社区生成摘要。面对"这个产品线的技术债主要集中在哪些模块"这类全局汇总型问题,系统直接调用社区摘要作答,不必遍历全图------这正是它在全局类问题上显著优于向量 RAG 的原因(简单事实查询两者差不多)。
arduino 复制代码
提问:"老张参与过哪些项目?"
  ↓ 定位实体
在图中找到"老张"
  ↓ 沿关系扩展 2 跳
取出子图:老张 ──负责──→ 支付网关 ──依赖──→ 风控服务
  ↓ 序列化成文字
LLM 组织成最终答案

要不要建图?先想清楚三件事

  • 图谱构建和查询的成本显著高于向量索引;
  • 如果你关心的是全局性、汇总性的问题("这个产品线的技术债主要集中在哪些模块?"),图的价值最大;
  • 如果只是普通的事实查询,向量 RAG 往往就够,不必为了用图而用图。

一个务实的折中:不预先建图,查询时让 LLM 从检索到的几段文本中现场抽取关系再推理。成本更低,适合数据量不大的阶段。


5.5 多模态数据:图片、音频、视频

现实中大量信息根本不是文字:架构图、报表截图、客服录音、培训视频。纯文本 RAG 对它们束手无策。好消息是,处理思路可以归结为三条通用路线。

路线一:先转成文字(最常用,起步推荐)

把非文本内容"翻译"成文字,然后走普通的文本 RAG:

数据类型 转换手段 补充要点
图片(含截图、流程图) OCR 提取文字;或用视觉模型(VLM)生成详细描述(caption) 架构图/流程图建议让 VLM 描述"结构和连接关系",而不只是罗列元素
PDF 里的表格 解析成 Markdown 或 CSV 表格直接向量化效果很差,务必先结构化
音频(录音、播客) 语音识别(ASR)转写 保留时间戳,方便答案溯源到"第几分钟"
视频 关键帧抽取 + 逐帧 VLM 描述 + 音轨 ASR 三者合并成带时间轴的结构化文本再入库

路线二:跨模态统一向量空间

用 CLIP 这类多模态编码模型,把文字和图片映射到同一个向量空间。这样就可以"用文字搜图片"------拿"海边日落"这句话的向量,直接匹配出语义相近的图片。适合以图为主、文字描述为辅的场景(素材库、商品图检索)。文本转文字路线做不到这种直接匹配,这是它独有的价值。

路线三:生成端支持多模态

检索到的如果包含原始图片,最后一步就不能用纯文本 LLM,而要用视觉语言模型(VLM),让它"看着图"回答。典型组合是:路线一负责"搜得到",路线三负责"答得准"。

选择建议:拿不准就从路线一开始。转文字方案组件成熟、调试直观;等文本化明显丢失关键信息(比如图表中的空间布局)时,再引入路线二、三。


5.6 其他值得了解的数据类型

除了上面五类,这三个类型在实践中也高频出现,提前了解一下:

① 代码库

  • 切块要感知语法:按函数、类、文件为单位切,而不是按字数硬切------一个被拦腰截断的函数对模型毫无意义。
  • 关键词索引反而更重要 :代码里充满精确标识符(parseConfigERR_TIMEOUT),向量检索对这类字符串并不敏感,BM25 全文索引往往是主力,向量做辅助。
  • 当前主流的 AI 编程工具,普遍采用"语义检索 + 关键词检索 + 让 Agent 主动调用搜索工具"的混合方式。

② 时序数据与日志

  • 检索前先做时间范围和指标维度过滤("昨晚 8 点到 10 点的 ERROR 日志"),再对过滤后的结果做语义/模式检索。
  • 数值趋势类问题("QPS 是不是涨了?")交给聚合查询,不要指望向量检索。

③ 表格文件(Excel / CSV)

  • 小表:整表转成 Markdown 放进上下文,简单直接;
  • 大表:入库(SQLite 即可)后走 Text-to-SQL;
  • 有大量文字批注的表格,字段值做 Embedding,数值列做过滤,回到 5.3 的半结构化套路。

6. 数据混杂怎么办:路由、质检纠错与 Agentic RAG

真实系统里,五类数据几乎总是同时存在。员工问小智"对比一下华东和华北去年成交量,再总结下两区的客诉焦点",一句话就同时砸中了关系型数据库和文本文档。

这时硬编码"if 问题类型 A 就走管道 A"会越来越难维护。更优雅的做法是 Agentic RAG

给 Agent 一组检索工具(向量搜索、SQL 查询、图遍历、图片理解......),让它自主决定:先查哪个 → 结果够不够 → 要不要换个工具再查 → 信息够了再作答。

sql 复制代码
用户问题
   ↓
Agent(决策中枢:判断信息够不够,决定下一步)
   ├── 需要精确数值 ──→ SQL 工具
   ├── 需要语义资料 ──→ 向量检索工具
   ├── 需要关系推理 ──→ 图查询工具
   └── 需要看图     ──→ VLM 工具
   ↓ 工具结果返回给 Agent,信息不够就换个工具或换个关键词再查
   ↓ 信息足够
生成最终答案

用 LangChain 1.0 的 create_agent,这套架构只需要三样东西:一组工具、一句系统提示、一个模型:

python 复制代码
from langchain.agents import create_agent
from langchain.tools import tool

@tool
def search_docs(query: str) -> str:
    """语义检索制度文档库。适合回答流程、政策、规定类问题。"""
    return "\n\n".join(d.page_content for d in doc_retriever.invoke(query))  # doc_retriever 见 5.1

@tool
def query_orders(sql: str) -> str:
    """对订单库执行只读 SQL。适合销量、金额、对比等精确数值问题。仅允许 SELECT。"""
    ...  # 实现见 5.2

@tool
def search_graph(entity: str) -> str:
    """在项目关系图中查询实体间的关联。适合"谁参与过什么、依赖哪些系统"类多跳问题。"""
    ...  # 图查询实现,思路见 5.4

agent = create_agent(
    model="openai:gpt-5.5",
    tools=[search_docs, query_orders, search_graph],
    system_prompt=(
        "你是公司助手小智。回答前先选择合适的工具收集信息;"
        "如果结果不够,换一个工具或换个关键词再查;信息足够后再作答。"
    ),
)

result = agent.invoke({"messages": [
    {"role": "user", "content": "对比华东和华北去年成交量,再总结两个区的客诉焦点"}
]})
print(result["messages"][-1].text)

注意系统提示里那句"信息不够就换个工具再查"------这正是 Agentic RAG 与固定管道的本质区别:检索策略不再是写死的流程,而是模型在循环中的自主决策

好处是扩展新数据源只需注册一个新工具;代价是多轮 LLM 调用带来的延迟和成本。建议:单数据源、问题模式固定的阶段,老老实实用固定管道;数据源多了、问题开始"跨界"了,再升级到 Agent。

与数据类型无关的四个编排层增强

下面这些方案不改变"先查再答"的骨架,而是在流程编排上做增强,任何数据类型都用得上:

  • Adaptive RAG(按复杂度路由):在一切开始前先判断问题复杂度。"今天周几"直接让模型答,根本不用检索;一般问题检索一次就够;复杂问题才走完整的"多工具 + 质检"流程。流量混杂的系统中,这一招能省下大量不必要的开销。复杂度分类器可以是一个微调的小模型,也可以直接用提示词让 LLM 判断,不必一开始就训练模型。
  • CRAG / Self-RAG(检索质检与自我纠错) :CRAG 在检索和生成之间加一道"质检员",逐条判断资料和问题相不相关:相关就用;不相关就换来源重查(比如回退到 Web 搜索,或退回"资料库中未找到"的拒答出口,见第 9 节误区 5);模棱两可就两边合并。Self-RAG 更进一步,生成后还要自查"我的每条论断都有资料支撑吗",没有就重写。它们共同对付的问题是:搜到的资料不行,还硬答
  • Multi-Agent RAG(多智能体分工):动机是单个 Agent 的过载------让它同时负责理解意图、挑选工具、校验质量、组织答案,提示词会越写越长,决策质量随之下降,就像让一个人同时当程序员、教练和主持人。于是把它拆成多个专职角色:路由 Agent 分发问题、各领域 Agent 各管一摊、质检 Agent 复核答案、写作 Agent 统一输出。每个环节可以独立优化,代价是链路更长、成本更高,数据源和权限复杂的企业级知识库才值得上。
  • Speculative RAG(推测式生成):延迟敏感的场景,可以把检索资料分成几组,用小模型并行各写一版草稿,再由大模型一次性验证、挑出最佳答案,缩短总耗时。它解决的不只是慢:资料全塞进一个提示词时,一条噪声资料就可能带偏整份答案,多草稿竞争能显著降低这种风险。

一句话总结:按数据类型选对检索方式是地基,这些编排技巧是地基之上的装修。


7. 选型决策速查表

前八行按数据类型选"怎么搜",后四行与数据类型无关,选"怎么编排":

你的情况 典型问题 推荐路线
PDF / Wiki / 工单等长文本 "报销流程是什么?" 文本切块 → 混合检索 → 重排
关系型数据库 "上季度销售额 Top 3?" Text-to-SQL(务必加安全防护)
JSON / 商品库等半结构化数据 "300 元以内的徒步鞋?" 字段过滤 + 向量检索
实体关系网络 "这个项目依赖哪些系统?" GraphRAG 或现场关系抽取
图片 / 音频 / 视频 "这张架构图里网关上游是什么?" 先转文字;图多再上跨模态向量
代码仓库 "这个函数在哪被调用?" 语法感知切块 + 关键词检索为主
日志 / 时序数据 "昨晚的报错在抱怨什么?" 时间维度过滤 + 语义检索
多种数据混合 "对比销量并总结客诉" 路由 / Agentic RAG
用户问法口语化、措辞多变 同一个意思有一百种问法 查询改写(Multi-Query / HyDE)
不能容忍幻觉 医疗、法律、金融答复 检索质检与纠错(CRAG / Self-RAG)
问题复杂度差异大 从闲聊到多文档综合分析 Adaptive RAG 路由
对响应速度敏感 在线客服、实时对话 Speculative RAG

8. 如何评估一个 RAG 系统

"感觉变好了"不是优化依据。建议从四个维度建立量化评估(RAGAS 等框架用的就是这套指标):

维度 问的问题 定位问题所在
上下文召回率 该找到的资料,找到了吗? 低 → 改切块、改检索、加查询改写
上下文精确率 找到的资料里,有用的占多少? 低 → 加重排、加过滤
忠实度 答案是否严格基于检索到的资料? 低 → 收紧提示词、加强引用校验
答案相关性 答的是不是用户问的? 低 → 改问题理解、改生成提示

操作上,先人工写 30~50 个真实问题和标准答案组成测试集,每改一处就跑一遍。这套流程比任何"玄学调参"都有效。


9. 五个常见误区

  1. 一上来就堆全家桶。Naive RAG + 人工看 badcase,永远是你该迈出的第一步。先跑通最简单的,再针对暴露的问题逐个升级。
  2. 只调提示词,不调检索。答案不好时,十有八九问题出在"找错了资料"而不是"没嘱咐好模型"。先检查检索结果,再动提示词。
  3. 忽视数据质量。文档本身版本混乱、内容冲突,RAG 只会把混乱放大。数据治理的投入回报常常高于算法优化。
  4. 所有数据都无脑向量化。数字、日期、枚举值没有语义,向量化它们既浪费又引入噪声。先分类:哪些该过滤,哪些该 Embedding。
  5. 没有兜底策略。检索不到任何相关内容时,系统应该明确回答"资料库中未找到",而不是逼着模型硬编。留好"拒答 + 转人工"的出口。

10. 小结与学习路线

三句话带走全文:

  1. RAG 的核心思想只有一句:先查资料,再回答------把"闭卷考试"变成"开卷考试"。
  2. 所有 RAG 系统共享同一个骨架(索引 + 查询),数据类型决定每个环节的具体做法:模糊语义用向量,精确结构用查询语言,关系网络用图,非文本内容先转文字。
  3. 从最简单的方案开始,用测试集量化评估,让 badcase 告诉你下一步该升级哪个环节。

建议的动手路径:

  1. 用一份几十页的 PDF + 任意向量数据库,跑通最朴素的"切块 → 向量化 → 检索 → 生成";
  2. 加上混合检索和重排,对比效果;
  3. 找一个真实数据库表,实现一个带只读防护的 Text-to-SQL;
  4. 把文本和 SQL 两条链路用一个路由(或 Agent)串起来;
  5. 建立你的 30 题测试集,开始量化迭代。

工具生态方面,向量数据库(Milvus、Qdrant、Chroma)、编排框架(本文示例使用的 LangChain 1.0 / LangGraph、LlamaIndex)、一体化平台(Dify、RAGFlow)都值得按需了解------但请记住,工具会过时,本文的思考框架不会

祝搭建顺利。

相关推荐
律宏阔21 分钟前
Headroom 宣传能省 60%~95% Token,真实会话能省多少?公开基准、独立 Agent 测试与社区实测整理
人工智能·agent
律宏阔23 分钟前
Backpass 能让 Claude Code / Codex 越用越好吗?公开测试、运行数据与宣传口径对照
人工智能·agent
xiaohe060136 分钟前
🎮 豆包完胜 DeepSeek ?!零玩家竞技场,AI Agent 专属对弈!
游戏·llm·agent
阿里云云原生40 分钟前
AI Coding 的观测与科学降本:从一次 Trace 到自动调优闭环
agent
武子康1 小时前
图像生成为什么需要独立的 Gateway 抽象:参数、重试与幂等设计
人工智能·llm·agent
tachibana21 小时前
微调和 RAG 各自的优劣势是什么?
人工智能·ai·大模型·llm·agent
ClouGence3 小时前
一句话直出可运行程序!GLM‑5.3 系列多任务实测
人工智能·agent·ai编程
阿里云云原生3 小时前
实验:回测、离线实验平台与题目级 Rubric丨AgentLoop 数据飞轮实践(四)
云原生·agent
DolphinScheduler社区3 小时前
把 Apache DolphinScheduler 变成 Agent 的“手和脚”:从调度平台到自然语言数据入口
人工智能·开源·apache·agent·技术分享·海豚调度·大数据工作流调度