Spring AI Alibaba ——检索增强生成(RAG)

💡 核心结论:一句话先记住 如果说大模型是一个"脑容量有限且不上网"的万事通(知识停留在被训练好的那一年,而且记不住海量企业文件),那么 RAG(检索增强生成) 就是给它配了一个"实时联网的企业私有资料库"。每次回答问题前,先去资料库里查一查,带着资料再开口,从此告别胡说八道!


🛑 一、 为什么需要 RAG?(大模型的两个致命伤)

  1. 有限的上下文(脑容量小): 它们无法一次性摄取整个语料库,你不可能把全公司的文档一次性塞进它的聊天框。
  2. 静态知识(知识被冻结): 它们的训练数据在某个时间点就被冻结了,不知道最新的业务动态和私有数据。

大白话解药: 检索(Retrieval)通过在查询时获取相关的外部知识来解决这些问题。RAG 的基础就是:使用特定上下文的信息来增强 LLM 的回答,产生基于事实的答案。


📁 二、 怎么搭一个 RAG?(两大核心步骤)

  1. 构建知识库 (Knowledge Base)

大白话: 也就是存放你用来检索的文档或结构化数据的存储库。

  • 从零建库: 你可以使用 Spring AI Alibaba 提供的"文档加载器"和"向量存储"从你自己的数据(如 PDF、Word)从头构建。
  • 用现成的库: 如果你已经有一个知识库(例如现有的 SQL 数据库、CRM 或内部文档系统),千万别重建它! 你可以直接:
    1. 将其连接为 Agent 的工具,用于 Agentic RAG
    2. 直接查询它,并将检索到的内容作为上下文提供给 LLM,用于 两步 RAG
  1. Spring AI Alibaba RAG 组件与构建模块

框架为你提供了一整套数据流水线上的"零件"(模块化 RAG 架构):

  • 文档加载器和解析器: 从外部源(文件、数据库、云存储等)摄取数据,返回标准化的文档对象。
  • 文本分割器: 把大型长文档切碎成更小的块,方便单独检索,也能塞进模型的上下文窗口。
  • 嵌入模型 (Embedding Model): 把文字变成机器能理解的数字向量。
  • 向量存储 (Vector Store): 专门用于存储和搜索嵌入的数据库。
  • 检索器 (Retriever): 负责在用户提问时,找出最相关的文档块。

🏛️ 三、 RAG 的三大架构流派(核心玩法)

  1. 两步 RAG (Two-step RAG) ------ 规矩老实人

大白话: 检索步骤总是在生成步骤之前执行。每次用户提问,系统先默默去查库,查到了资料,再把资料和问题一起交给大模型。

  • 优点: 架构简单、可预测。因为 LLM 调用的最大次数是已知且有上限的(就1次),延迟相对好控制(主要受网络和数据库查询速度影响)。
  • 适用场景: 明确需要查资料才能回答的业务场景。

💻 两步 RAG 代码展示(使用 Hook 拦截塞入资料): 在 Spring AI Alibaba 中,官方推荐使用 MessagesModelHookModelInterceptor 在模型调用前"偷塞"资料。

Java 复制代码
// 使用 MessagesModelHook 实现两步 RAG
import com.alibaba.cloud.ai.graph.agent.hook.ModelHook;

ModelHook ragHook = new MessagesModelHook() {
    @Override
    public CompletableFuture<Map<String, Object>> beforeModel(OverAllState state, RunnableConfig config) {
        // 1. 拿到用户提问
        String userQuery = (String) state.get("input");
        
        // 2. 从检索器中找出相关文档块
        List<Document> docs = retriever.retrieve(userQuery);
        String context = docs.stream().map(Document::getContent).collect(Collectors.joining("\n"));
        
        // 3. 把知识拼接到消息列表里喂给大模型
        List<Message> messages = (List<Message>) state.value("messages").orElse(new ArrayList<>());
        messages.add(new SystemMessage("请严格根据以下参考资料回答问题:\n" + context));
        
        return CompletableFuture.completedFuture(Map.of("messages", messages));
    }
};

// 挂载到 Agent 身上
ReactAgent agent = ReactAgent.builder()
        .name("two_step_rag_agent")
        .model(chatModel)
        .hooks(ragHook) // 拦截发功
        .build();
  1. Agentic RAG ------ 聪明智能体

大白话: 把你的系统(SQL 库、内部 Wiki)封装成工具 (Tool) 给 Agent。大模型拿到问题后,自己评估"这题我会不会?要不要用工具查?查几次?"。

  • 优点: 极其灵活,能处理复杂的复合问题。
  • 缺点: 延迟不可控,它可能来回调用好几次工具才给你最终答案。

💻 Agentic RAG 代码展示(把数据库变成工具):

Java 复制代码
// 封装查询现有系统的工具
ToolCallback dbSearchTool = FunctionToolCallback.builder("search_internal_db", (query) -> {
    return myDatabaseService.queryData(query);
}).description("当需要查询内部业务数据时,务必调用此工具").build();

// Agent 直接拿工具干活
ReactAgent agenticRagAgent = ReactAgent.builder()
        .name("agentic_rag_agent")
        .model(chatModel)
        .tools(dbSearchTool) // ⭐ 丢给它工具,让它自己判断何时调用
        .build();
  1. 混合 RAG (Hybrid RAG) ------ 究极缝合怪

大白话: 小孩子才做选择,大人全都要。在实际应用中,通常会将上述策略结合起来,或者在检索底层同时使用"关键词检索"+"向量检索"来保证极高的召回率和准确率。


🏆 四、 最佳实践总结

不要将 RAG 仅仅停留在"检索出一段文字"上。大多数实际应用需要更进一步:将检索与生成深度集成,产生基于事实的、上下文感知的答案。 采用模块化 RAG 架构(将加载、切分、检索解耦),可以让你在未来轻松替换组件(比如升级更强的向量数据库或嵌入模型)。


🎯 终极秒记口诀 模型脑子不够用,旧库僵化不顶用; RAG 把外脑来接通,找准资料再播送; 加载切分向量化,模块组件立大功; 两步 RAG Hook 塞,Agentic 工具向前冲!