此版本仍在开发中,尚未被视为稳定版。如需最新的快照版本,请使用 Spring AI 1.1.3spring-doc.cadn.net.cn

Advisors API

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

The key benefits include encapsulating recurring Generative AI patterns, transforming data sent to and from Large Language Models (LLMs), and providing portability across various models and use cases.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();

建议在构建时使用构建器的defaultAdvisors()方法注册顾问。spring-doc.cadn.net.cn

顾问也会参与可观测性栈中,因此您可以查看与它们执行相关的指标和跟踪信息。spring-doc.cadn.net.cn

核心组件

The API consists of CallAdvisor and CallAdvisorChain for non-streaming scenarios, and StreamAdvisor and StreamAdvisorChain for streaming scenarios. It also includes ChatClientRequest to represent the unsealed Prompt request, ChatClientResponse for the Chat Completion response. Both hold an advise-context to share state across the advisor chain.spring-doc.cadn.net.cn

Advisors API Classes

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

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

Spring AI框架创建的顾问链允许按其getOrder()值顺序依次调用多个顾问。较低的值会首先执行。 最后一个顾问会被自动添加,并将请求发送给LLM。spring-doc.cadn.net.cn

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

Advisors API Flow
  1. The Spring AI框架从用户的Prompt创建一个ChatClientRequest,并同时生成一个空的顾问context对象。spring-doc.cadn.net.cn

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

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

  4. The Chat Model 的响应随后通过顾问链传递,并转换为ChatClientResponse。之后包括共享顾问context实例。spring-doc.cadn.net.cn

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

  6. 最终返回给客户端的是ChatClientResponse,它是从ChatCompletion中提取出来的。spring-doc.cadn.net.cn

Advisor Order

The execution order of advisors in the chain is determined by the getOrder() method. Key points to understand: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概述

The main Advisor interfaces are located in the package org.springframework.ai.chat.client.advisor.api. Here are the key interfaces you’ll encounter when creating your own advisor: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);

}

继续链式建议,请在您的Advice实现中使用CallAdvisorChainStreamAdvisorChainspring-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

<h1>示例</h1>

我们将提供几个实践示例,以说明如何实现顾问来观察并增强用例的实现。spring-doc.cadn.net.cn

日志顾问

我们可以实现一个简单的日志记录顾问,该顾问在调用链中的下一个顾问之前和之后分别记录ChatClientRequestChatClientResponse。 请注意,顾问仅观察请求和响应,并不对它们进行修改。 此实现支持非流式和流式两种场景。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}

使用Spring AI框架针对用户输入查询实现应用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 The before method 增强用户的输入查询,应用了重读技术。
2 可以设置顺序值来控制执行顺序。较小的值优先执行。

Spring AI内置顾问

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

Chat Memory Advisors

这些顾问管理聊天历史记录在聊天记忆存储中: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.
reasoning advisor
内容安全顾问

流式与非流式

Advisors Streaming vs Non-Streaming Flow
  • 非流式顾问处理完整的请求和响应。spring-doc.cadn.net.cn

  • 流式顾问会话处理请求和响应作为连续的流,使用响应式编程概念(例如,对于响应使用 Flux)。spring-doc.cadn.net.cn

@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更改

顾问接口

上下文映射处理