昨天我们搭了一个能回答单轮问题的RAG系统。但如果你追问"能再详细讲讲吗",AI会一脸懵——因为它根本不知道"这"指的是什么。上下文缺失,这是多轮对话RAG最头疼的坎。
今天解决这个核心难题:对话记忆。让AI理解"它""那个"到底指代前文提到的什么东西。
![]()
核心难点:查询重写
假设你问了两句话:
• "LangChain是怎么工作的?"
• "能给我举个它的例子吗?"
检索器看到第二句里的"它",会真的去数据库里搜"它"这个字——结果当然是垃圾。因为检索器没有对话历史,无法把代词还原成具体概念。
解决方案是加一步历史感知检索(History-Aware Retrieval)。AI拿到你的追问和完整对话记录,先把代词、省略补全,重写成检索器能独立理解的完整问题,再去做文档搜索。
第一步:问题 contextualization
先搭一个子链,输入历史记录+新问题,输出"检索友好"的查询语句。
代码里用 create_history_aware_retriever 封装这个逻辑。关键在 contextualize_q_system_prompt 这段系统提示:告诉AI"根据对话历史和最新问题,生成一个脱离历史也能被理解的独立问题,不要回答"。
然后把之前Day 9的检索器包进去,得到 history_aware_retriever。
第二步:组装完整对话链
把历史感知检索器接入文档问答链,形成最终流程。
这里需要两个组件:
1. create_stuff_documents_chain —— 把检索到的文档塞进提示词,生成答案
2. create_retrieval_chain —— 把检索和问答串成完整链路
最终 rag_chain 的执行顺序是:先重写问题(含历史感知)→ 检索文档 → 基于文档生成回答。
实测效果
第一轮问"What is LangSmith?",AI正常回答。把问答记录更新进 chat_history。
第二轮追问"How do I get started with it?"——这里的"it"会被自动重写成"LangSmith",检索器能准确找到相关文档,不再搜"it"这个无意义关键词。
关键代码结构:
• 用 HumanMessage 和 AIMessage 维护对话历史
• 每次交互后 extend 更新历史
• 重写提示词里用 MessagesPlaceholder("chat_history") 占位注入历史
这套机制的本质是让检索层"理解"对话,而非让LLM硬背上下文。因为检索是RAG的瓶颈,检索错了,后面生成再强也救不回来。把代词消歧放在检索前做,比让生成模型去猜更可靠。
完整实现约30行核心代码,但解决了RAG从"问答工具"到"对话助手"的关键跃迁。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.