查询改写:用扩展、分解、HyDE 和指代消解提升 RAG 召回
用户的问题往往不适合直接检索:太短、含指代、口语化、需要多跳推理,或者缺少领域词。查询改写把原始问题变成更适合检索的查询,常见方法包括同义扩展、多查询(Multi-Query)、查询分解、HyDE(先生成假设答案再检索)、Step-back(先问更抽象的问题)和对话指代消解。
改写能提升召回,但会增加一次 LLM 调用的延迟和成本,也可能引入幻觉约束、偏离原意。是否值得,要用同一套评估集对比改写前后的 recall@k、答案正确率和延迟。
# 多查询:让 LLM 生成多个改写,分别检索后合并
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
llm=ChatOpenAI(model="gpt-4o-mini", temperature=0),
)
docs = retriever.invoke("这个报错怎么修?")
# HyDE:先生成假设答案,再用答案的向量检索
prompt = """根据问题写一段可能的技术文档答案,不要编造具体命令:
问题:{question}
答案:"""
hypothetical = llm.invoke(prompt.format(question=question)).content
docs = vectorstore.similarity_search(hypothetical, k=10)
# 对话指代消解:把“它/这个/上面说的”改写成完整问题
rewrite_prompt = """把用户问题改写成独立、可检索的查询,保留原意:
对话历史:{history}
当前问题:{question}
独立查询:"""
适用判断:
- 短查询/口语化 → 扩展或改写
- 多跳问题 → 分解成子问题
- 指代/省略 → 对话改写
- 精确词/错误码 → 不要过度改写,保留原词
合上页面,先回答,再展开对照。
小程序版
微信扫码,随时查命令