传统RAG过时了?从RAG到RAG Flow的架构演进与技术实现 |LLM应用探讨
大模型发展到现在,随着下游应用尤其是B端场景不断深入验证,无论是知识密集型的RAG搜索问答,还是更复杂的AI Agents,在架构上都开始跳出简单的提示工程和传统“链”式套路,向着更灵活、更强大的方向演进。本文就借着当前最常见的RAG(检索增强生成)应用,聊聊它的最新架构变化和技术实现。
目录里先列几个重点:LLM应用架构的演进、RAG应用面临的挑战、从RAG到RAG Flow、实现一个RAG Flow,最后收个尾。好,我们直接开讲。
01 LLM应用架构的演进
这里说的应用,是指
以LLM为核心驱动、能自主完成一系列设定工作步骤的“原生”LLM应用
- 随着大模型在专业领域越来越细分,再加上大量“小”模型涌现,“让合适的模型干合适的事”成了实实在在的技术考量。有的模型擅长某领域知识推理,有的针对RAG场景做了微调,有的则在Text2SQL任务上表现更优——各司其职,效果拉满。
从依赖单一模型到多模型协作。
- 大模型本身缺乏可解释性,如果完全依赖它自身的决策和思维链(COT),不确定性会非常大。这点在早期AutoGPT等Agent项目里体会很深——遇到复杂任务,结果基本是开盲盒。
从“黑盒子”转向开放、可编排、可跟踪。
- 场景复杂了,优化方法也多了,简单的顺序执行步骤已经不够用。分支、并行、迭代、循环这些更复杂的工作流,能充分挖掘大模型潜力,让效果更优。
从顺序式简单架构走向复杂WorkFlow。
再说个老朋友——还记得LangGraph吗?前几篇文章里剖析过它,其推出的根本动机就是为了适应越来越复杂的Agent工作流。传统的Chain和黑盒Agent组件满足不了新需求。LangGraph用图(Graph)这种更灵活的算法结构来定义任务节点、关系和状态迁移,几乎能应对无限场景下的复杂Agent需求,开发效率提升巨大。
多种模型、技术、算法与范式的融合架构。
下面,我们就从最常见的LLM RAG应用来认识这种架构转变和相关技术。
02 RAG应用面临的挑战
RAG的基本思想大家已经很熟了:
借助检索技术把外部知识和上下文补充给大模型,帮助它生成更准确、更可靠的回答,尽可能避免“幻觉”问题。
传统经典RAG架构看似简单,但实际用起来往往是“上手容易,做好极难”,尤其是要满足企业生产环境,更难。一部分原因来自企业运营——比如私有知识的管理和维护;另一部分则来自技术本身——自然语言的复杂性给检索和理解带来了不少挑战。主要挑战集中在以下几块:
知识召回的精准度
检索回来的外部知识是否有足够的相关性和覆盖性,直接决定了生成阶段的质量。如果召回的信息里掺杂了大量无用、噪声甚至矛盾的干扰,或者最重要的信息没落在大模型的“关注区域”里,那最终输出肯定要打折扣。
召回精准度通常涉及索引和检索两大环节:
- 原始知识数据(文档、数据库、网站等)的加载、识别、切分、索引处理。微观层面又会牵扯到多模态文档处理、切分块大小选择、索引机制选择、Embedding模型选择等一系列技术问题。
索引:
- 尽管当前基于Embedding的向量技术对语义检索能力有很大提升,但索引块的大小、Embedding算法、原始数据质量等问题,都可能导致检索结果不够理想。
检索:
大模型自身的生成能力
检索到的相关知识形成上下文,最终要靠LLM来理解并生成。所以LLM的生成能力是另一个关键环节。
不同场景怎么选模型、要多大参数规模,往往是实施RAG时最先遇到的困惑。简单知识问答可能6B、13B的模型也能表现不错;但SQL生成、Tools使用这类任务,即使千亿参数的大模型,也很难达到80%以上的准确率。
此外,检索结果的排序、干扰信息、多余信息、矛盾信息,都需要LLM自己去识别和区分。模型本身的“抗干扰”能力和“注意力”范围,对最终生成有重要影响。所以有些实际应用,会针对RAG场景微调大模型,让它更适合这个场景。
可能的技术限制与难点
还有几个常见的坑:携带过多关联知识可能撑爆大模型的上下文窗口;处理步骤太多会影响端到端响应性能;在多轮对话中,一个输入问题的完整语义可能分布在多轮交互里,如何合并这些语义形成完整检索输入,也是个技术活。
03 从RAG到RAG Flow
正是这些挑战,倒逼RAG架构不断优化演进。这里借用同济大学等团队最近的一篇调查报告《Retrieval-Augmented Generation for Large Language Models: A Survey》里的观点,来看RAG架构的发展:
从最早的顺序式RAG范式(输入→检索→生成)发展成了更具灵活性的模块化RAG(Modular RAG)架构

核心思想是:把RAG应用中的各个步骤拆成多个
模块类
模块
运算符/算法
这些模块和算法不再固定选择和流程,而是由开发者根据场景灵活组合编排,构建适合自己的RAG系统。这种灵活编排的工作流程,就是RAG Flow。
这里不逐个介绍每个模块和典型算法,感兴趣的话可以去原项目的GitHub(搜索RAG-Survey)看看。
从上面的图可以看到,
推理阶段的RAG Flow主要有四种基础模式:顺序、条件、分支和循环
【顺序范式】
经典RAG范式,不过相比简单的query-retrieve-generate,这里加上了Pre-Retrieval和Post-Retrieval模块。常用的算法比如Pre-Retrieval的Query Rewrite(查询重写)和Post-Retrieval的Rerank(重排序):
【条件范式】
顾名思义,条件范式的RAG Flow会根据不同条件选择不同的后续RAG路径。条件判断需要增加路由模块,可以根据关键词或语义路由到不同的后续路径,不同路径可以用不同的流程、模型、提示词、算法等。
这在构建RAG应用里很常见。
比如,你做一个企业知识助手,可以根据语义路由到不同知识库检索,甚至让LLM用不同语气回答。
【分支范式】
分支范式就是流程里出现多个并行分支,并行的部分可能是Retrieve检索环节,也可能是Generate生成环节。
这也是种常见优化范式。
比如在查询开始阶段,让LLM对输入问题进行扩展(比如扩充3-5个相关/相似问题),然后用相似问题多次检索,最后把检索到的知识再次排序后交给LLM生成。
【循环范式】
循环范式里推理过程更复杂,可以根据场景出现多次
迭代、递归、自适应检索
在每次迭代中,利用前一次迭代的模型输出作为特定上下文,帮助检索更多相关知识,再生成新知识,直到达到预定义迭代次数终止。显然,
这种RAG流的好处是通过多次迭代尽可能检索出更多相关知识,由LLM整理生成。
循环范式的知名案例是Self-RAG,一种借助LLM进行自我反思与按需检索的框架,用来提高生成准确性(可以在GitHub搜索Self-RAG)。
04 实现一个RAG Flow
实现相对复杂的RAG Flow架构,建议基于目前主流的两个开发框架:
LangChain或者LlamaIndex。
两者各有优势。LangChain更面向通用LLM应用设计,功能强大但相对复杂;推出了
LangGraph
这里以上面分支范式中的RAG Flow作为样例实现,这也是常见的一种优化RAG输出的方法,常用于基于LLM的精准搜索。由于流程里不涉及复杂“循环”,此处直接用Chain实现,不用LangGraph。
工作机制如下:
- 注意相似问题尽量能提供不同视角,以拓展输入问题的广度和深度。
借助LLM把原始查询扩展成多个相似但不同的问题。
为什么需要扩展查询?
通常我们使用问答或搜索系统时,只习惯用单个输入查询。但单个问题可能无法完整或深入地表达用户真正意图,导致检索到的关联知识也无法很好覆盖需要的内容。比如想了解“个人所得税专项附加扣除的相关规定”,可以生成“个税专项附加扣除的扣除标准”“个税专项附加扣除的在线操作流程”“个税专项附加扣除的主要类型”等相似问题,这些能帮助检索到更全面深入的知识。
对原始输入和新问题执行基于向量的语义搜索,获得搜索结果。
对多个搜索结果进行结果重排名,这里使用倒数排名融合算法(RRF)。
关于RRF:
倒数排名融合 (RRF) 是一种把多个搜索结果列表的排名组合起来,生成单个统一排名的技术。通过组合不同查询的排名,能增加最相关文档/知识出现在最终排名顶部的机会,帮助LLM提高生成质量。详细原理可以读这篇论文:https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf
把重新排序后的相关知识和输入问题交给LLM进行生成。
下面是主要代码实现(仅展示核心过程):
【构建向量库与检索器】
#加载知识文档
loader = TextLoader(file_path="test.txt")
document = loader.load()
#分割文档
text_splitter = CharacterTextSplitter(separator="n",chunk_size=500,chunk_overlap=0)
data = text_splitter.split_documents(document)
#嵌入并存储向量库
db=Chroma.from_documents(documents=data,embedding_function=OpenAIEmbeddings(),persist_directory="./chrom_db")
#检索器
retriever=db.as_retriever(k=5)
【查询扩展】
使用Langchain构建查询扩展chain
llm=ChatOpenAI(temperature=0.0,model_name='gpt-3.5-turbo-1106')
template = """
你是一个聪明的AI助手,能够根据输入的单个查询生成多个相关的查询问题.
请根据如下查询内容生成5个相关的搜索查询: {query}
"""
prompt = ChatPromptTemplate.from_template(template)
#LCEL语言构建一个Chain
generate_queries = (
prompt | llm | StrOutputParser() | (lambda x: x.split("n"))
)
【RRF排序】
#RRF实现算法:对每个相关问题搜索出来的文档列表依次处理
#重新计算每个文档的Score,最后形成重新排序的文档结果
def reciprocal_rank_fusion(results: list[list], k=60):
fused_scores = {}
for docs in results:
for rank, doc in enumerate(docs):
doc_str = dumps(doc)
if doc_str not in fused_scores:
fused_scores[doc_str] = 0
previous_score = fused_scores[doc_str]
fused_scores[doc_str] += 1 / (rank + k)
reranked_results = [
(loads(doc), score)
for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
]
return reranked_results
【Chain:生成->检索->重排】
#构造一个rag fusion的chain
#处理过程:生成相似问题 => 检索问题相关文档 => 文档重排序
ragfusion_chain = generate_queries | retriever.map() | reciprocal_rank_fusion
【Chain:生成最终结果】
template = """
基于如下上下文回答问题:
{context}
===
问题: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
#构建生成器的Chain
#输入:retriever返回的检索结果与输入问题
final_chain = ({"context": rag_fusion_chain, "question": RunnablePassthrough ()}
| prompt
| llm
| StrOutputParser ()
)
【测试】
final_chain.invoke({question:"请介绍个人所得税专项附加扣除的政策"})
05 结束语
前面简单聊了聊当前LLM原生应用在架构演进上的一些新特征和范式,特别是更灵活的基于WorkFlow的架构,它大大扩充了LLM的应用场景,也提升了任务准确性和可靠性。说到底,技术总是在挑战中迭代,而RAG Flow这种模块化、可编排的思路,正是解决实际生产问题的关键方向之一。
-
- 关于宇宙的好的网名有哪些
- 角色扮演 | 1
- 网名