SpringAI实现Reread(Advisor)

文章目录

1_Advisor介绍

Advisor 是 SpringAI 基于 AOP 机制实现与大模型对话过程的增强、拦截、修改等功能的关键组件。

所有的增强通知都需要实现 Advisor 接口。

常见的组件有如下几种:

  • Advisor:顶级接口,继承了 Ordered,可以定义拦截器(Advisor)的顺序。
  • ChatClientRequest:表示由 ChatClient 处理的请求,最终用于构建要发送到 LLM 的Prompt。
  • ChatClientResponse:表示由 ChatClient 返回的响应。
  • CallAdvisor:非流式场景的接口(增强 ChatClientRequest 和 ChatClientResponse)。
  • StreamAdvisor:流式场景的接口(增强 ChatClientRequest 和 ChatClientResponse)。
  • CallAdvisorChain:非流式场景的实例链,用于编排链中下一个 CallAdvisor 实例的执行。
  • StreamAdvisorChain:流式场景的实例链,用于编排链中下一个 StreamAdvisor 实例的执行。

常见的实现有如下几种:

  • BaseAdvisor:基础 Advisor,实现了 CallAdvisor, StreamAdvisor 两个接口。
  • SimpleLoggerAdvisor:日志记录的 Advisor。
  • MessageChatMemoryAdvisor:会话记忆的 Advisor。
  • SafeGuardAdvisor:拦截敏感词的 Advisor。
  • VectorStoreChatMemoryAdvisor:从 VectorStore 检索内存并将其添加到提示的系统文本中的Advisor。

最基本的两个接口是 CallAdvisor, StreamAdvisor,但有时并不知晓到底应该选择流式还是非流式,所以一般情况下都会一起实现。

而 BaseAdvisor 这个接口就可以方便我们快速创建自定义的 Advisor,只用实现其中的 before 和 after 方法。

根据以下源码可知,无论是流式还是非流式都会在请求传递给下一个 Advisor 前后分别调用 before 和 after 方法:

java 复制代码
public interface BaseAdvisor extends CallAdvisor, StreamAdvisor {

	Scheduler DEFAULT_SCHEDULER = Schedulers.boundedElastic();

	@Override
	default ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
		ChatClientRequest processedChatClientRequest = before(chatClientRequest, callAdvisorChain);
		ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(processedChatClientRequest);
		return after(chatClientResponse, callAdvisorChain);
	}

	@Override
	default Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
			StreamAdvisorChain streamAdvisorChain) {
		Flux<ChatClientResponse> chatClientResponseFlux = Mono.just(chatClientRequest)
			.publishOn(getScheduler())
			.map(request -> this.before(request, streamAdvisorChain))
			.flatMapMany(streamAdvisorChain::nextStream);

		return chatClientResponseFlux.map(response -> {
			if (AdvisorUtils.onFinishReason().test(response)) {
				response = after(response, streamAdvisorChain);
			}
			return response;
		}).onErrorResume(error -> Flux.error(new IllegalStateException("Stream processing failed", error)));
	}

	@Override
	default String getName() {
		return this.getClass().getSimpleName();
	}

	/**
	 * Logic to be executed before the rest of the advisor chain is called.
	 */
	ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain);

	/**
	 * Logic to be executed after the rest of the advisor chain is called.
	 */
	ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain);

	/**
	 * Scheduler used for processing the advisor logic when streaming.
	 */
	default Scheduler getScheduler() {
		return DEFAULT_SCHEDULER;
	}

}

总结:简单来说就是责任链模式。

2_reread介绍

重读策略的核心在于让 LLMs 重新审视输入的问题,这借鉴了人类解决问题的思维方式。

通过这种方式,LLMs 能够更深入地理解问题,发现复杂的模式,从而在各种推理任务中表现得更加强大。

可以按照如下方式编写提示词模版:

properties 复制代码
{Input_Query}
Read the question again: {Input_Query}

论文链接地址:https://arxiv.org/pdf/2309.06275。

3_实现 ReReadingAdvisor

基于 BaseAdvisor 来实现自定义的 Advisor,避免了重复代码的编写,只需专注自己的业务即可:

java 复制代码
@SuppressWarnings("all")
public class ReReadingAdvisor implements BaseAdvisor {

    private static final String DEFAULT_RE2_ADVISE_TEMPLATE = """
            {re2_input_query}
            Read the question again: {re2_input_query}
            """;

    @Override
    public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {
        // 拿到之前的提示词
        String userPrompt = chatClientRequest.prompt().getUserMessage().getText();
        String re2InputQuery = PromptTemplate.builder().template(DEFAULT_RE2_ADVISE_TEMPLATE)
                .variables(Map.of("re2_input_query", userPrompt))
                .build().render();
        return chatClientRequest.mutate() // 复制一个新的chatClientRequest
                .prompt(chatClientRequest.prompt().augmentUserMessage(re2InputQuery)).build();
    }

    @Override
    public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
        return chatClientResponse;
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

还可以进行扩展比如增加一个设置 Order 的方法。

相关推荐
宿州派大星3 小时前
Python实战:PyQt5 + OpenCV + Dlib 打造AI桌面应用
人工智能·python·qt
风娜4 小时前
IT 疑难杂症诊疗室:从现象到根因的系统排查方法论
人工智能·github
碧海银沙音频科技研究院4 小时前
炬芯ATS3089X手表的HFP通话不自动路由到设备BT的问题解决
网络·人工智能·嵌入式硬件·算法
承渊政道4 小时前
【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(开源大模型ChatGLM高级定制化应用实战)
人工智能·pytorch·python·llm·模型微调·glm
howdoyoudo2026064 小时前
AI审计手记 #28:从“暂停训练”到“切断联网”——AI安全控制手段的极限升级
大数据·人工智能·安全·ai·语言模型
colman wang4 小时前
人工智能课程(配套AIMA(Artificial Intelligence: A Modern Approach))
人工智能
Joy T5 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context
LinXunFeng8 小时前
Draw Things 换装 LoRA 实战:用 Silo 秒装,同一提示词对比出图
人工智能·开源·aigc
xiaohaiAIgeo8 小时前
【2026年】通风柜自动门安全吗?联锁逻辑与防夹设计
人工智能·安全·科普知识