news 2026/9/8 0:47:51

Spring AI 学习篇

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 学习篇

大模型:DeepSeek、阿里云百炼、ollama

下面以DeepSeek为例,进行学习

一、快速使用

1.添加依赖

在pom.xml添加

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

2.配置API key和模型

在application.properties添加

spring.ai.deepseek.api-key = ${DEEP_SEEK_KEY} spring.ai.deepseek.chat.options.model = deepseek-chat

3.测试

(1)同步阻塞式输出

@Test public void testDeepseek(@Autowired DeepSeekChatModel deepSeekChatModel){ String content = deepSeekChatModel.call("你好你是谁"); System.out.println(content); }

(2)流式输出

@Test public void testDeepseekStream(@Autowired DeepSeekChatModel deepSeekChatModel){ Flux<String> stream = deepSeekChatModel.stream("你好你是谁"); stream.toIterable().forEach(System.out::println); }

二、options配置选项

(1)temperature

范围:0-2,值越大,输出内容相似度越低-越热情;反之相似度越高-越冷淡

(2)maxTokens

限制生成的最大token数

(3)stop

截断你不想输出的内容

@Test public void testChatOptions(@Autowired DeepSeekChatModel deepSeekChatModel{ DeepSeekChatOptions options = DeepSeekChatOptions.builder() .model("deepseek-chat") // 指定大模型 //.maxTokens(5) // 限制字数 .stop(Arrays.asList(",")) // 从逗号截断 .temperature(1.9).build(); Prompt prompt = new Prompt("请写一句诗描述清晨。", options); ChatResponse res = deepSeekChatModel.call(prompt); System.out.println(res.getResult().getOutput().getText()); }

三、深度思考

1.修改application.properties

spring.ai.deepseek.api-key = ${DEEP_SEEK_KEY} spring.ai.deepseek.chat.options.model = deepseek-reasoner

2.测试

(1)同步阻塞式输出

@Test public void testDeepseekReasoning(@Autowired DeepSeekChatModel deepSeekChatModel{ Prompt prompt = new Prompt("你好你是谁"); ChatResponse res = deepSeekChatModel.call(prompt); DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)res.getResult().getOutput(); System.out.println(assistantMessage.getReasoningContent); // 思考内容 System.out.println(assistantMessage.getText()); // 最终回答内容 }

(2)流式输出

@Test public void testDeepseekStream(@Autowired DeepSeekChatModel deepSeekChatModel{ Prompt prompt = new Prompt("你好你是谁"); Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt); stream.toIterable().forEach(chatResponse -> { DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)chatResponse.getResult().getOutput(); System.out.println(assistantMessage.getReasoningContent()); // 思考内容 }); stream.toIterable().forEach(chatResponse -> { DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)chatResponse.getResult().getOutput(); System.out.println(assistantMessage.getText()); // 最终回答内容 }); }

插入一个概念

多模态:将图片、语音、视频传给大模型,让大模型识别后生成文本返回

四、ChatClient

由于我们对接大模型使用的ChatModel是不同的,而ChatClient适用所用的大模型,更加便捷

(1)只有一个大模型

@Test public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){ ChatClient chatClient = chatClientBuilder.build(); String content = chatClient.prompt() .user("你好") .call() .content(); System.out.println(content); }

(2)有多个大模型

@Test public void testChatClient(@Autowired DashScopeChatModel dashScopeChatModel){ // 使用哪个模型就传入哪个模型 ChatClient chatClient = ChatClient.builder(dashScopeChatModel).build(); String content = chatClient.prompt() .user("你好") .call() .content(); System.out.println(content); }

五、提示词

1.系统提示词

为ChatClient设置提示词,只要用到这个chatCilent的对话都会用到这个提示词

@Test public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){ ChatClient chatClient = chatClientBuilder .defaultSystem(""" #角色说明 你是一名专业法律顾问AI.. ## 回复格式 1.问题分析 2.相关依据 3.梳理和建议 **特别注意:** -不承担律师责任。 -不生成涉敏、虚假内容。 """) .build(); String content = chatClient.prompt() .user("你好") .call() .content(); System.out.println(content); }

为当前对话设置提示词

@Test public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){ ChatClient chatClient = chatClientBuilder .build(); String content = chatClient.prompt() .system(""" #角色说明 你是一名专业法律顾问AI.. ## 回复格式 1.问题分析 2.相关依据 3.梳理和建议 **特别注意:** -不承担律师责任。 -不生成涉敏、虚假内容。 """) .user("你好") .call() .content(); System.out.println(content); }

2.动态传参

@Test public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){ ChatClient chatClient = chatClientBuilder .defaultSystem(""" #角色说明 你是一名专业法律顾问AI.. ## 回复格式 1.问题分析 2.相关依据 3.梳理和建议 **特别注意:** -不承担律师责任。 -不生成涉敏、虚假内容。 当前服务的用户: 姓名:{name},年龄:{age} """) .build(); String content = chatClient.prompt() .system(p -> p.param("name","张三").param("age","22")) .user("你好") .call() .content(); System.out.println(content); }

3.提示词模版

(1)新建prompt.st,将提示词写入

(2)导入

@Test public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder,@Value("classpath:/files/prompt.st") Resource systemResource){ ChatClient chatClient = chatClientBuilder .defaultSystem(systemResource) .build(); String content = chatClient.prompt() .system(p -> p.param("name","张三").param("age","22")) .user("你好") .call() .content(); System.out.println(content); }

4.公式

「角色设定」+「具体任务(技能)」+「限制条件(约束)」+「示例参考」

六、Advisor

1.日志拦截器

ChatClient chatClient = chatClientBuilder .defaultAdvisors(new SimpleLoggerAdvisor()) .build();

直接执行是没有日志的,需要打开日志级别,才会显示。在application.properties添加

logging.level.org.springframework.ai.chat.client.advisor = DEBUG

2.敏感词拦截器

当用户输入“李四”时,不会调用大模型,直接抛错,所以相应速度会很快

ChatClient chatClient = chatClientBuilder .defaultAdvisors(new SimpleLoggerAdvisor(), new SafeGuardAdvisor(List.of("李四"))) .build();

3.自定义拦截器

public class ReReadingAdvisor implements BaseAdvisor { private static final String DEFAULT_USER_TEXT_ADVISE = """ {re2_input_query} Read the question again: {re2_input_query} """; @Override public ChatClientRequest before(ChatClientRequest chatClientRequest,AdvisorChain advisorChain){ // 用户提示词 String contents = chatClientRequest.prompt().getContents(); // 替换占位符中的内容 String re2InputQuery = PromptTemplate.builder() .template(DEFAULT_USER_TEXT_ADVISE) .render(Map.of("re2_input_query", contents)); // 新建一个ChatClientRequest返回 ChatClientRequest clientRequest = chatClientRequest.mutate() .prompt(Prompt.builder().content(re2InputQuery).build()) .build(); return clientRequest; } }
ChatClient chatClient = chatClientBuilder .defaultAdvisors(new SimpleLoggerAdvisor(), new ReReadingAdvisor()) .build();

七、会话记忆

LLM是无状态的,不会保留先前的交互信息

通过defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build())存储会话

1.添加依赖

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId> </dependency>

2.测试

@Test public void testMemoryAdvisor(@Autowired ChatClient.Builder builder, @Autowired ChatMemory chatMemory) { ChatClient chatClient = builder .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build()) .build(); String content = chatclient.prompt() .user("我是张三") .call() .content(); System.out.println(content); System.out.println("–----------------"); content = chatClient.prompt() .user("我叫什么?") .call() .content(); System.out.println(content); }

3.记忆最大存储数量

默认的消息窗口大小为20条消息

如果第11条会话进来,那么就会从第2条会话开始展示,确保最大只展示10条(先进先出原则)

MessageWindowChatMemory memory = MessageWindowChatMemory.builder() .maxMessages(10) .build();

4.多用户记忆隔离

如果没有配置记忆隔离,那么所有用户都会共享这一份聊天记录

通过advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1"))进行配置

@Test public void testMemoryAdvisor(@Autowired ChatClient.Builder builder, @Autowired ChatMemory chatMemory) { ChatClient chatClient = builder .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build()) .build(); String content = chatclient.prompt() .user("我是张三") .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1")) .call() .content(); System.out.println(content); System.out.println("–----------------"); content = chatClient.prompt() .user("我叫什么?") .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1")) .call() .content(); System.out.println(content); System.out.println("–----------------"); content = chatClient.prompt() .user("我叫什么?") .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "2")) .call() .content(); }

八、数据库存储对话记忆

Spring AI 通过方言抽象支持多种关系型数据库。开箱即支持以下数据库:

  • PostgreSQL

  • MySQL / MariaDB

  • SQL Server

  • HSQLDB

  • Oracle数据库

1.数据库存储

1.导入依赖

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--mysql驱动--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>

2.添加配置

spring.ai.chat.memory.repository.jdbc.initialize-schema=always <!--如果要覆盖架构脚本的位置--> spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql

3.连接数据库

spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/springai?characterEncoding=utf8&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver

2.Redis存储

1.导入依赖

<properties> <jedis.version>5.2.0</jedis.version> </properties> <!--基于redis记忆存储--> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-memory-redis</artifactId> </dependency>

2.连接数据库

ai: memory: redis: host: localhost port: 6379 timeout: 5000 password: 123456

九、多层记忆架构

当记忆越多的时候,说明越聪明,同时带来的问题是token上限。为解决此问题,使用多层记忆架构,具体如下:

近期记忆:保留在上下文窗口中的最近几轮对话,每轮对话完成后立即存储(可通过
ChatMemory);

中期记忆:通过RAG检索的相关历史对话(每轮对话完成后,异步将对话内容转换为向量并存入
向量数据库) ------>向量数据库进行相似性检索,然后提取与对话相关的内容出来

长期记忆:关键信息的固化总结

方式一:定时批处理

  • 通过定时任务(如每天或每周)对积累的对话进行总结和提炼
  • 提取关键信息、用户偏好、重要事实等
  • 批处理方式降低计算成本,适合大规模处理

方式二:关键点实时处理

  • 在对话中识别出关键信息点时立即提取并存储
  • 例如,当用户明确表达偏好、提供个人信息或设置持久性指令时
  • 采用"写入触发器"机制,在特定条件下自动更新长期记忆

十、Tool

定义:用于提供大模型不具备的信息和能力

1.使用

(1)提供了什么工具@Tool

(2)使用工具需要什么参数@ToolParam

@Tool(description ="获取指定位置天气,根据位置自动推算经纬度") public String getAirQuality(@ToolParam(description ="纬度") double latitude, @ToolParam(description ="经度") double longitude) { return "天晴"; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 0:47:50

PlugClaw实战:基于OpenClaw的AI代理硬件部署与Skill扩展指南

当业务需要把 OpenClaw 这样的个人 AI 代理真正跑起来时&#xff0c;很多朋友会卡在环境安装、依赖兼容、模型配置这些环节。折腾半天还没看到 Agent 回复一句话&#xff0c;体验非常劝退。本文围绕 PlugClaw 这套基于原生安卓系统的 OpenClaw 硬件方案&#xff0c;完整讲解它的…

作者头像 李华
网站建设 2026/9/7 22:13:57

tensor_of_ice 项目调研:从命名歧义到驱动与仿真器验证的通用方法

tensor_of_ice 这个名字&#xff0c;第一眼很容易被当成一个深度学习相关的小工具&#xff0c;因为“tensor”在技术圈里几乎就是张量运算的代名词。但真正去查资料时会发现&#xff0c;这个项目直接可用的介绍不多&#xff0c;甚至会被一起检索到“ice 1000仿真器驱动”这类明…

作者头像 李华
网站建设 2026/9/7 10:43:32

从零搭建AI算力共享平台:设备接入、任务调度与奖励结算

最近在逛 Hacker News 时&#xff0c;看到了一个很有意思的项目 Leiolai。它的核心思路用一句话概括&#xff1a;用户把电脑、手机、平板等设备的空闲算力贡献给 AI 平台&#xff0c;平台根据实际贡献给用户支付奖励。这个方向其实并不算新&#xff0c;但 Leiolai 把“设备算力…

作者头像 李华
网站建设 2026/9/7 2:33:54

《C# 抽象类详解》

C#中类&#xff0c;抽象类&#xff0c;构造函数&#xff0c;结构体&#xff0c;接口&#xff0c;重载和重写 1. 类&#xff08;Class&#xff09; 本质&#xff1a;引用类型&#xff0c;分配在托管堆上。特点&#xff1a;支持继承&#xff08;单继承&#xff09;、支持多态、可…

作者头像 李华
网站建设 2026/9/5 7:37:34

计算机毕业设计之基于Java web技术实现的医院住院管理系统

随着网络科技的不断发展以及人们经济水平的逐步提高&#xff0c;网络技术如今已成为人们生活中不可缺少的一部分&#xff0c;而信息管理系统是通过计算机技术&#xff0c;针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;相比于以前的传…

作者头像 李华
网站建设 2026/9/4 8:37:17

触宝校招后端大数据笔试全解析:从Java到Spark的实战复盘

1. 触宝校招笔试概览&#xff1a;一场没有硝烟的技术摸底 2017年秋季&#xff0c;触宝科技的校招笔试走到第二批&#xff0c;岗位锁定“后端大数据”方向。坦白讲&#xff0c;当时看到这个岗位名字心里就明白&#xff0c;这绝不是单纯考Java或者单纯考Hadoop&#xff0c;而是要…

作者头像 李华