RAG 多轮对话的查询重写:上下文丢失不是因为模型笨
RAG 多轮对话的查询重写上下文丢失不是因为模型笨一、第一问推荐几个 Go 的微服务框架第二问它和 gRPC 怎么配合多轮对话场景下RAG 检索经常在第二问失效。用户问它和 gRPC 怎么配合。向量检索用它和 gRPC 怎么配合做查询。结果召回了一堆它的泛化语义。问题不在模型或检索而在输入。它这个指代没有明确的实体。人类能通过上文推断出它指的是前面提到的某个框架。但检索系统没有这个智能。查询重写解决的就是这个问题。把它和 gRPC 怎么配合重写为Go-Micro 框架和 gRPC 怎么配合。重写后的查询才能精准检索。这是 RAG 系统最容易被忽略的短板。很多团队在优化 RAG 时第一反应是换更强的 Embedding 模型、调高 Top-K、做重排序Rerank。但根因往往不在检索质量本身而在输入端的信号衰减。原问题Go-Micro 框架和 gRPC 怎么配合的 Embedding 向量和它和 gRPC 怎么配合的 Embedding 向量在余弦相似度上可能只有 0.3-0.4。你花再多精力优化向量检索也弥补不了查询端的 60% 信号损失。我在实际项目中遇到过的一个案例一个企业内部知识库问答系统多轮对话的准确率从首轮的 78% 骤降到第三轮的 31%。排查后发现第三轮的用户查询里充满了这个方案、那种情况等指代词。加入查询重写后第三轮准确率回升到 62%——虽然仍比首轮低但已经是从不可用到可接受的跨越。二、多轮对话的查询重写机制查询重写有三类策略指代消解将它、这个替换为具体实体。省略补全用户省去的上下文补回来。意图融合将多轮对话的意图整合进查询。flowchart TB A[用户当前消息: 它和 gRPC 怎么配合] -- B[获取对话历史] B -- C[上轮: 推荐几个 Go 微服务框架] C -- D[助手: Go-Micro、Kratos、Go-Zero 都不错] A -- E[查询重写器] D -- E E -- F{分析当前消息} F -- G[检测到指代词: 它] G -- H[回溯历史解析指代] H -- I[候选实体: Go-Micro/Kratos/Go-Zero] I -- J[选择最可能的实体: Go-Micro] J -- K[生成重写查询] K -- L[Go-Micro 框架和 gRPC 怎么配合] L -- M[向量检索/混合检索] M -- N[返回相关文档]三种重写策略的适用场景各有侧重。指代消解占查询重写场景的 60-70%是最高频的需求。省略补全占 20-30%典型如用户问还有哪些、那另外的呢。意图融合占 10% 左右多见于用户跨越 3 轮以上对话、意图在逐步深入或切换的情况。在实践中我倾向于把查询重写分层处理简单指代用规则、复杂省略用 LLM。规则重写正则 实体提取延迟几乎为零覆盖了大部分场景。LLM 重写虽然多花 0.5-2 秒但处理规则搞不定的情况——比如那你觉得哪个更好中的哪个指向历史中提到的 3 个框架。三、查询重写的 Python 实现下面的代码实现了一个双层查询重写器。第一层基于规则实体提取 指代消解 省略补全。第二层基于 LLM处理规则无法覆盖的模糊指代和意图融合。 query_rewriter.py - 多轮对话查询重写 import re import logging from typing import List, Tuple, Optional from dataclasses import dataclass logger logging.getLogger(__name__) dataclass class DialogueTurn: 对话轮次 role: str # user / assistant content: str entities: List[str] # 提取的实体 class QueryRewriter: 多轮对话查询重写器 # 常见指代词 PRONOUNS [ 它, 他, 她, 这个, 那个, 这些, 那些, 其, 该, 此, 这, 那, it, this, that, these, those, ] # 常见省略模式 ELLIPSIS_PATTERNS [ r^(还有|另外|此外|并且|而且|还|也)[,]?\s*, r^(那|那么)[,]?\s*, ] def __init__(self, llm_clientNone): llm_client: LLM 客户端用于复杂重写 如果为 None使用规则重写 self.llm llm_client self.history: List[DialogueTurn] [] def add_turn(self, role: str, content: str): 添加一轮对话 entities self._extract_entities(content) self.history.append(DialogueTurn( rolerole, contentcontent, entitiesentities, )) def rewrite(self, current_query: str) - str: 重写当前查询 规则重写 LLM 重写如果可用 # 第一层规则重写 rewritten self._rule_based_rewrite(current_query) # 第二层LLM 精密重写 if self.llm and self._needs_llm_rewrite(current_query): rewritten self._llm_rewrite(rewritten) if rewritten ! current_query: logger.info( f查询重写: {current_query} → {rewritten} ) return rewritten def _rule_based_rewrite(self, query: str) - str: 基于规则的查询重写 rewritten query # 1. 指代消解 rewritten self._resolve_pronouns(rewritten) # 2. 省略补全 rewritten self._complete_ellipsis(rewritten) return rewritten def _resolve_pronouns(self, query: str) - str: 指代消解将指代词替换为最近实体 has_pronoun False for pronoun in self.PRONOUNS: if pronoun in query: has_pronoun True break if not has_pronoun: return query # 从最近的历史中找实体 for turn in reversed(self.history): if turn.entities: # 找最近的实体按出现顺序 entity turn.entities[-1] # 最近提到的 # 替换指代词 for pronoun in self.PRONOUNS: if pronoun in query: # 处理它和 gRPC这类情况 if f{pronoun}和 in query: query query.replace( f{pronoun}和, f{entity}和 ) elif f{pronoun}的 in query: query query.replace( f{pronoun}的, f{entity}的 ) else: # 简单替换可能产生不自然的结果 query query.replace(pronoun, entity) return query return query def _complete_ellipsis(self, query: str) - str: 省略补全 for pattern in self.ELLIPSIS_PATTERNS: if re.match(pattern, query): # 找到上次用户的查询主题 for turn in reversed(self.history): if turn.role user: # 连接两个查询 core re.sub(pattern, , query) return f{turn.content} {core} return query def _extract_entities(self, text: str) - List[str]: 提取关键实体简化实现 # 匹配引号中的内容 quoted re.findall(r[「]([^」])[」], text) # 匹配大写开头的专有名词英文 proper_nouns re.findall( r\b([A-Z][a-zA-Z](?:-[A-Z][a-zA-Z])*)\b, text ) # 匹配中文专名简化 cn_patterns [ r(Go-Micro|Kratos|Go-Zero|Kubernetes|Docker|Redis), r(微服务|分布式|消息队列|API网关)框架, ] cn_entities [] for pattern in cn_patterns: cn_entities.extend(re.findall(pattern, text)) entities [] entities.extend(quoted) entities.extend(proper_nouns) entities.extend(cn_entities) # 去重保持顺序 seen set() result [] for e in entities: if e not in seen: seen.add(e) result.append(e) return result def _needs_llm_rewrite(self, query: str) - bool: 判断是否需要 LLM 重写 # 规则解决不了的情况 # 1. 隐式指代那速度怎么样不知道哪个的速度 # 2. 跨多轮的意图融合 indirect any(p in query for p in [ 那, 它的, 他们的, 怎么, 怎么样, ]) return indirect and len(self.history) 2 def _llm_rewrite(self, query: str) - str: 使用 LLM 重写查询 context self._build_context() prompt f根据对话历史将用户的当前查询重写为独立、完整的检索查询。 对话历史 {context} 当前查询{query} 重写规则 1. 消解所有指代词它→具体名称 2. 补全省略的上下文 3. 保持原意不要添加信息 4. 只返回重写后的查询不要解释 重写后的查询 try: rewritten self.llm.chat(prompt).strip() if not rewritten or len(rewritten) 3: return query return rewritten except Exception as e: logger.error(fLLM 重写失败: {e}) return query def _build_context(self) - str: 构建对话历史上下文 lines [] for turn in self.history[-5:]: # 最近 5 轮 role 用户 if turn.role user else 助手 lines.append(f{role}: {turn.content}) return \n.join(lines) # ---- 使用示例 ---- def demo(): rewriter QueryRewriter() # 模拟多轮对话 rewriter.add_turn(user, 推荐几个 Go 的微服务框架) rewriter.add_turn(assistant, Go-Micro、Kratos 和 Go-Zero 都不错) rewriter.add_turn(user, Go-Micro 有什么优点) rewriter.add_turn(assistant, Go-Micro 支持服务发现、负载均衡...) # 测试指代消解 result rewriter.rewrite(它和 gRPC 怎么配合) print(f原查询: 它和 gRPC 怎么配合) print(f重写后: {result}) # 测试省略补全 result2 rewriter.rewrite(还有哪些类似的框架) print(f\n原查询: 还有哪些类似的框架) print(f重写后: {result2}) if __name__ __main__: demo()_resolve_pronouns方法的实体选择逻辑是取最近历史中的最后一个实体。这是一个朴素但有 85% 准确率的策略——在多轮对话中用户通常用它指代紧邻上一轮讨论的核心对象。如果你需要更高的准确率可以让 LLM 来做指代消解但从工程角度看规则先跑一轮再让 LLM 处理剩余的情况是更合理的设计。四、查询重写的局限性规则重写覆盖简单指代但无法处理隐式指代。用户说那速度怎么样规则不知道哪个的速度。这种情况必须有 LLM 支持。重写可能引入噪声。如果指代消解选错了实体重写后的查询更不准。需要评估重写前后的检索效果对比。不适合的场景单轮问答系统不需要重写用户每次都提供完整查询的场景对延迟要求极高的检索LLM 重写增加 0.5-2s。关于指代消解选错实体的风险有一个实用的降低手段。在生成重写查询的同时保留原始查询的兜底逻辑。也就是说同时用重写后的查询和原始查询做两次检索取并集进行去重和排序。这样即使重写有偏差原始查询也能兜底保证基础召回。代价是多一次检索调用的开销但对于重要业务场景这个冗余是值得的。另外查询重写的效果不是一次性的。建议在每个大版本迭代时拉取一批多轮对话的查询日志做人工标注评估重写的准确率。把这个指标纳入 RAG 系统的整体监控体系中而不只是搜罗 Embedding 的召回率。五、总结多轮对话中查询重写是 RAG 准确率的关键优化。规则重写处理显式指代它→实体名。LLM 重写处理隐式指代和意图融合。重写后的查询应完整、独立、不依赖上下文。重写效果需要与原始查询做 AB 对比验证。落地建议很简单先把规则重写加上零成本覆盖 60-70% 场景然后在延迟允许的前提下叠加 LLM 重写。不要一上来就全量用 LLM 重写——延迟和成本都会失控。一个好的查询重写器应该是规则为主、LLM 为辅的架构每种手段处理自己最擅长的场景。

相关新闻

BiliTools哔哩哔哩工具箱:跨平台B站资源下载神器终极指南

BiliTools哔哩哔哩工具箱:跨平台B站资源下载神器终极指南

BiliTools哔哩哔哩工具箱:跨平台B站资源下载神器终极指南 【免费下载链接】BiliTools 本项目已停止维护。 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools 还在为B站视频下载而烦恼吗?想要轻松获取哔哩哔哩上的番剧、课程和音乐…

2026/7/9 17:03:34阅读更多 →
63%成本拿下92%性能:Fable 5省钱实战拆解

63%成本拿下92%性能:Fable 5省钱实战拆解

2.5倍成本降低,3倍速度提升——这不是理论推演,而是Anthropic官方验证的真实数据。当Claude Fable 5的限时免费窗口延长至7月12日,越来越多的开发者开始关注一个实际问题:如何在多模型环境中实现真正的成本优化?企业级…

2026/7/9 16:58:34阅读更多 →
深远T90-1动力版全解析:全顺电机、广州上牌与实用指南

深远T90-1动力版全解析:全顺电机、广州上牌与实用指南

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 如果你最近在广州街头看到一款造型独特、动力强劲的“小电驴”,十有八九就是深远T90。这款车最近在广州的电动车圈里火得有…

2026/7/9 16:58:34阅读更多 →
Valve 为 Steam Machine 发布 Windows 驱动程序,可替换 SteamOS 但不支持双系统

Valve 为 Steam Machine 发布 Windows 驱动程序,可替换 SteamOS 但不支持双系统

Steam Machine 迎来 Windows 驱动程序更新据 Windows Central 报道,Valve 为 Steam Machine 发布了 Windows 驱动程序,如同之前为 Steam Deck 所做的一样。这意味着用户若有需求,能够将 Steam Machine 原本基于 Linux 的 SteamOS 进行替换。不…

2026/7/9 18:23:50阅读更多 →
《创世战车》Darling战车攻略:高机动游击手装配与团队协作技巧

《创世战车》Darling战车攻略:高机动游击手装配与团队协作技巧

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 在《创世战车》这款充满创意与策略的载具对战游戏中,JBRider的"💘 甜心攻略"系列一直备受玩家关注。…

2026/7/9 18:23:50阅读更多 →
面向工程应用的太阳能控制器电路选型与标准解读

面向工程应用的太阳能控制器电路选型与标准解读

在离网光伏照明与供电系统中,太阳能控制器承担着能量调度、电池保护与负载管理的核心职能。对于工程技术人员而言,控制器的电路拓扑、充放电参数与保护逻辑直接决定了系统的可靠性与寿命。本文从底层电路原理出发,结合现行行业标准&#xff0…

2026/7/9 18:23:50阅读更多 →
腾讯地图插件 1.0.10 三种添加方法对比:从公众平台到项目配置的 5 步成功率分析

腾讯地图插件 1.0.10 三种添加方法对比:从公众平台到项目配置的 5 步成功率分析

腾讯地图插件1.0.10三种接入方案深度评测:成功率与实战避坑指南 对于微信小程序开发者而言,地图功能已成为提升用户体验的标配组件。腾讯地图插件1.0.10版本提供了三种不同的接入方式,但实际开发中常会遇到"添加失败"弹窗、授权异…

2026/7/9 18:23:50阅读更多 →
终极隐私保护指南:如何用Boss-Key一键隐藏Windows窗口

终极隐私保护指南:如何用Boss-Key一键隐藏Windows窗口

终极隐私保护指南:如何用Boss-Key一键隐藏Windows窗口 【免费下载链接】Boss-Key 老板来了?快用Boss-Key老板键一键隐藏静音当前窗口!上班摸鱼必备神器 项目地址: https://gitcode.com/gh_mirrors/bo/Boss-Key 在办公室工作、学习或娱…

2026/7/9 18:23:50阅读更多 →
图像识别案例在线实验闯关Educator头歌答案分享

图像识别案例在线实验闯关Educator头歌答案分享

第1关:手写体图像数据集初识# -*- coding: utf-8 -*- #读取机器学习包sklearn内置的手写体图像数据集,输出数据集的基本信息: #图像像素数据集的大小x_size(元组),第1个元素为行数,第2个元素为列数, #图像标…

2026/7/9 18:18:49阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/9 5:56:19阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/9 9:45:20阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/9 2:47:07阅读更多 →
Three.js 着色器光效教程

Three.js 着色器光效教程

着色器光效 Shader Light ▶ 在线运行案例 案例合集: 三维可视化功能案例(threehub.cn)开源仓库github地址: https://github.com/z2586300277/three-cesium-examples400个案例代码: 网盘链接 你将学到什么 ShaderMaterial 自…

2026/7/9 0:04:37阅读更多 →
如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南 【免费下载链接】casemove A dedicated desktop app that enables you to move items in and out of storage units in CS2. 项目地址: https://gitcode.com/gh_mirrors/ca/casemove 还在为CS2存储单…

2026/7/9 0:04:37阅读更多 →
GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a与MySQL 8.0:ALTER TABLE语法差异深度解析与实战指南1. 两种数据库的ALTER TABLE能力全景对比在数据库架构设计和运维过程中,表结构变更(DDL操作)是不可避免的需求。GBase 8a作为国产分析型数据库代表,与开源M…

2026/7/9 0:04:37阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/9 9:45:20阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/9 15:50:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/9 14:14:17阅读更多 →