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 {
    
    @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);
                });
    }
}

故障排除

常见问题

  1. 模型连接失败

    • 检查 Ollama 服务是否启动:ollama list
    • 确认模型已下载:ollama pull model-name
  2. 日志不显示

    • 检查 application.yaml 中的日志级别配置
    • 确认 Advisor 已正确注册
  3. 记忆功能不生效

    • 确认 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
相关推荐
刘 大 望16 分钟前
网络编程--TCP/UDP Socket套接字
java·运维·服务器·网络·数据结构·java-ee·intellij-idea
没有bug.的程序员28 分钟前
AOT 编译与 GraalVM 实战:Java 云原生的终极进化
java·python·云原生·graalvm·aot
找不到、了43 分钟前
常用的分布式ID设计方案
java·分布式
野区捕龙为宠1 小时前
Unity Netcode for GameObjects(多人联机小Demo)
java·unity·游戏引擎
十八旬1 小时前
苍穹外卖项目实战(日记十)-记录实战教程及问题的解决方法-(day3-2)新增菜品功能完整版
java·开发语言·spring boot·mysql·idea·苍穹外卖
鞋尖的灰尘2 小时前
springboot-事务
java·后端
银迢迢2 小时前
SpringCloud微服务技术自用笔记
java·spring cloud·微服务·gateway·sentinel
用户0332126663672 小时前
Java 将 CSV 转换为 Excel:告别繁琐,拥抱高效数据处理
java·excel
Sirius Wu2 小时前
大数据平台ETL任务导入分库分表数据
大数据·数据仓库·etl
这周也會开心2 小时前
Java-多态
java·开发语言