1. 从关键词看趋势:为什么现在必须重新理解 RAG
过去两年,RAG 这个词被讲烂了。几乎每个做 AI 应用的人都能说上两句“检索增强生成”,但真正落到项目里,你会发现一个尴尬的现实:传统 RAG 在 Agent 场景下经常掉链子。用户问一个需要跨文档推理的问题,向量检索召回一堆语义相似但逻辑不相关的片段,模型拿着这些碎片拼出一个似是而非的答案,最后你只能靠调 prompt 和加 rerank 来硬撑。
问题的根源不在于 RAG 本身,而在于检索的粒度和结构与 Agent 的推理方式不匹配。Agent 不是单轮问答机器,它会拆解任务、调用工具、维护记忆、多步推理。当 Agent 需要“先找到 A 文档里的定义,再结合 B 文档里的约束,最后用 C 文档的格式输出”时,单纯的向量相似度检索根本撑不住这种链式需求。
这就是为什么 GraphRAG、LightRAG、Agentic RAG 这些词开始密集出现在技术社区。它们不是简单的“RAG 升级版”,而是针对不同 Agent 场景的检索架构重构。我最近把市面上主流的几种方案都跑了一遍,踩了不少坑,也总结出一些选型逻辑。这篇文章就把 Agent 时代真正值得关注的 8 种 RAG 方案一次讲清楚,从原理到实操,从选型到避坑,尽量让不同基础的读者都能找到能直接抄作业的部分。
提示:本文涉及的方案均基于公开技术文档和实际项目经验整理,具体参数和配置请以你使用的框架版本为准。
2. 先搞清楚:Agent 到底需要什么样的 RAG
2.1 Agent 的检索需求和传统问答有什么本质区别
传统 RAG 的典型流程是:用户提问 → 向量化 → 检索 Top-K 片段 → 拼接 prompt → 生成答案。这个流程假设了一个前提:答案存在于某个局部片段中,且语义相似度能代表相关性。但在 Agent 场景下,这个假设经常不成立。
Agent 的检索需求有三个显著特征。第一是多跳性,Agent 往往需要先检索一个实体,再根据这个实体去检索关联信息,形成检索链。第二是结构性,Agent 需要知道信息之间的层级、因果、时序关系,而不是一堆平铺的文本块。第三是动态性,Agent 会根据当前任务状态决定检索什么、检索多少、是否需要重新检索。
举个例子,你让 Agent 分析一份合同的风险点。传统 RAG 会把合同切成块,检索“风险”“违约”“赔偿”相关的片段。但 Agent 需要的是:先找到合同主体条款,再定位违约责任条款,然后对比附件中的补充协议,最后检查是否有冲突。这是一个结构化推理过程,向量检索只能提供素材,提供不了结构。
2.2 八种 RAG 方案的分类逻辑
我把这 8 种方案按检索结构和Agent 介入程度两个维度来分。检索结构从扁平到图结构,Agent 介入从被动到主动。
| 方案类型 | 检索结构 | Agent 介入 | 典型场景 |
|---|---|---|---|
| Naive RAG | 扁平向量 | 无 | 简单问答 |
| Advanced RAG | 扁平向量+重排 | 无 | 精度要求高的问答 |
| Modular RAG | 模块化流水线 | 部分 | 多阶段检索 |
| GraphRAG | 知识图谱 | 无 | 全局性、关系型问题 |
| LightRAG | 轻量图结构 | 无 | 资源受限的图检索 |
| Agentic RAG | 动态检索 | 强 | 多跳推理、工具调用 |
| Ontology RAG | 本体+图 | 中 | 领域知识建模 |
| Hybrid RAG | 混合索引 | 中 | 多模态、多源数据 |
这个分类不是绝对的,很多方案会交叉。比如 Agentic RAG 内部可能用 GraphRAG 做子检索,Hybrid RAG 可能同时维护向量索引和关键词索引。关键是理解每种方案解决的核心问题是什么。
2.3 选型前必须问自己的三个问题
在选具体方案之前,我建议先回答三个问题。第一,你的数据有没有内在结构?如果文档之间有明显的主从、因果、时序关系,图结构方案值得考虑;如果就是一堆独立的知识点,向量检索够用。第二,你的查询是单跳还是多跳?单跳问题用 Advanced RAG 加个好点的 rerank 就能解决,多跳问题必须上 Agentic 或 Graph 方案。第三,你的资源预算有多少?GraphRAG 的索引构建成本可能是向量索引的几十倍,LightRAG 就是为资源受限场景设计的。
这三个问题决定了你的技术选型方向,比盲目追新框架重要得多。
3. 八种 RAG 方案逐一拆解
3.1 Naive RAG:别急着淘汰,它仍是基线
Naive RAG 就是最基础的“切块-向量化-检索-生成”流程。很多人觉得它过时了,但我的经验是:任何新方案都应该先和 Naive RAG 对比,如果提升不明显,说明你的问题不在检索架构上。
Naive RAG 的核心参数是 chunk size 和 overlap。chunk size 太小,语义不完整;太大,噪声多。我一般从 512 token 开始试,overlap 设 10% 到 20%。对于中文文档,按标点切分比按固定长度切分效果好,因为中文的语义边界往往在句号、分号、换行处。
# 一个简单的中文友好切分示例 def split_by_punctuation(text, max_len=512): import re sentences = re.split(r'(?<=[。!?;\n])', text) chunks, current = [], "" for s in sentences: if len(current) + len(s) <= max_len: current += s else: if current: chunks.append(current) current = s if current: chunks.append(current) return chunksNaive RAG 的瓶颈很明显:它无法处理需要跨块推理的问题,也无法利用文档的元数据。但在数据量小、问题简单的场景下,它的性价比最高。我见过不少项目一上来就上 GraphRAG,结果索引构建花了两天,效果还不如调好参数的 Naive RAG。
注意:Naive RAG 的检索质量高度依赖 embedding 模型。中文场景下,建议至少用 bge-large-zh 或 m3e-base 这个级别的模型,小模型在长文本上的语义捕捉能力明显不足。
3.2 Advanced RAG:重排和查询改写是性价比最高的优化
Advanced RAG 在 Naive 的基础上加了两个关键环节:查询改写和重排。查询改写解决的是“用户问法和文档表述不一致”的问题,重排解决的是“向量相似度高但实际不相关”的问题。
查询改写我常用两种策略。一种是多查询生成,让模型把用户问题改写成 3 到 5 个不同角度的查询,分别检索后合并结果。另一种是** HyDE**,让模型先生成一个假设答案,再用这个答案去检索。HyDE 在专业领域效果特别好,因为假设答案的用词更接近文档表述。
重排模型的选择上,bge-reranker 系列是当前性价比最高的。它的原理是 cross-encoder,把查询和候选片段一起输入模型打分,比向量相似度准得多。实测下来,加一个 reranker 能让 Top-3 命中率提升 20% 到 40%,成本只是多一次模型推理。
# 伪代码:多查询 + 重排的检索流程 queries = generate_multi_queries(user_question) # 生成多个查询 all_candidates = [] for q in queries: candidates = vector_search(q, top_k=20) all_candidates.extend(candidates) # 去重后重排 unique_candidates = deduplicate(all_candidates) reranked = reranker.rank(user_question, unique_candidates, top_k=5)Advanced RAG 的局限在于它仍然是“一次性检索”,无法根据中间结果调整检索策略。如果你的问题需要多步推理,它就不够了。
3.3 Modular RAG:把检索拆成可编排的模块
Modular RAG 的思路是把 RAG 流程拆成多个独立模块:查询理解、路由、检索、重排、压缩、生成。每个模块可以独立替换和组合。这个思路在工程上很实用,因为不同场景需要的模块组合不一样。
比如一个客服场景,查询理解模块需要识别用户意图(咨询、投诉、查询订单),路由模块根据意图决定查哪个知识库,检索模块可能同时查 FAQ 库和产品文档库,最后压缩模块把多个来源的结果合并成简洁的上下文。
Modular RAG 的关键是路由策略。我一般用一个小模型做意图分类,或者用规则匹配。路由的准确率直接决定后续检索的质量。如果路由错了,后面再好的检索也白搭。
实操心得:Modular RAG 的模块不要拆得太细,否则编排复杂度会爆炸。我一般控制在 5 到 7 个模块,每个模块的输入输出格式统一用 JSON,方便调试和替换。
3.4 GraphRAG:用知识图谱解决全局性问题
GraphRAG 是微软提出的方案,核心思想是从文档中抽取实体和关系,构建知识图谱,然后基于图结构做检索。它解决的是传统 RAG 无法回答的“全局性”问题,比如“这份报告的主要主题是什么”“这些文档中哪些实体之间存在关联”。
GraphRAG 的索引构建流程分几步:先切块,然后用 LLM 从每个块中抽取实体、关系和声明,接着做实体消歧和关系合并,最后用社区检测算法把图分成多个社区,为每个社区生成摘要。检索时,根据问题定位到相关社区,再用社区摘要和原始文本一起生成答案。
这个方案的效果确实好,尤其是需要跨文档总结的场景。但成本也高得吓人。我实测过一份 100 页的文档,GraphRAG 的索引构建消耗了大约 50 万 token 的 LLM 调用,耗时接近一小时。如果文档量再大,成本会线性增长。
# GraphRAG 索引构建的典型命令(以某开源实现为例) python -m graphrag.index --root ./project --init # 编辑 settings.yaml 配置 LLM 和 embedding python -m graphrag.index --root ./projectGraphRAG 适合的场景很明确:文档量大、关系复杂、需要全局性回答。如果只是简单的事实查询,用它就是杀鸡用牛刀。
3.5 LightRAG:资源受限下的图检索折中方案
LightRAG 可以理解为 GraphRAG 的轻量版。它保留了图结构的核心思想,但简化了索引构建流程,降低了 LLM 调用量。LightRAG 的做法是用关键词和实体做双层检索,一层是低层实体检索,一层是高层主题检索,两者结合后生成答案。
LightRAG 的索引构建比 GraphRAG 快很多,因为它不需要为每个社区生成摘要,而是用图结构和向量索引混合的方式。实测下来,同样 100 页文档,LightRAG 的构建时间大约是 GraphRAG 的三分之一,token 消耗也少一半左右。
但 LightRAG 的检索精度不如 GraphRAG,尤其是在需要深度推理的场景下。它的优势在于部署简单、资源消耗低,适合中小规模的知识库。
注意:LightRAG 的图结构质量高度依赖实体抽取的准确性。如果文档中专业术语多、缩写多,建议先做一轮术语标准化,否则图里会充斥重复和错误的实体节点。
3.6 Agentic RAG:让 Agent 自己决定怎么检索
Agentic RAG 是当前最热的方向。它的核心思想是把检索决策权交给 Agent,Agent 根据当前任务状态决定是否检索、检索什么、检索几次、是否需要换检索策略。
一个典型的 Agentic RAG 流程是这样的:Agent 收到问题后,先判断自己是否知道答案。如果不知道,生成检索查询;检索后评估结果质量,如果不够好,改写查询重新检索;如果够了,生成答案并检查是否需要补充检索。整个过程可能循环多次。
# Agentic RAG 的简化循环逻辑 def agentic_rag(question, max_iterations=5): context = [] for i in range(max_iterations): if agent_knows_answer(question, context): break query = agent_generate_query(question, context) results = retrieve(query) if not agent_evaluate_results(results): query = agent_rewrite_query(query, results) results = retrieve(query) context.extend(results) return generate_answer(question, context)Agentic RAG 的优势是自适应性强,能处理复杂、多跳的问题。但它的缺点是延迟高、成本不可控。每次循环都要调用 LLM,如果 Agent 判断失误,可能陷入无效循环。我在实际项目中会给它设一个最大迭代次数和 token 预算,超过就强制生成答案。
3.7 Ontology RAG:用本体约束检索范围
Ontology RAG 是在图检索的基础上引入本体。本体定义了领域内的概念、属性和关系规则,相当于给知识图谱加了一层 schema。这样做的好处是检索时可以利用本体的推理能力,比如“如果 A 是 B 的子类,那么查 A 的时候也应该查 B”。
Ontology RAG 在医疗、法律、金融这些有成熟本体体系的领域特别有用。比如医疗领域有 SNOMED CT、ICD 这些标准本体,可以直接复用。但在通用领域,构建本体的成本很高,需要领域专家参与。
我的建议是:如果你的领域有现成的本体标准,Ontology RAG 值得投入;如果没有,先从 GraphRAG 或 LightRAG 起步,等图结构稳定后再考虑加本体层。
3.8 Hybrid RAG:多索引混合是工程上的务实选择
Hybrid RAG 不追求单一索引的极致,而是同时维护多种索引,根据查询类型路由到不同索引。常见的组合是向量索引加关键词索引(BM25),再加一个图索引。向量索引擅长语义匹配,关键词索引擅长精确匹配,图索引擅长关系推理。
路由策略上,我一般用查询分类器判断查询类型。事实型查询走向量加关键词,关系型查询走图索引,混合型查询走多路召回后融合。融合算法可以用 RRF(Reciprocal Rank Fusion),简单有效。
| 索引类型 | 擅长 | 不擅长 | 典型工具 |
|---|---|---|---|
| 向量索引 | 语义相似 | 精确匹配、关系 | FAISS, Milvus |
| 关键词索引 | 精确匹配、术语 | 语义泛化 | Elasticsearch, BM25 |
| 图索引 | 关系推理、多跳 | 模糊语义 | Neo4j, NetworkX |
Hybrid RAG 的工程复杂度最高,但效果也最稳。我参与过的一个企业知识库项目就是 Hybrid 架构,向量加 BM25 加图索引,查询路由用一个小型分类模型,最终准确率比单一向量索引高了将近 30%。
4. 实操:从零搭建一个 Agentic RAG 原型
4.1 环境准备和依赖安装
我以 Python 生态为例,搭建一个最小可用的 Agentic RAG 原型。需要的基础组件包括:向量数据库、embedding 模型、LLM 接口、以及一个简单的 Agent 编排逻辑。
# 创建虚拟环境 python -m venv rag_env source rag_env/bin/activate # Windows 用 rag_env\Scripts\activate # 安装核心依赖 pip install langchain langchain-community chromadb sentence-transformers pip install rank-bm25 jieba # 关键词检索和中文分词向量数据库我选 Chroma,因为它轻量、本地运行、API 简单。embedding 模型用 bge-small-zh,在中文短文本上表现不错,而且推理速度快。LLM 接口根据你实际使用的服务配置,这里用伪代码表示。
4.2 文档处理和索引构建
文档处理的关键是保留元数据。很多人切块时只保留文本,丢掉了来源、页码、标题这些信息,导致检索后无法追溯,也无法做基于元数据的过滤。
from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 中文友好的切分器 splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=80, separators=["\n\n", "\n", "。", ";", ",", " ", ""] ) # 假设 docs 是包含 text 和 metadata 的文档列表 chunks = [] for doc in docs: for i, chunk in enumerate(splitter.split_text(doc["text"])): chunks.append({ "text": chunk, "metadata": {**doc["metadata"], "chunk_index": i} }) # 构建向量索引 embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5") vectorstore = Chroma.from_texts( texts=[c["text"] for c in chunks], embedding=embeddings, metadatas=[c["metadata"] for c in chunks], persist_directory="./chroma_db" )同时构建一个 BM25 索引作为补充。BM25 在精确匹配场景下比向量检索更可靠,尤其是查询中包含产品型号、专有名词时。
from rank_bm25 import BM25Okapi import jieba tokenized = [list(jieba.cut(c["text"])) for c in chunks] bm25 = BM25Okapi(tokenized)4.3 Agent 检索循环的实现
Agentic RAG 的核心是检索循环。我把它拆成四个函数:判断是否需要检索、生成查询、评估结果、生成答案。每个函数都可以用 LLM 实现,也可以用规则做降级。
def should_retrieve(question, context): """判断当前上下文是否足够回答问题""" if not context: return True prompt = f"问题:{question}\n已有信息:{context}\n这些信息足够回答吗?只回答是或否。" return llm(prompt).strip() == "否" def generate_query(question, context): """根据问题和已有上下文生成检索查询""" prompt = f"问题:{question}\n已有信息:{context}\n生成一个用于检索的查询,只输出查询本身。" return llm(prompt).strip() def evaluate_results(question, results): """评估检索结果的相关性""" prompt = f"问题:{question}\n检索结果:{results}\n这些结果相关吗?只回答是或否。" return llm(prompt).strip() == "是" def agentic_retrieve(question, max_iter=4): context = [] for i in range(max_iter): if not should_retrieve(question, context): break query = generate_query(question, context) # 混合检索:向量 + BM25 vec_results = vectorstore.similarity_search(query, k=5) bm25_results = bm25.get_top_n(list(jieba.cut(query)), chunks, n=5) merged = merge_and_deduplicate(vec_results, bm25_results) if evaluate_results(question, merged): context.extend(merged) break context.extend(merged[:2]) # 保留部分结果,继续循环 return context这个循环的关键参数是max_iter和每次保留的结果数。max_iter设太大,延迟和成本会失控;设太小,复杂问题检索不充分。我的经验是 3 到 5 次比较合适,具体看问题复杂度。
4.4 效果评估和调参
评估 RAG 效果不能只看最终答案,要分环节看。我一般用三个指标:检索召回率(相关文档是否被检索到)、检索精确率(检索结果中相关文档的比例)、答案准确率(最终答案是否正确)。
调参的优先级是:先调 chunk size 和 overlap,再调检索 Top-K,然后调 rerank 阈值,最后调 Agent 循环参数。每次只调一个参数,观察指标变化。我见过有人一次性改五个参数,结果效果变差了也不知道是哪个参数的问题。
实操心得:建一个 50 到 100 条的问题测试集,覆盖不同类型的问题(事实型、关系型、多跳型)。每次调参后跑一遍测试集,记录指标。没有测试集的调参就是盲调。
5. 常见问题与排查技巧实录
5.1 检索结果不相关怎么办
这是最常见的问题。排查顺序是:先看查询本身是否清晰,再看 embedding 模型是否适合你的领域,然后看 chunk 切分是否合理,最后看是否需要加 rerank。
如果查询本身模糊,加一个查询改写步骤。如果 embedding 模型不适合,换一个在你的领域数据上微调过的模型。如果 chunk 切分把语义切断了,调整切分策略。如果以上都没问题,加 rerank。
我遇到过一个案例:用户查询“怎么退货”,文档里写的是“退换货流程”。向量检索没召回,因为“退货”和“退换货”的向量距离较远。后来加了 BM25 关键词检索,问题解决。这就是 Hybrid 检索的价值。
5.2 Agent 循环不收敛怎么处理
Agentic RAG 的循环不收敛通常有两个原因:评估函数太宽松,导致 Agent 一直觉得信息不够;或者查询生成重复,每次生成的查询差不多,检索结果也一样。
解决办法是给评估函数加一个明确的判断标准,比如“如果已有信息能回答问题的核心部分,就停止检索”。同时给查询生成加一个约束,要求每次生成的查询必须和之前的查询有实质区别。另外,设置硬性最大迭代次数,超过就强制生成。
5.3 图索引构建太慢怎么优化
GraphRAG 和 LightRAG 的索引构建慢,主要是 LLM 调用量大。优化方向有三个:减少抽取的实体类型,只抽关键类型;用更小的模型做抽取,比如用 7B 模型代替 70B;并行化处理,把文档分片后并行抽取。
我一般先用小模型跑一遍,看看实体抽取的质量。如果质量可接受,就用小模型;如果不行,再换大模型。另外,实体消歧这一步很耗时,可以用规则做初筛,只对疑似重复的实体做 LLM 判断。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 检索结果不相关 | 查询模糊/模型不匹配/切分不当 | 检查查询、换模型、看切分 | 查询改写、换 embedding、调 chunk |
| 答案遗漏关键信息 | Top-K 太小/重排阈值高 | 增大 Top-K、降低阈值 | 调参、加多路召回 |
| Agent 循环不收敛 | 评估太严/查询重复 | 看循环日志 | 放宽评估、加查询去重、设最大次数 |
| 图索引构建慢 | LLM 调用多/实体多 | 统计 token 消耗 | 小模型、减实体类型、并行 |
| 延迟太高 | 循环次数多/模型大 | 分环节计时 | 减循环、换小模型、加缓存 |
5.5 几个容易踩的坑
第一个坑是过度依赖向量检索。向量检索擅长语义匹配,但不擅长精确匹配和关系推理。如果你的数据里有大量专有名词、型号、代码,一定要加关键词检索。
第二个坑是忽略元数据。元数据可以做过滤、可以做排序、可以做去重。我见过一个项目,检索结果里同一份文档的不同版本混在一起,就是因为没利用版本号元数据做过滤。
第三个坑是不设预算上限。Agentic RAG 和 GraphRAG 都可能消耗大量 token。上线前一定要设 token 预算和超时时间,否则一个异常查询可能烧掉你一天的额度。
第四个坑是用通用 embedding 模型处理专业领域。通用模型在专业术语上的表现往往很差。如果预算允许,用领域数据微调一个 embedding 模型,效果提升很明显。
6. 选型建议:不同场景该用哪种 RAG
6.1 按数据规模选
数据量在 1000 个 chunk 以下,Naive RAG 加 rerank 就够了。1000 到 10000 个 chunk,考虑 Advanced RAG 或 LightRAG。10000 以上,或者文档间关系复杂,上 GraphRAG 或 Hybrid RAG。
数据规模不是唯一标准,但它是成本的主要驱动因素。GraphRAG 的索引成本随数据量线性增长,小数据量下用 GraphRAG 是浪费。
6.2 按查询复杂度选
单跳事实查询,Advanced RAG 足够。多跳推理查询,Agentic RAG 或 GraphRAG。全局总结查询,GraphRAG 或 LightRAG。混合型查询,Hybrid RAG。
我一般会先分析用户查询的分布。如果 80% 是单跳查询,先把 Advanced RAG 做好,再考虑为剩下的 20% 加 Agentic 或 Graph 能力。不要为了 20% 的场景把整个架构复杂化。
6.3 按团队能力选
团队里有没有懂图数据库的人?有没有能调 LLM 应用的人?有没有能做评估和调参的人?这些决定了你能驾驭多复杂的方案。
我的建议是从简单方案起步,逐步演进。先上 Naive RAG,加 rerank 变成 Advanced RAG,加路由变成 Modular RAG,需要多跳时加 Agentic 循环,需要关系推理时加图索引。每一步都基于实际需求,而不是技术潮流。
6.4 一个务实的演进路线
第一阶段:Naive RAG + 好的 embedding 模型 + rerank。解决 80% 的简单查询。
第二阶段:加查询改写和多路召回,变成 Advanced RAG。提升复杂查询的召回率。
第三阶段:加查询路由和模块化编排,变成 Modular RAG。支持多知识库、多场景。
第四阶段:根据需求选择 Agentic 循环或图索引。Agentic 解决多跳,图索引解决关系推理。
这个路线的好处是每一步都有明确的收益,而且每一步的投入都不大。我见过太多团队一上来就搞 GraphRAG,结果索引构建卡了两周,最后发现用户根本不需要那么复杂的检索。
提示:演进过程中一定要维护测试集。没有测试集,你无法判断每一步演进是否真的带来了提升。
7. 关于 Agent 记忆和 RAG 的边界
7.1 Agent 记忆和 RAG 不是一回事
很多人把 Agent 记忆和 RAG 混为一谈,其实它们的定位不同。RAG 解决的是“知识从哪来”的问题,Agent 记忆解决的是“经验怎么积累”的问题。RAG 检索的是外部知识库,记忆存储的是 Agent 与用户交互的历史、任务执行的结果、以及从经验中提炼的规则。
在实际项目中,两者往往配合使用。Agent 先用记忆判断当前任务是否处理过,如果有类似经验,直接复用;如果没有,走 RAG 检索外部知识。任务完成后,把关键信息写入记忆,供后续使用。
7.2 记忆的存储和检索策略
Agent 记忆一般分短期记忆和长期记忆。短期记忆是当前会话的上下文,通常直接放在 prompt 里。长期记忆需要持久化存储,检索时根据相关性召回。
长期记忆的检索可以用向量检索,也可以用关键词检索,取决于记忆的类型。事实型记忆用向量检索,规则型记忆用关键词或标签检索。我一般会给记忆加时间衰减因子,越近的记忆权重越高。
7.3 RAG 和记忆的协同
协同的关键是避免重复检索。如果记忆里已经有答案,就不要再去 RAG 检索。如果记忆里的答案过时了,要能识别出来并重新检索。
我实现过一个简单的协同逻辑:Agent 收到问题后,先查记忆,如果记忆中有高置信度的答案,直接返回;如果置信度中等,把记忆中的答案作为上下文,再去 RAG 检索补充;如果没有记忆,直接走 RAG。这个逻辑让重复问题的响应速度提升了很多。
8. 一些个人体会和后续方向
这套东西我断断续续折腾了大半年,最大的体会是:RAG 的效果上限不取决于你用了多先进的架构,而取决于你对数据的理解有多深。同样的 GraphRAG,有人跑出来效果惊艳,有人跑出来一堆噪声,差别往往在于实体抽取的 prompt 设计和数据预处理的质量。
另一个体会是评估比优化重要。没有评估,你就是在盲人摸象。我现在的习惯是每做一个 RAG 项目,先花两天建测试集,再花时间调优。测试集的质量直接决定了调优的方向是否正确。
后续我打算继续探索的方向有两个。一个是多模态 RAG,把图片、表格、图表也纳入检索范围。另一个是RAG 和微调的协同,用 RAG 处理动态知识,用微调处理固定模式和风格。这两个方向都有不少坑,等踩完了再分享。
最后分享一个小技巧:如果你的 RAG 系统在某个查询上表现不好,不要急着改架构,先把那个查询的检索过程完整打印出来,看看每一步发生了什么。十有八九问题出在某个你没想到的环节,而不是整体架构。