自定义Advisor
Spring官方提供了MessageChatMemoryAdvisor()和QuestionAnswerAdvisor()分别用来对话记忆和增强检索,但有可能不完全符合我们具体业务的需求。因此需要自定义Advisor来帮助我们更好地完成业务。
实现步骤:
1. 选择合适的接口实现:CallAroundAdvisor:处理同步请求和响应
或StreamAroundAdvisor:处理流式请求和响应
(建议一起实现)
2. 实现
3. 设置执行顺序,实现getOrder()
4. 提供唯一标识符,实现getName()
示例:
Spring提供的日志输出Advisor是debug级别的,我们要想实现info级别的就要自定义日志输出Advisor
@Slf4j
public class MyLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
public String getName() {
return this.getClass().getSimpleName();
}
public int getOrder() {
return 0;
}
private AdvisedRequest before(AdvisedRequest request) {
log.info("request: {}", request.userText());
return request;
}
private void observeAfter(AdvisedResponse advisedResponse) {
log.info("response: {}", advisedResponse.response().getResult().getOutput().getText());
}
public String toString() {
return MyLoggerAdvisor.class.getSimpleName();
}
public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
advisedRequest = this.before(advisedRequest);
AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
this.observeAfter(advisedResponse);
return advisedResponse;
}
public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
advisedRequest = this.before(advisedRequest);
Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);
return (new MessageAggregator()).aggregateAdvisedResponse(advisedResponses, this::observeAfter);
}
}
结构化输出
SpringAI 通过结构化输出转换器(Structured Output Converter)来将返回的文本输出转换为结构化数据格式,如JSON,Bean等
调用前在prompt后添加提示词,明确告诉模型使用哪种格式
响应后将文本转换为实例
SpringAI 提供了多种转换器实现,如MapOutputConverter,BeanOutputConverter和ListOutputConverter
实现:
record LoveReport(String title, List<String> suggestions) {
}
public LoveReport doChatWithReport(String message, String chatId) {
LoveReport loveReport = client
.prompt()
.system(SYSTEM_PROMPT + "要求的格式,上文定义的record的{title}和{建议List}")//在prompt加后缀,要求生成的结构
.user(message)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
.call()
.entity(LoveReport.class);//生成特定的结构
log.info("loveReport: {}", loveReport);
return loveReport;
}
对话记忆持久化
一般都是基于内存来保存对话记忆上下文,当重启后记忆就会消失。所以让对话记忆持久化是我们需要去实现的。
自定义实现ChatMemory
基于内存实现的ChatMemory存储的都是Message对象,所以要想实现自定义ChatMemory就要做到写消息时Message对象转换为文本,读消息时将文本转换为对象。即序列化和反序列化。
Prompt模板
PromptTemplate支持动态生成prompt
// 定义订单信息模板
String orderTemplate = "订单编号:{orderId},客户:{customer},商品:{product},数量:{quantity},总价:{totalPrice}元。";
// 创建模板对象
PromptTemplate orderPromptTemplate = new PromptTemplate(orderTemplate);
// 准备订单相关变量
Map<String, Object> orderVariables = new HashMap<>();
orderVariables.put("orderId", "ORD20230908001");
orderVariables.put("customer", "张三");
orderVariables.put("product", "无线耳机");
orderVariables.put("quantity", 2);
orderVariables.put("totalPrice", 998);
// 生成订单信息文本
String orderInfo = orderPromptTemplate.render(orderVariables);
// 结果: "订单编号:ORD20230908001,客户:张三,商品:无线耳机,数量:2,总价:998元。"
SpringAI 提供了几种专用的模板类:
SystemPromptTemplate:设置AI的行为和背景
AssistantPromptTemplate:设置AI回复的结构
从文件中加载模板
// 从类路径资源加载系统提示模板
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
// 直接使用资源创建模板
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
低侵入修改代码提示词
为不同场景提供不同提示词
多模态
多模态是同时处理多种不同数据类型的能力,比如文本,音频,图像等