跳到主要内容

🔍 [人工智能] 浅谈 RAG 系统

· 阅读需 44 分钟
卤代烃
微信公众号@卤代烃实验室

rag_hero.jpg

2025 年谈 RAG(Retrieval-augmented generation,检索增强生成) 技术,在日新月异的 AI 圈子里可能并不是很 fashion,但是从落地角度看,RAG 技术门槛低,效果提升明显,所以在有明显收益的预期下,不少的 机构/公司/部门 都会做 RAG 落地,也有各路学者出各种 RAG 优化方案,提升准确率。

之前为了支持一些内网服务的搜索功能,我搭建了相关的 RAG Server,在这个过程中调研了大量的 RAG 方案,也做了一些方案落地,所以今天就这篇文档和大家唠一唠 RAG。

因为时间和篇幅关系,本文主要是梳理 RAG 系统各个模块间的关系,整体节奏更偏科普性质,没有更多的涉及代码和算法细节。相关的细节可以根据文中的外链引用查看。


思路产生

照本宣科介绍 RAG 概念我觉得有些无聊了,我这里举一个较为感性的入门例子来说明一下 RAG 这个方案。

2025 年年初,国内最火的事件之一就是 《哪吒之魔童闹海》 这部电影了,目前已经是全球动画电影票房第一了。现有的各种已发布大模型,并没有用《哪吒2》的新数据做预训练,所以可以用它做测试数据。

然后演示用的大模型,我这里选用 DeepSeek。选择它的原因是他们 ChatBot 做的较为原始,不勾选「联网搜索」就不会联网;豆包等 chatbot 产品比较成熟,会根据用户意图触发搜索,不利于控制变量。


➊ 阶段:我们问他一个问题:“《哪吒之魔童闹海》这部电影中,申公豹的弟弟名字叫什么?”,大家肯定都清楚,对于这种完全没预训练过的数据,它会胡诌一顿,也就是常说的幻觉**:

➋ 阶段:当然,我们用 LLM 的时候有一个低成本但非常有效的技巧,那就是把大模型不知道的内容,直接放在 prompt 里,然后让它基于给定的上下文回答问题,准确率会非常高。在这里我们直接把《哪吒2》的剧情梗概发给它,可以看出来回答正确:

➌ 阶段:复制黏贴还是太麻烦了,用户体验不行,而且这种根据最新数据做总结的需求也很常见,所以各种 LLM ChatBot 很快都跟进了「联网搜索」这个功能。联网搜索的原理也很简单,就是把问题先用搜索引擎搜一下,然后把搜到的 topN 的网页内容塞到 prompt 里,再让大模型基于这些上下文对原问题做回答:

其实到了第 阶段,就是 RAG(Retrieval-augmented generation)的运用了:

  • Retrieval-augmented:从互联网上搜索内容,然后把搜索到的内容放到 prompt 里
  • Generation:让大模型基于检索到的内容再结合原始提问,生成想要的信息

通过这套组合拳,就可以大大提升大模型在未训练数据上的回答准确度。


RAG 这个技术的最大运用在于,它可以同时利用外挂知识库的知识和大模型涌现出的智能,去高效处理之前较为耗时的 检索/收集/总结 工作。要知道大模型本身训练时,是无法获取那些私有数据的,例如各种机构的机密信息和知识库。如果内部私有化部署 RAG Server + LLM Server,是可以大大提升公司内的相关事务处理效率的。


基础技术点

这一节从技术角度分析一下,做一个基础的 RAG 服务有哪些技术点。

其实从前面可以看出,RAG 其实和传统意义上的 AI infra 的关联并不是很大。一说到 LLM,我们可能先想到的就是什么 GPU/CUDA/pre-training/post-training 之类的,但是 RAG 更像一个以搜索为中心,结合各种数据 & 组件 & 大小模型运用 的复杂协同系统

下面是一个常见 RAG 服务的流程,我会对各个流程做一个详细的讲解展开。


文档解析

在企业内部做 RAG 服务,和互联网搜索引擎最大的区别就在于信息载体

Web Search 的信息载体主要是 HTML,经过多年的发展已经有非常成熟的 爬虫方案 和 HTML 解析方案;信息化做的比较好的互联网公司(比如说字节飞书),文本信息也主要承载在 HTML/Markdown 上,也都有比较成熟的方案。

但是对于大部分传统公司,信息载体主要还是 Word/Excel/PDF/Image/Chart 等格式,还有各种垂直领域的非标文件,那么如何把这些文件数据解析入库,就是 RAG 的第一步:

  • Word/Excel 这类较为通用的格式,也是有不少解析工具的,可以直接用
  • PDF/Image 等会用一些 OCR 方案,也是传统算法里比较成熟的,必要时刻也得根据数据本身做定制
  • 专业数据格式,就得一对一专项解决了

总之 数据处理/清洗 这块儿很重要,会直接影响最终的输出,不然就 garbage in, garbage out 了。这里也是非常典型的脏活累活,需要不停的调试去提升识别效果。

因为字节内部信息数据化做的很好了,所以我也没太多关注这里的细节,大家感兴趣可以扩充了解 文档智能(Document Intelligence) 这个领域的相关知识。


Chunking

简介

Chunking 指的就是把一篇长文档分为一份一份小 chunk 的过程。

就拿上面的的《哪吒2》为例,我的问题是 “申公豹的弟弟名字叫什么”,但是我给出的剧情上下文里,90% 的内容其实是和问题无关的。所以说这部分信息其实是多余的。

那么理想情况下,如果把这一段内容分 chunk,然后 RAG 搜索的时候,只把 “申公豹的弟弟申小豹来投奔” 这段话召回,理论上就能节省 90% 的 token 成本!而且 prompt 内容越短,LLM 的识别准确率越高,岂不美哉。

从另一个角度分析,chunking 和后续的「向量存储」也有关系。如果直接存储整篇的文档,在未来做存储和搜索时,都会遇到性能问题和准确率问题,所以最佳方案就是分而治之。


分割方案

这里为了演示方便,假设一个汉字占据一个 token,然后对下面的测试文本做 chunk 分割: 天劫之后,哪吒、敖丙的灵魂虽保住了,但肉身很快会魂飞魄散。太乙真人打算用七色宝莲给二人重塑肉身。但是在重塑肉身的过程中却遇到重重困难,哪吒、敖丙的命运将走向何方?

Chunk 分割有这么几种常见的分割方案:

1.固定长度分割

这个是最简单的,就是固定一个 chunk 的 token 数(这个上限一般是数据库可接受的最大 token),然后直接切。

对于上面的案例,假设每个 chunk 长度为 20,最后的切割结果如下,可以看到切割的很工整,但是有些生硬,从单个 chunk 的角度分析,有些上下文丢失了:

[
'天劫之后,哪吒、敖丙的灵魂虽保住了,但肉',
'身很快会魂飞魄散。太乙真人打算用七色宝莲',
'给二人重塑肉身。但是在重塑肉身的过程中却',
'遇到重重困难,哪吒、敖丙的命运将走向何方',
]

于是一个很常见的思路就是,允许每个 chunk 之间内容有重叠,通过一定的冗余加强上下文关联。这里在保持 chunk_size 为 20 的情况下,把 chunk_overlap 设置为 5。效果可能好了一些,但是切口还是比较硬的。

[
'天劫之后,哪吒、敖丙的灵魂虽保住了,但肉',
'住了,但肉身很快会魂飞魄散。太乙真人打算',
'乙真人打算用七色宝莲给二人重塑肉身。但是',
'肉身。但是在重塑肉身的过程中却遇到重重困',
'遇到重重困难,哪吒、敖丙的命运将走向何方',
]
提示

这里是为了演示做了很小的 chunk_size,实际工程一般是 512/1024/4096,相对会好一些


2.按句号/段落分割

上面的案例能看出固定长度分割是非常死板的,那么我们可以换个思路,运用一些文档中 meta 信息,那就是标点符号。人类在书写文字时,句号,换行符都是天然的结构划分方案,我们可以加以利用。

这里我们按 做文档分割,可以看出分割效果其实是好不少的,没有断句的问题:

[
'天劫之后,哪吒、敖丙的灵魂虽保住了,但肉身很快会魂飞魄散',
'太乙真人打算用七色宝莲给二人重塑肉身。',
'但是在重塑肉身的过程中却遇到重重困难,哪吒、敖丙的命运将走向何方?',
]

这里其实也可以采用一些 overlap 的思路,可以在按 句子/段落 分割的时候,把最近的几句话补充进去,丰富 chunk 的上下文:

[
'天劫之后,哪吒、敖丙的灵魂虽保住了,但肉身很快会魂飞魄散',
'天劫之后,哪吒、敖丙的灵魂虽保住了,但肉身很快会魂飞魄散。太乙真人打算用七色宝莲给二人重塑肉身。',
'太乙真人打算用七色宝莲给二人重塑肉身。但是在重塑肉身的过程中却遇到重重困难,哪吒、敖丙的命运将走向何方?',
]

当然,也可以按照两个方案的结合,先分割为一个一个的句子/段落,然后滚动拼接,最后逼近固定的 chunk 大小,兼顾两者的优点。


3.按文档结构分割

很多文档里是有标题结构的,这些也会表现在文档载体中。比如说 HTML 中有 <h1> <h2> 标签,markdown 中也有 # ## 这种结构标识。这些也是天然的经过人类确认编辑的 meta 信息。针对这种结构明确的文档,可以考虑利用这些内容做分割,更好的平衡 chunk_size 和 chunk 上下文。


元数据优化

其实构建 chunk 的时候,有个点经常被人忽视,那就是元数据的添加。

比如说我们处理文档的时候,文档本身就有很多预先被人工处理/分类的元数据,比如说:目录结构,文件名,链接,作者,类别等。

我们在构建 chunk 的时候,可以把这些 metadata 加进去,这样在后续的搜索召回时,可以先根据元数据做筛选,这样的分类优化其实要比依靠 LLM 猜更准确。


数据存储

无论数据是不做任何处理,还是细细地剁做臊子,它总是要存储的。我们可以再回顾一下 RAG 的核心诉求:高效的搜索并召回切合问题的内容。所以数据存储必须贴合「搜索」这个要求。

随着互联网发展,存储内容早已不是单纯的文本,文字/音频/视频/图像/交互行为 都有存储和检索的诉求,传统的关系数据库和基于文本的搜索算法越来越难以满足日益膨胀的检索诉求。

当然技术是一直发展的,后续发展了一个技术概念叫 vector embeddings,就是能把各种各样的数据都嵌入(embeddings)到同一个空间里。而且这个嵌入空间里,相同语义的内容 “距离” 更近,这种底层能力对于有搜索诉求的系统(例如搜索引擎,推荐系统 还有 RAG)非常重要。

embeddingsclustering

从上面可以看出,embeddings 有两个关注点:

  • 一是如何把数据的转为合理的向量
  • 二是如何比对两个向量之间的 “距离”

我们针对这两个关注点分别梳理一下发展历史,但是出于篇幅和聚焦角度考虑,不会对各个算法的细节做展开。另一个为了内容的简洁性,下面都是按「文本」为例介绍相关算法。


Embeddings 发展

这个小节我们说说如何把文字转为向量。

➊ TF-IDF

TF-IDF 的全称是 Term Frequency-Inverse Document Frequency,直译就是「词频-逆文档频率」

  • TF(词频):一个词在单篇文档中出现的次数越多,可能越重要。
  • IDF(逆文档频率):如果一个词在所有文档中出现得越普遍(比如“的”“是”),它越不重要

TF-IDF = TF × IDF,值越高,说明这个词对当前文档越独特、越关键。

通过这种频率的计算,我们可以对每个词得到一个向量,通过公式我们可以看出,文档中的罕见/关键词 会有比较高的权重,但是它还是基于频率的,没办法捕捉到向量背后的语义关系

而且这种方法有个问题是它产生的向量非常稀疏。向量的长度就是语料库中所有单词的大小。而英文中大概有 470k 个独特单词,而一个句子也就几十个单词,这就导致句子的向量非常稀疏(99.99% 的值为 0),信息量非常小,而且也不利于存储和计算。

➋ Word2Vec

词汇向量化上有个里程碑事件,就是 Word2Vec 的提出。这个是 2013 年 Google 论文《Efficient Estimation of Word Representations in Vector Space》提出的概念。

论文里的算法可以产生稠密向量,并且这个算法可以捕捉到词语间的语义联系。

论文里提出了两种把 word 转为 vector 的算法:CBOW 和 Skip-gram:

  • CBOW:用上下文词语(比如“我爱吃___”)预测中间缺失的词(比如“苹果”)
  • Skip-gram:反过来,用中心词(比如“苹果”)预测周围的词(比如“吃、甜、红色”)

这两种算法在训练计算向量时,都会联系到单词的上下文,所以最后生成的内容都保留了语义:

另一个是生成的向量是固定长度的,信息密度要比 TF-IDF 高得多。


但是 Word2Vec 其实还是有局限性的:

  • 首先它只能处理 “word”,但是我们的 RAG 系统录入的都是句子段落,这一点是不满足的
  • 其次它对单个单词的编码都是固定的,无法捕捉不同句子下相同单词的不同语义

所以即使 Word2Vec 已经蛮惊艳了,但是还是不符合 RAG 的需求,我们还是要寻找更合适的方案。


➌ Transformers

Transformers 架构在 2017 年《Attention Is All You Need》里提出,太著名了,所以也不展开讲了。Transformers 第一个模型是 Google 出的 BERT,随后又推出了 Sentence-BERT,允许计算句子的向量,并且有更好的语义理解。

Transformers 在 embedding 场景里,有这么几个优势:

  • 上下文动态编码:同一个词在不同句子中会有不同的向量(比如“苹果”在“吃苹果”和“苹果公司”中向量不同)
  • 捕捉长距离依赖:能理解句子中相隔很远的词语关系
  • 支持对句子/段落编码

这里有个表格可以对比一下这几种方案:

TF-IDFWord2VecTransformers
核心能力词频统计局部语义全局语义+上下文动态
计算资源极低中等极高
数据需求可多可少需要语料库海量预训练数据
语义理解度单词级语义复杂语义推理

➍ bge-m3

到目前为止,基于 Transformers 已经训练了很多专业的 Embedding Model,其中北京智源研究院出品的 BGE(BAAI General Embedding)系列就是其中的佼佼者。bge-m3 在多语言理解(尤其是中文)长文本输入/检索 这几个方向上做的都比较好,目前中文都是较为推荐使用这个模型的。


向量距离

计算向量距离的意义在于,向量距离越小,语义相似度越高。

常见的计算方式有这么 3 种:

曼哈顿距离 Manhattant distance (L1)欧几里得距离 Euclidean distance (L2)余弦距离 Cosine distance

NLP 领域中,用的最多一般是余弦距离,主要有两大原因:

  • 在最终的取值上,余弦距离的计算范围是 (-1, 1),好归一化,但是 L1 和 L2 的取值范围是 (0, +∞)
  • 在工程上,余弦距离只需要做加法和乘法运算,运算效率高

到这里理论知识就完备了,那么对于 RAG 来说,流程其实也很简单了:

  • 用 Embeddings Model 把 chunk 数据向量化,然后存储到向量数据库里
  • 对于用户的 Query,用同一个 Embeddings Model 也化为向量
  • 用余弦距离算法挨个比对向量库里的数据,取其前 topN 得分的 chunk 数据返回

搜索

Cosine distance

其实到了上一节的最后一步(计算余弦相似度并取 topN),其实已经算完成 RAG 的基础搜索了。

如果不做其它工作,把直接召回的内容扔到 prompt 里交给 LLM 做生成,效果其实也比裸调 LLM 好不少。论文《RAG for LLM: A Survey》把这种最基础的方案做了个定义,称之为 Naive RAG

但是工程师和研究者也马上发现,如果再做一些工程上的工作,其实可以提升不少召回准确率的,下面我们就说一下相关的方案。


Pre-Retrieval

Pre-Retrieval 这个环节,主要是对 Origin Query 的扩充和修改。

用户提出一个问题的时候,这个「问题」不一定是最完美的,那么是不是可以在这部分结合 LLM,去分析理解用户意图,把原始提问做扩充和修改,再进入后续的搜索召回环节?

这边我举几个相关的例子:

  • 拆分复杂问题
    • 修改前:「为什么 XXX 股价在 2024 年下跌,但 2025 年上涨?」
    • 修改后:「2024 年影响 XXX 股价下跌的因素」+「2025 年推动 XXX 股价上涨的原因」
    • 优势:拆分多任务问题为独立子问题,便于分别检索针对性内容
  • 扩展模糊描述
    • 修改前:「苹果的最新产品是什么?」
    • 修改后:「苹果公司在 2025 年发布的最新产品有哪些?」
    • 优势:分析语义,添加更合适的时间范围,避免检索到过时信息
  • 同义词替换与专业化
    • 修改前:「心脏病的治疗方法」
    • 修改后:「心血管疾病的临床治疗指南与最新药物研究进展」
    • 优势:使用专业术语替换口语化表达,方便更好的检索到专业内容而不是莆田广告

这些语义相关的例子有很多,相信 LLM 的能力更强后,Origin Query 优化会更准确。


前面说的了很多向量的事儿,又是语义又是余弦距离的,目的都是解决模糊搜索的问题,它对一些精准搜索的精度就没那么高了。工程师和学者早早发现,其实在一些场景上,传统的关键词搜索算法(例如 BM25),在一些精确场景上更有效。

其实向量搜索和关键词搜索都有各自的优势劣势,在工程上没必要比个高低,大家可以通力合作,共同提升召回效果,这种方案也叫 Hybrid Search。

你们都是我的翅膀.PNGHybrid Search

Hybrid Search 也有多种组织方式,比如说先用 Vector Search,然后在它的结果上再运行一下 Keyword Search;或者先 Keyword Search 再 Vector Search。但现在普遍做法是同时运行两类搜索,然后通过一些加权算法赋予结果不同的权重,最后把两路搜索结果混合起来。

经过这一轮,数据就从数据库里成功召回了,一般到这里取个 topN 就能直接用了。如果还想做一下精加工,就可以再来一道 Post-Retrival 环节。


Post-Retrival(rerank)

Post-Retrival,就是把从数据库中召回的数据再处理一遍。这里方案其实是两大类:内容压缩rerank

内容压缩理解起来较为简单。直接从数据库召回的数据,还是会有一些冗余的信息,直接放到最终的 prompt 里可能效果不好。那么一个思路就是提前过一遍 LLM 对原始的召回内容做个总结压缩,然后再交给后续步骤。


我们重点说说 rerank

Rerank 其实就是把搜索到的数据(可以理解为粗排数据),和 Query 一起交给 reranker,系统会结合 Query 给召回的一系列 chunk 数据做重新排序(精排数据)。这个经过多方验证,可以显著提升搜索质量:

目前市面上效果比较好的 reranker 模型也是智源的 bge-reranker:

在具体实践中,我们可以先提升召回数据的的 topN,比如说把原来的 top10 改为 top30,然后再做 rerank,取重排后的 top10,综合提升准确率。


上面这些工程方案都使用后,也可称这套方案为 Advanced RAG

综合来说,并不是这些所有的方案都上了就会好,比如说 Query Rewriting,Summary 这些方案都会调用 LLM,这些流程在总流程里都是串行的,不可避免的会增加整体的耗时,LLM 的参与也会在带来不可控的幻觉问题,长流程和多模块也会带来工程上的复杂度管理问题,所以最后的落地还是要贴合业务形态选用合适的技术方案。


前沿进展

2024 年前沿的一大特点就是,大模型深度参与到 RAG 的一些关键环节中

文档解析

前文也提到,RAG 在一些非互联网企业落地的时候,有时候会遇到一些「非结构化文档」,这些文档没办法用成熟的库去解析转换。这时候一般就会用 OCR 等方案,识别文档布局,提取文档信息。

2024 随着多模态模型的发展,其实这部分内容可以交给大模型去提取信息,效果还是提升了不少。


Chunking

在「基础技术点-Chunking」章节里,大家可能也发现了,无论用什么 chunking 方案,都会遇到一个上下文语义丢失的问题

比如说对于这句话:“天劫之后,哪吒、敖丙的灵魂虽保住了,但肉身很快会魂飞魄散”,哪吒敖丙出现在多部文艺作品里,我怎么确保这段 chunking 指向的是《哪吒2》而不是《哪吒传奇》?

这个问题业内也有一些解决方案,Anthropic Claude 的一篇 Blog 《Introducing Contextual Retrieval》给出了一个方案:生成每段 chunk 的时候,利用 LLM 给每个 chunk 引入特定的上下文解释

<document> 
{{document 原文}}
</document>
<chunk>
{{提前分割好的 chunk}}
</chunk>

为了提高搜索检索效果,请参考 document 给 chunk 提供一个简短的背景信息

这个方案其实还是有效的,就是 chunking 过程会拉长,而且会消耗不少 token,比较花钱。


GraphRAG

图这个结构我们都清楚,有点有边有权重,知识图谱这个概念也很早就有了,比如说飞书就有引用图谱结构:

既然上面的各种优化已经花了不少 token 了,那么不如索性来个大的。于是微软 2024 年年中开源了一套 RAG 方案——GraphRAG。它的特点就是 利用 LLM 自动抽取文档内的命名实体,然后利用这些实体自动构建知识图谱

具体在流程上,就是利用大模型的能力,构建数据库期间把 chunk 中的关键词提取出来,然后关键词之间建立 point/edage/weight 这些图关系,并和关键 chunk 关联;查询时会把 query 分解为多个关键词,然后根据关键词在图数据库里查询,最后把查询到的 chunk 信息拿到,交给大模型以流畅的语言回答问题。

-目标-
给定可能与此活动相关的文本文档和实体类型列表,从文本中识别出这些类型的所有实体以及所识别实体之间的所有关系。

-步骤-
1.识别所有实体。对于每个已识别的实体,提取以下信息:
-entity_name:实体名称,大写
-entity_type:以下类型之一:〔{entity_type}〕
-entity_description:对实体属性和活动的全面描述
将每个实体格式化为(“实体”{tuple_delimiter}<entity_name>{tuple-delimiter}<实体类型>{tuple _delimiter]<实体描述>

2.从步骤1中识别的实体中,识别彼此*明显相关*的所有对(source_entity、target_entity)。
对于每对相关实体,提取以下信息:
-source_entity:源实体的名称,如步骤1中所标识的
-target_entity:目标实体的名称,如步骤1中所标识的
-relationship_description:解释为什么你认为源实体和目标实体是相互关联的
-relationship_strength:一个数字分数,表示源实体和目标实体之间关系的强度
-关系关键字:一个或多个高级关键字,总结关系的总体性质,侧重于概念或主题,而不是具体细节
将每个关系格式化为(“关系”{tuple_delimiter}<source_entity>{tuple-delimiter}<target_entity>{tuple.delimiter}>关系描述>{tule_delimiter}<关系关键字>{tuple _delimiter]>关系强度>)

3.识别概括整篇文章主要概念、主题或主题的高级关键字。这些应该捕捉到文件中存在的总体想法。
将内容级关键字格式化为(“content_keywords”{tuple_delimiter}<high_level_keywords>

4.返回英文输出,作为步骤1和2中识别的所有实体和关系的单个列表。使用**{record_delimiter}**作为列表分隔符。

5.完成后,输出{completion_definer}
Entity_types:[人、技术、使命、组织、地点]
文本:
当亚历克斯咬紧牙关时,在泰勒威权主义确定性的背景下,沮丧的嗡嗡声变得沉闷起来。正是这种竞争性的暗流让他保持警惕,他和乔丹对发现的共同承诺是对克鲁兹狭隘的控制和秩序视野的无声反抗。

然后泰勒做了一件出乎意料的事。他们在约旦旁边停了下来,有一会儿,带着一种近乎敬畏的神情观察着这个装置。“如果这项技术能够被理解……”泰勒说,他们的声音更安静了,“它可能会改变我们的游戏规则。对我们所有人来说。”

早些时候的潜在解雇似乎动摇了,取而代之的是对他们手中事情的严重性的勉强尊重。乔丹抬头一看,他们的心跳转瞬即逝,目光锁定在泰勒身上,一种无言的意志冲突软化成了一种不安的休战。

这是一个很小的转变,几乎无法察觉,但亚历克斯内心点了点头。他们都是通过不同的途径被带到这里的
################
输出:
(“实体”{tuple_delimiter}“亚历克斯”{tule_delimiter]“人”{tuple _delimiter}Alex是一个经历挫折的角色,他对其他角色的动态非常敏锐。){record_delimitr}
(“实体”{tuple_delimiter}“泰勒”{tule_delimiter]“人”{tuple _delimiter}Taylor被描绘成具有权威性的确定性,并对设备表现出敬畏的时刻,表明视角发生了变化。){record_delimitr}
(“实体”{tuple_delimiter}“Jordan”{tule_delimiter]“人”{tuple _delimiter}Jordan与Taylor在设备方面有着共同的发现承诺和重要的互动。){record_delimitr}
(“实体”{tuple_delimiter}“Cruz”{tule_delimiter}“人”{tuple _delimiter}“Cruz与控制和秩序的视觉相关联,影响其他角色的动态。”){record_delimiter]
(“实体”{tuple_delimiter}“设备”{tule_delimiter]“技术”{tuple _delimiter}-“设备是故事的核心,具有潜在的改变游戏规则的意义,并受到泰勒的尊敬。”){record_delimiter}
(“关系”{tuple_delimiter}“Alex”{tule_delimiter]“Taylor”{tuple _delimiter}Alex受到Taylor权威确定性的影响,并观察到Taylor对设备态度的变化{tuple_delimiter}7){record_delimiter}
(“关系”{tuple_delimiter}“亚历克斯”{tule_delimiter}Jordan“{tuple-delimiter}”亚历克斯和乔丹共同致力于发现,这与克鲁兹的愿景形成鲜明对比{tuple_delimiter}6){record_delimiter}
(“关系”{tuple_delimiter}“Taylor”{tule_delimiter]“Jordan”{tuple _delimiter}“Taylor和Jordan直接就设备进行交互,导致相互尊重和不安的休战时刻{tuple_delimiter}8){record_delimiter}
(“关系”{tuple_delimiter}“Jordan”{tule_delimiter]“Cruz”{tuple _delimiter}Jordan对发现的承诺是对Cruz控制和秩序愿景的反叛{tuple_delimiter}5){record_delimiter}
(“关系”{tuple_delimiter}“Taylor”{tule_delimiter]“设备”{tuple _delimiter}Taylor对设备表示尊敬,表明其重要性和潜在影响{tuple_delimiter}9){record_delimiter}
(“content_keywords”{tuple_delimiter}“权力动态、意识形态冲突、发现、反叛”){completion_delimiter}

有图模型的加持下,GraphRAG 就可以捕捉到各个文档之间更为复杂和细微的联系和依赖了,可以更好的处理语义上的问题。


Multi-Modal

Multi-Modal RAG 概念的提出也是受到 VLM 在 2024 年的快速发展的影响。GPT-4o/Claude/Qwen-VL 这些模型的发布,让计算机视觉理解不再局限于之前的物体识别/物体分类上,而是可以对一些多模态文档做更加深入的理解。

目前的多模态文档的处理方式,是把各种信息转为文字,然后对文字做存储索引排序;现在的思路是可以直接对多模态文档做 embedding,省去 OCR 这些流程。

目前看此方案还是有一定的落地成本,但随着 2025 年的模型和基建的发展,还是有很大的想象空间。


Agentic

Agent 这个概念在 2024 年一直很火,2025 年应该也是重要的探索方向。

其实 Agent 和 RAG 的关系一直很紧密,RAG 本身就是 Agent 的重要算子,它可以解锁 Agent 访问数据的能力,Agent 也可以直接用在 RAG 系统里,提升 RAG 的整体能力。比如说上面介绍的各个组件中,都有一些 LLM 参与的工作(比如说用 LLM 做 Query 重写),这些环节都可以 Agent 化。

理论上 RAG 的各个组件都 Agent 化后,它就可以自行 规划/调整/迭代,而不是执行机械化的指令,最后可以找到一个最佳方案。

当然引入 Agent 后,Agent 目前的一些现有问题也会引入,比如说 token消耗高/死循环/幻觉 等,目前业内还没有看到大规模运用的案例,2025 年可能会有一些突破和落地。


常见问题

context window 越长,RAG 越没必要?

这个是个很典型的问题,我早期也有这个想法。

这个观点和争论的起因主要是各大厂商 发布/开源 了各种 long context window 的大模型,一些比较短的文档,确实是直接扔进去问问题就可以了。

但是宣传归宣传,实际体验用下来就是另一回事了。目前看会遇到这些问题:

  • 费用问题:尽管 LLM token 费用一降再降,但是还是远比一次数据查询贵的多(有机构估计两者费用是 100 亿倍),大家都是开门做生意的,成本还是很重要的
  • 速度问题:context 越长,后期的速度会下降,但是一次 RAG 查询是毫秒级的,有明显体验差异
  • 准确率问题:虽然宣传上各种夸 long context 的好,但是实际使用上,当 prompt 长度突破一个临界值后,生成的内容质量会有一个下降。就去年的一些热门模型,比如说用 Claude 3.5 生成代码,当单文件代码行数超过 1000 行后,错误率会明显的上升

这个事情其实也可以和计算机发展史相结合:

  • 安迪-比尔定律:硬件性能提升所带来的好处,很快会被软件的发展消耗掉
  • 内存越来越大,并不意味着大家不再需要硬盘

是否有引入 LangChain 这类框架?

这个看情况,如果是初步试水,用它来做 RAG 还是比较开箱即用的。

LangChain 有个问题就是封装的太厚了,如果有一些特殊的定制需求,就会发现它的部分模块很难修改,很多人改到最后,就会发现 LangChain 的比重越来越低,出于灵活性反而不如一开始就不用,所以 2024 年社区内有去 LangChain 的倾向。


Refs