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-example
https://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 已正确注册
 
 - 检查 
 - 
记忆功能不生效
- 确认 
ChatMemoryBean 正确配置 - 检查 
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
 
