Spring AI入门教程 - 从零开始学习Spring AI框架
Spring AI入门教程 - 从零开始学习Spring AI框架
目录
1. Spring AI简介
Spring AI是Spring官方推出的AI应用开发框架,旨在简化AI应用的开发过程。它提供了统一的API来集成各种AI模型和服务,包括OpenAI、Anthropic、Azure OpenAI、Google Vertex AI等。
主要特性:
✅ 统一的API:提供统一的接口访问不同的AI模型
✅ 多模型支持:支持OpenAI、Anthropic、Azure OpenAI等多种模型
✅ 向量数据库集成:支持Pinecone、Weaviate、Chroma等向量数据库
✅ RAG支持:内置RAG(检索增强生成)功能
✅ Spring生态集成:完美集成Spring Boot、Spring Data等
✅ 函数调用:支持AI函数调用功能
✅ 流式响应:支持流式输出响应
智能问答系统:构建基于知识的问答系统
文档分析:自动分析和总结文档
代码生成:AI辅助代码生成
内容创作:自动生成文章、摘要等
数据分析:智能数据分析和洞察
聊天机器人:构建智能对话系统
| 特性 | Spring AI | LangChain4j | 直接调用API |
|---|---|---|---|
| Spring集成 | ✅ 完美集成 | ⚠️ 需要适配 | ❌ 无 |
| 统一API | ✅ 是 | ✅ 是 | ❌ 否 |
| 向量数据库 | ✅ 内置支持 | ✅ 支持 | ❌ 需自己实现 |
| RAG支持 | ✅ 内置 | ✅ 支持 | ❌ 需自己实现 |
| 学习曲线 | ✅ 平缓 | ⚠️ 中等 | ⚠️ 陡峭 |
- Java版本:JDK 17或更高版本
- Spring Boot版本:3.2.0或更高版本
- Maven/Gradle:最新版本
2. 环境搭建
方式一:使用Spring Initializr
- 访问 https://start.spring.io/
- 选择项目配置:
- Project: Maven
- Language: Java
- Spring Boot: 3.2.0+
- Group: com.example
- Artifact: spring-ai-demo
- 添加依赖:
- Spring Web
- Spring AI OpenAI
- 点击Generate下载项目
方式二:使用IDE创建
- 打开IntelliJ IDEA
- File → New → Project
- 选择Spring Initializr
- 配置项目信息
- 添加依赖
方式三:手动创建
创建pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-ai-demo</artifactId>
<version>1.0.0</version>
<name>Spring AI Demo</name>
<description>Spring AI入门教程示例项目</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>0.8.1</spring-ai.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI OpenAI -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<!-- Spring AI Vector Store (Pinecone) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone-store-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestones</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>创建application.yml或application.properties:
application.yml:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY:your-api-key-here}
chat:
options:
model: gpt-4
temperature: 0.7
max-tokens: 1000
vectorstore:
pinecone:
api-key: ${PINECONE_API_KEY:your-pinecone-api-key}
environment: ${PINECONE_ENVIRONMENT:us-east1-gcp}
index-name: ${PINECONE_INDEX_NAME:spring-ai-index}
server:
port: 8080application.properties:
# OpenAI配置
spring.ai.openai.api-key=${OPENAI_API_KEY:your-api-key-here}
spring.ai.openai.chat.options.model=gpt-4
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.chat.options.max-tokens=1000
# Pinecone配置(可选)
spring.ai.vectorstore.pinecone.api-key=${PINECONE_API_KEY:your-pinecone-api-key}
spring.ai.vectorstore.pinecone.environment=${PINECONE_ENVIRONMENT:us-east1-gcp}
spring.ai.vectorstore.pinecone.index-name=${PINECONE_INDEX_NAME:spring-ai-index}
server.port=8080OpenAI API密钥
- 访问 https://platform.openai.com/
- 注册/登录账号
- 进入API Keys页面
- 创建新的API密钥
- 复制密钥并配置到
application.yml
Pinecone API密钥(可选,用于向量数据库)
- 访问 https://www.pinecone.io/
- 注册/登录账号
- 创建项目
- 获取API密钥和环境信息
- 配置到
application.yml
创建标准的Spring Boot项目结构:
spring-ai-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── SpringAiDemoApplication.java
│ │ │ ├── controller/
│ │ │ │ └── ChatController.java
│ │ │ ├── service/
│ │ │ │ └── ChatService.java
│ │ │ └── config/
│ │ │ └── AiConfig.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── static/
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── ChatServiceTest.java
└── pom.xml3. 第一个Spring AI应用
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringAiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
}
}package com.example.service;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ChatService {
private final ChatClient chatClient;
@Autowired
public ChatService(ChatClient chatClient) {
this.chatClient = chatClient;
}
/**
* 简单的对话方法
*/
public String chat(String message) {
return chatClient.call(message);
}
/**
* 使用Prompt模板
*/
public String chatWithTemplate(String topic) {
PromptTemplate promptTemplate = new PromptTemplate(
"请用简洁的语言解释一下{topic}是什么?"
);
Prompt prompt = promptTemplate.create(
Map.of("topic", topic)
);
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}package com.example.controller;
import com.example.service.ChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatService chatService;
@Autowired
public ChatController(ChatService chatService) {
this.chatService = chatService;
}
@PostMapping
public String chat(@RequestBody ChatRequest request) {
return chatService.chat(request.getMessage());
}
@GetMapping("/explain/{topic}")
public String explain(@PathVariable String topic) {
return chatService.chatWithTemplate(topic);
}
// 请求DTO
public static class ChatRequest {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}使用curl测试
# 简单对话
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "你好,请介绍一下Java编程语言"}'
# 解释主题
curl http://localhost:8080/api/chat/explain/Spring%20Framework使用Postman测试
- 创建POST请求:
http://localhost:8080/api/chat - 设置Body为JSON格式:
{
"message": "你好,请介绍一下Java编程语言"
}- 发送请求查看响应
# 使用Maven运行
mvn spring-boot:run
# 或使用IDE直接运行SpringAiDemoApplication4. Chat模型集成
Spring AI支持多种Chat模型:
- OpenAI:GPT-4, GPT-3.5-turbo
- Anthropic:Claude
- Azure OpenAI:Azure托管的OpenAI模型
- Google Vertex AI:Gemini, PaLM
- Ollama:本地运行的模型
基本配置
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4
temperature: 0.7
max-tokens: 2000
top-p: 1.0
frequency-penalty: 0.0
presence-penalty: 0.0高级Chat服务
package com.example.service;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
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.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class AdvancedChatService {
private final ChatClient chatClient;
@Autowired
public AdvancedChatService(ChatClient chatClient) {
this.chatClient = chatClient;
}
/**
* 流式响应
*/
public void streamChat(String message) {
Prompt prompt = new Prompt(new UserMessage(message));
chatClient.stream(prompt)
.forEach(chunk -> {
System.out.print(chunk.getResult().getOutput().getContent());
});
}
/**
* 带系统提示的对话
*/
public String chatWithSystemPrompt(String userMessage, String systemPrompt) {
SystemMessage systemMsg = new SystemMessage(systemPrompt);
UserMessage userMsg = new UserMessage(userMessage);
Prompt prompt = new Prompt(List.of(systemMsg, userMsg));
ChatResponse response = chatClient.call(prompt);
return response.getResult().getOutput().getContent();
}
/**
* 多轮对话
*/
public String multiTurnChat(List<Message> conversationHistory, String newMessage) {
List<Message> messages = new ArrayList<>(conversationHistory);
messages.add(new UserMessage(newMessage));
Prompt prompt = new Prompt(messages);
ChatResponse response = chatClient.call(prompt);
return response.getResult().getOutput().getContent();
}
/**
* 自定义选项
*/
public String chatWithCustomOptions(String message) {
OpenAiChatOptions options = OpenAiChatOptions.builder()
.withTemperature(0.9f)
.withMaxTokens(500)
.withTopP(0.9f)
.build();
Prompt prompt = new Prompt(
new UserMessage(message),
options
);
ChatResponse response = chatClient.call(prompt);
return response.getResult().getOutput().getContent();
}
}添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>配置
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-3-opus-20240229
temperature: 0.7
max-tokens: 2000package com.example.config;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.anthropic.AnthropicChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class MultiModelConfig {
@Bean
@Primary
@Qualifier("openai")
public ChatClient openAiChatClient(OpenAiChatClient client) {
return client;
}
@Bean
@Qualifier("anthropic")
public ChatClient anthropicChatClient(AnthropicChatClient client) {
return client;
}
}
// 使用
@Service
public class MultiModelService {
@Autowired
@Qualifier("openai")
private ChatClient openAiClient;
@Autowired
@Qualifier("anthropic")
private ChatClient anthropicClient;
public String chatWithOpenAI(String message) {
return openAiClient.call(message);
}
public String chatWithAnthropic(String message) {
return anthropicClient.call(message);
}
}5. 向量数据库和嵌入
向量嵌入(Embedding)是将文本转换为数值向量的过程,这些向量可以表示文本的语义信息,用于相似度搜索和检索。
package com.example.service;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class EmbeddingService {
private final EmbeddingClient embeddingClient;
@Autowired
public EmbeddingService(EmbeddingClient embeddingClient) {
this.embeddingClient = embeddingClient;
}
/**
* 获取文本的嵌入向量
*/
public List<Double> getEmbedding(String text) {
return embeddingClient.embed(text);
}
/**
* 批量获取嵌入向量
*/
public List<List<Double>> getEmbeddings(List<String> texts) {
return embeddingClient.embed(texts);
}
/**
* 计算相似度
*/
public double cosineSimilarity(List<Double> vec1, List<Double> vec2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int i = 0; i < vec1.size(); i++) {
dotProduct += vec1.get(i) * vec2.get(i);
norm1 += vec1.get(i) * vec1.get(i);
norm2 += vec2.get(i) * vec2.get(i);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
}Pinecone集成
package com.example.service;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.PineconeVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class VectorStoreService {
private final VectorStore vectorStore;
@Autowired
public VectorStoreService(PineconeVectorStore vectorStore) {
this.vectorStore = vectorStore;
}
/**
* 添加文档到向量数据库
*/
public void addDocuments(List<Document> documents) {
vectorStore.add(documents);
}
/**
* 相似度搜索
*/
public List<Document> similaritySearch(String query, int k) {
return vectorStore.similaritySearch(query, k);
}
/**
* 带过滤条件的搜索
*/
public List<Document> similaritySearchWithFilter(
String query,
int k,
Map<String, Object> filter) {
return vectorStore.similaritySearch(
SearchRequest.builder()
.withQuery(query)
.withTopK(k)
.withSimilarityThreshold(0.7)
.withFilterExpression(filter)
.build()
);
}
}其他向量数据库
Weaviate:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-weaviate-store-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>Chroma:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-chroma-store-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>Simple Vector Store(内存):
@Bean
public VectorStore simpleVectorStore(EmbeddingClient embeddingClient) {
return new SimpleVectorStore(embeddingClient);
}6. RAG应用开发
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索和文本生成的技术,通过检索相关文档来增强生成内容的质量和准确性。
- 文档加载:加载和分割文档
- 向量化:将文档转换为向量
- 存储:存储到向量数据库
- 检索:根据查询检索相关文档
- 增强提示:将检索到的文档添加到提示中
- 生成:使用增强后的提示生成回答
package com.example.service;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TextSplitter;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class RAGService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
@Autowired
public RAGService(ChatClient chatClient, VectorStore vectorStore) {
this.chatClient = chatClient;
this.vectorStore = vectorStore;
}
/**
* 加载文档到向量数据库
*/
public void loadDocument(Resource resource) {
// 读取文档
TextReader textReader = new TextReader(resource);
List<Document> documents = textReader.get();
// 分割文档
TextSplitter textSplitter = new TokenTextSplitter();
List<Document> splitDocuments = textSplitter.apply(documents);
// 存储到向量数据库
vectorStore.add(splitDocuments);
}
/**
* RAG查询
*/
public String ragQuery(String query) {
// 1. 检索相关文档
List<Document> relevantDocs = vectorStore.similaritySearch(query, 5);
// 2. 构建上下文
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));
// 3. 构建提示模板
PromptTemplate promptTemplate = new PromptTemplate("""
基于以下上下文信息回答问题。如果上下文中没有相关信息,请说明。
上下文:
{context}
问题:{question}
回答:
""");
Prompt prompt = promptTemplate.create(
Map.of("context", context, "question", query)
);
// 4. 生成回答
return chatClient.call(prompt).getResult().getOutput().getContent();
}
/**
* 批量加载文档
*/
public void loadDocuments(List<Resource> resources) {
resources.forEach(this::loadDocument);
}
}package com.example.controller;
import com.example.service.RAGService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/api/rag")
public class RAGController {
private final RAGService ragService;
@Autowired
public RAGController(RAGService ragService) {
this.ragService = ragService;
}
@PostMapping("/upload")
public ResponseEntity<String> uploadDocument(
@RequestParam("file") MultipartFile file) {
try {
// 保存文件
Path uploadPath = Paths.get("uploads/" + file.getOriginalFilename());
Files.createDirectories(uploadPath.getParent());
Files.write(uploadPath, file.getBytes());
// 加载到向量数据库
Resource resource = new FileSystemResource(uploadPath.toFile());
ragService.loadDocument(resource);
return ResponseEntity.ok("文档上传成功");
} catch (IOException e) {
return ResponseEntity.badRequest()
.body("上传失败: " + e.getMessage());
}
}
@PostMapping("/query")
public ResponseEntity<String> query(@RequestBody QueryRequest request) {
String answer = ragService.ragQuery(request.getQuery());
return ResponseEntity.ok(answer);
}
public static class QueryRequest {
private String query;
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
}/**
* 带元数据过滤的RAG
*/
public String ragQueryWithFilter(String query, Map<String, Object> metadata) {
List<Document> relevantDocs = vectorStore.similaritySearch(
SearchRequest.builder()
.withQuery(query)
.withTopK(5)
.withFilterExpression(metadata)
.build()
);
// ... 后续处理
}
/**
* 混合搜索(向量搜索 + 关键词搜索)
*/
public String hybridSearch(String query) {
// 向量搜索
List<Document> vectorResults = vectorStore.similaritySearch(query, 3);
// 关键词搜索(需要额外实现)
// List<Document> keywordResults = keywordSearch(query);
// 合并结果
// ...
}7. 图像生成
添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>图像生成服务
package com.example.service;
import org.springframework.ai.image.ImageClient;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageClient;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ImageGenerationService {
private final ImageClient imageClient;
@Autowired
public ImageGenerationService(ImageClient imageClient) {
this.imageClient = imageClient;
}
/**
* 生成图像
*/
public String generateImage(String prompt) {
ImagePrompt imagePrompt = new ImagePrompt(prompt);
ImageResponse response = imageClient.call(imagePrompt);
return response.getResult().getOutput().getUrl();
}
/**
* 带选项的图像生成
*/
public String generateImageWithOptions(String prompt, int n, String size) {
OpenAiImageOptions options = OpenAiImageOptions.builder()
.withN(n)
.withSize(size)
.withResponseFormat("url")
.build();
ImagePrompt imagePrompt = new ImagePrompt(prompt, options);
ImageResponse response = imageClient.call(imagePrompt);
return response.getResult().getOutput().getUrl();
}
}@RestController
@RequestMapping("/api/image")
public class ImageController {
private final ImageGenerationService imageService;
@Autowired
public ImageController(ImageGenerationService imageService) {
this.imageService = imageService;
}
@PostMapping("/generate")
public ResponseEntity<ImageResponse> generateImage(
@RequestBody ImageRequest request) {
String imageUrl = imageService.generateImage(request.getPrompt());
return ResponseEntity.ok(new ImageResponse(imageUrl));
}
public static class ImageRequest {
private String prompt;
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
}
public static class ImageResponse {
private String imageUrl;
public ImageResponse(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getImageUrl() {
return imageUrl;
}
}
}8. 语音处理
package com.example.service;
import org.springframework.ai.audio.speech.SpeechClient;
import org.springframework.ai.audio.speech.SpeechPrompt;
import org.springframework.ai.audio.speech.SpeechResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SpeechService {
private final SpeechClient speechClient;
@Autowired
public SpeechService(SpeechClient speechClient) {
this.speechClient = speechClient;
}
/**
* 文本转语音
*/
public byte[] textToSpeech(String text) {
SpeechPrompt prompt = new SpeechPrompt(text);
SpeechResponse response = speechClient.call(prompt);
return response.getResult().getOutput();
}
}9. 函数调用
函数调用允许AI模型调用外部函数来获取信息或执行操作,实现更强大的功能。
package com.example.service;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackWrapper;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Service
public class FunctionCallingService {
private final ChatClient chatClient;
@Autowired
public FunctionCallingService(ChatClient chatClient) {
this.chatClient = chatClient;
}
/**
* 定义函数
*/
public Function<String, String> getWeatherFunction() {
return (location) -> {
// 模拟天气查询
return "北京今天天气晴朗,温度25度";
};
}
/**
* 使用函数调用
*/
public String chatWithFunction(String userMessage) {
// 注册函数
FunctionCallback weatherCallback = FunctionCallbackWrapper.builder(
"get_weather",
"获取指定城市的天气信息",
getWeatherFunction()
).build();
// 创建选项
OpenAiChatOptions options = OpenAiChatOptions.builder()
.withFunctions(List.of(weatherCallback))
.build();
Prompt prompt = new Prompt(
new UserMessage(userMessage),
options
);
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}10. 实际项目案例
package com.example.service;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CustomerServiceService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
@Autowired
public CustomerServiceService(ChatClient chatClient, VectorStore vectorStore) {
this.chatClient = chatClient;
this.vectorStore = vectorStore;
}
public String handleCustomerQuery(String query) {
// 1. 从知识库检索相关信息
List<Document> relevantDocs = vectorStore.similaritySearch(query, 3);
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));
// 2. 构建系统提示
SystemMessage systemMsg = new SystemMessage("""
你是一个专业的客服助手。请根据提供的知识库信息回答用户问题。
如果知识库中没有相关信息,请礼貌地说明。
""");
// 3. 构建用户消息
String userMessage = String.format("""
知识库信息:
%s
用户问题:%s
""", context, query);
// 4. 生成回答
Prompt prompt = new Prompt(List.of(
systemMsg,
new UserMessage(userMessage)
));
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}@Service
public class DocumentSummaryService {
private final ChatClient chatClient;
@Autowired
public DocumentSummaryService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public String generateSummary(String documentContent) {
PromptTemplate template = new PromptTemplate("""
请为以下文档生成一个简洁的摘要(不超过200字):
{content}
""");
Prompt prompt = template.create(Map.of("content", documentContent));
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}11. 最佳实践与优化
public void streamResponse(String message, OutputStream outputStream) {
Prompt prompt = new Prompt(new UserMessage(message));
chatClient.stream(prompt)
.forEach(chunk -> {
try {
outputStream.write(
chunk.getResult().getOutput().getContent().getBytes()
);
} catch (IOException e) {
e.printStackTrace();
}
});
}public List<String> batchProcess(List<String> queries) {
return queries.parallelStream()
.map(this::processQuery)
.collect(Collectors.toList());
}@Cacheable("chat-responses")
public String getCachedResponse(String query) {
return chatClient.call(query);
}@Service
public class RobustChatService {
private final ChatClient chatClient;
@Autowired
public RobustChatService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public String safeChat(String message) {
try {
return chatClient.call(message);
} catch (Exception e) {
// 记录错误
log.error("Chat error: ", e);
// 返回友好错误消息
return "抱歉,处理您的请求时出现了问题,请稍后重试。";
}
}
public String chatWithRetry(String message, int maxRetries) {
int attempts = 0;
while (attempts < maxRetries) {
try {
return chatClient.call(message);
} catch (Exception e) {
attempts++;
if (attempts >= maxRetries) {
throw new RuntimeException("Max retries exceeded", e);
}
// 等待后重试
try {
Thread.sleep(1000 * attempts);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
return null;
}
}- API密钥管理:使用环境变量或密钥管理服务
- 输入验证:验证和清理用户输入
- 速率限制:实现API调用速率限制
- 内容过滤:过滤敏感内容
- 日志记录:记录重要操作
@Aspect
@Component
public class ChatMonitoringAspect {
private static final Logger log = LoggerFactory.getLogger(ChatMonitoringAspect.class);
@Around("execution(* com.example.service.*Service.*(..))")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().getName();
try {
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - startTime;
log.info("Method {} executed in {} ms", methodName, duration);
return result;
} catch (Exception e) {
log.error("Error in method {}: ", methodName, e);
throw e;
}
}
}12. 总结与进阶
通过本教程,你已经掌握了:
- ✅ Spring AI的基本概念和配置
- ✅ Chat模型的集成和使用
- ✅ 向量数据库和嵌入
- ✅ RAG应用的开发
- ✅ 图像生成和语音处理
- ✅ 函数调用功能
- ✅ 实际项目应用
- 多模态AI:图像理解、视频分析
- Agent开发:构建AI Agent系统
- Fine-tuning:模型微调
- 成本优化:API调用成本优化
- 企业级应用:大规模部署和运维
- Spring AI官方文档:https://docs.spring.io/spring-ai/reference/
- GitHub仓库:https://github.com/spring-projects/spring-ai
- 示例项目:Spring AI官方示例
- 社区论坛:Spring社区
Q1: 如何选择合适的模型?
A: 根据需求选择,GPT-4适合复杂任务,GPT-3.5适合简单任务,Claude适合长文本。
Q2: 如何处理API限制?
A: 实现重试机制、速率限制、缓存等。
Q3: 如何优化RAG效果?
A: 优化文档分割策略、调整检索数量、改进提示模板。
Q4: 成本如何控制?
A: 使用缓存、批量处理、选择合适的模型、监控API调用。
结语
Spring AI为Java开发者提供了强大的AI应用开发能力。通过本教程的学习,相信你已经掌握了Spring AI的核心功能和使用方法。
记住:
- 多实践:通过实际项目练习
- 关注性能:优化API调用和响应时间
- 注意成本:合理使用API,控制成本
- 持续学习:关注AI技术发展
祝你学习愉快,开发顺利! 🚀
本教程由Java突击队学习社区编写,如有问题欢迎反馈。