1. RAG策略架构设计的必要性
在基于Spring Boot和Spring AI构建的智能问答系统时,很多开发者会直接将RAG(检索增强生成)逻辑硬编码到对话流程中。这种看似简单的实现方式,随着业务复杂度提升会暴露出诸多问题。
典型的硬编码实现通常表现为:
java复制// 典型的问题实现方式
public String chat(String userInput) {
// 直接调用向量库检索
List<Document> docs = vectorStore.similaritySearch(userInput);
// 拼接Prompt
String prompt = buildPrompt(userInput, docs);
// 调用LLM生成
return llm.generate(prompt);
}
这种实现方式在初期确实简单直接,但当系统进入生产环境后,会面临以下挑战:
-
策略僵化问题:不同业务场景需要不同的检索策略。FAQ类问题适合关键词检索,技术文档需要向量检索,而制度类文档可能需要混合检索。硬编码实现无法灵活切换策略。
-
算法迭代困难:当需要对比BM25、向量检索或混合检索效果时,需要修改核心业务代码,违反开闭原则。
-
场景适配不足:某些场景如闲聊或推理问题本应跳过RAG流程,但硬编码实现难以动态关闭检索环节。
-
多租户支持薄弱:不同租户可能使用不同知识库,需要定制化检索策略,硬编码方式会导致大量条件判断语句。
-
功能扩展瓶颈:当需要新增如重排序(re-rank)或父文档检索(Parent-Document Retrieval)等高级功能时,代码会变得臃肿且难以维护。
关键设计原则:RAG组件应该作为独立策略模块存在,而非嵌入在业务流程中的固定代码块。这类似于电商系统中支付模块的设计 - 业务方不需要关心具体是支付宝还是微信支付,只需调用统一接口。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 可插拔架构的核心设计
2.1 三层架构设计
生产级RAG系统应采用清晰的三层架构:
code复制策略接口层 (RagStrategy)
├── 具体策略实现 (VectorOnly/HybridSearch/ParentDocument等)
上下文层 (RagContext)
策略工厂层 (RagStrategyFactory)
2.1.1 策略接口设计
定义统一的策略接口是解耦的关键:
java复制public interface RagStrategy {
/**
* 判断是否支持当前请求
* @param request 检索请求
* @return 是否支持
*/
boolean support(RagRequest request);
/**
* 执行检索操作
* @param request 检索请求
* @return 标准化结果
*/
RagResult retrieve(RagRequest request);
}
接口设计的几个关键点:
- 支持性检查:通过support()方法实现策略路由,不同策略可以基于query内容、知识库类型或业务标签决定是否处理该请求
- 统一返回格式:所有策略必须返回标准化的RagResult,确保上层调用方处理逻辑一致
- 无状态设计:策略实现应为无状态组件,所有上下文信息通过RagRequest传递
2.1.2 请求与响应模型
标准化输入输出是策略可替换的基础:
java复制public class RagRequest {
private String query; // 用户原始查询
private String knowledgeBaseId;// 知识库标识
private String tenantId;
