一个真实场景:用户先问"想买点水果,有什么推荐",AI推荐了车厘子和凤梨;用户追问"有货吗"——这句话单独拿去检索,系统根本不知道在问车厘子还是凤梨,检索不到东西,AI答非所问变成了推荐草莓。这一章就是把这个坑真正补上:搭一个"Query改写"节点,让检索之前先把用户的话"翻译"清楚。
7.1 为什么检索前要先"读懂、改好"问题
一句话:检索的上限,从用户按下回车那一刻就定了。 后面的检索、排序做得再好,如果送进去的问题本身残缺、跑偏,也救不回来。
两类典型的"问题本身有毛病":
省略/指代:"有货吗"——"它"、"这个"、"有货吗"这类话,
单独拿出来看,谁也不知道在问什么,
必须结合"上一轮聊的是什么"才能理解
口语化/表达不规范:"这个咋保存呀"——用户的口语问法,
和知识库里"XX保存方法"这种规范写法字面对不上,
关键词检索可能因为凑不齐共同词而漏检
Query理解,就是在真正检索之前,先做的这一步"读懂用户到底在问什么、把问题改写成检索友好的形式"的工作。它是系统的"调度员+翻译官":用户说的话不管多随意、多有省略,先在这一步被"翻译"成一句干净、完整、独立的问题,后面所有环节(意图判断、检索、生成回答)只需要处理这句"翻译后"的话。
7.2 两个核心动作:重写 vs 扩写
Query重写(求"准"): 把用户那句口语化、有省略的问题,改写成一句更规范、更贴近知识库表达、且信息补全的问题。比如把"这个咋保存呀"(结合上文知道"这个"指草莓)改写成"草莓怎么保存"。
Query扩写(求"全"): 给问题加上同义词、相关词,变成好几个查询一起去检索。比如"保存"扩成"保存/存放/怎么放"一起查,哪怕知识库写的是"存放方法"而不是"保存方法",也能查到。
一句话记住:重写求准(改成一句更好的),扩写求全(变成好几句一起查)。
用你们项目举个例子直观感受一下这两步分别救回了什么:
用户原话:"这个咋保存呀"
直接拿去检索 → 知识库标题是"草莓保存方法",字面对不上,命中0条
重写(去口语词+补全指代):"草莓怎么保存"
再检索 → 能命中"草莓保存方法"
扩写(加同义词):["草莓怎么保存", "草莓怎么存放"]
→ 命中范围更广,哪怕知识库写的是"存放"也能查到
这跟你们已经很熟的一件事是同一个原理: 第5章讲过的"知识库问题字段不要混合不同粒度的提问方式",本质上是"数据端"要规范;这一章讲的Query改写,是"提问端"要规范——两边一起做,检索才真正稳。
7.3 跟"记忆"功能的分工区别
记忆负责"存住"历史对话,Query改写负责"用"这段历史,把当前这句话说清楚。 只开记忆、不做改写,检索环节依然理解不了"有货吗"背后指的是车厘子还是凤梨——这正是开头那个真实案例证明的事:记忆只能帮助意图分类判断("这句话大概率还是在问水果"),但不能让检索环节把"有货吗"这三个字变成一句能查到东西的完整问题。
7.4 实用认知:重写要克制,扩写有成本
扩写的代价: 查询数翻几倍,检索延迟和调用成本也跟着涨。所以业内通常只对核心业务场景做扩写(比如"理赔咨询"这类高频、影响大的问题),简单FAQ不用扩。
重写也要克制: 模型对改写没把握时,宁可保留原始query,或者"原始问题+改写后的问题都查、结果合并",避免把用户本意改歪、越改越偏。
教学项目的取舍: 数据量小、场景简单,扩写这一步先不做,把"重写+指代消解"这一步跑通就够——这跟第5章"先跑通再优化"的方法论是同一个精神。
7.5 进阶技巧(了解即可,教学项目暂不需要)
HYDE(假设文档增强): 短查询(比如"等待期")关键词太少,向量"不够丰满",检索容易飘。反直觉的解法是:先让LLM根据问题编一段"可能的答案",把这段假答案向量化,再拿它去检索真实文档——假答案哪怕事实是错的也没关系,只是借它的"语义丰满度"来检索,最终回答仍然基于检索回来的真实资料。代价是多一次LLM调用,一般只在"短查询召回不好"时才用。
短期记忆 vs 长期记忆: 你们Query改写节点开的"记忆"开关、设的"记忆窗口",管的是短期记忆——只在这一次会话窗口里,记住"刚才聊了车厘子和凤梨",会话一断就可以丢。
但如果这个项目做到企业级成熟阶段,情况会不一样。类比淘宝这类成熟电商的AI导购:它能"记住"你,靠的不是这一次对话聊了什么,而是它手里握着长期记忆——你的用户标签(比如爱吃辣、母婴人群)、常用收货地址这类地点信息、购物车里放着什么、历史购买记录。这些信息不是"这次会话产生的",是跨会话、长期积累下来的,换个设备打开APP,它照样"记得你"。
短期记忆:靠"这次对话聊了什么"——数据来源是这次会话本身,
会话结束数据就可以丢,Dify的"记忆窗口"管的是这个
长期记忆:靠"这个用户是谁、有什么标签、历史行为是什么"——
数据来源不是对话,是用户画像、订单系统、购物车系统这些
独立的数据源,需要专门的存储(用户画像库、行为数据库),
Dify原生的"记忆"开关完全管不到这个
教学项目只有一个微信群、不区分用户身份,用短期记忆就够;真正做到淘宝级别的成熟企业应用,用户标签、地点信息、购物车信息这些长期记忆数据,才是"越用越懂你"这种体验的真正来源——这也是为什么大厂做AI导购,往往先花大量时间打通用户数据中台,而不是先纠结Prompt怎么写。
意图识别怎么做、意图太多怎么办这两块内容,跟"怎么建一个Query改写节点"关系不大,放到了实际搭建意图判断节点的第8章里,跟着真实界面一起讲。
7.6 实操:在Dify里搭建Query改写节点
在「开始」节点后插入一个新的LLM节点,命名为"Query改写"
配置模型
deepseek-flash(跟其他节点保持一致)打开这个节点的"对话历史"选项(跟其他需要记住历史的节点操作一样),确保Prompt里能引用到之前几轮的对话——没有这一步,节点根本看不到"上一轮聊的是车厘子和凤梨"这件事
配置Prompt:
你是一个查询改写助手。结合下面的对话历史,把用户最新这句话, 改写成一句独立、完整、清晰的问题。 如果这句话里有"它""这个""有货吗"这类指代或省略, 要结合历史补全清楚具体指的是什么; 如果这句话已经完整清楚,原样输出,不要画蛇添足。 对话历史: {对话历史占位符} 用户最新的话:{{#开始.query#}} 只输出改写后的问题,不要输出任何解释、不要加引号。关键的一步,也是最容易漏的一步: 从这个节点往后,所有原本引用
{{#开始.query#}}的地方,都要改成引用这个节点的输出变量{{#Query改写.text#}}——包括第8章意图判断节点的判断输入、第10章三个检索节点的"查询内容"变量、第11章三条Prompt里的"用户问题"这一行。漏改任何一处,这个节点等于白加了——后面的环节还是拿着用户那句"有货吗"去处理,没有用上改写后的完整问题。
7.7 验证:用你们已经验证过的真实案例测试
回顾开头那个真实场景:
第一轮:想买点水果,有什么推荐 → AI推荐车厘子和凤梨
第二轮:有货吗
→ 没有Query改写节点时:这句话直接被拿去检索,
跟"车厘子""凤梨"毫无关系,检索不到东西,
AI答非所问变成推荐草莓(这个坑记录在[附录A](appendix-a-troubleshooting.html))
→ 接了Query改写节点后,期望看到:
节点输出"车厘子和凤梨有货吗"这样补全后的完整问题
→ 检索节点拿这句话去查商品知识库
→ 生成回答基于车厘子/凤梨的真实信息作答,不再跑偏
验证方法: 在Dify的预览测试里,点开"Query改写"这个节点的运行详情,直接看它这一步实际输出的文本是什么——如果输出的还是"有货吗"三个字没有变化,说明对话历史没有正确传进这个节点,回去检查第3步"对话历史"选项有没有打开。
本章小结: 检索的效果,从用户那句话本身有没有被读懂就决定了;Query改写负责把省略、口语化的问题"翻译"成清晰完整的表达,跟"记忆"是完全不同的分工;这一章新加的"Query改写"节点插在最前面,但影响的是后面所有环节——意图判断、知识检索、生成回答,都要记得把输入源从原始问题切换成改写后的问题。