多轮查询改写是什么
多轮对话里用户很少把问题说完整:常见“那它呢”“这个报错怎么处理”,句子依赖上文才能理解。查询改写先用最近若干轮对话把当前问题补全成一个自包含的问句,再拿这个问句去检索。改写质量直接决定检索命中率,因为向量库只认查询文本,指代词与省略成分会让检索器完全抓不到主题。改写结果与原问题都要写进日志,否则排查“为什么没检索到”时无从下手。
基本信息
| 输入 | 最近 1-2 轮对话 + 当前问题 |
|---|---|
| 输出 | 无指代、可独立检索的完整问句 |
| 历史窗口 | 按 token 预算裁剪,越近的轮次权重越高 |
| 实现方式 | 小模型或主模型做改写,也可用规则兜底 |
| 失败表现 | 改写跑题或过度扩写,检索到无关文档 |
典型使用场景
- 客服问答:用户连续追问同一工单的不同细节,第二轮起必须补全上下文实体
- 技术文档助手:用户先问某个组件,再问“它的默认端口是多少”
- 多轮改写与检索合并:把历史拼进查询文本一起向量化,省一次生成调用
- 改写质量监控:抽样比对改写前后检索命中率,判断改写是否真的起作用
- 闲聊兜底:识别出无需检索的追问,直接走对话链路省一次检索
改写与检索流程
改写与检索流程
def retrieve_for_turn(history, question):
if is_standalone(question): # 已是完整问句,跳过改写
stand_alone = question
else:
stand_alone = llm_rewrite(history[-2:], question)
hits = retriever.search(stand_alone)
log(question, stand_alone, [h.id for h in hits]) # 两个查询都留痕
return hits改写提示词要点
改写提示词要点
把用户最新问题改写为不含指代、可独立检索的问题;
保留专名、型号与数字;不添加原问题没有的条件;
只输出改写结果,不要解释过程。常见改写错误与表现
| 错误 | 表现 | 处理 |
|---|---|---|
| 漏补实体 | 改写后仍含“它”,检索结果泛化 | 提示词要求逐项检查指代 |
| 过度扩写 | 加入原问题没有的限定词,召回变窄 | 限制只做补全不做推测 |
| 串话题 | 把上一轮的旧主题带进本轮 | 缩小历史窗口,只取近 2 轮 |
| 无谓改写 | 完整问句被改写后反而变差 | 先判断是否已自包含,能跳过就跳过 |
改写本身是一次生成调用,会增加延迟与成本:高频简单问题可先用规则判断是否已自包含,命中就跳过改写。改写的提示词版本也要记录,出问题时能区分是提示词变更还是数据变更。