臭名昭著aTrust隔离计划1.臭名昭著aTrust隔离计划2.VPN原理与aTrust隔离网络实践3.docker-easyconnect到底做了什么4.TUN(tunnel-隧道-虚拟网卡)模式
个人项目
personal(个人展示)GitHub Actions 自动部署个人展示项目
基于Quartz搭建的个人博客1.Quartz个人博客使用教程2.使用 rsync 增量部署 Quartz 博客3.使用 GitHub Actions 自动部署 Quartz 博客5.域名绑定6.CDN加速Obsidian、双向链接与知识图谱
旅行
行程攻略青岛三日游行程攻略
前端
NginxNginx配置与反向代理入门
Nodenpm与npx的区别
中华财险-公司项目
对外接口文档
基础数据码表对外接口(仅支持rpc调用)业务码表对外接口应用主数据对外接口
基础运营查询版本更新日志详情消息中心对外接口站内信对外接口站内信模板配置手册
权限中心权限中心对外接口文档(最新)权限中心对外接口文档前端ACL-CORE FACADE依赖版本
审计中心审计中心对外接口文档audit-center-facade版本
审批中心工作流迁审批流现状工作流迁审批流API能力替换方案老审批流接口文档审批中心接口文档审批中心业务回调FAQ
账号中心内部系统对接单点登录内部系统对接认证中心三方网页应用登录授权账号中心对外接口文档前端账号中心RPC接口文档账户变更对外广播消息文档账户中心对外接口HRMS外部员工变更广播消息文档HRMS外部员工对外接口
组织员工岗位🔥机构映射SDK接口文档员工岗位变更通知说明组织机构管营一体概念与用法组织员工对外广播消息文档组织员工岗位对外接口文档组织员工岗位对外接口文档前端组织员工岗位数据模型组织员工主数据业务场景案例organization-facade版本
hrms(大型人力资源外包管理系统)
项目架构说明HRMS Maven模块与依赖说明
项目说明0.流程中心模块0.组织模块说明1.业务线模块2.计划模块3.项目模块4.协议模块5.供应商模块6.合约域模块7.外包人员模块*核心:外包人员生命周期
项目运维外包人员项目编制差异排查与修复2.HRMS相关问题排查4.修改externalId(externalId和accountId不一致)
需求-系分
1.内部转外包0723外包人员关联历史内部账号系分新增外包人员关联历史账号内容(紧急0723上线)需求
2.工作岗位0820工作岗位0820需求工作岗位0820需求-系分
3.用工模式调整0917内部人员转外包用工系统需求2内部人员转外包用工系统需求-系分
sso(账号中心-单点登录)
项目架构说明aboss-sso项目架构入门AOP统一日志打印链路Maven多模块项目高级知识OAuth2.0
项目说明1.SSO-OAuth2.0与IDaaS登录流程2.外部账号创建流水号并发问题分析
AI
使用说明
第三方插件&技能简介Archify使用与安装指南Ponytail使用指南
CodexCodex CLI与IDE区别及使用指南Codex Hook单独配置与提交通知Codex MCP安装与使用指南Codex第三方插件安装与使用指南
Agent开发1.LLM、Token、上下文窗口与模型参数2.大模型 API、请求参数与响应结构3.Spring AI ChatClient4.Prompt、System Prompt、Prompt 模板6.结构化输出、JSON Schema7.SSE 流式响应8.会话 ID、聊天记录、Redis9.超时、重试、限流、降级10.完成可运行聊天接口
GitGit常用命令与Obsidian推送排查
Java
面试题Java基础与集合面试题
AtomicInteger原子计数与并发安全ConcurrentHashMap并发安全与计数Java线程、线程池与Future
python
基础Python基础语法
HTTPXHRMS员工详情接口调用(Python HTTPX)

一、💡 一句话理解

第 4 天核心结论

ChatClient 是你在 Spring Boot 业务代码中调用大模型的客户端。今天只要学会:Spring Boot 自动提供 ChatClient.Builder,你把它 build()ChatClient,再用 prompt(...).call().content() 得到模型回答。

本篇对应 0-学习路线 的第 4 天:Spring AI ChatClient

今天完成后,你应该能做到:启动现有 Spring Boot 项目,访问一个 Java 接口,并看到模型返回的普通文本。

浏览器或 HTTP 请求

Controller 使用 ChatClient 提问

模型服务生成回答

Controller 返回字符串

二、🧭 理论:它是什么

2.1 ChatClient 是什么

ChatClient 是 Spring AI 提供的高级调用客户端。它帮业务代码完成“组织本次提问 → 调用底层模型 → 取出回答”的过程。

可以把它理解成 Java 后端和大模型之间的一个操作面板:你给它问题,它负责把问题交给已经配置好的模型服务,再把回答交还给你的代码。

今天只关注普通文本问答,不学习模型角色、流式输出、记忆或工具调用。

2.2 ChatClientChatModel 的关系

组件现在先这样理解
ChatModel底层模型调用能力,负责和 DeepSeek、OpenAI 等服务通信。
ChatClient业务代码直接使用的客户端,调用方式更简洁。
ChatClient.Builder用来创建 ChatClient 的构建器。

在你的项目中,模型地址、模型名和 API Key 已经在 application.properties 与 IDEA 运行配置中准备好。Spring Boot 根据这些配置创建底层 ChatModel,再自动提供 ChatClient.Builder

所以今天的业务代码不需要再次写 API Key、模型名或 HTTP 请求地址。

三、⚙️ 理论:它是怎么工作的

3.1 ChatClient 从哪里来

Spring Boot 启动后,会把自动配置好的 ChatClient.Builder 放进 Spring 容器。Controller 的构造方法请求这个对象,Spring 就会自动注入它。

private final ChatClient chatClient;
 
public AiController(ChatClient.Builder builder) {
    this.chatClient = builder.build();
}

这四行代码的过程是:

Spring Boot 自动配置模型

创建 ChatClient.Builder

注入到 AiController 构造方法

builder.build() 得到可使用的 chatClient

chatClient 是 Controller 的成员变量,后续每个接口方法都可以使用它。

3.1.1 构造方法这一段逐行是什么意思

public AiController(ChatClient.Builder builder) {
    this.chatClient = builder.build();
}

先看结论:这不是你手动执行的代码。Spring Boot 启动时要创建 AiController 对象,发现它的构造方法需要一个 ChatClient.Builder,就从 Spring 容器中取出已经准备好的 Builder 传进来。

代码含义
public AiController(...)AiController 的构造方法。创建 Controller 对象时会执行一次。
ChatClient.Builder参数的类型。这个类型本身提供了 build() 方法。
builder参数变量名,只是当前方法里对 Builder 对象的称呼;也可以命名为 chatClientBuilder
builder.build()调用 Builder 的创建方法,得到一个真正可调用模型的 ChatClient 对象。
this.chatClient当前 AiController 对象中的成员变量。this 的意思是“当前这个 Controller 自己”。
=把刚创建的 ChatClient 保存到成员变量中,供 test1() 等接口方法后续使用。

为什么 builder 能调用 build()?因为它的类型是 ChatClient.Builder,而 Spring AI 在这个类型中定义了 build() 方法。Java 判断“能不能调用某个方法”,看的是变量的类型,不是变量名字。

下面两个写法完全一样,只是参数变量名不同:

public AiController(ChatClient.Builder builder) {
    this.chatClient = builder.build();
}
 
public AiController(ChatClient.Builder chatClientBuilder) {
    this.chatClient = chatClientBuilder.build();
}

Spring Boot 创建 Controller 的完整过程是:

Spring Boot 启动
  → 读取 Spring AI Starter、模型地址、模型名和 API Key 配置
  → 自动创建 ChatModel 和 ChatClient.Builder
  → 扫描到 @RestController 的 AiController
  → 发现构造方法需要 ChatClient.Builder
  → 从 Spring 容器取出 Builder,作为 builder 参数传入
  → 执行 builder.build()
  → 得到并保存 chatClient

这叫“构造方法注入”:对象一创建,就把它依赖的对象传给它。这样 AiController 不用自己 new ChatClient,也不用自己处理模型配置。

3.2 最小调用链

最简单的普通问答是:

String answer = chatClient
        .prompt("Spring Boot 和 Spring AI 有什么关系?")
        .call()
        .content();
调用当前作用
prompt("...")放入本次要问模型的文字。第 5 天会专门学习 Prompt、System Prompt 和模板。
call()声明使用普通的一次性调用方式。
content()真正取出模型生成的文本;结果类型是 String

调用流程是:

问题文本
  → ChatClient 组织本次调用
  → ChatModel 请求已配置的模型服务
  → 模型生成回答
  → content() 取出回答字符串

四、🚀 实践:从准备到验证

4.1 前置准备

本篇不重复第 1 天的项目创建和第 3 天的模型 API 配置。开始今天的代码前,只确认下面三件事已经完成。

4.1.1 已有 Spring Boot 项目和 OpenAI 兼容模型配置

你的当前项目已经使用 DeepSeek 的 OpenAI 兼容接口,配置应类似:

spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.model=deepseek-v4-flash

DEEPSEEK_API_KEY 的真实值放在 IntelliJ IDEA 的 AiApplication 运行配置的环境变量中,不写进这个文件。

如果还不理解 API Key、模型名和 base-url,先回看 2.大模型 API、请求参数与响应结构

4.1.2 已添加 Spring AI OpenAI Starter

pom.xml 中需要有:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

它的作用是让 Spring Boot 能够创建底层模型和 ChatClient.Builder

4.1.3 启动后端项目

打开 AiApplication,点击 IntelliJ IDEA 的绿色运行按钮。成功后保持项目运行,并确认服务监听 8080 端口。

今天用的是普通同步调用,不需要先学习 SSE,也不需要启动前端项目。

4.2 可以拿来干什么

4.2.1 做一次普通文本问答

用途:后端向模型发送固定问题,拿到一段普通字符串回答。这是后续聊天接口、Prompt、结构化输出、流式输出等能力的共同起点。

前置:已完成 4.1,并且已经通过构造方法创建了 chatClient

String answer = chatClient
        .prompt("Spring Boot 和 Spring AI 有什么关系?")
        .call()
        .content();

输入是问题字符串;输出是模型生成的 String。今天先把这个字符串直接返回给 HTTP 调用方,下一步再学习怎样控制问题格式和回答风格。

4.3 完整实践:第一个 ChatClient 接口

目标:在当前项目中新增一个 /test1 接口。访问它后,后端调用模型,并把模型回答直接返回。

4.3.1 在 Controller 中写入代码

文件位置:

src/main/java/com/afyke/ai/controller/AiController.java

如果文件已经存在,只需要确认其中有下面的 chatClient 字段、构造方法和 test1 方法;不要重复创建两个同名 Controller。

package com.afyke.ai.controller;
 
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class AiController {
 
    private final ChatClient chatClient;
 
    public AiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }
 
    @GetMapping("/test1")
    public String test1() {
        return chatClient
                .prompt("Spring Boot 和 Spring AI 有什么关系?")
                .call()
                .content();
    }
}

输入:代码中固定的问题“Spring Boot 和 Spring AI 有什么关系?”。

处理:test1() 调用 chatClient,模型生成文本,content() 取回文本。

输出:接口返回模型生成的一段普通文字。

4.3.2 用 HTTP Client 验证

在后端项目根目录的 request.http 中添加:

### 第 4 天:ChatClient 普通文本调用
GET http://localhost:8080/test1

启动 AiApplication 后,点击请求左侧的绿色运行按钮。

预期结果:HTTP 状态为 200,响应正文是一段模型对 Spring Boot 和 Spring AI 关系的回答。

至此,今天的链路已经跑通:

GET /test1
  → AiController.test1()
  → chatClient.prompt(...).call().content()
  → DeepSeek
  → 返回文本

五、📌 总结

  • 本篇对应学习路线第 4 天,只学习 ChatClient 的普通文本调用。
  • Spring Boot 自动提供 ChatClient.Builder,构造方法注入后调用 build() 得到 ChatClient
  • prompt(...).call().content() 是最小调用链,结果是 String
  • 今天的验收是 GET /test1 能返回模型回答。
  • 第 5 天再学习 Prompt、System Prompt 和 Prompt 模板。
  • 第 6 天再学习结构化输出;第 7 天学习 SSE;第 8 天学习会话 ID、聊天记录和 Redis。
  • RAG、Tool Calling 和 Agent 工作流属于后续阶段,不混入本篇。

记忆句:

ChatClient = 注入 Builder → build() → prompt() → call() → content()

官方资料: