Java转AI应用开发速成(3)—— 第一个 SpringAI 聊天应用

准备工作:

创建api-key,以deepSeek为例:DeepSeek开放平台

一、创建项目

Spring Boot 3.3+,JDK 21,添加依赖:

xml 复制代码
<!-- Spring AI  -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>

application.yml

yaml 复制代码
spring:
  application:
    name: java-tech-assistant

  ai:
    openai:
      api-key: ${DEEPSEEK_API_KEY:换成自己的key}
      base-url: https://api.deepseek.com
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7

server:
  port: 8080
  servlet:
#    否则流式输出乱码
    encoding:
      charset: UTF-8
      enabled: true
      force: true

二、最简单的聊天接口

java 复制代码
@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder
                .defaultSystem("你是一个专业的Java技术助手,回答简洁准确。")
                .build();
    }

    /**
     * 聊天接口 - 完整输出
     * GET /chat?message=你好
     */
    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .call().content();
    }
}

接口测试 测试:

AI 返回一连串 Java 八股文------你的第一个 AI 应用就跑通了。


三、加上流式输出(打字机效果)

上面那个是一口气吐完整段回复,没有 ChatGPT 那种逐字输出的效果。加流式输出:

java 复制代码
 /**
     * 流式聊天接口 - 逐字输出
     * GET /chat/stream?message=你好
     */
    @GetMapping(value = "/chat/stream", produces = "text/event-stream;charset=UTF-8")
    public Flux<String> streamChat(@RequestParam String message) {
        return chatClient.prompt()
                /**
                 * 创建一个 Prompt 对象,并设置用户输入的 message
                 */
                .user(message)
                .stream()
                .content();

    }

四、加上历史对话记忆

聊到第三句 AI 忘记了第一句?加上记忆:

java 复制代码
	public ChatController(ChatClient.Builder builder, ChatMemory chatMemory) {
        this.chatClient = builder
                .defaultSystem("你是一个专业的Java技术助手,回答简洁准确。")
                .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
                .build();
    }

    @GetMapping(value = "/chat/stream", produces = "text/event-stream;charset=UTF-8")
    public Flux<String> streamChat(
            @RequestParam String message,
            @RequestParam(defaultValue = "default") String sessionId) {
        return chatClient.prompt()
                .user(message)
                // 历史对话 
                .advisors(a -> a.param("chat_memory_conversation_id", sessionId))
                .stream()
                .content();
    }

核心机制是 Spring AI 的 MessageChatMemoryAdvisor:

数据流:

  • → Controller
  • → MessageChatMemoryAdvisor.aroundCall/aroundStream
    1. 从 InMemoryChatMemory 查 sessionId 对应的历史消息
    2. 将历史消息注入到 Prompt 的 messages 列表中
    3. 调用 LLM
    4. LLM 回复后,将本轮 User 消息 + Assistant 回复存入 InMemoryChatMemory
  • → 返回结果

一句话总结:

Advisor 拦截请求 → 从 Map<sessionId, 历史消息> 取出前文拼进 prompt → LLM 回复后把本轮问答追加回去。纯内存,默认保留最近 100 条。

五、加上页面测试

六. ChatClient API 速查表

1. 构建输入 --- .prompt()

方法 作用
.prompt() 创建请求入口,返回 PromptRequestSpec
.prompt(String text) 快捷方式,等价于 .prompt().user(text)

2. 组装消息 --- PromptRequestSpec

方法 说明
.user(String text) 用户消息
.system(String text) 系统角色设定
.messages(Message... msgs) 自定义消息列表
.messages(Consumer) 编程式追加消息
.options(ChatOptions ops) 模型参数(temperature、topP 等)
.advisors(Advisor... ads) 请求拦截器链(RAG、日志、对话记忆)
.advisors(Consumer) 编程式组装 advisor 链
.toolContext(Map) 传上下文给 advisor
.tools(Object... beans) 注册 Function Calling 工具

3. 发送 & 返回形式 --- PromptRequestSpec

方法 返回类型 用途
.call() ChatClientCallResponseSpec 同步、一次性返回完整结果
.stream() ChatClientStreamResponseSpec 流式、逐 token 输出
.entity(Class<T>) UserInputAdvisor 链 结构化提取(提前终止,不调 LLM)

4. 取结果

call() 的结果:

方法 返回
.chatResponse() ChatResponse(含 metadata、token 用量)
.content() String(纯文本,最常用)
.entity(Class<T>) 反序列化到实体
.entities(ParameterizedTypeRef<T>) 反序列化到泛型集合

stream() 的结果:

方法 返回
.chatResponse() Flux
.content() Flux(逐字推送文本)
.entity(Class<T>) Flux

付源码地址: https://gitee.com/menglinjie/hello-ai

相关推荐
ofoxcoding41 分钟前
Codex Computer Use 完整指南:AI 自动操控 Mac 与 Windows 桌面实战详解
人工智能·windows·macos·ai
结城明日奈是我老婆1 小时前
comfyui 控制图像Controlnet
ai·ai作画
一叶飘零_sweeeet1 小时前
IDEA 插件 Trae AI 最新全攻略(基于 TRAE AI: Coding Assistant 1.7.0.0)
java·intellij-idea·trae
KobeSacre1 小时前
CyclicBarrier 源码
java·jvm·算法
达达尼昂1 小时前
编码智能体中的模型选择与执行深度
人工智能·后端·程序员
用户6757049885021 小时前
写了 6 年 Go ,我终于领悟到了泛型的真正威力!
后端·go
志凌海纳SmartX2 小时前
构建 Agent Ready 的企业云基础设施(白皮书下载)
人工智能·ai·agent·smartx·企业云·榫卯企业云
我登哥MVP2 小时前
Hadoop成长史-从Nutch子项目到大数据生态王者
java·大数据·hadoop·分布式·云原生·云计算
进击切图仔2 小时前
SAM3 微调标注流水线和 Label Studio
java·服务器·前端
名字还没想好☜2 小时前
Go error 处理:errors.Is/As 与错误包装
开发语言·后端·golang·go·错误处理