关于 spring-ai-integration
面向 Java 开发者的 Spring AI 集成参考技能,帮助在 Spring 应用中构建 LLM 功能,涵盖聊天、记忆、提示词、结构化输出、RAG、流式响应及 GA 版本用法。
主要功能
- 01ChatClient 配置与用法
- 02对话记忆与提示词模板
- 03结构化输出映射
- 04RAG 流程配置
- 05流式响应
- 06Spring AI GA 迁移指引
适用场景
- 01使用 Spring AI 构建聊天服务
- 02按用户隔离对话历史
- 03构建检索增强生成流程
- 04返回结构化或流式模型响应
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ rrezartprebreza/ spring-boot-skills --skill spring-ai-integration安装后在 Claude Code 中输入/spring-ai-integration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlexamples/bad-ai-service.javagood-ai-service.javatemplates/AiServiceTemplate.javaanalyze-order.st详细介绍
Spring AI 集成
依赖项
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
</dependencies>
注意制品名称。 1.0 GA 移除了旧的
spring-ai-<x>-spring-boot-starter坐标。现在的命名模式为spring-ai-starter-model-<provider>(例如-model-anthropic、-model-openai)和spring-ai-starter-vector-store-<store>。基于 GA 前 Spring AI 训练的 Agent 会生成已失效的名称——这些名称在 Maven Central 中无法解析。
ChatClient — 基本用法
@Service
@RequiredArgsConstructor
public class DocumentSummaryService {
private final ChatClient chatClient;
public String summarize(String conversationId, String content) {
return chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(u -> u.text("Summarize the following document in 3 bullet points:\n\n{content}")
.param("content", content))
.call()
.content();
}
// With system prompt
public String analyzeFinancial(String conversationId, String document, String language) {
return chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.system("You are a financial analyst. Respond in {language}.")
.system(s -> s.param("language", language))
.user(document)
.call()
.content();
}
}
使用已配置的记忆顾问进行的每次调用,都必须提供用户级或会话级的 ChatMemory.CONVERSATION_ID。切勿让所有用户共用同一个会话 ID。
ChatClient Bean 配置
@Configuration
public class AiConfig {
@Bean
public ChatMemory chatMemory() {
// 1.0 GA: InMemoryChatMemory is GONE. Use MessageWindowChatMemory —
// it caps history to a sliding window and defaults to an in-memory repository.
return MessageWindowChatMemory.builder()
.maxMessages(20)
.build();
}
@Bean
public ChatClient chatClient(ChatClient.Builder builder, ChatMemory chatMemory) {
return builder
.defaultSystem("You are a helpful assistant for an e-commerce platform.")
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // GA: builder, not new(...)
new SimpleLoggerAdvisor() // logs prompts/responses
)
.build();
}
}
提示词模板(外部化)
// src/main/resources/prompts/analyze-order.st
// Analyze this order and identify any anomalies:
// Customer: {customerEmail}
// Items: {items}
// Total: {total}
// Flag any unusual patterns.
@Service
@RequiredArgsConstructor
public class OrderAnalysisService {
private final ChatClient chatClient;
@Value("classpath:prompts/analyze-order.st")
private Resource promptTemplate;
public String analyzeOrder(String conversationId, Order order) {
return chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(u -> u.text(promptTemplate)
.param("customerEmail", order.getCustomerEmail()) // must match {customerEmail} in the .st
.param("items", order.getItems().toString())
.param("total", order.getTotal()))
.call()
.content();
}
}
结构化输出
// Define the target record
public record OrderClassification(
String category,
String priority,
List<String> tags,
boolean requiresManualReview
) {}
@Service
public class OrderClassifier {
public OrderClassification classify(String orderDescription) {
return chatClient.prompt()
.user("Classify this order: " + orderDescription)
.call()
.entity(OrderClassification.class); // Spring AI handles JSON parsing
}
}
RAG 流水线
@Configuration
public class RagConfig {
// No manual VectorStore bean — the spring-ai-starter-vector-store-pgvector
// starter auto-configures one. Just inject it. (The old `new PgVectorStore(...)`
// constructor is removed in GA; if you must build one, use PgVectorStore.builder(...).)
@Bean
public ChatClient ragChatClient(ChatClient.Builder builder, VectorStore vectorStore) {
return builder
.defaultAdvisors(
QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().topK(5).build()) // GA: builder, not defaults().withTopK()
.build()
)
.build();
}
}
@Service
@RequiredArgsConstructor
public class KnowledgeService {
private final VectorStore vectorStore;
private final ChatClient ragChatClient;
// Ingest documents
public void ingest(List<String> documents) {
List<Document> docs = documents.stream()
.map(content -> new Document(content))
.toList();
vectorStore.add(docs);
}
// Query with RAG
public String ask(String question) {
return ragChatClient.prompt()
.user(question)
.call()
.content();
}
}
流式响应
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String prompt) {
return chatClient.prompt()
.user(prompt)
.stream()
.content();
}
application.yml
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: ${ANTHROPIC_MODEL}
max-tokens: 2048
temperature: 0.7
# OR for OpenAI:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: ${OPENAI_MODEL}
vectorstore:
pgvector:
initialize-schema: true
dimensions: 1536
注意事项
- Agent 在
.st文件中写的是{customerEmail}时,却绑定了.param("customer", ...)——默认渲染器会报错"Not all variables were replaced";请确保参数名称与模板占位符完全一致 - Agent 使用 GA 前的制品名称(
spring-ai-anthropic-spring-boot-starter)——GA 版本使用spring-ai-starter-model-anthropic - Agent 编写
new MessageChatMemoryAdvisor(new InMemoryChatMemory())——这两个类在 GA 版本中都已移除;请改用MessageChatMemoryAdvisor.builder(chatMemory)和MessageWindowChatMemory - Agent 编写
SearchRequest.defaults().withTopK(n)——GA 版本使用SearchRequest.builder().topK(n).build() - Agent 将 API 密钥硬编码——请始终使用环境变量 /
${...} - Agent 将提供商模型 ID 硬编码——请在外部配置,因为模型目录会变化
- Agent 通过字符串拼接来构建提示词——请使用
.param()模板变量 - Agent 将提示词直接写在代码中——请将其外部化到
src/main/resources/prompts/ - Agent 忽略结构化输出——请使用
.entity(MyClass.class),而不是手动解析 - Agent 使用
.entity(List.class)返回列表——泛型会被擦除;请传入new ParameterizedTypeReference<List<X>>() {} - Agent 跳过 API 调用的错误处理——请使用 try/catch,并区分处理
NonTransientAiException(不要重试)与TransientAiException(重试) - Agent 忘记为记忆顾问设置用户级
conversationId——所有用户会共用一份聊天记录 - Agent 使用了错误的模型字符串——请根据提供商文档核对模型名称
评论
支持 Markdown