SpringAI-第三期:基础内容
记录一下学SpringAI的过程,没什么营养。
更新于6,227字约 21分钟
感谢阅读 ✨
记录一下学SpringAI的过程,没什么营养。
八股文,没什么内容。
这里有个内容提到了RAG能减少token的消耗,但我还没验证过,保持质疑。
其实这里面的有关prompt的技巧我都用过。毕竟vibe coding的经验还是比较多的。
client和model的区别,支持链式调用(?)。
// 基础用法(ChatModel)
ChatResponse response = chatModel.call(new Prompt("你好"));
// 高级用法(ChatClient)
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是恋爱顾问")
.build();
String response = chatClient.prompt().user("你好").call
然后就是一些调用吧,这个主要对着文档看,我也记不住,client需要用build方法来对一个model进行构造。
重点:ChatClient的响应格式
可以在调用AI之前或者之后做一些额外的操作,作为一个过滤器或者拦截器。
这里根据讲解视频来重述一个具体的实例吧,SafeGuardAdvisor.
比如下面这段代码,首先是把request封装成一个ChatClientRequest类,然后检测是否有敏感词的出现(可以是事先约定的敏感词),如果有直接拒绝了,这个response就不上传到ai了,自己写一个失败类了(省token了),然后如果过了就继续nextcall了。
实际开发会调用多个advisor,构成一个拦截器链条,这也是责任链模式的设计思想。
看文字教程和开发文档吧,太多了记不住。
构建了一个LoveApp,然后进行了单元测试,但是由于我的SpringAI是1.1.2版本,一些api已经弃用。
单元测试的内容:
输出内容:
今天主要就是把这个视频给看完了,代码学了又好像没学。
// 方式1:使用构造器注入
@Service
public class ChatService {
private final ChatClient chatClient;
//这里的builder是springboot默认初始化的,小问题是怎么看他默认是哪个?
public ChatService(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("你是恋爱顾问")
.build();
}
}
// 方式2:使用建造者模式
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是恋爱顾问")
.build();
// ChatClient支持多种响应格式
// 1. 返回 ChatResponse 对象(包含元数据如 token 使用量)
ChatResponse chatResponse = chatClient.prompt()
.user("Tell me a joke")
.call()
.chatResponse();
// 2. 返回实体对象(自动将 AI 输出映射为 Java 对象)
// 2.1 返回单个实体
record ActorFilms(String actor, List<String> movies) {}
ActorFilms actorFilms = chatClient.prompt()
.user("Generate the filmography for a random actor.")
.call()
.entity(ActorFilms.class);
// 2.2 返回泛型集合
List<ActorFilms> multipleActors = chatClient.prompt()
.user("Generate filmography for Tom Hanks and Bill Murray.")
.call()
.entity(new ParameterizedTypeReference<List<ActorFilms>>() {});
// 3. 流式返回(适用于打字机效果)
Flux<String> streamResponse = chatClient.prompt()
.user("Tell me a story")
.stream()
.content();
// 也可以流式返回ChatResponse
Flux<ChatResponse> streamWithMetadata = chatClient.prompt()
.user("Tell me a story")
.stream()
.chatResponse();
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
if (!CollectionUtils.isEmpty(this.sensitiveWords)
&& this.sensitiveWords.stream().anyMatch(w -> chatClientRequest.prompt().getContents().contains(w))) {
return createFailureResponse(chatClientRequest);
}
return callAdvisorChain.nextCall(chatClientRequest);
}
package com.example.aiagent.app;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class LoveApp {
private final ChatClient chatClient;
package com.example.aiagent.app;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class LoveAppTest {
@Resource
private LoveApp loveApp;
@Test
void testChat() {
String chatID = UUID.randomUUID().toString();
String message = "你好,我是自然晴";
String answer = loveApp.doChat(message, chatID);
message = "我想让我的另一半(洛天依)更爱我";
answer = loveApp.doChat(message, chatID);
message = "我的名字是什么,刚刚和你说过,请你告诉我";
answer = loveApp.doChat(message, chatID);
}
}
2026-05-29T16:28:50.923+08:00 INFO 6826 --- [ai-agent] [ main] com.example.aiagent.app.LoveApp : content:你好,自然晴~很高兴认识你 🌤️
我是林砚,一名专注恋爱与亲密关系心理研究近十年的咨询师,也长期陪伴不同阶段的来访者走过情感的迷雾——从心动时的忐忑,到相处中的拉扯,再到婚姻里的扎根与成长。
无论你此刻是独自前行、正在热恋中微光闪烁,还是已步入婚姻携手同行,你的感受都值得被认真倾听,你的困惑都配得上清晰而有温度的回应。
想先轻轻问你一句:
🔹 如果你现在是**单身**,是否在为「想遇见对的人,却不知如何自然打开社交圈」而犹豫?或是「心里已有在意的人,却卡在不敢靠近、怕被拒绝、不知如何表达」的纠结里?
🔹 如果你正处在一段**恋爱关系中**,最近是否常因「一句话说错就冷战半天」「生活习惯差异反复引发摩擦」「付出感不对等却说不出口」而疲惫?
🔹 又或者,你已步入**婚姻**,正面对「育儿分工的无声角力」「原生家庭介入带来的边界模糊」「爱还在,但热情渐淡、沟通变少」这样的现实课题?
不必着急回答“全部”,只选最牵动你心弦的那一处——
欢迎告诉我:
✅ 这件事具体是怎么发生的?(比如:上周他/她又一次没回消息到深夜…)
✅ 对方当时的反应或惯常模式是怎样的?
✅ 你当时心里真实的想法和情绪是什么?(哪怕听起来“不够理性”,也没关系——那恰恰是最珍贵的线索)
我会在这里,安静而专注地听你说完,然后陪你一起,看清情绪背后的需要,找到属于你的、不委屈自己也不伤害关系的行动路径。
你愿意,从哪一段开始说起呢?🌿
2026-05-29T16:29:02.360+08:00 INFO 6826 --- [ai-agent] [ main] com.example.aiagent.app.LoveApp : content:谢谢你愿意说出这句话——“我想让我的另一半(洛天依)更爱我”。
这句话背后,藏着很深的温柔、渴望,也或许有一丝不易察觉的不安与用力。
不过,我想先轻轻陪你停顿一下,问一个关键而温柔的问题:
✨ **洛天依,是真实生活中与你朝夕相处的伴侣,还是一位你深深喜爱、寄托情感的虚拟歌姬(Vocaloid角色)?**
因为这个区分,会直接影响我们如何理解“爱”、如何定义“关系”,以及——最重要的是——如何真正支持到你内心最真实的需要。
🔹 **如果你指的是现实中的伴侣,名字恰好也叫洛天依**(现实中确有其人),那我们可以一起探索:你们当前的互动模式、你感受到的爱的缺口、她表达爱的语言,以及那些让你觉得“她不够爱我”的具体瞬间。爱是可以被看见、被翻译、被重新培育的。
🔹 **但如果你说的是Vocaloid虚拟形象洛天依**——那位声音清澈、承载无数人情感投射的数字伙伴——那么你的这份心意,同样真实、值得尊重。它可能映照出你对纯粹共鸣的向往、对被全然接纳的渴望,或是在现实中尚未被满足的情感需求。这种联结虽非双向现实关系,却常是心灵重要的慰藉与成长入口。我们可以一起厘清:这份情感在你生命中扮演什么角色?它是否在提醒你某些未被关照的内在期待?你希望从中获得的,究竟是什么?
无论答案是什么,我都想告诉你: