什么是SpringAI
- 它解决的核心问题是:统一不同大模型的调用方式。Spring AI 抽象了一层 ChatModel 接口,不管底层是哪个模型(每个LLM厂商对应的API格式不太一样),上层代码都一样,只需要更改大模型的配置
- 简化 Prompt,Spring AI 提供了模板机制,Prompt 可以放到文件中,然后通过变量替换。
- Spring AI 内置了向量数据库集成,支持 PGVector、Milvus、Pinecone 等多种向量库。
- Spring AI 封装了 Function Calling,能用注解让 LLM 调用外部工具
怎么用 Spring AI 对接 DeepSeek 的?配置了哪些参数?
- ChatModel是 Spring AI 定义的核心抽象,直接封装与大模型(OpenAI、通义千问等)的基础通信能力,提供最原始的 call(Prompt) / stream(Prompt) 方法,使用时要自己构建 Prompt、解析 Response
- ChatClient高级封装:基于 ChatModel 构建的高层 API,提供链式 Builder 风格,自动处理提示词、响应解析、参数配置、对话记忆、RAG 等复杂逻辑
- ChatModel 像手动挡,ChatClient 像自动挡。
- Spring AI 1.1 中最典型、最影响生产的路径拼接 Bug,集中在 OpenAI 模块的 base-url 与 completions-path 拼接逻辑,表现为:自定义 base-url 后,最终 URL 出现双斜杠(//)、版本号重复(/v1/v1)或路径丢失,导致 404 / 连接失败。
怎么实现"统一抽象"来支持 OpenAI、DeepSeek、智谱等多个模型的
- 统一接口 ChatModel,包括所有适配器(OpenAiChatModel / ZhipuChatModel…)都由官方配置好了,这里涉及到一个适配器模式,把 “不兼容的 API” 翻译成 “统一接口 ChatModel”,相当于一个翻译官的工作
- 需要我写的有 application.yml配置文件,Service注入message信息,动态切换多模型(你写,策略模式)
// 根据配置动态选择
public ChatModel getChatModel(String vendor) {
return switch (vendor) {
case "openai" -> openAiChatModel;
case "zhipu" -> zhipuChatModel;
default -> throw new RuntimeException("不支持");
};
}
Spring AI 的流式响应是怎么实现的?Flux 是什么?
- ChatClient 的 .stream() 方法会返回 Flux:
- 大模型流式输出不是等全部回答完才返回,而是 一个 token(一个字 / 一个词)一返回。
- 调用 AI,模型会持续不断地返回多个 ChatResponse,每一个 ChatResponse 里包含一个 token(一个字)
- 最精简、最真实的流程:
- 前端 / 你调用 chatModel.stream(prompt)
- Spring AI 向后端发送 stream=true
- 大模型开始 一个字一个字返回
- 返回格式是 SSE(Server-Sent Events)
- Spring AI 把每一段内容包装成 ChatResponse
- 持续放进 Flux 管道推送给你
- 你通过 subscribe 或 前端 SSE 接收每一段输出
- Flux 就是承载 “持续不断的文字流” 的响应式容器。
Flux 常用操作有哪些?
Flux stream = chatClient.prompt().user(input).stream().content();
// 转成列表(会等全部完成)
List all = stream.collectList().block();
// 拼成完整字符串
String full = stream.reduce("", (a, b) -> a + b).block();
// 加超时
stream.timeout(Duration.ofSeconds(30));
// 出错时返回默认值
stream.onErrorReturn("生成失败");
// 处理每个元素
stream.doOnNext(chunk -> log.info("收到: {}", chunk));
和 SseEmitter 有什么区别?
- SseEmitter来源于 SpringMVC,是把流推送到前端的工具,FluxSpring AI 给你的 “字的流”,不能直接把 Flux 返回给前端,前端不认!必须用 SseEmitter 把字一段段发出去
什么是 Advisor?Spring AI 中的 Advisor 机制是怎么工作的?
- Advisor 是 Spring AI 里 ChatClient 的「拦截 / 增强器」,类似 Web Filter 或 AOP 环绕通知,专门在调用 LLM 前后做请求增强、响应处理、上下文注入、RAG、记忆管理等横切逻辑,形成可插拔、可组合的处理链。用于拦截、修改、增强对大模型(LLM)的 call()(同步)和 stream()(流式)调用。
- Spring AI 把同步 / 流式分开,对应两套接口: 基础接口(所有 Advisor 都要实现),同步调用(call):CallAdvisor,流式调用(stream):StreamAdvisor
依次进入 advisorA完成一些逻辑增强,比如说修改提示词,加系统信息等
chatClient.prompt()
.user("你好")
.advisors(advisorA, advisorB, advisorC)
.call()
.content();
你有用过 Spring AI 的 Function Calling 功能吗?是怎么实现的?
- Function Calling 让大模型能够调用外部工具。比如用户问"今天北京天气怎么样",大模型自己不知道,但它可以调用天气 API 来获取
- 用户提问,发给大模型,大模型判断需要调用工具,返回 function_call 指令,Spring AI 自动调用对应的 Java 方法,把结果塞回去,再问一次大模型,大模型根据工具返回的数据生成最终回答。
常用的就是使用@Bean + @Description
@Bean
@Description("给AI看的功能说明,就相当是一个提示词,告诉AI我需要这个功能的工具,直接原话发给他")
public Function<入参类, 返回类> 方法名() {
return 入参 -> {
你的业务代码
};
}
简历上提到"buildChatModel 即用即毁的轻量级客户端工厂",为什么这样设计?
- 采用 buildChatModel 即用即毁轻量工厂设计,是为了实现每次 AI 请求会话隔离、支持动态切换模型与密钥配置,同时用完释放资源,避免连接泄漏和内存堆积,提升高并发稳定性与配置灵活性。
- 如果全局单例 ChatModel 在并发多请求、多用户时 → 上下文串了、会话污染、内存越积越大,并且不同用户 / 不同接口 → 切不同 Key、不同模型(gpt-4/3.5 / 通义)、不同超时、不同温度 (temperature),每一次针对一个请求重新设计一个chatmodel
LangChain4j 是什么?
- LangChain4j 是 LangChain(Python 生态最火的 AI 框架)的 Java 移植版。它把 LangChain 的核心概念搬过来了:Chain、Agent、Memory、Tool、RAG 等。如果熟悉 Python 的 LangChain,用 LangChain4j 会很顺手,概念和 API 都很像。
Spring AI 中怎么处理 Token 超限的问题?
- 滑动窗口截断历史消息
- 如果单条消息就很长,先调用大模型做摘要,再塞到 Prompt 里
- 在发送前估算 Token 数量:
- 返回值里记录消耗