本文将深入解析 Spring AI 中的 DocumentTransformer 和检索增强生成(RAG)模块,详细讲解每个核心类的功能、参数、使用方法以及高级技巧。通过结合实际代码示例和应用场景,帮助开发者全面掌握这些组件的使用。


一、Spring AI 中的 DocumentTransformer

DocumentTransformer 是 Spring AI ETL(Extract, Transform, Load)管道的关键组件,负责对文档执行转换操作,确保数据以最优格式进入后续的存储和检索阶段。

1.1 核心功能与实现类

DocumentTransformer 提供了多种实现类,每种实现类针对不同的转换需求提供了专门的功能。

1.1.1 TextSplitter:文档切割

功能描述

TextSplitter 用于将长文档切割成更小的文本块,以适应 AI 模型的上下文窗口限制。

核心实现类:TokenTextSplitter

  • 基于 Token 分割:采用 CL100K_BASE 编码,支持按 Token 数量分割文本。
  • 参数解析
    • defaultChunkSize:每个文本块的目标 Token 数量(默认 800)。
    • minChunkSizeChars:每个文本块的最小字符数(默认 350)。
    • minChunkLengthToEmbed:可嵌入分块的最小长度(默认 5)。
    • maxNumChunks:单个文本生成的最大分块数(默认 10000)。
    • keepSeparator:是否保留分隔符(默认 true)。

使用示例

TokenTextSplitter splitter = new TokenTextSplitter(500, 200, 10, 10000, true);
List<Document> splitDocuments = splitter.apply(documents);

高级技巧

  • 动态分块:根据文档类型动态调整分块大小。例如,技术文档可采用更小的分块以保留细节。
  • 分块优化:在分块时尽量保持语义完整性,避免在句子中间切割。

效果

  • 提高检索效率:小块文档更容易与查询匹配。
  • 节省内存:避免加载整个文档到内存。

1.1.2 ContentFormatTransformer:元数据格式化

功能描述

ContentFormatTransformer 将文档中的元数据转换为键值对格式,确保数据一致性。

核心实现

  • 模板配置:支持自定义元数据格式模板。
  • 参数解析
    • formatTemplate:指定元数据格式的模板字符串。
    • metadataKey:指定存储格式化后元数据的键。

使用示例

ContentFormatTransformer transformer = new ContentFormatTransformer(
    "{ \\\\"title\\\\": \\\\"%s\\\\", \\\\"author\\\\": \\\\"%s\\\\" }",
    "formatted_metadata"
);
List<Document> transformedDocs = transformer.apply(documents);

高级技巧

  • 统一格式:在多源数据整合时,统一元数据格式以便后续检索和分析。
  • 嵌套结构支持:通过复杂模板支持嵌套元数据结构。

效果

  • 提升数据一致性:确保所有文档的元数据格式统一。
  • 便于检索:格式化的元数据更容易被检索系统使用。

1.1.3 SummaryMetadataEnricher:摘要生成

功能描述

SummaryMetadataEnricher 利用 AI 模型为文档生成摘要,并将其存储为元数据。

核心实现

  • 摘要模板:支持自定义摘要生成模板。
  • 参数解析
    • chatModel:用于生成摘要的 AI 模型。
    • summaryTypes:指定生成摘要的类型(如当前文档摘要、前文档摘要、后文档摘要)。
    • summaryTemplate:自定义摘要生成模板。

使用示例

SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(
    chatModel,
    List.of(SummaryType.CURRENT, SummaryType.NEXT),
    "简洁风格摘要模板"
);
List<Document> enrichedDocs = enricher.apply(documents);

高级技巧

  • 上下文感知摘要:结合前后文档内容生成上下文感知的摘要。
  • 多风格支持:通过模板生成不同风格的摘要(如专业风格、通俗风格)。

效果

  • 快速定位核心内容:摘要信息帮助用户快速理解文档主题。
  • 提升检索效率:摘要作为元数据可加速文档检索。

1.1.4 KeywordMetadataEnricher:关键词提取

功能描述

KeywordMetadataEnricher 从文档内容中提取关键词,并将其添加到元数据中。

核心实现

  • 关键词数量:支持指定提取的关键词数量。
  • 参数解析
    • chatModel:用于提取关键词的 AI 模型。
    • keywordCount:指定提取的关键词数量。

使用示例

KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 5);
List<Document> enrichedDocs = enricher.apply(documents);

高级技巧

  • 自定义关键词:通过提示词模板自定义关键词提取逻辑。
  • 多语言支持:结合翻译模型提取多语言关键词。

效果

  • 提升文档可检索性:关键词作为元数据可提高文档检索精度。
  • 支持文档分类:关键词可用于文档的自动分类和标签生成。

1.2 高级功能与组合使用

1.2.1 组合多个转换器

通过 ChainingDocumentTransformer,可以将多个 DocumentTransformer 实现类组合在一起,形成强大的转换流水线。

使用示例

DocumentTransformer transformerPipeline = new ChainingDocumentTransformer(
    new ContentFormatTransformer(),
    new TokenTextSplitter(500, 200, true),
    new SummaryMetadataEnricher(chatModel, 3)
);
List<Document> transformedDocs = transformerPipeline.apply(documents);

效果

  • 流水线处理:文档依次经过格式化、分块和摘要生成,最终输出标准化的文档集合。
  • 灵活性:支持按需组合不同的转换器,适应多样化需求。

1.2.2 并行处理

利用 ParallelDocumentTransformer,可以加速大规模文档转换任务。

使用示例

DocumentTransformer parallelTransformer = new ParallelDocumentTransformer(
    new TokenTextSplitter(500, 200, true),
    4 // 线程数量
);
List<Document> transformedDocs = parallelTransformer.apply(documents);

效果

  • 性能提升:多线程处理显著减少文档转换时间。
  • 资源优化:合理利用 CPU 资源,提高系统吞吐量。

二、Spring AI 中的 RAG(检索增强生成)

RAG 是 Spring AI 的核心模块之一,通过检索相关文档并结合生成模型,提供精准的回答。以下将详细解析 RAG 的核心组件及其使用方法。

以下类图展示了 ETL 核心接口与实现类的关系架构。

2.1 RAG 的核心组件

2.1.1 QuestionAnswerAdvisor

功能描述

QuestionAnswerAdvisor 是一个开箱即用的 Advisor,用于执行检索增强生成(RAG)。它通过查询向量数据库获取与用户问题相关的文档,并将这些文档作为上下文提供给 AI 模型。

核心参数

  • vectorStore:向量数据库实例,用于存储和检索文档。
  • searchRequest:检索配置,包括相似度阈值、返回结果数量等。

使用示例

QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
    .searchRequest(SearchRequest.builder()
        .similarityThreshold(0.8d)
        .topK(6)
        .build())
    .build();

String response = ChatClient.builder(chatModel)
    .build()
    .prompt()
    .advisors(qaAdvisor)
    .user("What is the capital of Denmark?")
    .call()
    .content();

高级技巧

  • 动态过滤器:通过 FILTER_EXPRESSION 参数动态更新检索过滤条件。
  • 自定义模板:使用 promptTemplate 方法自定义上下文与用户查询的合并逻辑。

效果

  • 精准回答:基于检索到的文档生成精准的回答。
  • 上下文增强:附加的文档上下文帮助模型生成更准确的内容。

2.1.2 RetrievalAugmentationAdvisor

功能描述

RetrievalAugmentationAdvisor 是一个更灵活的 Advisor,支持构建自定义 RAG 流程。它集成了文档检索和查询增强功能。

核心参数

  • documentRetriever:文档检索器,用于从向量数据库检索文档。
  • queryAugmenter:查询增强器,用于处理用户查询并生成增强后的查询。

使用示例

Advisor advisor = RetrievalAugmentationAdvisor.builder()
    .documentRetriever(VectorStoreDocumentRetriever.builder()
        .vectorStore(vectorStore)
        .similarityThreshold(0.5)
        .topK(3)
        .build())
    .queryAugmenter(ContextualQueryAugmenter.builder()
        .allowEmptyContext(true)
        .build())
    .build();

String response = chatClient.prompt()
    .user("机器人有哪些功能?")
    .advisors(advisor)
    .call()
    .content();

高级技巧

  • 多查询扩展:结合 MultiQueryExpander 生成多个查询变体,提高检索召回率。
  • 查询重写:使用 RewriteQueryTransformer 优化查询结构,提升检索精度。

效果

  • 自动化流程:无缝集成文档检索和查询处理,简化开发工作。
  • 智能回答:基于增强后的查询生成更智能的回答。

2.1.3 ContextualQueryAugmenter

功能描述

ContextualQueryAugmenter 用于增强用户查询,通过附加检索到的文档内容生成更丰富的查询上下文。

核心参数

  • allowEmptyContext:是否允许空上下文查询。
  • maxTokens:查询上下文的最大 Token 数量。
  • temperature:控制查询扩展的创造性。

使用示例

ContextualQueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder()
    .allowEmptyContext(true)
    .maxTokens(300)
    .temperature(0.7)
    .build();

高级技巧

  • 上下文感知:结合历史对话生成上下文感知的查询。
  • 多轮对话支持:在多轮对话中动态更新查询上下文。

效果

  • 增强上下文:生成的查询包含更丰富的上下文信息,帮助模型生成更准确的回答。
  • 对话连贯性:保持多轮对话的连贯性,提升用户体验。

2.1.4 VectorStoreDocumentRetriever

功能描述

VectorStoreDocumentRetriever 用于从向量数据库检索与查询语义相似的文档。

核心参数

  • vectorStore:向量数据库实例。
  • similarityThreshold:文档匹配的最低相似度阈值。
  • topK:返回的文档数量。
  • filterExpression:基于元数据的过滤条件。

使用示例

DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .similarityThreshold(0.5)
    .topK(3)
    .filterExpression(new FilterExpressionBuilder()
        .eq("type", "tutorial")
        .build())
    .build();

List<Document> documents = retriever.retrieve(query);

高级技巧

  • 复杂过滤:使用 FilterExpressionBuilder 构建复杂的过滤条件。
  • 动态调整:根据查询动态调整相似度阈值和返回结果数量。

效果

  • 精准检索:基于相似度和元数据过滤返回最相关的文档。
  • 高效性:快速从大规模文档集合中定位目标文档。

2.2 RAG 的高级技巧与优化策略

2.2.1 多查询扩展与重写

通过结合 MultiQueryExpander 和 RewriteQueryTransformer,可以显著提升检索的召回率和精度。

使用示例

MultiQueryExpander queryExpander = MultiQueryExpander.builder()
    .chatClientBuilder(chatClientBuilder)
    .numberOfQueries(3)
    .includeOriginal(false)
    .build();

List<Query> expandedQueries = queryExpander.expand(new Query("What is AI?"));

RewriteQueryTransformer queryRewriter = RewriteQueryTransformer.builder()
    .chatClientBuilder(chatClientBuilder)
    .build();

Query rewrittenQuery = queryRewriter.transform(new Query("What is AI?"));

效果

  • 提高召回率:多查询扩展生成多个相关查询,增加检索结果的覆盖面。
  • 提升精度:查询重写优化查询结构,使检索结果更精准。

2.2.2 上下文感知查询

在多轮对话中,利用 CompressionQueryTransformer 处理带有上下文的查询,消除歧义并提高回答的准确性。

使用示例

Query query = Query.builder()
    .text("What is the capital of that country?")
    .history(
        new UserMessage("Which country has the largest population in Europe?"),
        new AssistantMessage("The country with the largest population in Europe is Germany.")
    )
    .build();

QueryTransformer contextTransformer = CompressionQueryTransformer.builder()
    .chatClientBuilder(chatClientBuilder)
    .build();

Query transformedQuery = contextTransformer.transform(query);

效果

  • 消除歧义:将模糊的查询转换为明确的查询(如 "What is the capital of Germany?")。
  • 对话连贯性:保持多轮对话的连贯性,提升用户体验。

2.2.3 文档合并与去重

使用 ConcatenationDocumentJoiner 合并来自多个查询或数据源的文档,并去除重复内容。

使用示例

DocumentJoiner documentJoiner = new ConcatenationDocumentJoiner();
List<Document> mergedDocuments = documentJoiner.join(documentsForQuery);

效果

  • 统一文档集合:将多个来源的文档合并为一个统一的文档集合。
  • 去重:自动去除重复文档,避免冗余信息。

2.2.4 错误处理与边界情况

通过配置 ContextualQueryAugmenter 和合理的异常处理机制,可以优雅地处理文档未找到或相似度过低的情况。

使用示例

Advisor advisor = RetrievalAugmentationAdvisor.builder()
    .queryAugmenter(ContextualQueryAugmenter.builder()
        .allowEmptyContext(true)
        .build())
    .documentRetriever(retriever)
    .build();

String response = chatClient.prompt()
    .user("What is the capital of Mars?")
    .advisors(advisor)
    .call()
    .content();

效果

  • 友好提示:当未找到相关文档时,返回友好的提示信息。
  • 引导用户:引导用户提供更多上下文信息,以生成更准确的回答。

2.3 RAG 的性能优化策略

2.3.1 向量存储优化

选择合适的向量存储方案,并根据数据规模优化存储配置。

使用示例

VectorStore vectorStore = SimpleVectorStore.builder(embeddingModel)
    .build();

优化建议

  • 内存存储:适用于小规模数据集的快速开发和测试。
  • 分布式存储:使用 Redis 或 MongoDB 等分布式存储方案,支持大规模数据集。

2.3.2 检索器配置优化

通过合理配置相似度阈值和返回结果数量,优化检索性能。

使用示例

DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .similarityThreshold(0.5)
    .topK(3)
    .build();

优化建议

  • 动态调整阈值:根据查询类型动态调整相似度阈值。
  • 限制结果数量:控制返回结果数量,避免过多不相关文档。

2.3.3 缓存机制

对频繁访问的文档启用缓存,减少重复计算和检索开销。

使用示例

CachingDocumentRetriever cachedRetriever = new CachingDocumentRetriever(retriever, 1000);

优化建议

  • 合理设置缓存大小:根据内存资源和文档访问频率设置缓存大小。
  • 缓存失效策略:定期清理过期缓存,确保数据新鲜度。

三、实战案例:构建智能文档检索系统

以下是一个完整的实战案例,展示如何使用 DocumentTransformer 和 RAG 模块构建智能文档检索系统。

3.1 配置类

@Configuration
public class DocumentProcessingConfig {

    @Bean
    public TikaDocumentReader tikaReader() {
        return new TikaDocumentReader("classpath:documents/");
    }

    @Bean
    public DocumentTransformer transformerChain() {
        return new ChainingDocumentTransformer(
            new ContentFormatTransformer(),
            new TokenTextSplitter(500, 200, true)
        );
    }

    @Bean
    public VectorStore vectorStore() {
        return new SimpleVectorStore(embeddingModel);
    }

    @Bean
    public QuestionAnswerAdvisor qaAdvisor() {
        return QuestionAnswerAdvisor.builder(vectorStore)
            .searchRequest(SearchRequest.builder()
                .similarityThreshold(0.8d)
                .topK(6)
                .build())
            .build();
    }
}

3.2 处理流程

@Service
public class DocumentProcessingService {

    @Autowired
    private TikaDocumentReader reader;

    @Autowired
    private DocumentTransformer transformer;

    @Autowired
    private VectorStore vectorStore;

    public void process() {
        // 读取文档
        List<Document> docs = reader.read();

        // 转换文档
        List<Document> transformedDocs = transformer.apply(docs);

        // 写入向量数据库
        vectorStore.add(transformedDocs);
    }
}

3.3 检索增强

@RestController
public class RetrievalController {

    @Autowired
    private ChatClient chatClient;

    @Autowired
    private QuestionAnswerAdvisor qaAdvisor;

    @PostMapping("/retrieve")
    public String retrieveDocuments(@RequestBody QueryRequest request) {
        String answer = chatClient.prompt()
            .user(request.getQuery())
            .advisors(qaAdvisor)
            .call()
            .content();
        return answer;
    }
}

3.4 高级功能集成

多查询扩展与重写结合

MultiQueryExpander queryExpander = MultiQueryExpander.builder()
    .chatClientBuilder(chatClientBuilder)
    .numberOfQueries(3)
    .includeOriginal(false)
    .build();

RewriteQueryTransformer queryRewriter = RewriteQueryTransformer.builder()
    .chatClientBuilder(chatClientBuilder)
    .build();

List<Query> expandedQueries = queryExpander.expand(new Query("What is AI?"));
Query rewrittenQuery = queryRewriter.transform(new Query("What is AI?"));

上下文感知查询

Query query = Query.builder()
    .text("What is the capital of that country?")
    .history(
        new UserMessage("Which country has the largest population in Europe?"),
        new AssistantMessage("The country with the largest population in Europe is Germany.")
    )
    .build();

QueryTransformer contextTransformer = CompressionQueryTransformer.builder()
    .chatClientBuilder(chatClientBuilder)
    .build();

Query transformedQuery = contextTransformer.transform(query);


3.5 完整高级检索

// 1. 初始化向量存储
SimpleVectorStore vectorStore = SimpleVectorStore.builder(embeddingModel)
        .build();

// 2. 配置AI助手角色
ChatClient chatClient = builder
        .defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\\\\n" +
                "1. 准确理解用户的具体需求\\\\n" +
                "2. 结合参考资料中的实际案例\\\\n" +
                "3. 提供专业的设计理念和原理解释\\\\n" +
                "4. 考虑实用性、美观性和成本效益\\\\n" +
                "5. 如有需要,可以提供替代方案")
        .build();

// 3. 构建复杂的文档过滤条件
var b = new FilterExpressionBuilder();
var filterExpression = b.and(
        b.and(
                b.eq("year", "2023"),         // 筛选2023年的案例
                b.eq("location", "indoor")),   // 仅选择室内案例
        b.and(
                b.eq("type", "interior"),      // 类型为室内设计
                b.in("room", "living_room", "study", "kitchen")  // 指定房间类型
));

// 4. 配置文档检索器
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
        .vectorStore(vectorStore)
        .similarityThreshold(0.5)    // 设置相似度阈值
        .topK(3)                     // 返回前3个最相关的文档
        .filterExpression(filterExpression.build())
        .build();

// 5. 创建上下文感知的查询增强器
Advisor advisor = RetrievalAugmentationAdvisor.builder()
        .queryAugmenter(ContextualQueryAugmenter.builder()
                .allowEmptyContext(true)
                .build())
        .documentRetriever(retriever)
        .build();

// 6. 执行查询并获取响应
String userQuestion = "根据已经提供的资料,请描述所有相关的场景风格,输出案例编号,尽可能详细地描述其内容。";
String response = chatClient.prompt()
        .user(userQuestion)
        .advisors(advisor)
        .call()
        .content();

四、总结

Spring AI 的 DocumentTransformer 和 RAG 模块提供了强大的工具集,帮助开发者构建高效的文档处理和检索系统。通过合理选择和配置这些组件,可以显著提升文档处理效率和检索精度。

  • DocumentTransformer:通过多样化的转换功能(如分块、格式化、摘要生成、关键词提取)确保数据以最优格式进入后续流程。
  • RAG 模块:通过检索增强生成技术,结合文档检索和生成模型,提供精准的回答。

高级技巧总结

  • 组合使用:通过 ChainingDocumentTransformer 组合多个转换器,形成强大的转换流水线。
  • 并行处理:利用 ParallelDocumentTransformer 加速大规模文档转换任务。
  • 多查询扩展:结合 MultiQueryExpander 和 RewriteQueryTransformer 提升检索召回率和精度。
  • 上下文感知:利用 CompressionQueryTransformer 处理带有上下文的查询,消除歧义并提高回答的准确性。
  • 文档合并:使用 ConcatenationDocumentJoiner 合并来自多个查询或数据源的文档,并去除重复内容。

通过深入理解和灵活运用这些组件,开发者可以构建高效、智能的文档处理和检索系统,满足复杂业务场景的需求。

欢迎查看文章:Spring AI 中的 DocumentTransformer 与 RAG 深度解析 | Honesty Blog

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐