文章目录打破 Top-K 限制跨向量聚合问题的 Text-to-SQL 解决方案引言问题分析为什么向量检索做不了聚合三种解决方案对比架构设计核心实现RagTool定义聚合查询工具注册工具到 ChatClientSuperSQL 配置SuperSqlIntegrationService为什么用 Tool Calling 而不用 Router验证效果小结打破 Top-K 限制跨向量聚合问题的 Text-to-SQL 解决方案引言RAG 系统有一个隐藏的致命盲区它无法处理聚合类查询。当用户问张三出现在哪些班级“时答案可能分散在 20 个不同的文档片段中。但向量检索的 Top-K 机制只返回最相关的 5 个片段剩下 15 个信息全部丢失。大模型只能基于 5 个片段回答张三出现在 5 个班级”——这是错误的。这就是跨向量聚合难题。本文将介绍如何通过Text-to-SQL Spring AI Tool Calling解决这个问题让 LLM 在识别到聚合类问题时自动调用 SQL 查询工具从关系型数据库中获取精确结果。问题分析为什么向量检索做不了聚合向量检索的本质是找最像的不是找所有的用户问artisan这个热词出现了多少次 向量检索返回Top-5个包含artisan的片段LLM基于5个片段回答可能只看到了部分数据向量检索擅长的是语义理解“报销流程是什么”不擅长的是精确统计“出现了多少次”。三种解决方案对比方案核心思路优点缺点适用场景知识库隔离一个文件一个知识库零噪音仍受 Top-K 限制多租户Text-to-SQL结构化查询分流到 SQL精确支持复杂逻辑需维护两套库统计/聚合Map-Reduce分批总结再汇总能处理全文多次 LLM 调用全局总结本项目采用Text-to-SQL方案通过 SuperSQL 引擎实现自然语言到 SQL 的转换。架构设计用户提问artisan这个热词出现了多少次│ ▼LLM分析意图 → 识别为聚合操作│ ▼ 自动调用ToolRagTool.getAggregationQuery(question)│ ├─→SuperSQL:自然语言 →SQL│SELECT word, count_num FROM word_frequency WHERE word artisan│ ├─→ 执行SQL获取结果 │[{word:artisan,count_num:45}]│ └─→ 返回JSON给LLM│ ▼LLM基于SQL结果生成自然语言回答artisan这个热词一共出现了 45 次。关键设计让 LLM 自己决定是否调用工具而不是由开发者硬编码路由规则。核心实现RagTool定义聚合查询工具ServicepublicclassRagTool{AutowiredprivateSpringSqlEnginesqlEngine;AutowiredprivateChatModelchatModel;Tool(description涉及统计数据、求和、计数、平均值等聚合操作)publicStringgetAggregationQuery(ToolParam(description用户的提问)Stringquestion){// 1. Text-to-SQL自然语言转 SQLStringactualSqlsqlEngine.setChatModel(chatModel).setOptions(RagOptions.builder().topN(10).rerank(false).limitScore(0.1).build()).generateSql(question);// 2. 执行 SQLObjectobjectsqlEngine.executeSql(actualSql);// 3. 返回 JSON 结果returnJSON.toJSONString(object);}}Tool(description ...)是 Spring AI 的工具注解。LLM 会根据这段描述判断何时调用——当用户问题涉及统计、求和、计数、平均值时LLM 会自动选择调用这个工具。注册工具到 ChatClientthis.chatClientChatClient.builder(chatModel).defaultSystem(DEFAULT_SYSTEM_PROMPT).defaultAdvisors(...).defaultTools(ragTool)// 注册工具.build();SuperSQL 配置super-sql:init-train:false# 首次设为 true 训练表结构之后改为 falsescope:ALONE# 单库训练schemas:-schema:xushu_rag# 指定数据库首次启动时设置init-train: trueSuperSQL 会读取xushu_rag数据库的所有表结构DDL学习表名、字段名和关系。训练完成后改为false。SuperSqlIntegrationServiceServicepublicclassSuperSqlIntegrationService{AutowiredprivateSpringSqlEnginesqlEngine;publicStringgenerateSql(Stringquestion){StringsqlsqlEngine.generateSql(question);log.info(SuperSQL 生成: question{}, sql{},question,sql);returnsql;}publicvoidtrainWithDDL(Stringddl){TrainBuildertrainBuilderTrainBuilder.builder().content(ddl).policy(TrainPolicyType.DDL).build();sqlEngine.train(trainBuilder);}}为什么用 Tool Calling 而不用 Router代码中注释了一种 Router 方案// Router 方案已弃用booleanisSqlchatClient.prompt().system(用户的查询是否涉及统计数据).user(message).call().entity(Boolean.class);这种方案的问题每次对话都需要额外一次 LLM 调用做意图识别增加延迟和 API 成本意图识别本身可能不准确Tool Calling 的优势LLM 在生成回答的过程中自动判断是否需要调用工具不需要额外的意图识别步骤少一次远程调用。验证效果聚合查询用户出现次数最多的前5个热词是什么 生成SQLSELECTword,count_numFROMword_frequencyORDERBYcount_numDESCLIMIT5AI出现次数最多的前5个热词是1.报销-45次2.流程-38次...普通问题不触发 Tool用户公司的报销流程是什么 →LLM判断不是聚合问题走正常RAG向量检索小结Text-to-SQL Tool Calling 是解决 RAG 聚合难题的高性价比方案Tool注解声明式定义工具LLM 自动决策SuperSQL 将自然语言转为 SQL无需手写查询向量检索和 SQL 查询互补覆盖所有查询场景核心理念让 LLM 自己判断用什么工具解决什么问题