Spring AI 1.0.0 M6 发布

发布 | Mark Pollack | 2025 年 2 月 14 日 | ...

我们很高兴地宣布 Spring AI 1.0.0 Milestone 6 发布。为了庆祝这次发布,我们创建了一个特别的 AI 生成音乐播放列表,以增强您的博客阅读和编码体验!

与往常一样,本次发布包含了一些新功能和错误修复。我们继续从设计角度审查代码库。虽然我们已努力通过在一个发布周期内弃用方法和类来使此次过渡平稳,但有一些已知的破坏性更改,以及可能未知的更改,所以请多包涵。有关详细信息,请参阅本文末尾的 破坏性更改 部分。

新功能

🎵 工具时间!

函数调用(现在更普遍地称为工具调用)的整体设计和功能集得到了重大改进。非常感谢 Thomas Vitale 推动了这些改进。

现在有几种定义工具的方法

  • 使用 @Tool@ToolParam 注解的声明式基于方法的工具
  • 使用 MethodToolCallback 的编程式基于方法的工具
  • 使用 FunctionToolCallback 的基于函数的工具
  • 从 Spring Bean 进行动态工具解析

这是一个使用 @Tool 注解创建用于获取当前日期和时间的工具的示例。

import java.time.LocalDateTime;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

class DateTimeTools {

    @Tool(description = "Get the current date and time in the user's timezone")
    String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }
}

// Using the tool with ChatClient
String response = ChatClient.create(chatModel)
        .prompt("What day is tomorrow?")
        .tools(new DateTimeTools())
        .call()
        .content();

当模型需要了解当前日期和时间时,它将自动请求调用该工具。ChatClient 在内部处理工具执行,并将结果返回给模型,然后模型使用此信息生成最终响应。JSON Schema 是使用类和工具注解自动生成的。

在弃用方面,org.springframework.ai.model.function 包中的所有内容都已被弃用,并且新接口和类可在 org.springframework.ai.tool 包中使用。

相关 API 已更新

  • FunctionCallingOptionsToolCallingChatOptions
  • ChatClient.builder().defaultFunctions()ChatClient.builder().defaultTools()
  • ChatClient.functions()ChatClient.tools()

有关更多信息,请参阅 工具迁移指南

工具调用功能还有其他各种改进,请查看 工具参考文档 了解更多信息。

🎵 MCP,就是这么简单,1、2、3。

去年 11 月,我们迎来了一个“惊喜”,而不是 10 月的惊喜:模型上下文协议 (Model Context Protocol) 发布,并受到了 AI 社区的广泛欢迎。

简而言之,模型上下文协议 (MCP) 提供了一种统一的方式来将 AI 模型连接到不同的数据源和工具,从而实现无缝且一致的集成。它帮助您在大型语言模型 (LLM) 之上构建代理和复杂的工作流。由于 LLM 经常需要与数据和工具集成,MCP 提供了

  • 不断增长的预构建集成列表,LLM 可直接接入
  • 切换 LLM 提供商和供应商的灵活性
  • 工具发现和执行的标准接口

spring-ai-mcp 实验项目于去年 11 月启动,此后一直在不断发展。Spring AI 团队与 Anthropic 的 David Soria Parra 等人合作,将该实验项目整合到官方 MCP Java SDK 中。MCP Java SDK 具有以下核心功能:

  • 同步和异步 MCP 客户端/服务器实现
  • 协议版本兼容性协商
  • 带更改通知的工具发现和执行
  • 带 URI 模板的资源管理
  • 根列表管理和通知
  • 提示处理和管理
  • AI 模型交互的采样支持

还有多种传输选项

  • 基于 Stdio 的传输,用于进程间通信
  • 基于 Java HttpClient 的 SSE 客户端传输
  • 基于 Servlet 的 SSE 服务器传输
  • Spring 特有的传输,WebFlux SSE 传输用于响应式 HTTP 流,WebMVC SSE 传输用于基于 Servlet 的 HTTP 流

请查看 MCP Java SDK 文档,了解有关 SDK 入门的更多信息,并访问 MCP Java SDK GitHub 仓库 来提交问题和参与讨论。

随着核心组件已移至 Anthropic Java SDK,与 Spring AI 的集成侧重于提供更简单的开发体验,以利用 Spring Boot Autoconfiguration 创建客户端和服务器实现。

这是一个小型客户端示例,展示了如何在简单的聊天机器人应用程序中使用 Brave Search API

@SpringBootApplication
public class Application {
    @Bean
    public CommandLineRunner predefinedQuestions(
            ChatClient.Builder chatClientBuilder, 
            ToolCallbackProvider tools,
            ConfigurableApplicationContext context) {
        return args -> {
            var chatClient = chatClientBuilder
                    .defaultTools(tools)
                    .build();

            String question = "Does Spring AI support the Model Context Protocol?";
            System.out.println("ASSISTANT: " + 
                chatClient.prompt(question).call().content());
        };
    }
}

配置很简单

spring.ai.mcp.client.stdio.enabled=true
spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json

服务器配置如下:

{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-brave-search"
      ],
      "env": {
      }
    }
  }
}

在依赖配置中,导入 Spring AI Bom 并添加 Spring Boot 客户端启动器,此处以 Maven 为例。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>

MCP 是一个庞大的主题。参考文档中有更多信息,并且有几个 示例

Vector Store 增强功能

VectorStore API 已得到改进,但带来了一些破坏性更改。
VectorStore 接口的 delete 方法已简化为 void 操作,移除了之前的 Optional返回类型。开发者现在应使用异常处理来管理删除失败,而不是检查返回值。有关更多信息,请参阅 参考文档

基于过滤器的删除

现在您可以根据元数据标准删除文档,而不仅仅是文档 ID。

这是一个示例

// Create and add documents to the store
Document bgDocument = new Document("content", 
    Map.of("country", "BG", "year", 2020));
Document nlDocument = new Document("content", 
    Map.of("country", "NL", "year", 2021));
vectorStore.add(List.of(bgDocument, nlDocument));

// Delete documents using string filter expression
vectorStore.delete("country == 'BG'");

// Or use the Expression-based API
Filter.Expression expr = // ... your filter expression
vectorStore.delete(expr);

此功能已在所有向量存储提供商中实现,包括 Chroma、Elasticsearch、PostgreSQL、Weaviate、Redis、Milvus 等。

原生客户端访问

新的 getNativeClient() API 允许开发人员在需要时访问底层的原生客户端实现

WeaviateVectorStore vectorStore = // get vector store
Optional<WeaviateClient> nativeClient = vectorStore.getNativeClient();
if (nativeClient.isPresent()) {
    WeaviateClient client = nativeClient.get();
    // Use native client capabilities
}

Simple Vector Store 改进

SimpleVectorStore 实现现在支持使用 Spring Expression Language (SpEL) 的元数据过滤

Postgres Vector Store 改进

PostgreSQL 向量存储实现已得到改进,可以更灵活地处理不同的 ID 列类型。它不再强制要求 UUID 作为唯一的复合键类型,而是支持

  • UUID
  • TEXT
  • INTEGER
  • SERIAL
  • BIGSERIAL

这使得与现有数据库模式和不同的 ID 管理策略集成更加容易。

移除已弃用的 Amazon Bedrock Chat 模型

这些模型现已替换为 Amazon Bedrock Converse API,后者更灵活,并支持使用相同 API 的不同模型。

🎵 都是关于这些代理的……

每个人都在谈论代理。我们短期内不会构建代理框架,因为 Anthropic 的博文 “构建有效的代理” 与团队产生了强烈的共鸣。

来自博文

在过去一年里,我们与各行各业的数十个团队合作构建了大型语言模型 (LLM) 代理。一贯地,最成功的实现并不是使用复杂的框架或专用库。相反,它们是使用简单、可组合的模式来构建的。

代理系统主要分为两类:工作流和代理

  • 工作流:LLM 和工具通过预定义的代码路径进行编排的系统
  • 代理:LLM 动态指导其自身流程和工具使用,并控制其完成任务方式的系统

Spring AI 已经提供了“构建块:增强型 LLM”——一种通过检索、工具和内存等增强功能而得到增强的 LLM。利用这个构建块,博文描述了构建有效代理的几种工作流:

  1. 链式工作流 – 将任务分解为顺序步骤,其中每次 LLM 调用都会处理上一步的输出,确保结构化进展。
  2. 评估者-优化器 – 使用评估者 LLM 来评估另一个 LLM 的输出,通过提供反馈和改进响应来提高质量。
  3. 协调器-工作器 – 一个中央协调器 LLM 将任务委派给专门的工作器 LLM,从而实现模块化和可扩展的任务执行。
  4. 并行化工作流 – 将任务分解为可以并行运行的独立子任务,提高效率并聚合多个视角。
  5. 路由工作流 – 对输入进行分类并将其定向到相应的 LLM 模型或处理路径,以优化准确性和效率。

有关这些模式的详细实现,请参阅 Spring AI 的 使用 Spring AI 构建有效代理 (第一部分) 以及配套的 示例

这是第一个模式的示例

Spring AI 中的链式工作流

在此示例中,我们将创建一个链式工作流,通过以下步骤处理业务报告:

  1. 提取数值指标
  2. 标准化其格式
  3. 对它们进行排序
  4. 以干净的表格格式呈现它们

以下是使用 Spring AI 实现此模式的方法

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    // Sample business report with various metrics in natural language
    String report = """
            Q3 Performance Summary:
            Our customer satisfaction score rose to 92 points this quarter.
            Revenue grew by 45% compared to last year.
            Market share is now at 23% in our primary market.
            Customer churn decreased to 5% from 8%.
            New user acquisition cost is $43 per user.
            Product adoption rate increased to 78%.
            Employee satisfaction is at 87 points.
            Operating margin improved to 34%.
            """;

    @Bean
    public CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {
        return args -> {
            new ChainWorkflow(chatClientBuilder.build()).chain(report);
        };
    }
}

/**
 * Implements a prompt chaining workflow that breaks down complex tasks into a sequence
 * of simpler LLM calls, where each step's output feeds into the next step.
 */
public class ChainWorkflow {
    /**
     * System prompts that define each transformation step in the chain.
     * Each prompt acts as a gate that validates and transforms the output
     * before proceeding to the next step.
     */
    private static final String[] CHAIN_PROMPTS = {
        // Step 1: Extract numerical values
        """
        Extract only the numerical values and their associated metrics from the text.
        Format each as 'value: metric' on a new line.
        Example format:
        92: customer satisfaction
        45%: revenue growth""",
        
        // Step 2: Standardize to percentages
        """
        Convert all numerical values to percentages where possible.
        If not a percentage or points, convert to decimal (e.g., 92 points -> 92%).
        Keep one number per line.
        Example format:
        92%: customer satisfaction
        45%: revenue growth""",
        
        // Step 3: Sort in descending order
        """
        Sort all lines in descending order by numerical value.
        Keep the format 'value: metric' on each line.
        Example:
        92%: customer satisfaction
        87%: employee satisfaction""",
        
        // Step 4: Format as markdown
        """
        Format the sorted data as a markdown table with columns:
        | Metric | Value |
        |:--|--:|
        | Customer Satisfaction | 92% |"""
    };

    private final ChatClient chatClient;

    public ChainWorkflow(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public String chain(String userInput) {
        String response = userInput;
        
        for (String prompt : CHAIN_PROMPTS) {
            response = chatClient.prompt(
                String.format("{%s}\n{%s}", prompt, response)
            ).call().content();
        }
        
        return response;
    }
}

关键数据流是每个步骤的输出成为下一步的输入。对于我们的示例报告,数据流如下:

  • 步骤 1 提取指标,例如“92:客户满意度”,“45%:收入增长”
  • 步骤 2 标准化为百分比格式:“92%:客户满意度”
  • 步骤 3 按降序对值进行排序
  • 步骤 4 创建格式化的 markdown 表格

完整的源代码,以及其他代理模式的实现,可在 spring-ai-examples 仓库和 使用 Spring AI 构建有效代理 (第一部分) 中找到。

贡献者

大量贡献者对代码进行了其他重构、错误修复和文档增强。如果您的 PR 尚未处理,我们将尽快处理,请耐心等待。感谢以下贡献者:

破坏性变更

本次发布包含一些破坏性更改,因为我们继续优化 API 设计。主要更改包括:

  • 将与函数相关的包和类重命名为相应的与工具相关的名称 (例如,`org.springframework.ai.model.function` 到 `org.springframework.ai.tool`)
  • 更新 VectorStore API
  • 更改模型客户端配置属性

有关破坏性更改的完整列表和详细的升级说明,请参阅参考文档中的 升级说明

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

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

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看所有