1. 入门安装
1.1 环境要求
在开始之前,请确保您的开发环境满足以下条件:
-
JDK: 17 或更高版本
-
Spring Boot: 3.5.x 版本
-
Maven: 3.8+ 或 Gradle 7.x+
-
阿里云账号: 用于获取 DashScope API Key
1.2 创建 Spring Boot 项目
推荐使用 Spring Initializr 创建项目,选择以下依赖:
-
Spring Boot 3.5.8
-
Spring Web
-
其他您需要的依赖(如 Lombok、Spring Data JPA 等)
1.3 添加 Maven 依赖
在项目的 pom.xml 中添加 Spring AI Alibaba 的核心依赖:
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
https://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.5.8</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-ai-alibaba-demo</artifactId>
<version>1.0.0</version>
<name>Spring AI Alibaba Demo</name>
<properties>
<java.version>17</java.version>
<spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
<spring-ai.version>1.1.2</spring-ai.version>
</properties>
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI Alibaba Starter -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- 可选:Nacos 配置中心支持 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-config-nacos</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- 可选:Graph 可观测性支持 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-graph-observation</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<!-- Spring Milestone Repository -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
依赖说明:
| 依赖 | 作用 | 是否必须 |
|---|---|---|
spring-ai-alibaba-starter |
核心功能,包含 Chat/Embedding/Image 模型支持 | 是 |
spring-ai-alibaba-starter-config-nacos |
Nacos 配置中心集成,支持动态配置 | 否 |
spring-ai-alibaba-starter-graph-observation |
Micrometer 可观测性支持 | 否 |
1.4 获取 API Key
-
登录 阿里云百炼平台
-
进入"API Key 管理"页面
-
创建新的 API Key
-
复制并保存好您的 Key(格式通常为
sk-xxxxxxxx)
2. 基础配置
2.1 最小化配置
在 src/main/resources/application.yml 中添加最基础的配置:
XML
spring:
ai:
alibaba:
dashscope:
api-key: ${DASHSCOPE_API_KEY:your-api-key-here}
安全提示:生产环境建议将 API Key 配置在环境变量中,避免硬编码到代码仓库。
2.2 完整配置详解
以下是生产环境推荐的完整配置:
bash
spring:
ai:
alibaba:
dashscope:
# API 密钥配置
api-key: ${DASHSCOPE_API_KEY}
# 聊天模型配置
chat:
options:
# 模型名称,可选值:
# - qwen-max: 通义千问 Max,综合能力最强
# - qwen-plus: 通义千问 Plus,平衡性能与成本
# - qwen-turbo: 通义千问 Turbo,响应速度最快
model: qwen-max
# 温度参数,控制生成随机性 (0.0 - 2.0)
# 越低越确定,越高越创造性
temperature: 0.7
# 最大生成 token 数
max-tokens: 2048
# Top-P 采样,控制多样性 (0.0 - 1.0)
top-p: 0.9
# 重复惩罚系数 (1.0 - 2.0)
# 越高越不容易重复
repetition-penalty: 1.1
# 向量模型配置
embedding:
options:
# 向量模型名称
model: text-embedding-v3
# 向量维度
dimensions: 1536
# 图像模型配置
image:
options:
# 图像生成模型
model: wanx-v1
# 图像尺寸
size: 1024x1024
# HTTP 客户端配置(高级)
client:
# 连接超时时间(秒)
connect-timeout: 30
# 读取超时时间(秒)
read-timeout: 60
# 连接池最大连接数
max-connections: 100
# 单个路由最大连接数
max-connections-per-route: 20
2.3 配置参数调优建议
| 参数 | 默认值 | 调优建议 |
|---|---|---|
temperature |
0.7 | 创意写作: 0.9+;代码生成: 0.2-0.5;问答: 0.3-0.7 |
max-tokens |
2048 | 长文本生成可设为 4096 或更高 |
top-p |
0.9 | 与 temperature 配合,通常保持 0.9-1.0 |
repetition-penalty |
1.0 | 对话场景建议 1.1-1.2 |
3. 对话功能
3.1 使用 ChatClient 进行对话
ChatClient 是 Spring AI 提供的高级对话接口,使用方式简单直观。
代码示例:
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
@Service
public class ChatService {
private final ChatClient chatClient;
// 通过构造函数注入 ChatClient
public ChatService(ChatClient.Builder chatClientBuilder) {
// 可以在这里设置默认的系统提示词
this.chatClient = chatClientBuilder
.defaultSystem("你是一个 helpful 的 AI 助手,请用中文回答用户问题。")
.build();
}
/**
* 单轮对话
*/
public String chat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call() // 发起调用
.content(); // 获取文本内容
}
/**
* 多轮对话(带上下文)
*/
public String chatWithHistory(String userMessage, String conversationHistory) {
return chatClient.prompt()
.system("以下是之前的对话历史:" + conversationHistory)
.user(userMessage)
.call()
.content();
}
/**
* 流式输出(打字机效果)
*/
public Flux<String> streamChat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.stream() // 启用流式输出
.content();
}
/**
* 获取完整的响应对象
*/
public ChatResponse chatWithMetadata(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.chatResponse();
}
}
Controller 层示例:
java
import com.example.demo.service.ChatService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatService chatService;
public ChatController(ChatService chatService) {
this.chatService = chatService;
}
@PostMapping("/ask")
public String ask(@RequestBody String message) {
return chatService.chat(message);
}
@PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestBody String message) {
return chatService.streamChat(message);
}
}
3.2 使用 ChatModel 进行底层控制
如果您需要更精细的控制,可以直接使用 ChatModel:
java
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;
@Service
public class AdvancedChatService {
private final ChatModel chatModel;
public AdvancedChatService(ChatModel chatModel) {
this.chatModel = chatModel;
}
/**
* 使用自定义参数进行对话
*/
public String chatWithCustomOptions(String message) {
// 创建自定义选项
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("qwen-max")
.temperature(0.3) // 更确定的回答
.maxTokens(1024)
.build();
// 构建 Prompt
Prompt prompt = new Prompt(
new UserMessage(message),
options
);
// 调用模型
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getText();
}
}
3.3 Spring AI 标准 vs Alibaba 扩展
| 特性 | SPRING AI 标准 | SPRING AI ALIBABA 扩展 |
|---|---|---|
| 模型支持 | OpenAI、Azure 等 | 阿里云 DashScope 全系模型 |
| 默认模型 | gpt-3.5-turbo | qwen-max |
| 中文优化 | 基础支持 | 针对中文场景深度优化 |
| 向量模型 | text-embedding-ada-002 | text-embedding-v3 |
4. 文本向量化
4.1 基础向量化
将文本转换为向量(Embedding),用于语义搜索、相似度计算等场景:
java
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmbeddingService {
private final EmbeddingModel embeddingModel;
public EmbeddingService(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
/**
* 单文本向量化
*/
public float[] embed(String text) {
return embeddingModel.embed(text);
}
/**
* 批量向量化
*/
public List<float[]> embedBatch(List<String> texts) {
EmbeddingRequest request = new EmbeddingRequest(texts, null);
EmbeddingResponse response = embeddingModel.call(request);
return response.getResults().stream()
.map(result -> result.getOutput())
.toList();
}
/**
* 计算两个文本的相似度
*/
public double calculateSimilarity(String text1, String text2) {
float[] embedding1 = embed(text1);
float[] embedding2 = embed(text2);
return cosineSimilarity(embedding1, embedding2);
}
/**
* 余弦相似度计算
*/
private double cosineSimilarity(float[] vec1, float[] vec2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int i = 0; i < vec1.length; i++) {
dotProduct += vec1[i] * vec2[i];
norm1 += vec1[i] * vec1[i];
norm2 += vec2[i] * vec2[i];
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
}
4.2 向量存储与检索(简单内存版)
java
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
@Service
public class SimpleVectorService {
private final VectorStore vectorStore;
private final EmbeddingService embeddingService;
public SimpleVectorService(EmbeddingService embeddingService) {
this.embeddingService = embeddingService;
// 使用内存向量存储(仅适用于开发和测试)
this.vectorStore = SimpleVectorStore.builder(embeddingService.getEmbeddingModel()).build();
}
/**
* 添加文档到向量库
*/
public void addDocument(String content, Map<String, Object> metadata) {
Document document = new Document(content, metadata);
vectorStore.add(List.of(document));
}
/**
* 相似性搜索
*/
public List<Document> search(String query, int topK) {
return vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.topK(topK)
.build()
);
}
}
5. 图像生成
5.1 基础图像生成
java
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.stereotype.Service;
@Service
public class ImageService {
private final ImageModel imageModel;
public ImageService(ImageModel imageModel) {
this.imageModel = imageModel;
}
/**
* 根据描述生成图像
*/
public String generateImage(String description) {
ImagePrompt prompt = new ImagePrompt(description);
ImageResponse response = imageModel.call(prompt);
// 返回图像 URL
return response.getResult().getOutput().getUrl();
}
/**
* 生成特定风格的图像
*/
public String generateStyledImage(String description, String style) {
String styledPrompt = String.format(
"%s,风格:%s,高质量,细节丰富",
description,
style
);
return generateImage(styledPrompt);
}
}
6. RAG 检索增强
RAG(Retrieval-Augmented Generation)将检索与生成结合,让 AI 基于私有知识回答问题。
6.1 完整 RAG 实现
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.List;
@Service
public class RagService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
public RagService(ChatClient.Builder chatClientBuilder,
VectorStore vectorStore) {
this.vectorStore = vectorStore;
this.chatClient = chatClientBuilder
.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
.build();
}
/**
* 加载文档到知识库
*/
@PostConstruct
public void initKnowledgeBase() {
// 方式1:从文件加载
// Resource resource = new ClassPathResource("knowledge.txt");
// loadDocument(resource);
// 方式2:从字符串加载
String knowledge = """
Spring AI Alibaba 是阿里云开发的 Spring AI 实现,
提供了对 DashScope 模型的一站式支持。
支持的功能包括:对话、向量化、图像生成等。
""";
loadFromText(knowledge);
}
/**
* 从文本加载知识
*/
public void loadFromText(String text) {
// 将长文本切分成小块
TokenTextSplitter splitter = new TokenTextSplitter(
500, // 每个块的最大token数
50, // 重叠token数
10, // 最小块大小
1000, // 最大块大小
true // 保留分隔符
);
List<Document> documents = splitter.split(new Document(text));
// 存储到向量库
vectorStore.add(documents);
}
/**
* 基于知识库回答问题
*/
public String askWithKnowledge(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
6.2 Controller 使用示例
java
import com.example.demo.service.RagService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/rag")
public class RagController {
private final RagService ragService;
public RagController(RagService ragService) {
this.ragService = ragService;
}
@PostMapping("/ask")
public String ask(@RequestParam String question) {
return ragService.askWithKnowledge(question);
}
@PostMapping("/upload")
public String uploadKnowledge(@RequestParam("file") MultipartFile file) {
try {
String content = new String(file.getBytes());
ragService.loadFromText(content);
return "知识库更新成功";
} catch (Exception e) {
return "上传失败: " + e.getMessage();
}
}
}
7. 工具函数
Function Calling 让 AI 可以调用外部工具,实现与真实世界的交互。
7.1 定义工具函数
java
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
@Component
public class WeatherTools {
/**
* 获取城市天气
*/
@Tool(name = "get_weather",
description = "获取指定城市的当前天气信息")
public String getWeather(
@ToolParam(description = "城市名称,如:北京、上海")
String city) {
// 这里应该调用真实的天气 API
// 示例返回
return String.format("%s今天天气晴朗,气温25°C", city);
}
/**
* 计算表达式
*/
@Tool(name = "calculate",
description = "计算数学表达式的结果")
public double calculate(
@ToolParam(description = "数学表达式,如:2+3*4")
String expression) {
// 简化实现,生产环境应使用更安全的计算方式
return switch (expression) {
case "2+3*4" -> 14;
case "100/5" -> 20;
default -> 0;
};
}
}
7.2 使用工具函数的 ChatClient
java
import com.example.demo.tools.WeatherTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbacks;
import org.springframework.stereotype.Service;
@Service
public class ToolChatService {
private final ChatClient chatClient;
public ToolChatService(ChatClient.Builder chatClientBuilder,
WeatherTools weatherTools) {
// 将工具函数注册到 ChatClient
this.chatClient = chatClientBuilder
.defaultTools(ToolCallbacks.from(weatherTools))
.build();
}
/**
* 支持工具调用的对话
*/
public String chatWithTools(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
7.3 测试工具调用
java
@SpringBootTest
class ToolChatServiceTest {
@Autowired
private ToolChatService toolChatService;
@Test
void testWeatherQuery() {
String response = toolChatService.chatWithTools(
"北京今天天气怎么样?"
);
System.out.println(response);
// 输出:北京今天天气晴朗,气温25°C
}
@Test
void testCalculation() {
String response = toolChatService.chatWithTools(
"帮我计算 2+3*4 等于多少"
);
System.out.println(response);
// 输出:2+3*4 等于 14
}
}
8. 智能体 Agent
Agent 是具备自主决策能力的智能体,能够自动规划任务并使用工具。
8.1 使用 ReactAgent 构建智能体
java
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ResearchAgent {
private final ReactAgent agent;
public ResearchAgent(ChatClient.Builder chatClientBuilder,
List<ToolCallback> tools) {
this.agent = ReactAgent.builder()
.name("research-agent")
.description("一个研究型助手,能够搜索信息并总结报告")
.instruction("""
你是一个专业的研究助手。当用户提出问题时,
你需要:
1. 分析问题需要哪些信息
2. 使用可用工具收集信息
3. 整理并总结答案
4. 如有必要,请求用户澄清
""")
.chatClient(chatClientBuilder.build())
.tools(tools)
.build();
}
/**
* 执行研究任务
*/
public String research(String topic) {
return agent.call(topic).getText();
}
}
8.2 高级 Agent 配置(基于 Nacos)
java
import com.alibaba.cloud.ai.agent.nacos.NacosReactAgentBuilder;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentConfiguration {
@Value("${spring.cloud.nacos.config.server-addr}")
private String nacosServerAddr;
/**
* 从 Nacos 配置中心加载 Agent 配置
*/
@Bean
public ReactAgent nacosAgent() {
return new NacosReactAgentBuilder()
.nacosOptions(options -> options
.serverAddr(nacosServerAddr)
.agentName("my-intelligent-agent")
.namespace("ai-agent")
)
.build();
}
}
8.3 Nacos 配置格式
在 Nacos 中创建以下配置文件:
agent-base.json:
bash
{
"name": "my-intelligent-agent",
"description": "智能客服助手",
"promptKey": "customer-service-prompt",
"modelKey": "qwen-max-config"
}
customer-service-prompt.json:
bash
{
"template": "你是专业的客服助手。请用友好、专业的语气回答用户问题。",
"variables": ["user_name", "product_name"]
}
9. 故障排查
9.1 常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
401 Unauthorized |
API Key 无效或过期 | 检查 API Key 配置,确认未过期 |
429 Too Many Requests |
超出请求频率限制 | 降低请求频率或升级服务套餐 |
Connection timeout |
网络问题或配置不当 | 增加 connect-timeout 和 read-timeout |
NullPointerException |
模型未正确初始化 | 检查依赖注入和配置类 |
| 返回内容为空 | 提示词问题或参数设置 | 检查 prompt 和 temperature 设置 |
9.2 调试日志配置
在 application.yml 中开启调试日志:
bash
logging:
level:
# 查看 HTTP 请求详情
org.springframework.web: DEBUG
# 查看 AI 调用日志
org.springframework.ai: DEBUG
# 查看 DashScope 调用日志
com.alibaba.cloud.ai: DEBUG
9.3 健康检查接口
java
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthController {
private final ChatClient chatClient;
public HealthController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@GetMapping("/health/ai")
public String checkAI() {
try {
String response = chatClient.prompt()
.user("你好")
.call()
.content();
return "AI 服务正常: " + response.substring(0, Math.min(20, response.length()));
} catch (Exception e) {
return "AI 服务异常: " + e.getMessage();
}
}
}
10. 最佳实践
10.1 配置管理建议
- 多环境配置:
bash
# application-dev.yml(开发环境)
spring:
ai:
alibaba:
dashscope:
api-key: ${DEV_API_KEY}
chat:
options:
model: qwen-turbo # 开发用轻量级模型
# application-prod.yml(生产环境)
spring:
ai:
alibaba:
dashscope:
api-key: ${PROD_API_KEY}
chat:
options:
model: qwen-max # 生产用最强模型
- 连接池优化:
bash
spring:
ai:
alibaba:
dashscope:
client:
max-connections: 200
max-connections-per-route: 50
connect-timeout: 10
read-timeout: 30
10.2 性能优化建议
-
流式输出 :对于长文本生成,使用
stream()而非call() -
批量向量化 :使用
embedBatch()而非循环调用embed() -
向量缓存:对于频繁查询的向量,考虑使用 Redis 缓存
-
异步处理 :使用
@Async注解处理非阻塞 AI 调用
10.3 安全建议
-
API Key 管理:
-
使用环境变量或配置中心存储
-
定期轮换 API Key
-
生产环境启用 IP 白名单
-
-
输入过滤:
java
@Service
public class SafeChatService {
private final ChatClient chatClient;
private final List<String> blockedWords = List.of("敏感词1", "敏感词2");
public String safeChat(String input) {
// 输入过滤
if (containsBlockedWords(input)) {
return "输入包含不适当内容";
}
return chatClient.prompt()
.user(input)
.call()
.content();
}
private boolean containsBlockedWords(String input) {
return blockedWords.stream().anyMatch(input::contains);
}
}
