W7D1 学习手册 1.ChatClient2.API3.统一多模型4.Advisor5.内置 6.自定义7.结构化原理8.绑定9.对比W110.平台定位 资源达标①达标②自测速记

FDE W7D1 学习手册 · Spring AI 基础(ChatClient、Advisor、Structured Output)

W7 周级拆解 Day1 · A 级(必须掌握,面试核心)· 约 4h · 学完能讲清"Java 侧如何用 Spring AI 统一多模型、做拦截治理、并稳定拿到结构化对象"

本日定位:W1 我们用"自研 Model Adapter"做了多模型统一接入的轻量网关;W7 进入"企业级 Java 侧 AI 平台"实战,第一天先掌握 Spring AI 的三大基石:ChatClient(统一对话入口)、Advisor(拦截器链)、Structured Output(输出绑定 Java 对象)。这是把 W1 原型升级为生产框架的起点。
学完能回答:① ChatClient / Advisor / Structured Output 各自解决什么问题、怎么用;② Spring AI 如何做到"换模型不改业务代码";③ 它和 W1 自研 Adapter 的取舍(框架级 vs 轻量网关)。
使用方法:通读原理 → 重点看「🔧 工程含义」「🎤 面试话术」「⚠ 易错点」→ 做末尾自测清单 → 配合《FDE-W7D1-评测题.md》。选中不熟的词可标注(左下 ★ 重要 / 右下 📌 待查)。候选人背景:36 岁,Java + 大数据 + 医疗保险,回答时务必把能力落到"Java 企业 AI 平台"上。

一、ChatClient:统一对话入口

1.1 是什么

ChatClient 是 Spring AI 面向应用层的统一对话入口,封装了底层各种模型的 ChatModel 实现(如 QwenChatModelDeepSeekChatModelAnthropicChatModel)。业务代码只面向 ChatClient 编程,不直接依赖具体厂商 SDK

业务代码 → ChatClient → ChatModel(Qwen / DeepSeek / Claude)→ HTTP 厂商 API

1.2 核心能力

ChatClient 是"门面(Facade)"——业务侧只认它,底层模型可插拔。对企业 AI 平台意味着:同一套 RAG / Agent 业务代码,可在 Qwen(低成本)、DeepSeek(推理强)、Claude(长上下文)之间切换,业务零改动。
ChatClient 是 Spring AI 的统一对话门面,业务代码只面向它写,底层 Qwen / DeepSeek / Claude 随意换。它支持多角色 Prompt、流式、Advisor 拦截链、以及把输出直接绑定成 Java 对象。
① ChatClient 不是"魔法"——它只是封装了 ChatModel,真正的网络调用、协议差异仍在 ChatModel 实现里,模型特有参数(如某个厂商的 thinking 开关)仍需透传。② 别把 ChatClient 当单例乱灌状态——它是无状态门面,但传入的 Prompt / Advisor 链要小心线程安全。③ 流式 stream() 返回的 Flux 必须被订阅(subscribe 或 collectList),否则不会发起请求。

二、ChatClient 核心 API 与构建

2.1 构建方式

@Bean
public ChatClient chatClient(ChatModel chatModel) {
    return ChatClient.builder(chatModel)
            .defaultSystem("你是医疗保险理赔助手,回答需基于知识库")
            .defaultAdvisors(new LoggingAdvisor(), new RetryAdvisor())
            .build();
}

2.2 调用方式

// 非流式,拿文本
String ans = chatClient.prompt()
        .user("特药理赔需要哪些材料?")
        .call()
        .content();

// 流式
Flux<String> flux = chatClient.prompt()
        .user("解释等待期")
        .stream()
        .content();

// 直接拿结构化对象
ClaimDecision d = chatClient.prompt()
        .user(u -> u.text("判断该理赔是否成立:{0}", claimJson))
        .call()
        .entity(ClaimDecision.class);

2.3 关键方法对照

方法返回用途
call().content()String非流式取纯文本
call().entity(Class)Java Bean结构化输出(见 s7)
call().response()ChatResponse要拿 token 用量 / 元数据时用
stream().content()Flux<String>流式打字机
prompt().advisors(a...)链式本次调用叠加/覆盖 Advisor
生产里优先用 call().entity(Class) 拿强类型对象而非手写 JSON parse;需要成本统计时 response().getMetadata().getUsage() 取 token 用量(呼应 W4 Trace 的 cost 字段)。
ChatClient 用 builder 注入默认 system 提示和默认 Advisor;调用时 call().content() 拿文本、entity(Class) 拿对象、response() 拿 token 用量、stream() 流式。

三、ChatClient 如何统一多模型(Qwen / DeepSeek / Claude)

3.1 靠 ChatModel 抽象 + 自动装配

Spring AI 为每个厂商提供了 ChatModel 实现,并通过 Spring Boot 的 spring-ai-starter-model-* 自动装配。只要换配置(或换 bean),ChatClient 背后就换了模型。

# application.yml 仅改 provider 和 key,业务代码不动
spring:
  ai:
    qwen:
      api-key: ${QWEN_KEY}
      chat.options.model: qwen-max
    # 切换 DeepSeek 时换成 spring.ai.deepseek.*

3.2 多模型路由的两种落地

对比 W1:W1 自研 Adapter 是我们手写 ModelRouter 做"按 provider 选 HTTP client + 统一响应结构";Spring AI 是框架级提供 ChatModel 抽象 + starter 自动装配,省去手写协议适配,但抽象层级更高、可控性略低。
企业 AI 平台通常"两层统一":接入层 Gateway(W7D4,统一鉴权/限流/成本/路由)做横切治理;应用层 ChatClient 做业务编排。两者不冲突,Gateway 在 ChatModel 的 HTTP 出口之前,ChatClient 在业务和 ChatModel 之间。
Spring AI 靠 ChatModel 抽象 + starter 自动装配统一多模型:业务只写 ChatClient,换模型只需换配置或换 ChatModel bean,零改业务代码。多模型可在配置层切换,也可运行时注入多个 ChatModel 做路由。
① 不同厂商参数集合不同(如 Claude 的 max_tokens 必填、Qwen 的 enable_thinking),ChatClient 的"统一"只到方法签名层面,厂商特有参数要用 .with(ChatOptions) 透传,别假设完全等价。② 切换模型后输出风格/JSON 合规性会变,结构化输出成功率要重新压测。③ 统一不等于"一个 prompt 通吃所有模型"——长上下文、工具调用能力因模型而异。

四、Advisor:拦截器链(类比 Servlet Filter)

4.1 是什么

Advisor 是 Spring AI 在 ChatClient 调用前后插入的拦截器,概念上完全类比 Servlet Filter / Spring 的 HandlerInterceptor:围绕一次对话请求做横切处理(日志、重试、限流、改写、记忆)。

请求 → Advisor① → Advisor② → ... → ChatModel → 回程逐层返回 → 业务

4.2 执行模型

Advisor 是"治理逻辑与业务代码解耦"的关键。企业平台常见的日志审计、敏感词拦截、限流、重试、注入知识库上下文(RAG Advisor)都该放在 Advisor 里,业务方法保持干净。
Advisor 就是 LLM 版的 Filter Chain:一次对话前后被一串 Advisor 包裹,可改 prompt、做日志/重试/限流/改写。顺序靠 order 控制,治理逻辑与业务解耦。
① Advisor 链顺序很重要——"先限流还是先写日志""先注入知识还是先记 Trace"会影响成本和正确性,要在设计文档里固定。② Advisor 里不要做耗时阻塞又无超时的操作,会拖慢整条对话链路。③ 在 Advisor 内修改 prompt 后,要同步更新 AdvisorContext,否则下游 Advisor 看不到变化。

五、内置 Advisor(日志 / 重试 / 限流 / 提示改写)

5.1 常用内置

Advisor作用企业场景
LoggingAdvisor打印请求/响应(可脱敏)调试、审计留痕
RetryAdvisor / Re2Advisor失败重试(指数退避)网络抖动、限流 429
RateLimitAdvisor令牌桶限流保护后端模型配额
MessageChatMemoryAdvisor注入会话记忆多轮对话(见 W7D2)
QuestionAnswerAdvisor内置 RAG(向量检索注入)保险知识库问答
ChatMemory + Prompt 改写压缩/改写用户问题长上下文裁剪

5.2 重试 Advisor 示例

@Bean
public Advisor retryAdvisor() {
    return new RetryAdvisor(3, Duration.ofSeconds(1)); // 最多3次,间隔1s
}
重试要配合"幂等"——对话请求本身非天然幂等(同 prompt 两次可能不同答案),重试只应针对传输/限流错误,对"答案不满意"不要盲目重试,要靠带反馈重试(见 W1 结构化)。
Spring AI 内置了日志、重试、限流、记忆、RAG、提示改写等 Advisor。重试只针对传输/429 错误,不要对"答案不好"盲目重试。

六、自定义 Advisor(实现 + 顺序)

6.1 实现方式

public class AuditAdvisor implements Advisor {
    private final MeterRegistry meter;
    public AuditAdvisor(MeterRegistry meter){ this.meter = meter; }
    @Override public int getOrder(){ return 1; } // 越早就越靠近入口
    @Override
    public AdvisedResponse adviseCall(AdvisedRequest req, CallAdvisorChain chain) {
        long t0 = System.nanoTime();
        AdvisedResponse resp = chain.nextAroundCall(req); // 放行
        meter.timer("ai.call").record(System.nanoTime()-t0, TimeUnit.NANOSECONDS);
        return resp;
    }
    // adviseStream 类似,注意流式要透传 Flux
}

6.2 注册

通过 ChatClient.builder().defaultAdvisors(auditAdvisor, retryAdvisor) 注册全局 Advisor,或在单次调用 .advisors(...) 临时叠加。

自定义 Advisor 是企业 AI 平台"统一埋点/统一限流/统一脱敏"的标准扩展点。建议把 Trace 注入(trace_id 透传)、成本统计、敏感词拦截都做成内置 Advisor,新业务自动获得能力。
自定义 Advisor 实现 getOrder() 定顺序、adviseCall/adviseStream 包裹链,在 builder().defaultAdvisors() 注册。流式的 adviseStream 必须把 Flux 透传下去,不能提前 collect。
① 实现 adviseStream务必透传 Flux,若 collectList() 再返回就失去了流式,还可能导致上游异常时拿不到部分结果。② getOrder()@Order 二选一,混用易乱;建议只用 getOrder() 集中管理。③ 多 Advisor 修改同一字段要防互相覆盖(用 AdvisedRequest.mutate() 生成新对象而非改原对象)。

七、Structured Output 原理(输出绑定 Java 对象)

7.1 是什么

Structured Output 让模型返回的内容自动绑定成 Java 对象,底层靠 JSON Schema 约束 + 解析。Spring AI 用 BeanOutputConverter / StructuredOutputConverter 把 Java 类型信息翻译成 JSON Schema 注入 prompt 或 response_format,再把响应解析回对象。

Java Class → 反射生成 JSON Schema → 注入 prompt/response_format → 模型输出 JSON → 解析为对象

7.2 与 W1 结构化输出的关系

对比 W1 的 Pydantic:Spring AI 的 BeanOutputConverter 等于"Jackson 版 schema 自动生成 + 反序列化"。但语义校验(值是否合理)仍是业务自己的事——框架只保证形,Spring 的 @NotNull / @Min Bean Validation 可补一层。
Structured Output = Java 类型 → 自动生成 JSON Schema → 注入模型 → 响应解析回对象。Spring AI 用 Jackson 反射完成,等于 Java 版 Pydantic,但语义校验仍要自己做。
① Spring AI 的 schema 生成依赖 Jackson 注解(@JsonProperty / @JsonClassDescription),字段没描述、没类型约束,模型更易瞎填。② 复杂嵌套/泛型/Optional 的 schema 生成可能不全,成功率下降,越简单越稳。③ 解析失败不要静默返回 null,要抛异常走重试/降级(呼应 W1 校验重试)。

八、用 BeanOutputConverter / entity() 实现结构化输出

8.1 定义 Bean + 描述

@JsonClassDescription("特药理赔审核结论")
public class ClaimDecision {
    @JsonPropertyDescription("理赔是否成立") boolean approved;
    @JsonPropertyDescription("拒赔原因,成立时为空") String rejectReason;
    @JsonPropertyDescription("风险等级 low/medium/high") String riskLevel;
    @JsonPropertyDescription("引用的知识库条款 id 列表") List<String> clauseIds;
    @JsonPropertyDescription("无法判断时为 true") boolean shouldRefuse;
}

8.2 调用

ClaimDecision d = chatClient.prompt()
        .user(u -> u.text("根据以下理赔材料给出结论:\n{claim}", claim))
        .call()
        .entity(ClaimDecision.class); // 内部用 BeanOutputConverter

// 或显式拿 converter
BeanOutputConverter<ClaimDecision> conv = new BeanOutputConverter<>(ClaimDecision.class);
String schema = conv.getJsonSchema();
Prompt p = new Prompt("按 schema 输出:" + schema + "\n材料:" + claim);
ClaimDecision d2 = conv.convert(chatClient.prompt().user(p.contents()).call().content());

8.3 校验增强

叠加 Bean Validation:validator.validate(d) 校验 @NotNull / 枚举 / 范围,失败则带反馈重试(同 W1 思路)。

生产推荐:entity(Class) + Bean Validation(@NotNull/@Pattern/@Min)+ 失败带反馈重试(把校验错误喂回 prompt)+ 超限降级(默认值/转人工)。把这套封成平台级 Advisor 最省心。
@JsonClassDescription + @JsonPropertyDescription 给字段加描述,调用 call().entity(ClaimDecision.class) 直接拿对象;再叠 Bean Validation 做语义校验,失败带反馈重试。

九、与 W1 自研 Model Adapter 的对比(框架级 vs 轻量网关)

维度W1 自研 Model Adapter(轻量网关)Spring AI(框架级)
抽象层级薄封装:统一 HTTP + 响应结构厚框架:ChatClient/Advisor/记忆/工具/向量全套
多模型手写 ModelRouter 按 provider 选 clientChatModel 抽象 + starter 自动装配
结构化手动 response_format + PydanticBeanOutputConverter 自动 schema + 反序列化
治理自己写限流/重试/日志Advisor 链 + 内置 Advisor
可控性高,每行都自己写中,受框架约定约束
开发速度慢,但灵活快,约定优于配置
适用需极致定制/自研网关(W7D4)业务侧快速搭 AI 能力
实际企业平台是"自研 Gateway + Spring AI 双栈":Gateway(接入层,W7D4)统一做鉴权、路由、限流、成本、Trace;Spring AI(应用层)做业务编排、Advisor 治理、结构化。W1 自研 Adapter 演进成 Gateway,Spring AI 做业务侧统一。两者互补不冲突。
W1 自研 Adapter 是薄网关(统一 HTTP + 响应),Spring AI 是厚框架(对话/Advisor/记忆/工具/向量全套)。实战里自研 Gateway 做接入层治理,Spring AI 做应用层编排,互补。
① 别把"用 Spring AI 就不需要 Gateway"——Spring AI 管不到跨业务线的统一配额/成本/审计,那是 Gateway 的活。② 也别"啥都自研"——重复造 ChatClient/Advisor 轮子浪费人力,业务侧直接用 Spring AI 更快。③ 面试常坑:把两者对立,正确是分层。

十、候选人视角:Java 企业 AI 平台能力定位

作为 36 岁、Java + 大数据 + 医疗保险背景的候选人,讲 Spring AI 时要落到企业 AI 平台工程能力,而非"会用 API":

大数据背景优势:把 LLM 调用日志接入现有 Kafka + 数仓做成本/质量分析;医疗保险背景优势:懂"理赔结论必须可校验、可拒答、可审计"的强约束场景,正好用 Structured Output + 校验兜底。
讲 Spring AI 时突出"平台能力":统一多模型编排、Advisor 内建治理、结构化输出兜底、Trace 接入现有监控。结合医保/保险强约束场景(结论可校验、可拒答、可审计),比单纯会用 API 高一个层次。

十一、学习资源(中文 / 官方)

本日非 OpenAI 体系:全程围绕 Spring AI(Java 侧)+ 国内可用模型 Qwen / DeepSeek + Claude。符合"企业 Java AI 平台"定位。

十二、面试达标线①:ChatClient / Advisor / Structured Output 各自作用

组件一句话作用关键点
ChatClient统一对话门面,业务只面向它编程多角色 Prompt、流式、Advisor 链、entity() 结构化
Advisor对话前后拦截器链,做横切治理类比 Filter,可改 prompt、做日志/重试/限流/改写,order 控序
Structured Output把模型输出绑成 Java 对象Jackson 反射生成 JSON Schema + 反序列化,需校验兜底
达标线①核心:ChatClient=统一对话门面;Advisor=拦截器链做治理(类比 Filter);Structured Output=模型输出绑 Java 对象(JSON Schema + 反射)。三者分别解决"统一入口、横切治理、稳定输出"三个问题。

十三、面试达标线②:Spring AI 怎么统一多模型、与 W1 自研 Adapter 取舍

Spring AI 统一多模型 = ChatModel 抽象 + starter 自动装配(换配置/换 bean 即换模型) vs W1 自研 Adapter = 手写 ModelRouter + 统一响应结构(轻量网关) → 实战:接入层自研 Gateway(W7D4)+ 应用层 Spring AI 双栈互补
  1. 统一多模型:业务只写 ChatClient;换模型改 spring.ai.*.api-key/model 配置或注入不同 ChatModel bean,业务零改动;运行时可注入多个 ChatModel 做场景路由。
  2. 与 W1 取舍:W1 自研 Adapter 是薄网关、可控性最高,适合做企业 Gateway(限流/成本/审计跨业务线);Spring AI 是厚框架、开发快,适合业务侧快速搭 AI 能力。两者分层互补:Gateway 在接入层、Spring AI 在应用层,不是二选一。
  3. 易踩坑:厂商特有参数要透传、换模型后结构化成功率要重测、统一不等于一个 prompt 通吃。

十四、W7D1 自测清单

十五、高频面试题速记卡

Q:ChatClient 和 ChatModel 什么关系?
ChatClient 是面向业务的统一门面,内部委托 ChatModel(Qwen/DeepSeek/Claude 等实现)。业务只认 ChatClient,模型可插拔。
Q:Advisor 类比什么?能做什么?
类比 Servlet Filter / HandlerInterceptor,围绕对话做横切治理:日志、重试、限流、提示改写、注入记忆。顺序靠 order 控制。
Q:Spring AI 怎么统一多模型?
ChatModel 抽象 + starter 自动装配;换配置或换 ChatModel bean 即可,业务代码零改动。运行时可注入多个做路由。
Q:Structured Output 底层原理?
用 Jackson 反射把 Java 类型转成 JSON Schema 注入模型,再把响应反序列化成对象。框架只保证"形",语义校验仍要自己做。
Q:entity() 拿到对象后还要校验吗?
要。框架只保语法/字段正确,值可能幻觉。叠 Bean Validation + 业务校验 + 失败带反馈重试 + 降级。
Q:Spring AI 能取代 AI Gateway 吗?
不能。Spring AI 是应用层业务编排,管不到跨业务线的统一配额/成本/审计;Gateway 在接入层做这些。两者分层互补。
Q:自研 Adapter(W1)和 Spring AI 怎么取舍?
自研=薄网关、可控高、适合 Gateway;Spring AI=厚框架、开发快、适合业务侧。实战双栈:Gateway 接入层 + Spring AI 应用层。
Q:自定义 Advisor 流式要注意什么?
adviseStream 必须透传 Flux,不能 collectList 阻断流式;顺序管理只用 getOrder 避免混乱。
Q:换模型后有什么隐患?
厂商特有参数需透传;输出风格/JSON 合规性变化,结构化成功率要重新压测;一个 prompt 未必通吃所有模型。
Q:为什么把治理逻辑放 Advisor 而不是业务里?
解耦、可复用、可集中管控。审计/限流/脱敏/埋点做成平台级 Advisor,新业务自动继承,避免散落各处。
FDE W7D1 学习手册 · Spring AI 基础(面试级)· 配合《FDE-W7D1-评测题.md》自测
📌 待查★ 重要