目录
Spring AI 介绍
Spring AI 组件介绍
Spring AI 结构化输出
Srping AI 多模态
Spring AI 本地Ollama
Spring AI 源码
Spring AI Advisor机制
Spring AI Tool Calling
Spring AI MCP
Spring AI RAG
Spring AI Agent
一、技术架构与核心流程
检索增强生成 (RAG) 的技术,用于解决将相关数据纳入提示以实现准确 AI 模型响应。
该方法涉及批处理风格的编程模型,其中作业从您的文档中读取非结构化数据,对其进行转换,然后将其写入矢量数据库。 概括地说,这是一个 ETL (提取、转换和加载) 管道。 向量数据库用于 RAG 技术的检索部分。
作为将非结构化数据加载到矢量数据库的一部分,最重要的转换之一是将原始文档拆分为更小的部分。 将原始文档拆分为较小部分的过程有两个重要步骤:
- 将文档拆分为多个部分,同时保留内容的语义边界。 例如,对于包含段落和表格的文档,应避免在段落或表格的中间拆分文档。 对于代码,请避免在方法实现的中间拆分代码。
- 将文档的各个部分进一步拆分为大小占 AI 模型令牌限制的一小部分。
RAG 的下一阶段是处理用户输入。 当 AI 模型要回答用户的问题时,该问题和所有“相似”文档片段都会被放入发送到 AI 模型的提示中。 这就是使用向量数据库的原因。它非常擅长寻找相似的内容。
1. 动态知识增强机制
RAG 通过实时检索外部知识库(如向量数据库)获取相关信息,再将检索结果作为上下文输入生成模型,解决传统大模型的“知识冻结”问题。
- 对比传统生成模型:
维度 | 传统生成模型 | RAG 架构 |
---|---|---|
知识更新 | 依赖训练数据时效性 | 实时检索最新数据 |
可解释性 | 黑盒生成 | 可追溯参考文档路径 |
2. 四大核心步骤
- 文档智能分块:
使用算法(如 TokenTextSplitter)将文档切割为语义连贯的片段,避免破坏表格、代码块等结构化内容。 - 向量编码:
通过嵌入模型(如 OpenAI Embeddings)将文本转化为数学向量,使语义相近的内容(如“续航时间”与“电池容量”)具有相似向量特征。 - 相似检索:
将用户问题编码为向量,通过相似度匹配(如余弦相似度)从知识库中检索最相关的文档片段。 - 生成增强:
将检索结果作为上下文输入生成模型(如 GPT-4),输出附带参考资料溯源路径的回答。
二、Spring AI 的模块化实现
1. 核心组件
- 检索模块:
- VectorStoreDocumentRetriever:基于向量数据库(如 Redis、PgVector)实现高效相似性检索。
- 支持动态过滤(如 similarityThreshold=0.5)和查询重写(RewriteQueryTransformer)。
- 生成模块:
- QuestionAnswerAdvisor:标准化流程,集成检索与生成,支持多模型切换(如 OpenAI/Qwen)。
2. 模块化扩展
- 预处理阶段:自定义文档分块策略(如按章节或语义边界切割)。
- 后处理阶段:对检索结果排序或加权(如时效性优先)。
三、优化策略与挑战
1. 性能调优
- 检索效率:
- 为分块添加标签(如“技术规格”“操作指南”)提升检索精准度。
- 使用多查询扩展技术,生成问题变体以提高检索覆盖率。
- 生成质量:
- 设置空上下文处理策略(allowEmptyContext=true)控制无匹配时的行为。
2. 典型挑战
- 语义连贯性:分块时需避免割裂上下文关联(如代码块拆分)。
- 向量对齐:不同嵌入模型生成的向量需保证语义空间一致性。
四、应用场景示例
1. 智能客服:回答时自动引用最新产品说明书或法律条文。
2. 内容生成:基于检索结果输出带参考文献路径的专业报告。
3. 推荐系统:如结合 22,000 种啤酒数据集生成精准推荐。
五、详解
1. Advisors
Advisor 工作机制
- 采用类似 WebFilter 的链式处理模式,通过 aroundCall 方法拦截请求/响应流
- 支持优先级控制(实现 Ordered 接口),默认预留 1000 个优先级槽位供扩展
- 通过 AdvisorContext 的 Map 结构实现数据在 Advisor 链中的流转
2. QuestionAnswerAdvisor
- RAG 流程封装
QuestionAnswerAdvisor 是 Spring AI 提供的开箱即用 RAG 组件,封装了检索(向量库查询)→ 上下文拼接 → 生成(LLM 调用)的完整流程,开发者仅需配置基础参数即可实现知识增强问答。 - 设计目标
通过标准化接口降低 RAG 实现复杂度,特别适合快速构建基于企业知识库的问答系统。 - 核心配置参数
QuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().similarityThreshold(0.5) // 相似度过滤阈值.topK(3) // 返回文档数量.filterExpression("a==b") // 元数据过滤条件.build()).build();
支持动态参数注入,如运行时通过 advisors(a -> a.param(“filterExpression”, “a==b”)) 修改过滤条件。
技术实现细节
-
检索阶段
- 自动将用户问题转换为向量查询
- 支持混合检索策略(语义+关键词)
- 结果存入响应元数据 RETRIEVED_DOCUMENTS 供后续评估
-
生成阶段
- 内置提示词模板拼接检索结果与原始问题
- 支持通过 ChatClient 绑定任意生成模型(如 GPT-4)
3. RetrievalAugmentationAdvisor
核心架构设计
1. 拦截器模式
继承 BaseAdvisor 接口实现双重拦截能力,同步调用通过 aroundCall 方法处理,异步流式调用通过 aroundStream 方法处理,采用责任链模式传递请求/响应16。
public interface BaseAdvisor extends CallAroundAdvisor, StreamAroundAdvisor {default AdvisedResponse aroundCall(AdvisedRequest request, CallAroundAdvisorChain chain) {AdvisedRequest processedRequest = before(request);AdvisedResponse response = chain.nextAroundCall(processedRequest);return after(response);}
}
2. 模块化流程
支持三阶段自定义扩展:
- 预检索:通过 QueryTransformer 实现查询重写或扩展(如 HyDE 策略)48
- 检索:集成向量数据库查询,支持相似度阈值过滤和元数据筛选34
- 后处理:通过 DocumentCompressor 压缩上下文长度,提升生成效率5
关键配置参数
RetrievalAugmentationAdvisor.builder().documentRetriever(VectorStoreDocumentRetriever.builder().vectorStore(weaviateVectorStore) // 绑定向量库.similarityThreshold(0.6) // 相似度过滤.filterExpression("category=='tech'") // 元数据过滤.build()).queryAugmenter(new HyDEQueryAugmenter()) // 查询增强.build();
支持动态注入运行时参数(如通过 advisors(a -> a.param(“filterExpression”, “status==‘active’”)) 修改过滤条件)。
核心特性
1. 优先级控制
实现 Ordered 接口,默认优先级为 HIGHEST_PRECEDENCE + 1000,允许通过 setOrder 调整执行顺序。
2. 上下文管理
自动将检索结果存入 AdvisorContext,可通过 RETRIEVED_DOCUMENTS 键值获取匹配文档列表,供后续评估或日志记录。
3. 错误降级机制
重写 after 方法可实现检索失败时的默认响应生成,保障服务可用性。
性能优化建议
1. 检索阶段
- 对高频查询实施 Redis 缓存,减少向量计算开销
- 使用 similarityThreshold 和 topK 平衡召回率与响应速度
- 生成阶段
- 通过 DocumentCompressor 移除冗余文本,降低 Token 消耗
- 监控 aroundCall 方法耗时定位瓶颈(如向量查询或 LLM 调用延迟)
扩展开发示例
1. 自定义检索器
public class HybridRetriever implements DocumentRetriever {@Overridepublic List<Document> retrieve(String query) {// 混合语义检索+关键词检索}
}
2. 动态查询增强
public class DynamicQueryAugmenter implements QueryAugmenter {@Overridepublic String augment(String query, Map<String,Object> context) {// 根据上下文重写查询}
}
Modules
pring AI 实现了一个模块化 RAG 架构
Pre-Retrieval
预检索模块负责处理用户查询以实现最佳检索结果。
查询转换
一个用于转换输入查询以使其更有效地执行检索任务、解决挑战的组件 例如格式不佳的查询、不明确的术语、复杂的词汇或不支持的语言。
- CompressionQueryTransformer
使用大型语言模型来压缩对话历史记录和后续查询 转换为捕获对话本质的独立查询。
Query query = Query.builder().text("And what is its second largest city?").history(new UserMessage("What is the capital of Denmark?"),new AssistantMessage("Copenhagen is the capital of Denmark.")).build();QueryTransformer queryTransformer = CompressionQueryTransformer.builder().chatClientBuilder(chatClientBuilder).build();Query transformedQuery = queryTransformer.transform(query);
- RewriteQueryTransformer
使用大型语言模型重写用户查询,以便在 查询目标系统,例如 Vector Store 或 Web 搜索引擎。
Query query = new Query("I'm studying machine learning. What is an LLM?");QueryTransformer queryTransformer = RewriteQueryTransformer.builder().chatClientBuilder(chatClientBuilder).build();Query transformedQuery = queryTransformer.transform(query);
- TranslationQueryTransformer
使用大型语言模型将查询转换为支持的目标语言 通过用于生成文档嵌入的嵌入模型。
Query query = new Query("Hvad er Danmarks hovedstad?");QueryTransformer queryTransformer = TranslationQueryTransformer.builder().chatClientBuilder(chatClientBuilder).targetLanguage("english").build();Query transformedQuery = queryTransformer.transform(query);
查询扩展
一个组件,用于将输入查询扩展为查询列表,以解决诸如格式不正确的查询等挑战 通过提供替代查询公式,或将复杂问题分解为更简单的子查询。
- MultiQueryExpander
使用大型语言模型将查询扩展为多个语义不同的变体 捕获不同的视角,有助于检索其他上下文信息和增加机会 找到相关结果。
MultiQueryExpander queryExpander = MultiQueryExpander.builder().chatClientBuilder(chatClientBuilder).numberOfQueries(3).build();
List<Query> queries = queryExpander.expand(new Query("How to run a Spring Boot app?"));
Retrieval
检索模块负责查询数据系统(如 vector store)并检索最相关的文档。
文件搜索
负责从底层数据源(如搜索引擎、向量存储、 数据库或知识图谱)。
- VectorStoreDocumentRetriever
从向量存储中检索语义上与输入相似的文档 查询。它支持根据元数据、相似性阈值和 top-k 结果进行筛选。
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder().vectorStore(vectorStore).similarityThreshold(0.73).topK(5).filterExpression(new FilterExpressionBuilder().eq("genre", "fairytale").build()).build();
List<Document> documents = retriever.retrieve(new Query("What is the main character of the story?"));
文档联接
一个组件,用于将基于多个查询和从多个数据源检索的文档合并到 单个文档集合。作为连接过程的一部分,它还可以处理重复文档和互惠 排名策略。
- ConcatenationDocumentJoiner
合并基于多个查询和多个数据源检索的文档 将它们连接到单个文档集合中。如果存在重复的文档,则保留第一次出现。 每个文档的分数保持原样。
Map<Query, List<List<Document>>> documentsForQuery = ...
DocumentJoiner documentJoiner = new ConcatenationDocumentJoiner();
List<Document> documents = documentJoiner.join(documentsForQuery);
Post-Retrieval
检索后模块负责处理检索到的文档,以实现最佳的生成结果。
一个组件,用于根据查询对检索到的文档进行后处理,解决诸如中间丢失、模型中的上下文长度限制以及减少检索信息中的噪声和冗余等挑战。
例如,它可以根据文档与查询的相关性对文档进行排名,删除不相关或冗余的文档,或者压缩每个文档的内容以减少干扰和冗余。
Generation
生成模块负责根据用户查询和检索到的文档生成最终响应。
查询扩充
一个组件,用于使用其他数据来扩充输入查询,可用于提供大型语言模型 替换为回答用户查询所需的上下文。
ContextualQueryAugmenter 使用来自所提供文档内容的上下文数据来增强用户查询。
QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().build();
六、ETL
提取、转换和加载 (ETL) 框架是检索增强生成 (RAG) 用例中数据处理的主干。
ETL 管道编排从原始数据源到结构化向量存储的流程,确保数据处于最佳格式,以便 AI 模型进行检索。
RAG 用例是文本,通过从数据主体中检索相关信息来提高生成输出的质量和相关性,从而增强生成模型的功能。
TL 管道创建、转换和存储实例。
ETL 管道有三个主要组件:
- DocumentReader实现Supplier<List>
- DocumentTransformer实现Function<List, List>
- DocumentWriter实现Consumer<List>
DocumentReader
public interface DocumentReader extends Supplier<List<Document>> {default List<Document> read() {return get();}
}
DocumentTransformer
public interface DocumentTransformer extends Function<List<Document>, List<Document>> {default List<Document> transform(List<Document> transform) {return apply(transform);}
}
DocumentWriter
public interface DocumentWriter extends Consumer<List<Document>> {default void write(List<Document> documents) {accept(documents);}
}
相关类
DocumentReader
Transformers
TextSplitter
一个抽象基类,可帮助划分文档以适应 AI 模型的上下文窗口。
TokenTextSplitter
使用 CL100K_BASE 编码根据令牌计数将文本拆分为块。
@Component
class MyTokenTextSplitter {public List<Document> splitDocuments(List<Document> documents) {TokenTextSplitter splitter = new TokenTextSplitter();return splitter.apply(documents);}public List<Document> splitCustomized(List<Document> documents) {TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true);return splitter.apply(documents);}
}
ContentFormatTransformer
这是一个使用生成式 AI 模型从文档内容中提取关键字并将其添加为元数据。
@Component
class MyKeywordEnricher {private final ChatModel chatModel;MyKeywordEnricher(ChatModel chatModel) {this.chatModel = chatModel;}List<Document> enrichDocuments(List<Document> documents) {KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(this.chatModel, 5);return enricher.apply(documents);}
}
KeywordMetadataEnricher
KeywordMetadataEnricher是一个DocumentTransformer,它使用生成式AI模型从文档内容中提取关键字并将其添加为元数据。
@Component
class MyKeywordEnricher {private final ChatModel chatModel;MyKeywordEnricher(ChatModel chatModel) {this.chatModel = chatModel;}List<Document> enrichDocuments(List<Document> documents) {KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(this.chatModel, 5);return enricher.apply(documents);}
}
SummaryMetadataEnricher
SummaryMetadataEnricher是一个DocumentTransformer,它使用生成式AI模型为文档创建摘要并将其添加为元数据。它可以为当前文档以及相邻文档(上一个和下一个)生成摘要。
@Configuration
class EnricherConfig {@Beanpublic SummaryMetadataEnricher summaryMetadata(OpenAiChatModel aiClient) {return new SummaryMetadataEnricher(aiClient,List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));}
}@Component
class MySummaryEnricher {private final SummaryMetadataEnricher enricher;MySummaryEnricher(SummaryMetadataEnricher enricher) {this.enricher = enricher;}List<Document> enrichDocuments(List<Document> documents) {return this.enricher.apply(documents);}
}
Writers
文件
FileDocumentWriter是一个DocumentWriter实现,它将文档对象列表的内容写入文件。
@Component
class MyDocumentWriter {public void writeDocuments(List<Document> documents) {FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, false);writer.accept(documents);}
}
VectorStore 矢量数据库
矢量数据库是一种特殊类型的数据库,在 AI 应用程序中起着至关重要的作用。
在矢量数据库中,查询不同于传统的关系数据库。 它们执行相似性搜索,而不是完全匹配。 当给定一个向量作为查询时,向量数据库会返回与查询向量“相似”的向量。