用 Spring AI Alibaba 打造智能查询增强引擎

news2026/3/27 20:12:29
用 Spring AI Alibaba 打造智能查询增强引擎系列导读在上一篇文章《基于 Spring AI Alibaba 构建混合 RAG Agent》中我们描绘了一套融合“侦探的灵活”与“会计的严谨”的架构蓝图。其中查询增强Query Enhancement被置于六大核心步骤之首。很多开发者会有疑问“大模型上下文窗口那么大直接把历史对话丢进去不就行了为什么还要多此一举去改写问题”本文将深入代码一线通过真实的QueryEnhancementHook实现为你揭示没有查询增强的 RAG就像让一个记忆力超群但耳朵背的专家去工作——他记得住所有书却听不清你在问什么。一、为什么“丰富的上下文”救不了检索在 RAG检索增强生成的流程中存在一个致命的时序错位用户提问“它多少钱”依赖上文检索阶段(Retrieval)系统拿着“它多少钱”去向量数据库搜索。失败数据库里没有“它”只有“iPhone 15”。生成阶段(Generation)系统把检索到的可能是错误的文档 完整的历史对话丢给 LLM。LLM 回答LLM 看着历史对话说“哦你刚才问的是 iPhone所以它是 8999 元。”发现问题了吗虽然 LLM 在最后一步通过上下文猜对了答案但检索阶段已经失败了。LLM 是基于“错误检索到的文档”在强行解释或者完全依靠它训练时的内部知识在回答这会导致幻觉且无法利用企业私有知识库。查询增强的核心价值就是在第 2 步检索发生之前把“它多少钱”改写成“iPhone 15 Pro Max 最新价格是多少”。只有问题清晰了检索才能精准只有检索精准了RAG 才有意义。二、代码实战Spring AI Alibaba 中的QueryEnhancementHook基于 Spring AI Alibaba 强大的AgentHook机制我们可以轻松在 Agent 执行前拦截请求完成“翻译”工作。以下是我们生产环境中的核心实现。1. Hook 的定义与入口我们定义了一个QueryEnhancementHook它继承自AgentHook并标注HookPositions({HookPosition.BEFORE_AGENT})确保它在任何工具调用或检索发生之前执行。Slf4jRequiredArgsConstructorHookPositions({HookPosition.BEFORE_AGENT})publicclassQueryEnhancementHookextendsAgentHook{privatefinalChatClientchatClient;// 用于执行重写的小模型OverridepublicStringgetName(){returnquery_enhancement;}OverridepublicCompletableFutureMapString,ObjectbeforeAgent(OverAllStatestate,RunnableConfigconfig){// ... 核心逻辑见下文拆解}}2. 核心三步走策略在beforeAgent方法中我们并没有盲目地调用大模型而是执行了严密的三步走策略第一步精准提取“当前意图”用户的消息列表里可能包含多轮对话我们需要锁定最后一条用户消息。// 提取历史消息ListMessagemessages(ListMessage)state.value(messages).orElse(List.of());// 【关键】获取最后一个有效的用户查询StringoriginalQuerymessages.stream().filter(msg-msginstanceofUserMessage).map(msg-((UserMessage)msg).getText()).reduce((first,second)-second)// 取最后一条.orElse();if(originalQuery.trim().isEmpty()){returnCompletableFuture.completedFuture(Map.of());// 无内容则跳过}第二步注入“长期记忆” (User Profile)这是本架构的亮点之一。传统的查询重写只依赖短期对话历史而忽略了用户是谁。我们通过config.store()加载用户的长期画像如职位、偏好、过往关注点。用户画像更新以及持久化应该在每次与LLM交互后进行后面会有详细介绍。// 加载长期记忆用户档案 偏好StringuserContextloadUserContext(config);// loadUserContext 内部逻辑// 1. 从 Store 获取 user_profiles/{userId}_profile// 2. 获取 user_profiles/{userId}_preferences// 3. 格式化为 prompt 的一部分例如// 【用户档案】// - 职位: 高级Java架构师// - 偏好: 喜欢简洁的代码示例不喜欢长篇理论场景举例用户问“推荐个方案。”无画像重写为“推荐一个技术方案。”太泛有画像重写为“为高级Java架构师推荐一个高并发微服务架构方案要求简洁的代码示例。”精准命中知识库第三步LLM 智能重写 (The Magic)构造一个精心设计的 Prompt调用chatClient进行重写。这里我们采用了降级策略如果 LLM 挂了直接返回原查询保证系统可用性。privateStringenhanceQueryLogic(StringcurrentQuery,ListMessagehistory,StringuserContext){// 构建对话历史上下文StringconversationHistoryhistory.stream().map(m-m.getMessageType(): m.getText()).collect(Collectors.joining(\n));// 动态指令长文本压缩 vs 短文本补全StringinstructioncurrentQuery.length()500?用户输入过长请压缩至 500 字以内保留关键实体消除歧义。:结合【对话历史】和【用户背景】消除指代歧义如它补充隐含主语使查询成为独立完整的陈述句。;StringpromptTextString.format( ### 角色 你是一个专业的查询重写专家。 ### 用户背景来自长期记忆 %s ### 对话历史短期记忆 %s ### 当前用户输入 %s ### 任务指令 %s ### 输出要求 1. 仅输出重写后的查询文本不要任何解释。 2. 必须利用【用户背景】补全缺失的主语或偏好。 3. 必须保留所有具体参数日期、ID、版本。 4. 如果原句已清晰则原样输出。 ### 重写后的查询 ,userContext,conversationHistory,currentQuery,instruction);try{// 调用 LLM 执行重写StringresultchatClient.prompt().user(promptText).call().content();returnresult!null?result.trim():currentQuery;}catch(Exceptione){log.warn(LLM 查询增强失败降级使用原始查询,e);returncurrentQuery;// 故障安全}}这里会从短期记忆中加载对话历史并注入上下文长对话可能超过 LLM 的上下文窗口。常见的解决方案包括修剪消息。在调用 LLM 之前移除前 N 条或后 N 条消息删除消息。从 Graph 状态中永久删除消息总结消息。总结历史中较早的消息并用摘要替换它们【推荐】自定义策略。自定义策略例如消息过滤等这允许 Agent 在 reasoning-acting 循环中持续跟踪对话而不超过 LLM 的上下文窗口。后面会介绍我的实现。3. 状态更新无缝替换一旦获得增强后的查询我们不是把它放在一边而是直接替换state中的消息列表。这样后续的 RAG 节点、Tool Router 拿到的就是已经“翻译”好的完美问题无需任何额外适配。if(!enhancedQuery.equals(originalQuery)){log.info(查询已增强[{}] - [{}],originalQuery,enhancedQuery);// 构建新消息列表仅替换最后一条 UserMessageListMessageenhancedMessagesnewArrayList(messages);intlastUserIndexfindLastUserMessageIndex(messages);// 辅助方法倒序查找if(lastUserIndex!-1){enhancedMessages.set(lastUserIndex,newUserMessage(enhancedQuery));}// 返回修改后的 stateSpring AI 会自动应用returnCompletableFuture.completedFuture(Map.of(messages,enhancedMessages));}三、效果对比有无增强的天壤之别让我们看两个真实场景的对比感受查询增强的威力。场景 A多轮对话中的指代消解步骤用户行为无增强 (传统 RAG)有增强(混合 RAG)Round 1用户“2026年的病假流程是什么”检索“2026年病假流程” ✅ 成功检索“2026年病假流程” ✅ 成功Round 2用户“那事假呢”检索“那事假呢” ❌失败(向量库无此句) 结果胡乱匹配或返回空重写“2026年的事假申请流程是什么” ✅成功(精准命中)Round 3用户“需要审批吗”检索“需要审批吗” ❌失败(不知道指哪个流程)重写“2026年事假申请流程需要审批吗” ✅成功(上下文完整)场景 B个性化偏好注入维度无增强有增强用户画像(系统未知)职位运维工程师偏好只要 Shell 脚本不要 Python用户提问“怎么重启服务”“怎么重启服务”重写结果“怎么重启服务”“Linux 环境下重启服务的Shell 脚本命令是什么”检索结果混杂了 Java、Python、Windows 的通用教程精准命中Linux Shell 相关文档最终体验用户需要二次追问“我要 Shell 版的”一次命中用户感觉 AI“懂我”四、避坑指南与最佳实践在实现过程中我们也踩过一些坑总结以下几点供参考不要过度重写如果用户的问题已经很清晰如“什么是 Spring Boot”LLM 可能会画蛇添足。对策在 Prompt 中明确强调“如果当前输入已经非常清晰且无指代则原样输出”。性能与成本的平衡查询增强需要额外调用一次 LLM。对策使用小模型如 Qwen-Turbo 或本地部署的 7B 模型专门做重写速度快、成本低。配合语义缓存本系列下一篇重点高频问题直接缓存根本不需要触发重写和检索。容错设计LLM 可能会超时或报错。对策务必像代码中那样做try-catch降级。增强是“锦上添花”不能因为增强失败导致整个对话不可用。Fail-fast, fallback to original.五、结语查询增强Query Enhancement绝不是多余的步骤它是连接人类模糊语言与机器精准检索的唯一桥梁。通过 Spring AI Alibaba 的AgentHook我们不仅实现了指代消解更将长期用户画像融入到了检索的源头。这使得我们的 RAG 系统不再是一个冷冰冰的搜索引擎而是一个能听懂“弦外之音”、记得住“老客喜好”的智能助手。下一步预告问题清楚了检索也精准了但如果每次都要重新查一遍速度够快吗下一篇我们将深入语义缓存Semantic Cache的实现揭秘如何让高频问题实现“毫秒级”响应进一步降低 Token 成本

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2433966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…