(本篇先只讲基础操作)

Spring AI是什么?它是干什么的?

首先 Spring AI 是一个应用程序框架(类似spring boot)

它的目标是将 Spring 生态系统的设计原则应用于 AI 领域,比如:

  • 用 Spring 容器管理 AI 相关组件
  • 用统一接口封装不同模型提供商,降低耦合
  • 把聊天模型、向量存储、提示词模板等组件像普通 Spring Bean 一样组合起来

(补充spring的设计原则:通过 IoC 容器统一管理对象的创建和依赖关系(DI),从而实现低耦合;同时配合面向接口编程、分层设计和约定优于配置,使系统具有良好的可扩展性和可维护性)

从最核心的接口之一(chatclient)出发

为什么使用chatclient,他是干什么的?

首先chatclient的作用是作为门面,屏蔽底层不同 AI 供应商(如 OpenAI, Ollama, Azure 等)的接口差异,功能有:

  • 输入封装:方便地传递文本、模板参数、多模态数据(图片/音频)。
  • 上下文管理:支持维护对话记忆(Chat Memory)。
  • 结构化输出:自动将 AI 返回的字符串映射为 Java 对象(POJO)。

之前我们是直接使用 Spring Boot 注入的 ChatModel 来调用大模型完成对话,ChatClient 是对 ChatModel 的更高层次封装,提供更友好、更易用的 API,通常作为应用层的首选入口

// 基础用法(ChatModel)
ChatResponse response = chatModel.call(new Prompt("你好"));

// 高级用法(ChatClient)支持链式调用
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultSystem("你是恋爱顾问")
    .build();
    
String response = chatClient.prompt().user("你好").call().content();

基本使用流程

  1. 实例化,通过 ChatClient.Builder 来创建一个实例,可以预设一些通用的配置(如默认系统指令)
    // 方式1:使用构造器注入
    public class ChatService {
        private final ChatClient chatClient;
        
        public ChatService(ChatClient.Builder builder) {
            this.chatClient = builder
                .defaultSystem("你是恋爱顾问")
                .build();
        }
    }
    
    // 方式2:使用建造者模式
    ChatClient chatClient = ChatClient.builder(chatModel)
        .defaultSystem("你是恋爱顾问")
        .build();
  2. 发起请求
    1. 有了实例,你就可以通过链式调用来发送消息
      String response = chatClient.prompt()
          .user("请解释什么是依赖注入")
          .call()
          .content(); // 获取文本结果
    2. 返回 ChatResponse 对象(包含元数据如 token 使用量)
      ChatResponse chatResponse = chatClient.prompt()
          .user("Tell me a joke")
          .call()
          .chatResponse();
    3. 返回单个实体
      record ActorFilms(String actor, List movies) {}
      ActorFilms actorFilms = chatClient.prompt()
          .user("Generate the filmography for a random actor.")
          .call()
          .entity(ActorFilms.class);
    4. 流式返回(适用于打字机效果)
      // 响应式流
      Flux streamWithMetadata = chatClient.prompt()
          .user("Tell me a story")
          .stream()
          .chatResponse();
      
      streamResponse.subscribe(
          chunk -> System.out.print(chunk),  // 每收到一个片段就打印
          error -> System.err.println("Error: " + error),
          () -> System.out.println("\n--- Story completed ---")
      );

然后就是多轮对话的实现 ChatMemory

每次 AI 调用本质上都是一次独立请求,AI 本身并不会记住之前的内容。

所以如果你想让 AI 知道前面说了什么,就必须手动把历史消息加到 prompt 里。

ChatMemory memory = new InMemoryChatMemory(); // 初始化基于内存的对话记忆,当然也有储存在其他地方的

ChatClient client = ChatClient.builder()
    .advisor(new ChatMemoryAdvisor(memory)) //加在client
    .build();
ChatResponse response = client.prompt()
                    .user(message) 
                    //给 Advisor 传参数
                    .advisors(spec -> spec
                            .param(ChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) //CHAT_MEMORY_CONVERSATION_ID_KEY → 指定哪一段记忆(不同会话不同历史)已存在就读取,不存在就创建
                            .param(ChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) //CHAT_MEMORY_RETRIEVE_SIZE_KEY → 取最近多少条消息,控制多轮上下文长度
                    .call()
                    .chatResponse();

ChatMemoryAdvisor可以做到在每次用户请求和回复时

  • before()读取历史消息,构建 prompt
  • after()把本轮消息写回记忆

好了,以上对话的基础操作就到这里,我也在不断学习,接下来再是Advisor、结构化输出、记忆持久化、提示词模板等内容

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐