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 社群所有即將舉行的活動。

檢視所有