行业资讯
📅 2026/9/1 15:24:06
Spring AI 学习篇
大模型DeepSeek、阿里云百炼、ollama下面以DeepSeek为例进行学习一、快速使用1.添加依赖在pom.xml添加dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-deepseek/artifactId /dependency /dependencies2.配置API key和模型在application.properties添加spring.ai.deepseek.api-key ${DEEP_SEEK_KEY} spring.ai.deepseek.chat.options.model deepseek-chat3.测试1同步阻塞式输出Test public void testDeepseek(Autowired DeepSeekChatModel deepSeekChatModel){ String content deepSeekChatModel.call(你好你是谁); System.out.println(content); }2流式输出Test public void testDeepseekStream(Autowired DeepSeekChatModel deepSeekChatModel){ FluxString stream deepSeekChatModel.stream(你好你是谁); stream.toIterable().forEach(System.out::println); }二、options配置选项1temperature范围0-2值越大输出内容相似度越低-越热情反之相似度越高-越冷淡2maxTokens限制生成的最大token数3stop截断你不想输出的内容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.propertiesspring.ai.deepseek.api-key ${DEEP_SEEK_KEY} spring.ai.deepseek.chat.options.model deepseek-reasoner2.测试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(你好你是谁); FluxChatResponse 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.公式「角色设定」「具体任务(技能)」「限制条件(约束)」「示例参考」六、Advisor1.日志拦截器ChatClient chatClient chatClientBuilder .defaultAdvisors(new SimpleLoggerAdvisor()) .build();直接执行是没有日志的需要打开日志级别才会显示。在application.properties添加logging.level.org.springframework.ai.chat.client.advisor DEBUG2.敏感词拦截器当用户输入“李四”时不会调用大模型直接抛错所以相应速度会很快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 groupIdorg.springframework.ai/groupId artifactIdspring-ai-autoconfigure-model-chat-memory/artifactId /dependency2.测试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 通过方言抽象支持多种关系型数据库。开箱即支持以下数据库PostgreSQLMySQL / MariaDBSQL ServerHSQLDBOracle数据库1.数据库存储1.导入依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-chat-memory-repository-jdbc/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency !--mysql驱动-- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency2.添加配置spring.ai.chat.memory.repository.jdbc.initialize-schemaalways !--如果要覆盖架构脚本的位置-- spring.ai.chat.memory.repository.jdbc.schemaclasspath:/custom/path/schema-mysql.sql3.连接数据库spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/springai?characterEncodingutf8useSSLfalse driver-class-name: com.mysql.cj.jdbc.Driver2.Redis存储1.导入依赖properties jedis.version5.2.0/jedis.version /properties !--基于redis记忆存储-- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-memory-redis/artifactId /dependency2.连接数据库ai: memory: redis: host: localhost port: 6379 timeout: 5000 password: 123456九、多层记忆架构当记忆越多的时候说明越聪明同时带来的问题是token上限。为解决此问题使用多层记忆架构具体如下近期记忆保留在上下文窗口中的最近几轮对话每轮对话完成后立即存储可通过ChatMemory;中期记忆通过RAG检索的相关历史对话(每轮对话完成后异步将对话内容转换为向量并存入向量数据库) ------向量数据库进行相似性检索然后提取与对话相关的内容出来长期记忆关键信息的固化总结方式一定时批处理通过定时任务如每天或每周对积累的对话进行总结和提炼提取关键信息、用户偏好、重要事实等批处理方式降低计算成本适合大规模处理方式二关键点实时处理在对话中识别出关键信息点时立即提取并存储例如当用户明确表达偏好、提供个人信息或设置持久性指令时采用写入触发器机制在特定条件下自动更新长期记忆十、Tool定义用于提供大模型不具备的信息和能力1.使用1提供了什么工具Tool2使用工具需要什么参数ToolParamTool(description 获取指定位置天气根据位置自动推算经纬度) public String getAirQuality(ToolParam(description 纬度) double latitude, ToolParam(description 经度) double longitude) { return 天晴; }