Spring AI 集成实战:从 Prompt 模板到 RAG 管道的全链路方案
Spring AI 集成实战:从 Prompt 模板到 RAG 管道的全链路方案
一、裸调 API 的集成困局——企业级大模型接入的工程断层
在 Java 后端体系中集成大模型能力,最常见的做法是直接使用 HTTP 客户端调用模型供应商的 REST API。这种"裸调"方式在 POC 阶段快速验证可行,但在企业级生产环境中会暴露出一系列工程断层。
第一,Prompt 管理混乱。Prompt 模板散落在各个 Service 类的字符串常量中,修改一个 Prompt 需要重新部署应用。不同开发者的 Prompt 风格不统一,变量占位符格式各异(有的用 {},有的用 ${},有的用 Mustache),缺乏标准化管理。
第二,上下文窗口浪费。大模型的上下文窗口是稀缺资源,GPT-4o 的 128K Token 看似充裕,但系统指令、Few-shot 示例、对话历史和用户查询叠加后,很容易触及上限。没有合理的上下文裁剪策略,要么关键信息被截断,要么 Token 被无效内容浪费。
第三,RAG 管道缺乏框架支撑。检索增强生成(RAG)需要文档切分、向量化、检索、重排序、上下文组装等多个环节串联。每个环节用不同库实现,接口不统一,切换向量数据库或重排序模型时需要大量重构。
Spring AI 作为 Spring 生态的 AI 集成框架,提供了从 Prompt 模板到 RAG 管道的全链路抽象。本文将深入分析其架构设计,并给出生产级的集成方案。
二、Spring AI 的分层架构——从模型抽象到 RAG 编排
Spring AI 的核心设计理念是"模型可替换、管道可编排"。通过分层抽象,将模型调用、Prompt 管理、向量存储和 RAG 管道解耦,使每个环节可以独立替换和优化。
flowchart TB
subgraph 应用层
A[ChatService] --> B[DocumentQAService]
end
subgraph Spring AI 核心抽象
C[ChatClient 统一调用接口]
D[Prompt Template 模板引擎]
E[Advisors 拦截器链]
end
subgraph RAG 管道
F[DocumentReader 文档读取]
G[DocumentTransformer 文档切分]
H[EmbeddingModel 向量化]
I[VectorStore 向量存储与检索]
J[QuestionAnswerAdvisor RAG 顾问]
end
subgraph 模型适配层
K[OpenAI ChatModel]
L[DeepSeek ChatModel]
M[Ollama ChatModel]
end
A --> C
B --> J
C --> D
C --> E
J --> I
I --> H
F --> G --> H
E --> K
E --> L
E --> M
ChatClient 是 Spring AI 的统一调用入口,类似于 Spring 的 RestTemplate 或 WebClient。它封装了模型选择、Prompt 组装、Advisor 拦截和响应解析的完整流程。
Advisors 是 Spring AI 的拦截器机制,类似于 Servlet Filter。可以在请求发送前修改 Prompt,在响应返回后进行后处理。RAG 的上下文注入、对话历史的裁剪、内容安全过滤等都可以通过 Advisor 实现。
VectorStore 抽象了向量数据库的读写接口,支持 Milvus、PgVector、Chroma、Redis 等多种实现,切换向量数据库只需更换依赖和配置,无需修改业务代码。
三、生产级代码:Spring AI 全链路集成实现
3.1 Prompt 模板管理与动态变量注入
/**
* Prompt 模板服务:集中管理所有业务场景的 Prompt 模板
* 模板使用 Spring AI 的 PromptTemplate 语法,
* 支持 {variable} 占位符和条件逻辑
*/
@Service
public class PromptTemplateService {
private final Map<String, PromptTemplate> templateRegistry;
/**
* 初始化时加载所有模板文件
* 模板文件存放在 classpath:prompts/ 目录下,
* 支持 .st(Spring AI 模板)格式
*/
@PostConstruct
public void loadTemplates() {
templateRegistry = new HashMap<>();
// 加载代码审查模板
templateRegistry.put("code-review",
new PromptTemplate("""
你是一位资深的代码审查专家,请对以下代码进行审查。
审查维度:
1. 代码规范:命名、格式、注释
2. 潜在缺陷:空指针、资源泄漏、并发问题
3. 性能风险:不必要的对象创建、低效算法
4. 安全隐患:SQL注入、XSS、敏感信息泄露
编程语言:{language}
代码片段:
```
{code}
```
请按维度逐一给出审查意见,标注严重等级(高/中/低)。
"""
)
);
}
/**
* 渲染模板:注入变量并生成 Prompt
* 变量缺失时抛出异常,避免模型收到不完整的 Prompt
*/
public Prompt render(String templateName, Map<String, Object> variables) {
PromptTemplate template = templateRegistry.get(templateName);
if (template == null) {
throw new IllegalArgumentException(
"模板不存在: " + templateName
);
}
// 校验必需变量是否全部提供
Set<String> requiredVars = template.getInputTypes().keySet();
for (String var : requiredVars) {
if (!variables.containsKey(var)) {
throw new IllegalArgumentException(
"模板 " + templateName + " 缺少必需变量: " + var
);
}
}
return template.create(variables);
}
}
3.2 RAG 管道:文档切分、向量化与检索增强
/**
* RAG 文档问答服务:完整的检索增强生成管道
* 流程:用户提问 -> 向量检索相关文档片段 -> 组装上下文 -> 调用模型生成回答
*/
@Service
public class DocumentQAService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
private final TokenCountEstimator tokenEstimator;
/**
* 构建带 RAG Advisor 的 ChatClient
* QuestionAnswerAdvisor 自动完成"检索 + 上下文注入"流程
*/
public DocumentQAService(ChatClient.Builder clientBuilder,
VectorStore vectorStore,
TokenCountEstimator tokenEstimator) {
this.vectorStore = vectorStore;
this.tokenEstimator = tokenEstimator;
this.chatClient = clientBuilder
.defaultAdvisors(
// RAG 顾问:检索相关文档并注入到 Prompt 上下文
new QuestionAnswerAdvisor(vectorStore,
SearchRequest.builder()
.topK(5) // 检索 Top5 相关片段
.similarityThreshold(0.75) // 相似度阈值
.build()
),
// 对话历史顾问:裁剪历史消息,控制上下文窗口
new MessageChatMemoryAdvisor(
new InMemoryChatMemory(),
ChatMemory.CONVERSATION_ID_KEY,
10 // 保留最近 10 轮对话
)
)
.build();
}
/**
* 文档问答接口
* 自动完成检索增强,无需手动组装上下文
*/
public String ask(String question, String conversationId) {
return chatClient.prompt()
.user(question)
.system("""
你是一个专业的技术文档助手。请基于提供的上下文文档回答用户问题。
如果上下文中没有相关信息,请明确说明"文档中未找到相关信息",
不要编造答案。
""")
.advisors(a -> a
.param(ChatMemory.CONVERSATION_ID_KEY, conversationId)
)
.call()
.content();
}
/**
* 导入文档到向量库
* 包含切分策略和元数据标注
*/
public void importDocument(Resource document, String docType) {
// 文档切分:按段落切分,保留语义完整性
TextSplitter splitter = new TokenTextSplitter(
800, // 每个片段目标 Token 数
200, // 相邻片段重叠 Token 数
5, // 最大片段数上限
10000, // 单片段最大字符数
true // 保留分隔符
);
List<Document> chunks = splitter.split(
new TextReader(document).get()
);
// 为每个片段添加元数据,便于后续过滤
chunks.forEach(chunk ->
chunk.getMetadata().put("doc_type", docType)
);
// 批量写入向量库(Spring AI 自动调用 EmbeddingModel 向量化)
vectorStore.add(chunks);
}
}
3.3 多模型切换与降级配置
# application.yml - Spring AI 多模型配置
spring:
ai:
# 默认模型配置
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0.3
max-tokens: 2048
# 备选模型:DeepSeek(通过 OpenAI 兼容接口)
deepseek:
base-url: https://api.deepseek.com
api-key: ${DEEPSEEK_API_KEY}
chat:
options:
model: deepseek-chat
temperature: 0.3
# 向量模型配置
embedding:
options:
model: text-embedding-3-small
# 向量数据库配置
vectorstore:
milvus:
client: ${MILVUS_HOST:localhost}
port: 19530
database-name: ai_docs
collection-name: document_chunks
dimension: 1536
metric-type: COSINE
四、Spring AI 的成熟度边界与生产风险
1. 框架成熟度与 API 稳定性
Spring AI 目前仍在快速迭代中,API 在小版本升级时可能发生不兼容变更。例如 1.0.0-M5 到 M6 之间,ChatClient 的构建方式从 Builder 模式变更为流式 API。在生产项目中引入 Spring AI,需要锁定版本并预留升级适配的工作量。
2. 向量数据库的性能瓶颈
Spring AI 的 VectorStore 抽象虽然统一了接口,但不同向量数据库的性能差异巨大。Milvus 在百万级向量检索时 P99 延迟约 50ms,而 PgVector 在同等数据量下可能达到 500ms。框架层的抽象屏蔽了这些差异,但也意味着开发者无法利用特定数据库的优化特性。
3. RAG 的检索质量瓶颈
RAG 的回答质量高度依赖检索的准确性。Top-K 检索可能返回语义相似但无关的片段,导致模型生成"看似合理但事实错误"的回答。Spring AI 的 QuestionAnswerAdvisor 目前不支持重排序(Reranking),需要自行集成 Cohere Reranker 或 BGE-Reranker 等模型。
4. Advisor 链的执行顺序敏感性
多个 Advisor 的执行顺序直接影响结果。例如,对话历史裁剪 Advisor 应在 RAG Advisor 之前执行,否则裁剪后的历史可能导致 RAG 检索方向偏移。Spring AI 的 Advisor 排序机制目前不够直观,需要开发者手动管理优先级。
| 风险维度 | 影响程度 | 缓解策略 |
|---|---|---|
| API 不兼容 | 高 | 锁定版本 + 升级适配测试 |
| 向量库性能 | 中 | 基准测试选型 + 读写分离 |
| 检索准确率 | 高 | 引入 Reranking + 人工评测 |
| Advisor 排序 | 中 | 显式声明顺序 + 集成测试 |
五、总结
Spring AI 为 Java 生态提供了大模型集成的标准化方案,其核心价值在于将 Prompt 管理、模型调用、RAG 管道和向量存储统一到 Spring 编程模型中。通过 ChatClient 和 Advisor 机制,开发者可以用声明式的方式组装 AI 能力,而不必关心底层模型供应商的差异。
落地路线建议:第一步,在非核心业务中引入 Spring AI 的 ChatClient 和 PromptTemplate,建立 Prompt 管理规范;第二步,对知识库问答场景搭建 RAG 管道,从文档切分到向量检索全链路验证;第三步,引入 Advisor 拦截器实现对话历史裁剪和内容安全过滤;第四步,在 RAG 管道中增加 Reranking 环节提升检索准确率,并建立人工评测机制持续优化。