Spring系列之Spring AI入门
概述
GitHub,官网,目前最新版是1.0.1。
功能:
- 跨AI提供商的可移植API:用于聊天、文本到图像和嵌入模型。
- 支持同步和流API选项。还支持下拉访问模型特定功能。
- 跨Vector Store提供商的可移植API,包括同样可移植的新颖的类似SQL的元数据过滤器API。支持8个矢量数据库
- 函数调用。Spring AI使AI模型可以轻松调用
java.util.Function
POJO对象 - AI模型和向量存储的Spring Boot自动配置和启动器
- 数据工程的ETL框架。这为将数据加载到矢量数据库提供了基础,有助于实现检索增强生成模式。
如需使用SNAPSHOT版本,Maven配置添加以下仓库:
<repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository><repository><id>central-portal-snapshots</id><name>Central Portal Snapshots</name><url>https://central.sonatype.com/repository/maven-snapshots/</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository>
</repositories>
Spring Initializr:https://start.spring.io/
application.yml
配置文件:
spring:ai:chat:memory:repository:jdbc:initialize-schema: nerveropenai:api-key: embedding:options:model: text-embedding-v4base-url: https://dashscope.aliyuncs.com/compatible-mode/chat:options:model: qwen-maxvectorstore:pgvector:enabled: trueindexType: HNSWredis:initialize-schema: trueindex-name: custom-indexprefix: custom-prefixzhipuai:api-key: ${ZHIPUAI_API_KEY}mcp:server:name: webflux-mcp-serverversion: 1.0.0type: ASYNC sse-message-endpoint: /mcp/messagesclient:request-timeout: 30ssse:connections:server1:url: https://mcp.amap.comsse-endpoint: /sse?key=?server2:url: https://mcp-pan/baidu.comsse-endpoint: /sse?access_token=?server3:url: https://mcp-youxuan.baidu.comsse-endpoint: /mcp/sse?key=?toolcallback:enabled: truestdio:servers-configuration: classpath:/mcp-servers-config.json
amap:key: ${AMAP_API_KEY}
代码片段
PromptTemplate template = new PromptTemplate("请用{style}风格解释:{topic}");
Prompt prompt = template.create(Map.of("style", "幽默", "topic", "量子力学"));@Bean
VectorStore vectorStore(EmbeddingClient embeddingClient) {return new SimpleVectorStore(embeddingClient);
}@Resource
private SyncMcpToolCallbackProvider toolCallbackProvider;var chatClient = chatClientBuilder.defaultTools(toolCallbackProvider).build();// 实现Tool
@Service
public class WeatherService {@Tool(description = "Get weather information by city name")public String getWeather(String cityName) {}
}
// 注册Tool
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService) {return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();}
Chat Client,用于简化与AI模型的交互过程,支持同步和反应式编程模型,隐藏诸多底层细节:
- 提示词管理:定制和组装模型的输入(Prompt)
- 响应处理:格式化解析模型的输出(Structured Output)
- 参数选项:调整模型交互参数(ChatOptions)
- 高级功能:整合聊天记忆、函数调用、RAG等能力
Spring AI提供两种方式创建ChatClient:使用自动配置的Builder或编程方式。
@RestController
public class ChatController {private final ChatClient chatClient;public ChatController(ChatClient.Builder builder) {this.chatClient = builder.build();}@GetMapping("/chat")public String chat(String input) {return this.chatClient.prompt().user(input).call().content();}
}
禁用自动配置:spring.ai.chat.client.enabled=false
// 通常通过自动装配获取ChatModel实例
ChatModel myChatModel =
// 使用Builder
ChatClient chatClient = ChatClient.builder(myChatModel).build();
// 直接create
ChatClient chatClient = ChatClient.create(myChatModel);
ChatClient的流畅API通过prompt
方法提供三种不同的方式来创建Prompt:
prompt()
:无参方法,允许从头开始构建提示,后续可添加用户消息、系统消息等。chatClient.prompt().user("你好").call().content();
prompt(Prompt prompt)
:接受Prompt
对象参数,允许传入使用非流畅API创建的Prompt
实例。
Prompt myPrompt = new Prompt(List.of(new UserMessage("你好")));
chatClient.prompt(myPrompt).call().content();
prompt(String content)
:便捷方法,直接接受用户文本内容作为参数。
chatClient.prompt("你好").call().content();
ChatResponse
包含完整的响应数据和元数据,如Token使用情况。
entity()
方法还提供一个重载版本,允许传入自定义参数来指导实体转换过程:
record Product(String name, String description, Double price) {}Product product = chatClient.prompt().user("创建一个价格在100元以内的产品").call().entity(Product.class, EntityPreference.create().withFormat(EntityFormat.JSON).build());
ChatClient提供两个核心方法来获取响应:
call
:用于同步响应,返回ResponseWithChatClient
对象;stream()
:用于流式响应,返回StreamWithChatClient`对象。
Flux<String> responseStream = chatClient.prompt().user("给我讲一个长故事").stream().content();
默认值:
ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem("你是一位专业的Java开发助手,擅长使用Spring框架").defaultUser("默认用户消息").defaultOptions(options -> options.withTemperature(0.7f)).defaultResponseFormat(new StructuredResponseFormat<>(MyResponseType.class)).build();
ToolCallback
之前叫FunctionCallback,升级:
- 术语更准确:从"函数"改为"工具",更符合行业通用术语
- 架构更清晰:分离工具定义与实现,提高复用性
- 功能更强大:支持更灵活的工具注册和调用方式
- 注解驱动:新增
@Tool
注解,开发更便捷
FunctionToolCallback.builder("getWeather", service).description("获取天气")
结构化输出
如JSON格式优势:
- 便于程序解析和处理
- 确保数据格式一致性
- 方便与前端或其他服务集成
StructuredOutputConverter
- 在LLM调用前:转换器会向提示词追加格式指令,为模型生成目标输出结构提供明确指导。
- 在LLM调用后:转换器将模型的原始文本输出转换为结构化类型,将其映射为对应的结构化JSON特定的数据结。
StructuredOutputConverter实现类型:接口允许您从基于文本的AI模型输出中获取结构化数据,默认BeanOutConverter实现类
public News generateAsString(String message) {News news = this.chatClient.prompt().user(promptUserSpec -> promptUserSpec.text(message)).call().entity(News.class);
}@Data
public class News {private String entity;private String time;private String summary;
}
RAG
添加依赖:
implementation 'org.springframework.ai:spring-ai-starter-vector-store-redis:1.0.1'
private final VectorStore vectorStore;
public String similaritySearch(String query) {SearchRequest request = SearchRequest.builder().query(query).topK(1).build();List<Document> results = this.vectorStore.similaritySearch(request);return JSONObject.valueToString(results);
}
或其他向量数据库。
模型
CogView-4:智谱开源文生图模型,支持任意长度的中英双语输入,能够生成在给定范围内的任意分辨率图像。
implementation ‘org.springframework.ai:spring-ai-starter-model-zhipuai:1.0.1’
private final ZhiPuAiImageModel zhiPuAiImageModel;public String getImage(String imageName) {ImageResponse response = zhiPuAiImageModel.call(new ImagePrompt(imageName, ZhiPuAiImageOptions.builder().build()));return response.getResult().getOutput().getUrl();
}
Chat Memory
ChatMemory接口,支持实现不同类型的内存策略,默认MessageWindowChatMemory类
ChatMemoryRepository:专责消息的存储与检索,底层消息存储实现默认实现 InMemoryChatMemoryRepository 类
引入依赖:implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc:1.0.1'
,JdbcChatMemoryRepository
配置:
spring.ai.chat.memory.repository.jdbc.initialize-schema=nerver
public ChatClientService(ChatClient.Builder builder,JdbcChatMemoryRepository chatMemoryRepository)
ChatMemory chatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository).maxMessages(10).build();
ChatClient chatClient = builider.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).build();chatClient.prompt().user("你好").advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId)).call().content();
Advisors
用于拦截、修改和增强AI驱动的交互,封装常见的生成式AI模式,转换发送到和接收自LLMs的数据,在各种模型和用例之间提供可移植性。
优势:
- 封装常见模式:将RAG、内容安全检查等模式封装为可重用组件
- 数据转换:在请求发送前和响应接收后修改和增强数据
- 跨模型可移植性:编写一次Advisor,可用于多种AI模型和用例
- 可观测性:Advisors参与可观测性堆栈,支持指标和跟踪功能
工作原理类似于AOP:
- 在AI交互的请求和响应阶段拦截处理流程
- 可以访问和修改请求内容和上下文
- 可以访问和修改响应内容和上下文
- 多个Advisors可以组成处理链,按特定顺序执行
API
- Advisor:基础接口,定义名称和顺序等基本特性
- CallAdvisor:用于非流式场景的接口
- StreamAdvisor:用于流式场景的接口
- BaseAdvisor:同时继承CallAdvisor和StreamAdvisor的接口
- BaseChatMemoryAdvisor:继承BaseAdvisor的接口
- MessageChatMemoryAdvisor:将记忆作为消息集合添加到prompt
- PromptChatMemoryAdvisor:将记忆整合到prompt的系统文本中
- SafeGuardAdvisor:用于防止模型生成有害或不适当的内容
- ChatModelCallAdvisor:
- ChatModelStreamAdvisor:
- SimpleLoggerAdvisor:日志记录
继承关系图
其他相关API:
- ChatClientRequest:请求
- ChatClientResponse:响应
- CallAdvisorChain:
- StreamAdvisorChain:
Advisors的执行顺序由getOrder()
方法决定:
- 较低的order值优先执行
- Advisor链按照栈的方式工作:第一个加入链的Advisor最先处理请求;也是最后处理响应的Advisor
- 高优先级的Advisor先执行请求处理,后执行响应处理
- 如果多个Advisor具有相同的order值,它们的执行顺序不保证
Advisors支持两种处理模式:
- 非流式处理:处理完整的请求和响应,实现
CallAdvisor
接口,重写adviseCall()
方法; - 流式处理:处理连续的请求和响应流,实现
StreamAdvisor
接口,重写adviseStream()
方法,使用响应式编程概念(如Flux)。
示例:
// 创建带有Advisors的ChatClient
var chatClient= ChatClient.builder(chatModel).defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build(), // 聊天记忆顾问QuestionAnswerAdvisor.builder(vectorStore).build() // RAG顾问).build();// 设置运行时参数
String response= chatClient.prompt().advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, "678")).user(userText).call().content();
Prompt Engineering
几个参数:
-
Temperature:控制模型响应的随机性或创造力
- 较低的值:
0.0-0.3
,更具确定性、更集中的响应。适用于事实类问题、分类或对一致性要求严格的任务; - 中等值:
0.4-0.7
,在确定性和创造力之间取得平衡。适用于一般用例; - 较高值:
0.8-1.0
,更具创造力、多样化且可能带来惊喜的响应。适用于创意写作、头脑风暴或生成多样化选项。
- 较低的值:
-
MaxTokens:限制模型在其响应中可生成Token数量
- 较低值:适用于单个词、短语或分类标签。
- 中等值:适用于段落或简短解释。
- 较高值:适用于长篇内容、故事或复杂解释。
-
采样控制:两个参数,允许对生成过程中的Token选择进行细粒度控制。
- Top-K:将Token选择限制在K个最有可能的下一个Token中。较高值(如40-50)会引入更多多样性
- Top-P:核采样,从累积概率超过P的最小Token集合中动态选择。常见的值如 0.8-0.95。
Role Prompting
public void rolePrompting(ChatClient chatClient) {String result = chatClient.prompt().system(s -> s.text("你是一位经验丰富的Java开发专家,专注于Spring框架。请以简洁、专业的方式回答问题,并提供代码示例。")).user(u -> u.text("如何在Spring Boot应用中实现基本的认证功能?")).call().content();
}
Self-Consistency通过生成多个独立的推理路径,然后选择最一致的答案来提高复杂推理任务的准确性。
public void selfConsistencyPrompting(ChatClient chatClient) {// 生成多个推理路径List<String> responses = newArrayList<>();for (int i = 0; i < 3; i++) {String response = chatClient.prompt().user(u -> u.text("""问题: 小明有5个苹果,他给了小红2个,又从小华那里得到3个,然后他又吃了1个。小明现在有多少个苹果?让我们一步步思考得出答案。""")).options(ChatOptions.builder().temperature(0.7).build()) // 使用较高温度以获得多样化的推理路径.call().content(); responses.add(response);}
}
解读:上面的让我们一步步思考得出答案
正体现Chain-of-Thought Prompting。
MCP
MCP能力:
- 标准化交互协议:统一AI模型与外部工具的通信方式
- 多传输支持:STDIO/HTTP/SSE全兼容,适应本地或云端部署
- 会话管理:v0.8.0全新升级的会话架构
MCP Java SDK采用清晰的三层设计,可轻松集成到现有系统:
- 客户端/服务端层
McpClient
:搞定协议协商、工具调用McpServer
:暴露工具接口,管理资源URI- 支持同步/异步调用,兼容HTTP长连接和进程间通信
- 会话层:通过
McpSession
管理对话状态,多轮交互不再丢上下文 - 传输层:JSON-RPC消息一键序列化,三种传输任选:
- STDIO:本地进程间通信
- HTTP SSE:Servlet/WebFlux双版本支持
- Reactive流:WebFlux实现高并发
server模块引入依赖:
implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webflux:1.0.1'
implementation 'org.springframework.ai:spring-ai-starter-mcp-server:1.0.1'
implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc:1.0.1'
client引入依赖:
implementation 'org.springframework.ai:spring-ai-starter-mcp-client:1.0.1'
implementation 'org.springframework.ai:spring-ai-starter-mcp-client-webflux:1.0.1'
MCP Server
诸如:
- 高德MCP Server:提供全场景覆盖的地图服务,包括地理编码、逆地理编码、IP定位、天气查询、骑行路径规划、步行路径规划、驾车路径规划、公交路径规划、距离测量、关键词搜索、周边搜索、详情搜索等。
- 百度网盘MCP:核心API现已全面兼容MCP协议。涵盖用户信息、获取文件信息、文件上传、文件管理、文件搜索等。 开发者仅需简单配置,即可快速接入百度网盘服务,实现文件上传、文件管理等能力,大幅降低开发者调用网盘服务门槛,显著提升开发者的开发效率。
- 百度优选MCP:提供MCP工具列表包含8个核心API,涵盖参数对比、品牌排行、商品检索、交易等。为用户提供全维度对比决策助手,实时品牌天梯榜单,轻松获取全网相关SPU与优质低价商品链接等能力。
- Playwright MCP:微软推出的现代化跨浏览器自动化测试工具,支持Chromium、Firefox和WebKit,提供高速、可靠的端到端测试能力,适用于Web应用开发和持续集成。结合LLM能够无障碍与网页进行交互,从而实现智能浏览器页面操作。
- Office-Word-MCP:用于创建、读取、编辑和格式化Microsoft Word文档。主要操作能力如下:创建表格、添加不同级别的标题、插入段落可选样式;格式化加粗、斜体、下划线、颜色和字体属性、搜索和替换;边框和样式格式化表格、格式表头行、应用单元格阴影和自定义边框。
- antvis/mcp-server-chart:用于生成可视化图表的,目前支持 15+ 种图表:
- 条形图、饼图、 柱形图、 折线图
- 鱼骨图、思维导图、流程图、
- 直方图、线型图、树形图、网络图
- 雷达图、二维散点图、词语图、区域图表
- MySQL MCP:提供SQL语句查询数据库的能力:
- execute_query :支持select查询、show展示、describe描述;
- get_table_info:获取数据表的详细结构信息;
- list_tables:列出数据库中的所有数据表。
- Excel-MCP:基于MCP的文件处理服务器,提供读取、写入和分析Excel文件的功能:
- 读取Excel文件:获取工作表列表,读取特定工作表的数据,读取所有工作表的数据;
- 写入Excel文件:创建新的Excel文件,向特定工作表写入数据,支持多工作表;
- 分析Excel结构:分析工作表结构,将结构导出到新文件
- Nacos MCP Router:一个基于MCP官方标准SDK实现的的MCP Server,提供一组工具,提供推荐、分发、安装及代理其他MCP Server的功能,帮助用户更方便地使用MCP Server服务。
安装较新版Nacos,打开管理后台,MCP管理,创建MCP Server。 - @Joooook/12306-mcp:提供简单的API接口,允许用户搜索12306的车票。
- HowToCooke MCP,让AI助手能够为你推荐菜谱、规划膳食,解决"今天吃什么"的世纪难题!
- 查询全部菜谱:获取所有可用菜谱数据,做菜百科全书
- 根据分类查询菜谱:按照分类筛选菜谱,想吃水产?早餐?荤菜?主食?一键搞定!
- 智能推荐膳食:根据你的忌口、过敏原和用餐人数,为你规划整整一周的美味佳肴
- 不知道吃什么:选择困难症福音!根据人数直接推荐今日菜单,再也不用纠结了
- mcp-server-weread:支持将微信读书的书籍、笔记和划线数据提供给支持MCP的LLM:
- 从微信读书获取书架信息;
- 搜索书架中的图书;
- 获取图书的笔记和划线;
- 支持按章节组织笔记和划线。
- Fetch MCP:从互联网上抓取URL并将其内容作为Markdown文件,接口参数:
url
: 要抓取的URLmax_length
:返回的最大字符数,默认5000start_index
:字符索引开始提取内容,默认0raw
:获取未经MarkDown转换的原始内容,默认false
{"mcpServers": {"playwright": {"command": "npx.cmd","args": ["@playwright/mcp@latest"]},"nacos-mcp-router": {"command": "docker","args": ["run","-i","--rm","--network","host","-e","NACOS_ADDR=localhost:8848","-e","NACOS_USERNAME=nacos","-e","NACOS_PASSWORD=nacos","-e","TRANSPORT_TYPE=stdio","nacos/nacos-mcp-router:latest"]},"amap-maps": {"command": "npx","args": ["-y","@amap/amap-maps-mcp-server"],"env": {"AMAP_MAPS_API_KEY": ""}},"mysql": {"command": "npx","args": ["mysql-mcp-server"],"env": {"MYSQL_HOST": "127.0.0.1","MYSQL_PORT": "3306","MYSQL_USER": "root","MYSQL_PASSWORD": "root","MYSQL_DB": "demo"}},"excel": {"command": "npx","args": ["--yes","@zhiweixu/excel-mcp-server"],"env": {"fileAbsolutePath": "D:\data\excel"}},"12306-mcp": {"command": "npx","args": ["-y","12306-mcp"]},"word-document-server": {"command": "uvx","args": ["--from","office-word-mcp-server","word_mcp_server"]},"fetch": {"command": "uvx","args": ["mcp-server-fetch"]},"mcp-server-chart": {"command": "npx.cmd","args": ["-y","@antv/mcp-server-chart"]}}
}