SpringAI1.0.1实战教程:避坑指南25年8月最新版
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:
SpringAI1.0.1教程: 本项目是一个基于 Spring AI 1.0.1 的聊天应用示例,集成了 Ollama 模型,展示了如何使用 Spring AI 的核心功能: - 多模型动态切换 - 聊天记忆管理 - 自定义 Advisor(日志记录、拦截器等) - 用户会话隔离 - 流式响应处理https://gitee.com/Lapper/ChatAI
教程如下:
本项目是一个基于 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 {@Beanpublic ChatMemory chatMemory(){return MessageWindowChatMemory.builder().build();}@Beanpublic 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 {@Autowiredprivate ChatMessageRepository repository;@Overridepublic 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);});}@Overridepublic 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);@Overridepublic 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;}@Overridepublic 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));}@Overridepublic int getOrder() {return 100; // 执行顺序,数字越小优先级越高}
}
4.2 权限验证 Advisor
@Component
public class AuthorizationAdvisor implements CallAdvisor {@Overridepublic 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<>();@Overridepublic 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: ChatAIai:ollama:base-url: http://localhost:11434 # Ollama 服务地址chat:model: deepseek-r1:7b # 默认模型options:temperature: 0.2 # 创造性参数# 日志配置
logging:level:com.example.chatai.Config.CustomLoggingAdvisor: INFOorg.springframework.ai.chat.client.advisor: DEBUGorg.springframework.ai: INFOpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
6. 完整的使用示例
6.1 基础聊天示例
@RestController
public class ExampleController {@Autowiredprivate 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 {@Autowiredprivate 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@Primarypublic ChatClient optimizedChatClient(OllamaChatModel model) {return ChatClient.builder(model).defaultAdvisors(// 缓存 Advisornew CacheAdvisor(),// 限流 Advisornew 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);}@Overridepublic 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: DEBUGorg.springframework.web: DEBUGcom.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 {@Overridepublic ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {String tenantId = request.advisorParams().get("tenantId");// 设置租户上下文TenantContext.setCurrentTenant(tenantId);try {return chain.nextCall(request);} finally {TenantContext.clear();}}
}
参考资源
- Spring AI 官方文档
- Ollama 官网
- Spring Boot 文档
联系方式
- 作者:胖虎爱java
- 邮箱:shibaizhelianmeng@163.com
- CSDN:胖虎爱java