为您的 AI 应用程序提供动力:Spring AI Advisors

工程 | Christian Tzolov | 2024 年 10 月 2 日 | ...

在快速发展的人工智能世界中,开发人员不断寻求增强其 AI 应用程序的方法。Spring AI,一个用于构建 AI 驱动型应用程序的 Java 框架,引入了一项强大的功能:Spring AI Advisors

Advisors 可以为您的 AI 应用程序提供强大的支持,使其更具模块化、可移植性,并且更易于维护。

如果阅读文章不方便,您可以收听这个**实验性**播客,它**由 AI 生成**,内容来自博客文章。

什么是 Spring AI Advisors?

Spring AI Advisor 的核心是组件,它们会拦截并可能修改 AI 应用程序中聊天补全请求和响应的流程。系统中的关键参与者是 AroundAdvisor,它允许开发人员动态地转换或利用这些交互中的信息。

使用 Advisor 的主要好处包括:

  1. 封装重复性任务:将常见的 GenAI 模式打包成可重用单元。
  2. 转换:增强发送到语言模型 (LLM) 的数据,并格式化发送回客户端的响应。
  3. 可移植性:创建可重用的转换组件,这些组件可以跨各种模型和用例工作。

Advisor 如何工作

Advisor 系统作为一个链式结构运行,序列中的每个 Advisor 都有机会处理传入的请求和传出的响应。下面是简化的流程:

spring-ai-advisors-flow

  1. 从用户的提示创建一个 AdvisedRequest,以及一个空的 advisor-context
  2. 链中的每个 Advisor 都会处理请求,可能会修改它,然后将执行转发给链中的下一个 Advisor。或者,它也可以选择通过不调用下一个实体来阻止请求。
  3. 最后一个 Advisor 将请求发送到 Chat Model。
  4. Chat Model 的响应被作为 AdvisedResponse 传递回 Advisor 链,它结合了原始的 ChatResponse 和链的输入路径中的 advise context。
  5. 每个 Advisor 都可以处理或修改响应。
  6. 从最终的 AdvisedResponse 中增强的 ChatResponse 被返回给客户端。

使用 Advisor

Spring AI 提供了几个预构建的 Advisor 来处理常见场景和 Gen AI 模式。

使用 ChatClient API,您可以在管道中注册所需的 Advisor。

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

String response = chatClient.prompt()
    // Set chat memory parameters at runtime
    .advisors(advisor -> advisor.param("chat_memory_conversation_id", "678")
            .param("chat_memory_response_size", 100))
    .user(userText)
    .call()
	.content();

实现您自己的 Advisor

Advisor API 包含用于非流式处理的 CallAroundAdvisorCallAroundAdvisorChain,以及用于流式处理场景的 StreamAroundAdvisorStreamAroundAdvisorChain。它还包括 AdvisedRequest 来表示未封锁的 Prompt 请求数据,以及 AdvisedResponse 来表示聊天补全数据。AdvisedRequestAdvisedResponse 都有一个 advise-context 字段,用于在 Advisor 链中共享状态。

简单日志 Advisor

创建自定义 Advisor 非常简单。让我们实现一个简单的日志 Advisor 来演示这个过程。

public class SimpleLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
    private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);

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

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

    @Override
    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
        logger.debug("BEFORE: {}", advisedRequest);
        AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
        logger.debug("AFTER: {}", advisedResponse);
        return advisedResponse;
    }

    @Override
    public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
        logger.debug("BEFORE: {}", advisedRequest);
        Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);
        return new MessageAggregator().aggregateAdvisedResponse(advisedResponses,
                advisedResponse -> logger.debug("AFTER: {}", advisedResponse));
    }
}

此 Advisor 会在请求被处理之前记录请求,并在收到响应之后记录响应,从而为 AI 交互过程提供有价值的见解。

aggregateAdvisedResponse(...) 工具将 AdviseResponse 块聚合为单个 AdvisedResponse,返回原始流并接受一个 Consumer 回调以获取完成的结果。它保留了原始内容和上下文。

重读 (Re2) Advisor

让我们基于 Re-Reading (Re2) 技术实现一个更高级的 Advisor,该技术受此 论文 启发,可以提高大型语言模型的推理能力。

public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
    private static final String DEFAULT_USER_TEXT_ADVISE = """
        {re2_input_query}
        Read the question again: {re2_input_query}
        """;

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

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

    private AdvisedRequest before(AdvisedRequest advisedRequest) {

        String inputQuery = advisedRequest.userText(); //original user query

        Map<String, Object> params = new HashMap<>(advisedRequest.userParams());        
        params.put("re2_input_query", inputQuery);

        return AdvisedRequest.from(advisedRequest)
                .withUserText(DEFAULT_USER_TEXT_ADVISE)
                .withUserParams(params)
                .build();
    }

    @Override
    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
        return chain.nextAroundCall(before(advisedRequest));
    }

    @Override
    public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
        return chain.nextAroundStream(before(advisedRequest));
    }
}

此 Advisor 修改输入查询,以包含一个“重读”步骤,可能可以提高 AI 模型对问题的理解和推理能力。

高级主题

Spring AI 的高级主题涵盖了 Advisor 管理的重要方面,包括*顺序控制*、*状态共享*和*流式处理能力*。Advisor 的执行顺序由 getOrder() 方法决定。Advisor 之间的状态共享通过共享的 advise-context 对象实现,从而支持复杂的多个 Advisor 场景。该系统同时支持流式处理和非流式处理 Advisor,允许处理完整的请求和响应,或使用响应式编程概念处理连续的数据流。

控制 Advisor 顺序

Advisor 在链中的顺序至关重要,它由 getOrder() 方法决定。具有较低顺序值的 Advisor 会先执行。由于 Advisor 链是一个栈,链中的第一个 Advisor 最后处理请求,最先处理响应。如果您想确保某个 Advisor 最后执行,请将其顺序设置为接近 Ordered.LOWEST_PRECEDENCE 的值;反之,要先执行,请将其顺序设置为接近 Ordered.HIGHEST_PRECEDENCE 的值。如果您有多个具有相同顺序值的 Advisor,则执行顺序不确定。

使用 AdvisorContext 进行状态共享

AdvisedRequestAdvisedResponse 都共享一个 advise-context 对象。您可以使用 advise-context 在链中的 Advisor 之间共享状态,并构建涉及多个 Advisor 的更复杂的处理场景。

流式处理与非流式处理

Spring AI 支持流式处理和非流式处理 Advisor。非流式处理 Advisor 处理完整的请求和响应,而流式处理 Advisor 则使用响应式编程概念(例如,Flux 用于响应)来处理连续的流。

对于流式处理 Advisor,需要注意的是,单个 AdvisedResponse 实例仅代表整个 Flux<AdvisedResponse> 响应的一部分。相比之下,对于非流式处理 Advisor,AdvisedResponse 包含了完整的响应。

最佳实践

  1. 保持 Advisor 专注于特定任务,以提高模块化程度。
  2. 在必要时,使用 advise-context 在 Advisor 之间共享状态。
  3. 实现 Advisor 的流式处理和非流式处理版本,以获得最大的灵活性。
  4. 仔细考虑 Advisor 在链中的顺序,以确保正确的数据流。

结论

Spring AI Advisor 提供了一种强大而灵活的方式来增强您的 AI 应用程序。通过利用此 API,您可以创建更复杂、可重用且易于维护的 AI 组件。无论您是实现自定义逻辑、管理对话历史还是改进模型推理,Advisor 都提供了清晰有效的解决方案。

我们鼓励您在项目中尝试使用 Spring AI Advisor,并与社区分享您的自定义实现。可能性是无限的,您的创新可能有助于塑造 AI 应用程序开发的未来!

祝您编码愉快,愿您的 AI 应用程序越来越智能、响应迅速!

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有