免费POC,零成本试错

AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


深入解析RAG多轮会话优化:从查询重写到高级策略

发布日期:2025-08-17 21:02:48 浏览次数: 1514
作者:大模型RAG和Agent技术实践

微信搜一搜,关注“大模型RAG和Agent技术实践”

推荐语

解密RAG多轮会话优化的核心技术,从查询重写到实战策略一网打尽。

核心内容:
1. 多轮会话在RAG系统中的关键挑战与必要性
2. 查询重写策略的原理与典型应用场景
3. 主流开源框架(LlamaIndex/LangChain)的实战解决方案

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家
Agent技术实践" data-from="2" data-headimg="https://api.ibos.cn/v4/weapparticle/accesswximg?aid=121779&url=aHR0cDovL21tYml6LnFwaWMuY24vc3pfbW1iaXpfcG5nL0lKSTNkV0RQZlhBQXFrVWljaHUxcUJKR1JvaWFvdGljSzlwaWFoVVFtNlFwSVZ3Um13YmJDNVlBNXJyb2tTYlhaTVZXYnBzYjVMdmljTDJzUGljWEhFWTkwMjFRLzA/d3hfZm10PXBuZw==" data-signature="专注RAG、Agents、dify、Ragflow、知识图谱等大模型应用研发企业落地实践、案例教程、最新技术动态等内容,重在技术前沿、企业应用和实战,欢迎大家交流。" data-id="MzE5ODEyMTI4MA==" data-is_biz_ban="0" data-service_type="1" data-verify_status="0">

一、背景:为何多轮会话是RAG的"必修课"?

检索增强生成(Retrieval-Augmented Generation, RAG)技术通过结合外部知识库,极大地提升了大型语言模型(LLM)回答问题的准确性和时效性。一个基础的RAG应用在处理单轮、独立的问答时表现优异。然而,真实世界的交互远不止于此。人类的交流充满了上下文依赖,是自然流畅的多轮对话。

用户很自然地会将这种交流习惯带入与AI的互动中。例如,在客户服务场景中,用户可能会先问"我的订单到哪了?",在得到回复后接着问"能加急吗?"或者"怎么修改收货地址?"。如果系统无法理解后续问题中的"它"或"那个"指代的是前一轮对话的订单,那么交互体验将大打折扣。这种上下文的缺失,尤其是在检索环节,是当前许多RAG应用面临的核心挑战。本文将深入探讨如何优化RAG系统中的多轮会话能力。

多轮对话例子
客服机器人基于知识文档(产品退换政策)与用户进行多轮对话

二、核心策略:查询重写(Query Rewriting)

面对多轮对话中上下文依赖的问题,业界普遍采用且行之有效的核心策略是查询重写(Query Rewriting),也称为查询压缩(Query Condensing)。其基本思想非常直观:在进行检索之前,利用LLM的理解能力,将当前用户的问题与之前的对话历史相结合,生成一个全新的、独立的、包含完整上下文信息的问题。

例如,对于之前的对话:

用户:我想了解一下关于保罗·格雷厄姆(Paul Graham)的信息。

AI:好的,保罗·格雷厄姆是Y Combinator的联合创始人之一,也是一位著名的程序员和作家。

用户:他后来做了什么?

直接用"他后来做了什么?"去知识库检索,效果会很差。而查询重写模块会将其改写为:"在联合创办Y Combinator之后,保罗·格雷厄姆做了什么?"。这个新问题是独立的,包含了所有必要信息,可以被RAG系统的检索模块高效、准确地处理。

RAG系统工作流程图
在RAG流程中,查询重写发生在用户输入(Query)之后,信息检索(Search Relevant Information)之前


三、开源框架实战

目前主流的RAG框架,如LlamaIndex、LangChain,都为多轮对话场景提供了开箱即用的解决方案,其核心逻辑都离不开对会话历史的管理和查询重写。

1. LlamaIndex 的 CondenseQuestionChatEngine

LlamaIndex 提供了专门用于会话场景的 Chat Engine。其中,CondenseQuestionChatEngine是实现多轮对话的基础。它的工作流程正如其名:先压缩(Condense)问题,再查询。

下面是一个使用 LlamaIndex 实现多轮对话的完整示例:

# 1. 安装必要的库
# pip install llama-index openai

import os
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.openai import OpenAI

# 设置你的OpenAI API密钥
# os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"

# 配置LLM
Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0)

# 2. 准备数据和索引
# 创建一个虚拟的知识库文件
os.makedirs("data", exist_ok=True)
with open("data/paul_graham_essay.txt""w", encoding="utf-8"as f:
    f.write("Paul Graham co-founded Y Combinator. After YC, he started painting. He spent most of 2014 painting. In March 2015, he started working on Lisp again.")

documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(documents)

# 3. 配置并使用 CondenseQuestionChatEngine
chat_engine = index.as_chat_engine(
    chat_mode="condense_question"
    verbose=True# 设置为True以查看重写后的问题
)

# 第一轮对话
response = chat_engine.chat("What did Paul Graham do after YC?")
print(response)

# 第二轮追问
# chat_engine会记住上一轮的上下文
response_follow_up = chat_engine.chat("What about after that?")
print(response_follow_up)
                

当执行第二轮追问 chat("What about after that?")时,verbose=True会在控制台打印出类似下面的信息,清晰地展示了查询重写的威力:

Querying with: What did Paul Graham do after he started painting after leaving YC?

LlamaIndex 使用的默认Prompt模板如下,它指示LLM根据聊天记录(Chat History)和新的追问(Follow Up Message)生成一个独立的、包含所有相关上下文的问题。

Given a conversation (between Human and Assistant) and a follow up message from Human, 
rewrite the message to be a standalone question that captures all relevant context 
from the conversation.

<Chat History>
{chat_history}

<Follow Up Message>
{question}

<Standalone question>

2. LangChain 的记忆机制与会话链

LangChain 作为一个灵活的LLM应用开发框架,提供了强大的"记忆"(Memory)组件来管理和操作对话历史。这是其实现多轮对话的核心。

记忆(Memory)组件

LangChain的记忆组件负责在对话链(Chain)的调用之间存储和传递状态。常见的记忆类型包括:

  • ConversationBufferMemory:这是最直接的记忆类型,它将完整的对话历史原封不动地存储起来。优点是信息无损,缺点是当对话变长时,会消耗大量Token,可能超出模型上下文窗口。
  • ConversationSummaryMemory:当对话历史变长时,此记忆类型会调用一个LLM对历史进行总结,用一个精炼的摘要来代替冗长的对话记录。这有效解决了上下文窗口的限制,但可能会在摘要过程中丢失细节。

使用 ConversationalRetrievalChain 实现多轮RAG

ConversationalRetrievalChain是LangChain中专门用于构建多轮对话RAG应用的链。它巧妙地集成了记忆、查询重写和检索,其工作流程如下:

  1. 接收用户的新问题(question)和对话历史(chat_history)。
  2. 使用一个LLM将新问题和对话历史结合,生成一个独立的、重写后的问题(standalone_question)。
  3. 将重写后的问题传递给检索器(Retriever),从知识库中获取相关文档。
  4. 将检索到的文档和原始问题(注意,不是重写后的问题)一起传递给另一个LLM,生成最终答案。

下面是一个使用LangChain实现多轮RAG对话的代码示例:

# 1. 安装必要的库
# pip install langchain langchain-openai langchain-community faiss-cpu

import os
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ConversationBufferMemory
from langchain.document_loaders import TextLoader

# 设置你的OpenAI API密钥
# os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"

# 2. 准备数据和索引
# 使用与LlamaIndex示例相同的数据
os.makedirs("data", exist_ok=True)
with open("data/paul_graham_essay.txt""w", encoding="utf-8"as f:
    f.write("Paul Graham co-founded Y Combinator. After YC, he started painting. He spent most of 2014 painting. In March 2015, he started working on Lisp again.")

loader = TextLoader("./data/paul_graham_essay.txt")
documents = loader.load()
vectorstore = FAISS.from_documents(documents, OpenAIEmbeddings())

# 3. 配置记忆和会话检索链
# 使用ConversationBufferMemory来存储对话历史
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
llm = ChatOpenAI(temperature=0)

# 创建ConversationalRetrievalChain
qa_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    memory=memory
)

# 4. 进行多轮对话
# 第一轮
result1 = qa_chain.invoke({"question""What did Paul Graham do after YC?"})
print(result1['answer'])

# 第二轮
result2 = qa_chain.invoke({"question""What about after that?"})
print(result2['answer'])

在这个例子中,ConversationalRetrievalChain内部自动处理了查询重写和上下文管理,为开发者提供了非常便捷的多轮对话RAG实现方案。

从以上主流框架的实现可以看出,基于LLM的查询重写是解决RAG多轮对话问题的通用且简洁的方案

四、进阶优化策略

查询重写解决了多轮对话的核心问题,但要构建一个体验极致的对话系统,我们还可以探索更多高级策略。

1. 上下文管理(Context Management)

随着对话轮次增多,完整的对话历史可能会变得非常长,超出LLM的上下文窗口限制,并增加API调用成本。因此,高效的上下文管理至关重要。常见策略包括:

  • 滑动窗口(Sliding Window):只保留最近的N轮对话作为历史记录。
  • 对话摘要(Summarization):定期或在历史过长时,使用LLM对早期的对话进行摘要,用一个简短的摘要替换多轮对话,从而压缩上下文。
  • 上下文过滤(Contextual Pruning):仅保留与当前对话主题相关的历史记录,过滤掉无关的闲聊或已完结的话题。

2. 查询扩展(Query Expansion)

除了将问题重写为单个独立问题外,还可以让LLM生成多个相关的问题变体。例如,当用户问"这个功能怎么用?"时,可以扩展为"XX功能的使用方法是什么?"、"XX功能的入门教程"、"XX功能的常见问题"等多个查询,然后并行检索,汇总结果。这能有效提高召回率,尤其是在知识库内容组织多样化的情况下。

3. 混合搜索(Hybrid Search)

一个经过精心重写的查询,包含了丰富的语义和关键词信息。此时,单一的向量检索可能不是最优解。混合搜索结合了向量检索(捕捉语义相似性)和传统的关键词检索(如BM25,精确匹配术语),能够为重写后的查询提供更全面、更准确的检索结果。

4. 意图驱动的RAG(Intent-Driven RAG)

这是一种更前沿的方法。系统首先尝试识别用户的对话意图(例如:查询信息、比较产品、请求操作),然后根据意图来指导后续的检索和生成策略。例如,如果识别到用户的意图是"比较",系统可以专门去检索包含对比信息或规格参数的文档。

5. 多智能体系统(Multi-Agent Systems)

对于极其复杂的任务,可以将对话流程拆解给不同的"智能体"处理。例如,可以有一个"对话管理智能体"负责与用户交互和重写查询,一个"研究智能体"负责执行复杂的检索任务,还有一个"总结智能体"负责整合信息生成答案。

五、总结与展望

打造具备优秀多轮对话能力的RAG应用,是提升用户体验的关键一步。本文从工业界实践出发,阐述了查询重写作为解决此问题的核心与基础策略,并通过LlamaIndex和LangChain框架展示了其具体实现。

查询重写虽然简单,但效果显著,是所有RAG开发者都应掌握的基础技术。在此之上,通过引入更精细的上下文管理、查询扩展、混合搜索乃至更前沿的意图识别和多智能体架构,我们可以将RAG应用的对话能力推向新的高度,使其不仅能准确回答问题,更能像一个真正的专家助手一样,与用户进行自然、连贯、深入的交流。



欢迎加入我的知识星球

本星球有更多的技术和实战内容,专注RAG、Agents、Dify、Ragflow、知识图谱等大模型应用研发企业落地实践、案例教程、最新技术动态等内容,重在技术前沿、企业应用和实战,欢迎大家交流。




53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询