切换主题
Spring AI 1.1.3 手术刀式拆解
当前主线:先把 Spring AI Core 的请求生命周期看透,再进入 Tool Calling、Spring AI Alibaba、Agent Framework 与 Graph Core。
为什么使用三个月仍然容易模糊
下面的业务代码很短:
java
String answer = chatClient.prompt()
.user(question)
.call()
.content();但它隐藏了完整执行链:
text
ChatClient
→ RequestSpec 收集配置
→ ChatClientRequest / Prompt 组装
→ Advisor Around Chain
→ ChatModel 统一抽象
→ DeepSeekChatModel 协议适配
→ DeepSeekApi HTTP 调用
→ ChatResponse / Generation / Message 包装
→ content() / chatResponse() / entity() 提取如果没有形成方法级地图,遇到下面的问题时就只能猜:
prompt()、call()、content()分别做了什么?- 默认 system 和本次 system 是覆盖还是追加?
- 默认 Advisor 和本次 Advisor 会不会同时存在?
- Advisor 的 before 和 after 为什么方向相反?
- Memory 在什么时候读历史、写 UserMessage、写 AssistantMessage?
- DeepSeek 的非流式与流式真正调用点在哪里?
content与reasoningContent被放到了哪里?- Tool Calling 为什么可能再次请求模型?
- 流式取消后为什么可能留下半轮对话?
这套课程只做一件事:
把 Spring AI 隐藏在流式 API 背后的对象、状态、调用顺序和失败边界全部显影。
精确版本基准
本阶段固定为:
text
JDK 17
Spring AI Core 1.1.3
Spring AI 官方 DeepSeek 模块
DeepSeek 作为主要模型提供方必须区分:
text
Spring AI Core 1.1.3
Spring AI Alibaba 的版本
Agent Framework / Graph Core 的版本
DeepSeek 供应商协议版本本阶段源码结论以:
text
spring-projects/spring-ai
v1.1.3 标签为准,不把主分支或更高版本行为直接套进来。
Spring AI 九层剖面
第 1 层:业务入口
业务层决定:
- conversationId 和租户边界;
- 是否启用 Memory、RAG、Tool;
- 使用非流式还是流式;
- 超时、取消、重试和幂等语义;
- 对外返回字符串、结构化对象还是事件流。
第 2 层:ChatClient
ChatClient 是业务门面,不是模型。
它负责:
text
收集调用配置
组织 Advisor
创建响应操作对象
提供 content()、chatResponse()、entity() 等结果视图第 3 层:DefaultChatClientRequestSpec
执行:
java
chatClient.prompt()
.system(...)
.user(...)
.messages(...)
.advisors(...)
.options(...)
.tools(...);主要是在可变 RequestSpec 中收集配置,还没有调用 DeepSeek。
第 4 层:ChatClientRequest 与 Prompt
执行 call() 或 stream() 时,框架才会正式:
text
渲染模板
创建 SystemMessage / UserMessage
合并显式 messages
处理工具选项
创建 Prompt
创建 ChatClientRequest
构建 Advisor Chain消息基本顺序:
text
SystemMessage
→ 显式 messages
→ UserMessage第 5 层:Advisor Chain
Advisor 不是简单的前置拦截器,而是环绕链:
text
Advisor A before
→ Advisor B before
→ ChatModel
→ Advisor B after
→ Advisor A after每个 Advisor 都可以:
text
修改请求
继续调用下游
短路模型调用
处理响应第 6 层:ChatModel
ChatModel 是聊天模型统一抽象:
java
ChatResponse call(Prompt prompt);
Flux<ChatResponse> stream(Prompt prompt);实际实现可能是:
text
DeepSeekChatModel
OpenAiChatModel
DashScopeChatModel
OllamaChatModel第 7 层:DeepSeekChatModel
它负责:
- 合并 DeepSeek 默认参数和运行时参数;
- 转换 Spring AI Message;
- 创建 DeepSeek
ChatCompletionRequest; - 转换工具定义;
- 执行或递归处理工具调用;
- 把 DeepSeek 返回转换成 Spring AI 响应;
- 保存普通回答和
reasoningContent。
第 8 层:DeepSeekApi
真正远程调用发生在:
java
deepSeekApi.chatCompletionEntity(request);以及:
java
deepSeekApi.chatCompletionStream(request);第 9 层:响应包装
text
DeepSeek ChatCompletion / Chunk
→ Choice
→ Generation
→ DeepSeekAssistantMessage
→ ChatResponse
→ ChatClientResponse
→ content() / chatResponse() / entity()其中:
text
普通回答 → DeepSeekAssistantMessage.getText()
思考内容 → DeepSeekAssistantMessage.getReasoningContent()当前课程目录
课程不是平均铺开,而是按“主链 → 横切增强 → 模型适配 → 工程故障”推进。
第一批:建立主调用链
| 课程 | 核心问题 | 状态 |
|---|---|---|
| L01:ChatClient 请求解剖 | prompt()、call()、终结方法分别做什么? | 已完成校准 |
| L02:Advisor 与 Memory | Advisor 在什么时候执行,Memory 何时读写? | 下一实际学习 |
| L03:DeepSeek 调用与返回 | 真正 HTTP 调用点和流式/非流式返回如何包装? | 待学习 |
第二批:从“知道主链”进入“能排错”
| 课程 | 核心问题 | 真实产出 |
|---|---|---|
| L04:默认与运行时配置合并 | 哪些覆盖、哪些追加、哪些会二次合并? | 最终 Prompt 观察 Advisor |
| L05:Advisor 环绕顺序 | order 怎样决定 before/after,异常和短路会怎样? | Advisor 顺序实验 |
| L06:Memory 失败边界 | 模型失败或流式取消后为什么会留下半轮对话? | Memory 故障矩阵 |
当前校准结论
截至 2026-07-31,已经确认:
已掌握
prompt()创建本次 RequestSpec,而不是直接创建最终模型请求;.system()、.user()主要先把数据收集到 RequestSpec;call()会组装请求和 Advisor Chain,但真正执行由content()、chatResponse()等终结方法触发;ChatClient是业务组织门面,ChatModel是模型统一抽象;- Advisor 链包围模型调用,链底由
ChatModelCallAdvisor或ChatModelStreamAdvisor接入模型; - 运行时 system 覆盖默认 system;
- 默认 Advisor 与本次 Advisor 会合并存在。
当前需要继续加深
- 不同类型配置为什么采用不同合并策略;
- Advisor
order和 before/after 的真实顺序; - 同步异常、流式错误和取消时哪些 after 不会执行;
- Memory 的半轮对话、conversationId 隔离和持久化一致性;
- DeepSeek options 二次合并和返回对象包装。
这说明当前不是 API 入门水平,而是正在从“会用框架”转向“能解释执行过程并定位故障”。
每节固定学习方法
text
提出一个核心问题
→ 先预测
→ 运行最小实验
→ 观察日志和对象状态
→ 找到源码入口
→ 追踪正常路径
→ 追踪失败、取消和边界路径
→ 回到工程方案
→ 完成 3~5 个验证问题不从源码第一行开始读,也不把源码抄一遍当成理解。
本阶段真实产出
完成 L01~L06 后,需要形成一份:
text
Spring AI 1.1.3 + DeepSeek 请求生命周期与故障地图至少包含:
- RequestSpec 中有哪些状态;
- Prompt 和 Message 的组装点;
- 默认配置与运行时配置合并点;
- Advisor 排序、进入、退出和短路位置;
- Memory 读取、UserMessage 写入和 AssistantMessage 写入位置;
- ChatModel 调用点;
- DeepSeek 非流式与流式 HTTP 调用点;
content与reasoningContent存放位置;- Tool Calling 递归入口;
- 同步失败、流式取消和半轮对话风险。
没有完成这张图,不判定为完全掌握。
后续主线
L01~L06 完成后,按当前工作优先级进入:
text
Tool Calling 完整循环
→ DeepSeek 思考模式与工具调用兼容
→ 自定义 Advisor 与可观测性
→ ChatMemory 持久化和一致性
→ Spring AI Alibaba 如何扩展 Spring AI
→ Agent Framework
→ Graph Core
→ 主子 Agent、中断、恢复与取消不会因为一次临时问题推翻主线,但真实工作中的问题会被吸收为后续案例。
源码阅读地图
text
spring-ai-client-chat
├─ ChatClient.java
├─ DefaultChatClient.java
├─ DefaultChatClientBuilder.java
├─ DefaultChatClientUtils.java
├─ ChatClientRequest.java
├─ ChatClientResponse.java
├─ ChatClientMessageAggregator.java
└─ advisor/
├─ DefaultAroundAdvisorChain.java
├─ ChatModelCallAdvisor.java
├─ ChatModelStreamAdvisor.java
├─ MessageChatMemoryAdvisor.java
└─ api/
├─ BaseAdvisor.java
└─ BaseChatMemoryAdvisor.java
spring-ai-model
└─ chat/memory/ChatMemory.java
models/spring-ai-deepseek
├─ DeepSeekChatModel.java
├─ DeepSeekChatOptions.java
├─ DeepSeekAssistantMessage.java
└─ api/DeepSeekApi.java当前状态
官方源码基准
官网稳定文档可能已经描述更高版本行为。课程中的执行结论以
v1.1.3标签源码为准。