Advisors API

Spring AI Advisors API 提供了一种灵活而强大的方式来拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。 通过利用 Advisors API,开发人员可以创建更复杂、可重用和可维护的 AI 组件。spring-doc.cadn.net.cn

主要优势包括封装重复出现的生成式 AI 模式、转换与大型语言模型 (LLM) 发送和发送的数据,以及提供跨各种模型和用例的可移植性。spring-doc.cadn.net.cn

您可以使用 ChatClient API 配置现有顾问,如以下示例所示:spring-doc.cadn.net.cn

ChatMemory chatMemory = ... // Initialize your chat memory store
VectorStore vectorStore = ... // Initialize your vector store

var chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(
        MessageChatMemoryAdvisor.builder(chatMemory).build(), // chat-memory advisor
        QuestionAnswerAdvisor.builder(vectorStore).build()    // RAG advisor
    )
    .build();

var conversationId = "678";

String response = this.chatClient.prompt()
    // Set advisor parameters at runtime
    .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
    .user(userText)
    .call()
	.content();

建议在构建时使用 builder 的defaultAdvisors()方法。spring-doc.cadn.net.cn

顾问还参与可观测性堆栈,因此您可以查看与其执行相关的指标和跟踪。spring-doc.cadn.net.cn

核心组件

该 API 包括CallAdvisorCallAdvisorChain对于非流式处理方案,以及StreamAdvisorStreamAdvisorChain用于流式处理方案。 它还包括ChatClientRequest表示未密封的 Prompt 请求,ChatClientResponse用于聊天补全响应。两者都持有advise-context在整个顾问链中共享状态。spring-doc.cadn.net.cn

Advisors API 类

adviseCall()adviseStream()是关键的顾问方法,通常执行诸如检查未密封的 Prompt 数据、自定义和扩充 Prompt 数据、调用顾问链中的下一个实体、(可选)阻止请求、检查聊天补全响应以及抛出异常以指示处理错误等作。spring-doc.cadn.net.cn

此外,getOrder()方法确定链中的顾问顺序,而getName()提供唯一的顾问名称。spring-doc.cadn.net.cn

由 Spring AI 框架创建的 Advisor Chain 允许按顺序调用由其getOrder()值。 首先执行较低的值。 自动添加的最后一个顾问将请求发送到 LLM。spring-doc.cadn.net.cn

以程图说明了顾问链和聊天模型之间的交互:spring-doc.cadn.net.cn

Advisors API 流程
  1. Spring AI 框架创建了一个ChatClientRequest从用户的Prompt以及一个空的顾问context对象。spring-doc.cadn.net.cn

  2. 链中的每个顾问都处理请求,可能会对其进行修改。或者,它可以选择通过不调用调用下一个实体来阻止请求。在后一种情况下,顾问负责填写回复。spring-doc.cadn.net.cn

  3. 框架提供的最终顾问将请求发送到Chat Model.spring-doc.cadn.net.cn

  4. 然后,聊天模型的响应通过顾问链传回并转换为ChatClientResponse.Later 包括共享顾问context实例。spring-doc.cadn.net.cn

  5. 每个顾问都可以处理或修改响应。spring-doc.cadn.net.cn

  6. 决赛ChatClientResponse通过提取ChatCompletion.spring-doc.cadn.net.cn

Advisor Order

链中顾问的执行顺序由getOrder()方法。要了解的要点:spring-doc.cadn.net.cn

订单和执行顺序之间看似矛盾是由于顾问链的堆栈性质:spring-doc.cadn.net.cn

提醒一下,这里是 Spring 的语义Ordered接口:spring-doc.cadn.net.cn

public interface Ordered {

    /**
     * Constant for the highest precedence value.
     * @see java.lang.Integer#MIN_VALUE
     */
    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

    /**
     * Constant for the lowest precedence value.
     * @see java.lang.Integer#MAX_VALUE
     */
    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

    /**
     * Get the order value of this object.
     * <p>Higher values are interpreted as lower priority. As a consequence,
     * the object with the lowest value has the highest priority (somewhat
     * analogous to Servlet {@code load-on-startup} values).
     * <p>Same order values will result in arbitrary sort positions for the
     * affected objects.
     * @return the order value
     * @see #HIGHEST_PRECEDENCE
     * @see #LOWEST_PRECEDENCE
     */
    int getOrder();
}

对于需要在输入端和输出端都排在链中的第一个的用例:spring-doc.cadn.net.cn

  1. 为每一方使用单独的顾问。spring-doc.cadn.net.cn

  2. 使用不同的订单值配置它们。spring-doc.cadn.net.cn

  3. 使用顾问上下文在它们之间共享状态。spring-doc.cadn.net.cn

API 概述

主要的 Advisor 接口位于包中org.springframework.ai.chat.client.advisor.api.以下是您在创建自己的顾问时会遇到的关键界面:spring-doc.cadn.net.cn

public interface Advisor extends Ordered {

	String getName();

}

同步顾问和响应式顾问的两个子接口是spring-doc.cadn.net.cn

public interface CallAdvisor extends Advisor {

	ChatClientResponse adviseCall(
		ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain);

}
public interface StreamAdvisor extends Advisor {

	Flux<ChatClientResponse> adviseStream(
		ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain);

}

要继续建议链,请使用CallAdvisorChainStreamAdvisorChain在建议实施中:spring-doc.cadn.net.cn

public interface CallAdvisorChain extends AdvisorChain {

	/**
	 * Invokes the next {@link CallAdvisor} in the {@link CallAdvisorChain} with the given
	 * request.
	 */
	ChatClientResponse nextCall(ChatClientRequest chatClientRequest);

	/**
	 * Returns the list of all the {@link CallAdvisor} instances included in this chain at
	 * the time of its creation.
	 */
	List<CallAdvisor> getCallAdvisors();

}
public interface StreamAdvisorChain extends AdvisorChain {

	/**
	 * Invokes the next {@link StreamAdvisor} in the {@link StreamAdvisorChain} with the
	 * given request.
	 */
	Flux<ChatClientResponse> nextStream(ChatClientRequest chatClientRequest);

	/**
	 * Returns the list of all the {@link StreamAdvisor} instances included in this chain
	 * at the time of its creation.
	 */
	List<StreamAdvisor> getStreamAdvisors();

}

实施顾问

要创建顾问,请实现CallAdvisorStreamAdvisor(或两者兼而有之)。实现的关键方法是nextCall()对于非流式传输或nextStream()适用于流媒体顾问。spring-doc.cadn.net.cn

例子

我们将提供一些动手示例来说明如何实施顾问来观察和增强用例。spring-doc.cadn.net.cn

日志记录顾问

我们可以实现一个简单的日志记录顾问,记录ChatClientRequestbefore 和ChatClientResponse在调用链中的下一个顾问之后。 请注意,顾问仅观察请求和响应,不会修改它们。 此实现支持非流式处理和流式处理方案。spring-doc.cadn.net.cn

public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {

	private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);

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

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


	@Override
	public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
		logRequest(chatClientRequest);

		ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(chatClientRequest);

		logResponse(chatClientResponse);

		return chatClientResponse;
	}

	@Override
	public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
			StreamAdvisorChain streamAdvisorChain) {
		logRequest(chatClientRequest);

		Flux<ChatClientResponse> chatClientResponses = streamAdvisorChain.nextStream(chatClientRequest);

		return new ChatClientMessageAggregator().aggregateChatClientResponse(chatClientResponses, this::logResponse); (3)
	}

	private void logRequest(ChatClientRequest request) {
		logger.debug("request: {}", request);
	}

	private void logResponse(ChatClientResponse chatClientResponse) {
		logger.debug("response: {}", chatClientResponse);
	}

}
1 为顾问提供唯一名称。
2 您可以通过设置订单值来控制执行顺序。较低的值首先执行。
3 MessageAggregator是一个实用程序类,用于将 Flux 响应聚合到单个 ChatClientResponse 中。 这对于日志记录或其他观察整个响应而不是流中的单个项的处理非常有用。 请注意,您无法更改MessageAggregator因为它是只读作。

重读 (Re2) 顾问

重读提高大型语言模型中的推理”一文介绍了一种称为重读 (Re2) 的技术,该技术提高了大型语言模型的推理能力。 Re2 技术需要像这样增强输入提示:spring-doc.cadn.net.cn

{Input_Query}
Read the question again: {Input_Query}

实现将 Re2 技术应用于用户输入查询的顾问可以按如下方式完成:spring-doc.cadn.net.cn

public class ReReadingAdvisor implements BaseAdvisor {

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

	private final String re2AdviseTemplate;

	private int order = 0;

	public ReReadingAdvisor() {
		this(DEFAULT_RE2_ADVISE_TEMPLATE);
	}

	public ReReadingAdvisor(String re2AdviseTemplate) {
		this.re2AdviseTemplate = re2AdviseTemplate;
	}

	@Override
	public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) { (1)
		String augmentedUserText = PromptTemplate.builder()
			.template(this.re2AdviseTemplate)
			.variables(Map.of("re2_input_query", chatClientRequest.prompt().getUserMessage().getText()))
			.build()
			.render();

		return chatClientRequest.mutate()
			.prompt(chatClientRequest.prompt().augmentUserMessage(augmentedUserText))
			.build();
	}

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

	@Override
	public int getOrder() { (2)
		return this.order;
	}

	public ReReadingAdvisor withOrder(int order) {
		this.order = order;
		return this;
	}

}
1 before方法应用重读技术来增强用户的输入查询。
2 您可以通过设置订单值来控制执行顺序。较低的值首先执行。

Spring AI 内置顾问

Spring AI 框架提供了多个内置顾问来增强您的 AI 交互。以下是可用顾问的概述:spring-doc.cadn.net.cn

聊天记忆顾问

这些顾问在聊天内存存储中管理对话历史记录:spring-doc.cadn.net.cn

问答顾问
  • QuestionAnswerAdvisorspring-doc.cadn.net.cn

    此顾问使用向量存储来提供问答功能,实现朴素 RAG(检索增强生成)模式。spring-doc.cadn.net.cn

  • RetrievalAugmentationAdvisorspring-doc.cadn.net.cn

    Advisor that implements common 检索增强生成(RAG) flows using the building blocks defined in the `org.springframework.ai.rag` package and following the Modular RAG Architecture.
推理顾问
内容安全顾问

流媒体与非流媒体

顾问流式处理与非流式处理流
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain chain) {

    return  Mono.just(chatClientRequest)
            .publishOn(Schedulers.boundedElastic())
            .map(request -> {
                // This can be executed by blocking and non-blocking Threads.
                // Advisor before next section
            })
            .flatMapMany(request -> chain.nextStream(request))
            .map(response -> {
                // Advisor after next section
            });
}

最佳实践

  1. 让顾问专注于特定任务,以实现更好的模块化。spring-doc.cadn.net.cn

  2. 使用adviseContext必要时在顾问之间共享状态。spring-doc.cadn.net.cn

  3. 实现顾问的流式处理和非流式处理版本,以获得最大的灵活性。spring-doc.cadn.net.cn

  4. 仔细考虑链中顾问的顺序,以确保正确的数据流。spring-doc.cadn.net.cn

重大 API 更改

顾问接口

上下文映射处理