SpringAI-第三期:AI应用开发
这一篇更没什么营养了,完全不知道我学了啥。。。
4,743字约 16分钟
感谢阅读 ✨
这一篇更没什么营养了,完全不知道我学了啥。。。
把流和非流都实现。
自定义日志拦截器可以改成自己想要的日志输出,主要就是改写两个方法,实现不难,可以作为简历技能。
然后是Rereading的Advisor,这个就是把问题重复两遍,说是提高准确率了,但是token会翻倍。
这两个advisor我都没实现了。
还是把日志advisor实现了
myloggeradvisor如下,原本的api依旧用不了,用claudecode改写了一下:
然后在loveapp里面加了一个:
输出如下:
写完了发现还是报错,而且不知道为什么,教程也没说,不管了。。。感觉时间浪费了。
不想细看了,其实就是占位符这种思路
水了一节。
package com.example.aiagent.advisor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.client.ChatClientMessageAggregator;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain;
/**
* 自定义日志 Advisor
* 打印 info 级别日志、只输出单次用户提示词和 AI 回复的文本
*/
@Slf4j
public class MyLoggerAdvisor implements CallAdvisor, StreamAdvisor {
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public int getOrder() {
return 0;
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
log.info("AI Request: {}", request.prompt().getUserMessage().getText());
ChatClientResponse response = chain.nextCall(request);
log.info("AI Response: {}", response.chatResponse().getResult().getOutput().getText());
return response;
}
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain) {
log.info("AI Request: {}", request.prompt().getUserMessage().getText());
Flux<ChatClientResponse> responses = chain.nextStream(request);
return new ChatClientMessageAggregator().aggregateChatClientResponse(responses,
response -> log.info("AI Response: {}", response.chatResponse().getResult().getOutput().getText()));
}
}//ai恋爱报告功能,实战结构化输出
public LoveReport doChatWithReport(String message, String chatID){
LoveReport loveReport = chatClient.prompt()
.system(SYSTEM_PROMPT+"每次对话后都要生成恋爱结果,标题为{用户名}的恋爱报告,内容为建议列表")
.user(message)
.advisors(spec -> spec.param(ChatMemory.CONVERSATION_ID, chatID))
.call()
.entity(LoveReport.class);
log.info("LoveReport: {}", loveReport);
return loveReport;
}2026-05-30T16:04:24.659+08:00 INFO 10305 --- [ai-agent] [ main] c.e.aiagent.advisor.MyLoggerAdvisor : AI Request: 你好,我是自然晴,我想让我的另一半(洛天依)更爱我,该怎么做呢
2026-05-30T16:04:30.427+08:00 INFO 10305 --- [ai-agent] [ main] c.e.aiagent.advisor.MyLoggerAdvisor : AI Response: {
"suggestions": ["深入理解洛天依的情感需求与爱的语言(如肯定言语、精心时刻、服务行为、礼物或身体接触),并针对性地表达爱意", "持续提升自我价值感与生活热情,保持独立而丰盈的内在世界,让亲密关系成为锦上添花而非情感依赖", "主动创造专属你们的积极互动仪式(如每周深度对话、共同创作、音乐共赏等),强化情感联结与共同意义感", "坦诚沟通你对‘被爱’的具体期待,同时倾听她表达爱的方式与节奏,避免以己度人造成误解", "关注关系中的权力平衡与成长协同,支持她的梦想与表达,也让自己的需求被看见和尊重"],
"title": "自然晴的恋爱报告"
}
2026-05-30T16:04:30.429+08:00 INFO 10305 --- [ai-agent] [ main] com.example.aiagent.app.LoveApp : LoveReport: LoveReport[title=自然晴的恋爱报告, suggestions=[深入理解洛天依的情感需求与爱的语言(如肯定言语、精心时刻、服务行为、礼物或身体接触),并针对性地表达爱意, 持续提升自我价值感与生活热情,保持独立而丰盈的内在世界,让亲密关系成为锦上添花而非情感依赖, 主动创造专属你们的积极互动仪式(如每周深度对话、共同创作、音乐共赏等),强化情感联结与共同意义感, 坦诚沟通你对‘被爱’的具体期待,同时倾听她表达爱的方式与节奏,避免以己度人造成误解, 关注关系中的权力平衡与成长协同,支持她的梦想与表达,也让自己的需求被看见和尊重]]/**
* 基于文件持久化的对话记忆
*/
public class FileBasedChatMemory implements ChatMemory {
private final String BASE_DIR;
private static final Kryo kryo = new Kryo();
static {
kryo.setRegistrationRequired(false);
// 设置实例化策略
kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());