AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 47|检索增强生成 RAG · RAG 架构:混合 RAG

混合 RAG 结合了两步 RAG 和 Agentic RAG 的特点。它引入了中间步骤,如查询预处理、检索验证和生成后检查。这些系统比固定管道提供更多灵活性,同时保持对执行的一定控制。

典型组件包括:

  • 查询增强:修改输入问题以提高检索质量。这可能涉及重写不清晰的查询、生成多个变体或用额外上下文扩展查询。
  • 检索验证:评估检索到的文档是否相关且充分。如果不够,系统可能会优化查询并再次检索。
  • 答案验证:检查生成的答案的准确性、完整性以及与源内容的一致性。如果需要,系统可以重新生成或修订答案。

架构通常支持这些步骤之间的多次迭代:

Spring AI Alibaba RAG

Java 实现示例

混合 RAG 使用 ReactAgent 整合多工具检索和验证步骤:

import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.hook.AgentHook;
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.agent.hook.HookPositions;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelInterceptor;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelRequest;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelResponse;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelCallHandler;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import org.springframework.ai.document.Document;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.ChatModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

// 假设你已经有一个配置好的向量存储和 ChatModel
VectorStore vectorStore = ...;
ChatModel chatModel = ...;

// ========== 1. 多工具检索(来自 Agentic RAG) ==========

// 文档搜索工具
class DocumentSearchTool {
  private final VectorStore vectorStore;

  public DocumentSearchTool(VectorStore vectorStore) {
      this.vectorStore = vectorStore;
  }

  public record Request(String query) {}
  public record Response(String content) {}

  public Response search(Request request) {
      List<Document> docs = vectorStore.similaritySearch(
          org.springframework.ai.vectorstore.SearchRequest.builder()
              .query(request.query())
              .topK(5)
              .build()
      );
      String content = docs.stream()
          .map(Document::getText)
          .collect(Collectors.joining("

"));
      return new Response(content);
  }
}

// 网络搜索工具(示例)
class WebSearchTool {
  public record Request(String query) {}
  public record Response(String content) {}

  public Response search(Request request) {
      // 实际实现中调用网络搜索 API
      return new Response("网络搜索结果: " + request.query());
  }
}

DocumentSearchTool docSearchTool = new DocumentSearchTool(vectorStore);
WebSearchTool webSearchTool = new WebSearchTool();

ToolCallback documentSearchCallback = FunctionToolCallback.builder("document_search",
  (Function<DocumentSearchTool.Request, DocumentSearchTool.Response>)
  req -> docSearchTool.search(req))
  .description("从文档库中搜索相关信息")
  .inputType(DocumentSearchTool.Request.class)
  .build();

ToolCallback webSearchCallback = FunctionToolCallback.builder("web_search",
  (Function<WebSearchTool.Request, WebSearchTool.Response>)
  req -> webSearchTool.search(req))
  .description("从互联网搜索最新信息")
  .inputType(WebSearchTool.Request.class)
  .build();

// ========== 2. 查询增强 Hook(来自两步 RAG) ==========

@HookPositions({HookPosition.BEFORE_AGENT})
class QueryEnhancementHook extends AgentHook {
  private final ChatModel chatModel;
  private static final String ENHANCED_QUERY_KEY = "enhanced_query";

  public QueryEnhancementHook(ChatModel chatModel) {
      this.chatModel = chatModel;
  }

  @Override
  public String getName() {
      return "query_enhancement";
  }

  @Override
  public CompletableFuture<Map<String, Object>> beforeAgent(OverAllState state, RunnableConfig config) {
      // 从状态中提取用户查询
      Optional<Object> messagesOpt = state.value("messages");
      if (messagesOpt.isEmpty()) {
          return CompletableFuture.completedFuture(Map.of());
      }

      @SuppressWarnings("unchecked")
      List<Message> messages = (List<Message>) messagesOpt.get();

      // 提取最后一个用户消息作为查询
      String userQuery = messages.stream()
          .filter(msg -> msg instanceof UserMessage)
          .map(msg -> ((UserMessage) msg).getText())
          .reduce((first, second) -> second) // 获取最后一个
          .orElse("");

      if (userQuery.isEmpty()) {
          return CompletableFuture.completedFuture(Map.of());
      }

      // 使用 LLM 增强查询(只执行一次,在整个 Agent 执行过程中)
      // 简化示例:实际可以使用 RewriteQueryTransformer
      String enhancedQuery = enhanceQuery(userQuery);

      // 如果查询被增强,更新消息列表
      if (!enhancedQuery.equals(userQuery)) {
          List<Message> enhancedMessages = new ArrayList<>();
          // 保留系统消息和其他消息,只替换用户消息
          for (Message msg : messages) {
              if (msg instanceof UserMessage) {
                  enhancedMessages.add(new UserMessage(enhancedQuery));
              } else {
                  enhancedMessages.add(msg);
              }
          }

          // 将增强后的查询存储到 metadata 中,供后续使用
          config.metadata().ifPresent(meta -> {
              meta.put(ENHANCED_QUERY_KEY, enhancedQuery);
          });

          // 返回更新后的消息列表
          return CompletableFuture.completedFuture(Map.of("messages", enhancedMessages));
      }

      return CompletableFuture.completedFuture(Map.of());
  }

  private String enhanceQuery(String query) {
      // 简化示例:实际可以使用 RewriteQueryTransformer 或调用 LLM 进行查询重写
      // 这里只是示例,实际应该调用 LLM 增强查询
      // 例如:使用 RewriteQueryTransformer.builder().chatClientBuilder(...).build().transform(query)
      return query; // 实际实现中会调用 LLM 增强查询
  }
}

// ========== 3. 答案验证 Interceptor(来自两步 RAG) ==========

class AnswerValidationInterceptor extends ModelInterceptor {
  private final ChatModel chatModel;
  private static final double MIN_CONFIDENCE = 0.7;

  public AnswerValidationInterceptor(ChatModel chatModel) {
      this.chatModel = chatModel;
  }

  @Override
  public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
      // 先调用模型生成答案
      ModelResponse response = handler.call(request);

      // 验证答案质量(简化示例)
      AssistantMessage answer = response.getResult().getOutput();
      boolean isValid = validateAnswer(answer.getText(), request);

      if (!isValid) {
          // 如果答案质量不足,可以添加提示要求重新生成
          SystemMessage validationPrompt = new SystemMessage(
              "请重新检查你的答案,确保基于提供的上下文信息,并且准确完整。"
          );

          ModelRequest retryRequest = ModelRequest.builder(request)
              .systemMessage(validationPrompt)
              .build();

          // 可以选择重试或返回当前答案
          return handler.call(retryRequest);
      }

      return response;
  }

  private boolean validateAnswer(String answer, ModelRequest request) {
      // 简化示例:实际可以使用 LLM 验证答案与上下文的一致性
      // 检查答案长度、是否包含关键信息等
      return answer != null && answer.length() > 20; // 简单验证
  }

  @Override
  public String getName() {
      return "answer_validation";
  }
}

// ========== 4. 创建混合 RAG Agent ==========

ReactAgent hybridRAGAgent = ReactAgent.builder()
  .name("hybrid_rag_agent")
  .model(chatModel)
  .instruction("""
      你是一个智能助手,可以访问多个信息源来回答问题。

      使用工具时:
      1. 优先使用 document_search 搜索文档库
      2. 如果需要最新信息,使用 web_search
      3. 基于检索到的信息生成准确、完整的答案
      4. 如果信息不足,可以多次调用工具
      """)
  .tools(documentSearchCallback, webSearchCallback)
  .hooks(new QueryEnhancementHook(chatModel))
  .interceptors(new AnswerValidationInterceptor(chatModel))
  .build();

// ========== 5. 使用混合 RAG Agent ==========

AssistantMessage response = hybridRAGAgent.call("Spring AI Alibaba支持哪些向量数据库?");
System.out.println("答案: " + response.getText());

混合 RAG 的特点:

  1. 多工具检索(Agentic RAG):Agent 可以自主选择使用文档搜索、网络搜索等工具
  2. 查询增强(两步 RAG):在 Agent 开始时通过 AgentHook 增强查询(只执行一次,避免每次 reasoning 循环都调用,降低成本),提高检索质量
  3. 答案验证(两步 RAG):在生成后通过 Interceptor 验证答案质量,必要时重新生成
  4. 灵活组合:结合了 Agentic RAG 的灵活性和两步 RAG 的质量控制

性能优化:使用 AgentHook 进行查询增强,只在 Agent 开始时执行一次,而不是每次模型调用前都执行,显著降低了 LLM 调用成本。

这种架构适用于:

  • 具有模糊或不明确查询的应用
  • 需要验证或质量控制步骤的系统
  • 领域特定的问答系统,要求高准确性
  1. 选择合适的架构:

    简单 FAQ → 两步 RAG
    复杂研究任务 → Agentic RAG
    需要质量保证 → 混合 RAG

  2. 优化检索质量:

    使用合适的文本分割策略
    选择高质量的嵌入模型
    实现查询重写和扩展

  3. 控制上下文大小:

    限制检索到的文档数量
    使用文档排序和过滤
    考虑模型的上下文窗口限制

  4. 监控和评估:

    跟踪检索质量指标
    评估答案准确性
    收集用户反馈

  5. 性能优化:

    缓存常见查询的检索结果
    使用异步检索
    批量处理文档嵌入

本文整理自 Spring AI Alibaba 官方文档《检索增强生成 RAG》:https://java2ai.com/docs/frameworks/agent-framework/advanced/rag

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 47|检索增强生成 RAG · RAG 架构:混合 RAG

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册