Spring AI 1.0.1 使用教程
项目简介
作为一个Java的开发者 听到Java也有ai框架了 很高兴~~~
本来想学一下SpringAI但是网上卖课的一大堆,并且大部分课程都是五月的,到2025年的8月份,SpringAI的版本做了很多更新,所以我本人参考网上示例,很多代码走不通,一些方法被废弃了,搞得有点破防。。。
于是我自行阅读了SpringAI1.0.1的官方教程
目前应该是全网最新的示例教程 ,欢迎初学者小白git clone
前人栽树 后人乘凉 给大家避坑的 可以点赞收藏加个绿泡泡不??

作者邮箱:shibaizhelianmeng@163.com 绿泡泡wx@:EonNetWork
代码仓库:
代码拉取下来就可以跑
github:
Lappercn/SpringAI-examplehttps://github.com/Lappercn/SpringAI-examplegitee:
教程如下:
本项目是一个基于 Spring AI 1.0.1 的聊天应用示例,集成了 Ollama 模型,展示了如何使用 Spring AI 的核心功能:
- 多模型动态切换
- 聊天记忆管理
- 自定义 Advisor(日志记录、拦截器等)
- 用户会话隔离
- 流式响应处理
环境要求
- Java 17+
- Spring Boot 3.5.4
- Spring AI 1.0.1
- Ollama(本地运行)
快速开始
1. 安装 Ollama
# 下载并安装 Ollama
curl -fsSL https://ollama.ai/install.sh | sh
# 拉取模型(示例)
ollama pull deepseek-r1:7b
ollama pull qwen2:7b
ollama pull llama3.2:3b
2. 启动项目
# 克隆项目
git clone <your-repo-url>
cd ChatAI
# 启动应用
./mvnw spring-boot:run
3. 测试接口
# 基本聊天
curl "http://localhost:8080/ai/chat?prompt=你好&chatid=1&model=deepseek-r1:7b"
# 切换模型
curl "http://localhost:8080/ai/chat?prompt=讲个笑话&chatid=1&model=qwen2:7b"
核心功能详解
1. ChatClient 配置
文件位置: src/main/java/com/example/chatai/Config/CommonConfigOllama.java
@Configuration
public class CommonConfigOllama {
@Bean
public ChatMemory chatMemory(){
return MessageWindowChatMemory.builder().build();
}
@Bean
public ChatClient client(OllamaChatModel model){
return ChatClient.builder(model)
.defaultSystem("你是一个可爱的小女孩你的回答语气 非常可爱是一个智能助手")
.defaultAdvisors(
new SimpleLoggerAdvisor(),
MessageChatMemoryAdvisor.builder(chatMemory()).build(),
new CustomLoggingAdvisor()
)
.build();
}
}
核心接口说明:
ChatClient.builder(model)
: 创建聊天客户端构建器.defaultSystem(String)
: 设置默认系统提示词.defaultAdvisors(...)
: 注册默认的 Advisor 链
2. 动态模型切换
文件位置: src/main/java/com/example/chatai/Controller/ChatController.java
@GetMapping(value = "/chat", produces = "text/html;charset=utf-8")
public Flux<String> chat(String prompt, int chatid,
@RequestParam(defaultValue = "deepseek-r1:7b") String model) {
return client.prompt()
.options(OllamaOptions.builder()
.model(model)
.build())
.user(prompt)
.advisors(a -> a.param(CONVERSATION_ID, chatid))
.stream()
.content();
}
接口定义:
client.prompt()
: 开始构建提示.options(OllamaOptions)
: 设置模型参数.user(String)
: 设置用户消息.advisors(...)
: 配置会话级 Advisor.stream()
: 启用流式响应.content()
: 获取内容流
OllamaOptions 常用配置:
OllamaOptions.builder()
.model("deepseek-r1:7b") // 模型名称
.temperature(0.7f) // 温度参数
.topP(0.9f) // Top-P 采样
.maxTokens(1000) // 最大 Token 数
.build()
3. 聊天记忆管理
3.1 基础记忆配置
@Bean
public ChatMemory chatMemory(){
// 滑动窗口记忆(保留最近 N 条消息)
return MessageWindowChatMemory.builder()
.maxMessages(10) // 最大消息数
.build();
}
3.2 用户会话隔离
通过 CONVERSATION_ID
实现多用户隔离:
.advisors(a -> a.param(CONVERSATION_ID, chatid))
不同用户示例:
# 用户1的对话
curl "http://localhost:8080/ai/chat?prompt=我叫张三&chatid=1"
curl "http://localhost:8080/ai/chat?prompt=我叫什么名字?&chatid=1"
# 用户2的对话
curl "http://localhost:8080/ai/chat?prompt=我叫李四&chatid=2"
curl "http://localhost:8080/ai/chat?prompt=我叫什么名字?&chatid=2"
3.3 持久化记忆(扩展)
自定义持久化记忆实现:
@Component
public class DatabaseChatMemory implements ChatMemory {
@Autowired
private ChatMessageRepository repository;
@Override
public void add(String conversationId, List<Message> messages) {
// 保存到数据库
messages.forEach(msg -> {
ChatMessageEntity entity = new ChatMessageEntity();
entity.setConversationId(conversationId);
entity.setContent(msg.getContent());
entity.setRole(msg.getMessageType().getValue());
entity.setTimestamp(LocalDateTime.now());
repository.save(entity);
});
}
@Override
public List<Message> get(String conversationId, int lastN) {
// 从数据库查询
return repository.findTopNByConversationIdOrderByTimestampDesc(
conversationId, lastN)
.stream()
.map(this::toMessage)
.collect(Collectors.toList());
}
}
4. 自定义 Advisor 开发
4.1 日志记录 Advisor
文件位置: src/main/java/com/example/chatai/Config/CustomLoggingAdvisor.java
@Component
public class CustomLoggingAdvisor implements CallAdvisor, StreamAdvisor, Ordered {
private static final Logger logger = LoggerFactory.getLogger(CustomLoggingAdvisor.class);
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
// 请求前处理
logger.info("请求开始: {}", request.userText());
long startTime = System.currentTimeMillis();
// 调用下一个节点
ChatClientResponse response = chain.nextCall(request);
// 响应后处理
long duration = System.currentTimeMillis() - startTime;
logger.info("请求完成: 耗时{}ms, 响应长度: {}",
duration, response.getResult().getOutput().getContent().length());
return response;
}
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain) {
logger.info("流式请求开始: {}", request.userText());
return chain.nextStream(request)
.doOnNext(chunk -> logger.debug("接收到分片: {}",
chunk.getResult().getOutput().getContent()))
.doOnComplete(() -> logger.info("流式响应完成"))
.doOnError(error -> logger.error("流式响应错误", error));
}
@Override
public int getOrder() {
return 100; // 执行顺序,数字越小优先级越高
}
}
4.2 权限验证 Advisor
@Component
public class AuthorizationAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
// 从请求中获取用户信息
String userId = request.advisorParams().get("userId");
// 验证用户权限
if (!hasPermission(userId)) {
throw new UnauthorizedException("用户无权限访问");
}
// 检查敏感词
if (containsSensitiveWords(request.userText())) {
throw new IllegalArgumentException("包含敏感词汇");
}
return chain.nextCall(request);
}
private boolean hasPermission(String userId) {
// 实现权限检查逻辑
return true;
}
private boolean containsSensitiveWords(String text) {
// 实现敏感词检测逻辑
return false;
}
}
4.3 速率限制 Advisor
@Component
public class RateLimitAdvisor implements CallAdvisor {
private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String userId = request.advisorParams().get("userId");
// 获取或创建限流器(每分钟10次请求)
RateLimiter limiter = limiters.computeIfAbsent(userId,
k -> RateLimiter.create(10.0 / 60.0));
if (!limiter.tryAcquire()) {
throw new TooManyRequestsException("请求过于频繁,请稍后再试");
}
return chain.nextCall(request);
}
}
5. 配置文件详解
文件位置: src/main/resources/application.yaml
spring:
application:
name: ChatAI
ai:
ollama:
base-url: http://localhost:11434 # Ollama 服务地址
chat:
model: deepseek-r1:7b # 默认模型
options:
temperature: 0.2 # 创造性参数
# 日志配置
logging:
level:
com.example.chatai.Config.CustomLoggingAdvisor: INFO
org.springframework.ai.chat.client.advisor: DEBUG
org.springframework.ai: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
6. 完整的使用示例
6.1 基础聊天示例
@RestController
public class ExampleController {
@Autowired
private ChatClient chatClient;
// 简单聊天
@GetMapping("/simple-chat")
public String simpleChat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
// 带系统提示的聊天
@GetMapping("/system-chat")
public String systemChat(@RequestParam String message) {
return chatClient.prompt()
.system("你是一个专业的代码审查员")
.user(message)
.call()
.content();
}
// 流式聊天
@GetMapping("/stream-chat")
public Flux<String> streamChat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}
6.2 高级功能示例
@RestController
public class AdvancedController {
@Autowired
private ChatClient chatClient;
// 多轮对话与记忆
@PostMapping("/conversation")
public ResponseEntity<String> conversation(@RequestBody ConversationRequest request) {
String response = chatClient.prompt()
.user(request.getMessage())
.advisors(advisor -> advisor
.param(CONVERSATION_ID, request.getUserId())
.param("userId", request.getUserId()))
.call()
.content();
return ResponseEntity.ok(response);
}
// 带选项的聊天
@PostMapping("/chat-with-options")
public String chatWithOptions(@RequestBody ChatRequest request) {
return chatClient.prompt()
.options(OllamaOptions.builder()
.model(request.getModel())
.temperature(request.getTemperature())
.maxTokens(request.getMaxTokens())
.build())
.user(request.getMessage())
.call()
.content();
}
// 函数调用示例(如果模型支持)
@PostMapping("/function-call")
public String functionCall(@RequestParam String query) {
return chatClient.prompt()
.user(query)
.functions("getCurrentWeather", "searchDatabase")
.call()
.content();
}
}
最佳实践
1. 错误处理
@RestController
public class ChatController {
@GetMapping("/safe-chat")
public ResponseEntity<String> safeChat(@RequestParam String message) {
try {
String response = chatClient.prompt()
.user(message)
.call()
.content();
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("聊天请求失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("抱歉,服务暂时不可用");
}
}
}
2. 性能优化
@Configuration
public class ChatClientConfig {
@Bean
@Primary
public ChatClient optimizedChatClient(OllamaChatModel model) {
return ChatClient.builder(model)
.defaultAdvisors(
// 缓存 Advisor
new CacheAdvisor(),
// 限流 Advisor
new RateLimitAdvisor(),
// 日志 Advisor(低优先级)
new SimpleLoggerAdvisor()
)
.build();
}
}
3. 监控指标
@Component
public class MetricsAdvisor implements CallAdvisor {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer responseTimer;
public MetricsAdvisor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("ai.requests.total").register(meterRegistry);
this.responseTimer = Timer.builder("ai.response.duration").register(meterRegistry);
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
return Timer.Sample.start(meterRegistry)
.stop(responseTimer, () -> {
requestCounter.increment();
return chain.nextCall(request);
});
}
}
故障排除
常见问题
-
模型连接失败
- 检查 Ollama 服务是否启动:
ollama list
- 确认模型已下载:
ollama pull model-name
- 检查 Ollama 服务是否启动:
-
日志不显示
- 检查
application.yaml
中的日志级别配置 - 确认 Advisor 已正确注册
- 检查
-
记忆功能不生效
- 确认
ChatMemory
Bean 正确配置 - 检查
CONVERSATION_ID
参数传递
- 确认
调试技巧
# 开启详细日志
logging:
level:
org.springframework.ai: DEBUG
org.springframework.web: DEBUG
com.example.chatai: DEBUG
扩展开发
自定义模型适配
@Configuration
public class CustomModelConfig {
@Bean
@ConditionalOnProperty(name = "app.model.provider", havingValue = "custom")
public ChatModel customChatModel() {
// 实现自定义模型适配
return new CustomChatModel();
}
}
多租户支持
@Component
public class MultiTenantAdvisor implements CallAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String tenantId = request.advisorParams().get("tenantId");
// 设置租户上下文
TenantContext.setCurrentTenant(tenantId);
try {
return chain.nextCall(request);
} finally {
TenantContext.clear();
}
}
}
参考资源
联系方式
- 作者:胖虎爱java
- 邮箱:shibaizhelianmeng@163.com
- CSDN:胖虎爱java