1. 工程結構概覽

spring-ai-client-chat 是 Spring AI 的高級 API 模塊,提供了類似 WebClient 的流式 API,讓 AI 對話編程變得更加簡單和直觀。

spring-ai-client-chat/
├── ChatClient.java              # 核心接口,流式 API
├── DefaultChatClient.java       # 默認實現
├── ChatClientRequest.java       # 請求對象
├── ChatClientResponse.java      # 響應對象
│
└── advisor/                     # Advisor 機制
    ├── api/                     # Advisor 接口定義
    │   ├── Advisor.java
    │   ├── CallAdvisor.java
    │   ├── StreamAdvisor.java
    │   └── BaseAdvisor.java
    ├── ChatModelCallAdvisor.java    # 調用模型的 Advisor
    ├── ChatModelStreamAdvisor.java  # 流式調用的 Advisor
    ├── ToolCallAdvisor.java         # 工具調用 Advisor
    └── SimpleLoggerAdvisor.java    # 日誌 Advisor

2. 技術體系與模塊關係

ChatClient 建立在 ChatModel 之上,通過 Advisor 機制提供了強大的擴展能力:

分析Chat示例的源代碼 - 付海東的個人頁面 -_java

3. 關鍵場景示例代碼

3.1 基礎使用

ChatClient 提供了非常友好的流式 API:

@Autowired
private ChatModel chatModel;

public void basicUsage() {
    ChatClient chatClient = ChatClient.create(chatModel);
    
    String response = chatClient.prompt()
        .user("什麼是 Spring AI?")
        .call()
        .content();
    
    System.out.println(response);
}

3.2 流式調用

流式調用非常簡單:

public void streamUsage() {
    ChatClient chatClient = ChatClient.create(chatModel);
    
    chatClient.prompt()
        .user("講一個故事")
        .stream()
        .content()
        .doOnNext(chunk -> System.out.print(chunk))
        .blockLast();
}

3.3 使用 Advisor

Advisor 是 ChatClient 的核心特性,可以增強請求和響應:

public void advisorUsage() {
    // 創建 RAG Advisor
    RetrievalAugmentationAdvisor ragAdvisor = 
        RetrievalAugmentationAdvisor.builder()
            .documentRetriever(vectorStoreRetriever)
            .build();
    
    ChatClient chatClient = ChatClient.builder(chatModel)
        .defaultAdvisors(ragAdvisor)
        .build();
    
    String response = chatClient.prompt()
        .user("查詢文檔中的信息")
        .call()
        .content();
}

3.4 結構化輸出

ChatClient 支持直接將響應轉換為 POJO:

public void structuredOutput() {
    BeanOutputConverter<WeatherInfo> converter = 
        new BeanOutputConverter<>(WeatherInfo.class);
    
    WeatherInfo weather = chatClient.prompt()
        .user("查詢北京天氣,返回 JSON:" + converter.getFormat())
        .call()
        .entity(converter);
}

4. 核心時序圖

4.1 同步調用流程

分析Chat示例的源代碼 - 付海東的個人頁面 -_spring_02

4.2 流式調用流程

分析Chat示例的源代碼 - 付海東的個人頁面 -_spring_03

5. 入口類與關鍵類關係

分析Chat示例的源代碼 - 付海東的個人頁面 -_spring_04

6. 關鍵實現邏輯分析

6.1 流式 API 設計

ChatClient 的流式 API 設計非常巧妙,使用了 Builder 模式和函數式接口:

public interface ChatClient {
    ChatClientRequestSpec prompt();
    
    interface ChatClientRequestSpec {
        PromptUserSpec user(String text);
        PromptSystemSpec system(String text);
        AdvisorSpec advisors(Advisor... advisors);
        CallResponseSpec call();
        StreamResponseSpec stream();
    }
    
    interface CallResponseSpec {
        String content();
        <T> T entity(Class<T> type);
        ChatResponse chatResponse();
    }
}

這種設計讓 API 既類型安全又易於使用。

6.2 Advisor 機制

Advisor 是 ChatClient 的核心擴展機制,類似於 Spring AOP 的切面:

public interface CallAdvisor extends Advisor {
    ChatClientResponse adviseCall(
        ChatClientRequest request, 
        CallAdvisorChain chain
    );
}

Advisor 鏈的執行流程

  1. Before 階段:每個 Advisor 可以在調用前修改請求
  2. Call 階段:調用下一個 Advisor 或最終調用模型
  3. After 階段:每個 Advisor 可以在調用後修改響應
public class DefaultAroundAdvisorChain implements CallAdvisorChain {
    public ChatClientResponse nextCall(ChatClientRequest request) {
        if (currentIndex >= advisors.size()) {
            // 鏈的末尾,調用模型
            return chatModelCallAdvisor.adviseCall(request, this);
        }
        
        CallAdvisor currentAdvisor = advisors.get(currentIndex);
        return currentAdvisor.adviseCall(request, 
            new DefaultAroundAdvisorChain(currentIndex + 1, ...));
    }
}

6.3 工具調用處理

ToolCallAdvisor 負責處理工具調用,它會在檢測到工具調用時自動執行:

public class ToolCallAdvisor implements CallAdvisor {
    @Override
    public ChatClientResponse adviseCall(...) {
        boolean isToolCall = false;
        do {
            // 調用模型
            chatClientResponse = callAdvisorChain.nextCall(request);
            
            // 檢查是否有工具調用
            isToolCall = chatClientResponse.chatResponse().hasToolCalls();
            
            if (isToolCall) {
                // 執行工具調用
                ToolExecutionResult result = 
                    toolCallingManager.executeToolCalls(...);
                
                // 將工具結果作為新的請求再次調用
                request = new Prompt(result.getConversationHistory());
            }
        } while (isToolCall);
        
        return chatClientResponse;
    }
}

這種設計實現了自動工具調用循環,直到模型不再請求工具調用。

6.4 流式處理實現

流式處理通過 ChatModelStreamAdvisor 實現:

public class ChatModelStreamAdvisor implements StreamAdvisor {
    @Override
    public Flux<ChatClientResponse> adviseStream(...) {
        Flux<ChatResponse> responseFlux = 
            chatModel.stream(request.prompt());
        
        return responseFlux.map(chunk -> 
            ChatClientResponse.builder()
                .chatResponse(chunk)
                .context(request.context())
                .build()
        );
    }
}

流式 Advisor 鏈的處理更復雜,因為需要在流式響應中插入處理邏輯。

7. 外部依賴

spring-ai-client-chat 的依賴:

  • spring-ai-model:核心模型抽象
  • Reactor Core:響應式流式處理
  • Spring Framework:IoC 和核心功能
  • Jackson:JSON 處理(用於結構化輸出)
  • MCP SDK:Model Context Protocol 支持

8. 工程總結

spring-ai-client-chat 模塊的設計體現了幾個重要的設計原則:

流式 API 設計。ChatClient 的 API 風格和 Spring WebClient 很像,用起來很順手。開發者不需要學習新的 API,就能快速上手。

Advisor 機制。這是 ChatClient 的核心能力。通過 Advisor,我們可以給請求和響應"加料",比如做 RAG、記錄對話歷史、打日誌、安全檢查等,而且不需要改核心代碼。

責任鏈模式。多個 Advisor 按順序執行,每個 Advisor 都能修改請求和響應,就像過濾器鏈一樣。

工具調用自動化ToolCallAdvisor 會自動處理工具調用循環,模型説要調用工具,它就自動調用,然後把結果再傳給模型,直到模型不再需要工具。整個過程對用户是透明的。

類型安全。通過泛型和函數式接口,API 既靈活又安全,編譯期就能發現很多錯誤。

總的來説,spring-ai-client-chat 是一個設計得很好的高級 API。它讓 AI 對話編程變得簡單,同時通過 Advisor 機制提供了強大的擴展能力。簡單場景用起來很順手,複雜場景也能通過 Advisor 靈活擴展。