Spring AI 1.1.4 项目源码深度解析

目录

  1. 项目概览

  2. 整体架构设计

  3. 核心模块详解

  4. 模型集成层

  5. 向量存储系统

  6. [RAG 检索增强生成](#RAG 检索增强生成)

  7. [MCP 模型上下文协议](#MCP 模型上下文协议)

  8. 工具调用机制

  9. [Spring Boot 自动配置](#Spring Boot 自动配置)

  10. 最佳实践与设计模式


1. 项目概览

1.1 项目定位

Spring AI 是 Spring 生态系统针对人工智能领域的扩展项目,其设计目标是:

  • 可移植性:提供统一的 API 抽象,支持不同 AI 提供商的切换

  • 模块化设计:各个功能组件松耦合,可独立使用

  • POJO 编程模型:延续 Spring 传统,使用简单的 Java 对象构建 AI 应用

  • 与 Spring 生态无缝集成:支持 Spring Boot 自动配置、依赖注入等特性

1.2 项目统计

指标 数据
版本 1.1.4
Maven 模块数 180+
支持的模型提供商 20+
支持的向量数据库 19+
核心编程语言 Java 17+

1.3 模块分类

复制代码
spring-ai-1.1.4/
├── 核心抽象层
│   ├── spring-ai-model          # 模型核心抽象
│   ├── spring-ai-client-chat    # 聊天客户端
│   ├── spring-ai-vector-store   # 向量存储抽象
│   ├── spring-ai-commons        # 公共组件
│   └── spring-ai-rag           # RAG 框架
├── 模型实现层
│   └── models/                  # 20+ AI 提供商实现
│       ├── spring-ai-openai
│       ├── spring-ai-zhipuai
│       ├── spring-ai-azure-openai
│       └── ...
├── 向量存储实现层
│   └── vector-stores/          # 19+ 向量数据库实现
│       ├── spring-ai-pgvector-store
│       ├── spring-ai-milvus-store
│       ├── spring-ai-elasticsearch-store
│       └── ...
├── 内存存储层
│   └── memory/repository/       # 聊天内存存储实现
├── 文档读取层
│   └── document-readers/        # 文档解析
├── MCP 层
│   └── mcp/                    # Model Context Protocol
├── Spring Boot 集成层
│   ├── auto-configurations/     # 自动配置
│   └── spring-ai-spring-boot-starters/  # Starter
└── 其他工具
    ├── spring-ai-retry         # 重试机制
    ├── spring-ai-test          # 测试工具
    └── spring-ai-docs          # 文档

2. 整体架构设计

2.1 架构全景图

复制代码

2.2 核心设计原则

2.2.1 接口隔离原则 (ISP)

Spring AI 将功能拆分为细粒度的接口:

java 复制代码
// 基础模型接口 - 最抽象的调用契约
public interface Model<TReq extends ModelRequest<?>, TRes extends ModelResponse<?>> {
    TRes call(TReq request);
}
​
// 聊天模型接口 - 针对对话场景的扩展
public interface ChatModel extends Model<Prompt, ChatResponse>, StreamingChatModel {
    String call(String message);
    ChatResponse call(Prompt prompt);
    Flux<ChatResponse> stream(Prompt prompt);
}
​
// 嵌入模型接口 - 专门处理文本向量化
public interface EmbeddingModel extends Model<EmbeddingRequest, EmbeddingResponse> {
    float[] embed(String text);
    float[] embed(Document document);
}
​
// 图像模型接口 - 处理图像生成
public interface ImageModel extends Model<ImagePrompt, ImageResponse> {
    ImageResponse call(ImagePrompt prompt);
}
2.2.2 构建器模式 (Builder Pattern)

几乎所有配置对象都使用构建器模式:

java 复制代码
// ChatClient 构建示例
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultSystem("你是一个 helpful 助手")
    .defaultOptions(ChatOptions.builder()
        .temperature(0.7)
        .maxTokens(1000)
        .build())
    .build();
​
// VectorStore 构建示例
VectorStore vectorStore = PgVectorStore.builder(embeddingModel)
    .dimensions(1536)
    .distanceType(PgVectorStore.PgDistanceType.COSINE_DISTANCE)
    .initializeSchema(true)
    .build();
2.2.3 顾问模式 (Advisor Pattern)
java 复制代码
Advisor 是 Spring AI 的核心扩展机制:

// Advisor 接口定义
public interface Advisor {
    // 在调用模型前执行
    ChatClientRequest before(ChatClientRequest request, AdvisorChain chain);
    
    // 在获得响应后执行
    ChatClientResponse after(ChatClientResponse response, AdvisorChain chain);
}
​
// 常见 Advisor 实现
- MessageChatMemoryAdvisor    // 聊天历史管理
- QuestionAnswerAdvisor       // RAG问答增强
- SimpleLoggerAdvisor         // 日志记录
- SafeGuardAdvisor           // 内容安全

3. 核心模块详解

3.1 spring-ai-model 模块

这是整个 Spring AI 的基石模块,定义了所有 AI 模型的抽象接口。

3.1.1 核心接口层次结构
复制代码
3.1.2 消息模型详解

Spring AI 定义了完整的消息类型体系:

java 复制代码
// 基础消息接口
public interface Message extends Content {
    MessageType getMessageType();
}
​
// 消息类型枚举
public enum MessageType {
    USER("user"),           // 用户消息
    ASSISTANT("assistant"), // 助手消息
    SYSTEM("system"),       // 系统消息
    TOOL("tool");           // 工具响应消息
}
​
// 具体消息实现
public class UserMessage extends AbstractMessage {
    private final List<Media> media;  // 支持多模态
    private final String text;
}
​
public class AssistantMessage extends AbstractMessage {
    private final List<ToolCall> toolCalls;  // 工具调用请求
    private final String text;
}
​
public class ToolResponseMessage extends AbstractMessage {
    private final String toolName;
    private final String responseData;  // 工具执行结果
}
​
public class SystemMessage extends AbstractMessage {
    private final String text;
}

设计亮点

  • 支持多模态内容(文本 + 图片 + 音频)

  • 工具调用采用请求-响应模式

  • 所有消息都是不可变对象(Immutable)

3.1.3 Prompt 设计
java 复制代码
// Prompt 是发送给模型的完整上下文
public class Prompt implements ModelRequest<List<Message>> {
    private final List<Message> instructions;  // 消息列表
    private final ChatOptions options;         // 模型参数
}
​
// 使用示例
Prompt prompt = new Prompt(
    List.of(
        new SystemMessage("你是一个专业程序员"),
        new UserMessage("解释 Spring 的依赖注入")
    ),
    ChatOptions.builder()
        .temperature(0.3)  // 创造性较低,更准确
        .build()
);
3.1.4 工具调用架构

工具调用是现代 AI 应用的核心能力:

java 复制代码
// 工具回调接口 - 模型可触发的功能
public interface ToolCallback {
    ToolDefinition getToolDefinition();  // 工具元数据
    ToolMetadata getToolMetadata();      // 执行配置
    String call(String toolInput);       // 同步执行
    String call(String toolInput, ToolContext context);  // 带上下文执行
}
​
// 工具定义 - 告诉模型如何调用
public interface ToolDefinition {
    String name();                       // 工具名称
    String description();                // 工具描述(模型据此决定是否调用)
    String inputSchema();                // JSON Schema 参数定义
}
​
// 工具调用管理器
public interface ToolCallingManager {
    List<ToolDefinition> resolveToolDefinitions(ToolCallingChatOptions options);
    ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse response);
}

工具调用流程

复制代码

3.2 spring-ai-client-chat 模块

这是面向开发者的高层 API,提供流畅的 DSL 风格接口。

3.2.1 ChatClient 架构
java 复制代码
// 入口接口
public interface ChatClient {
    // 创建方法
    static ChatClient create(ChatModel chatModel);
    static Builder builder(ChatModel chatModel);
    
    // 开始构建请求
    ChatClientRequestSpec prompt();
    ChatClientRequestSpec prompt(String content);
    ChatClientRequestSpec prompt(Prompt prompt);
    
    // 变异构建
    Builder mutate();
}
3.2.2 流畅 API 设计
java 复制代码
// 典型使用模式
String response = chatClient.prompt()
    .system("你是一个 helpful 助手")           // 系统提示
    .user("讲一个关于 Spring 的笑话")        // 用户输入
    .options(options -> options.temperature(0.8))  // 参数设置
    .advisors(new SimpleLoggerAdvisor())      // 添加 Advisor
    .tools(new DateTimeTools())               // 注册工具
    .call()                                   // 执行调用
    .content();                               // 获取内容
​
// 结构化输出
ActorFilms actorFilms = chatClient.prompt()
    .user("告诉我 Tom Hanks 的电影")
    .call()
    .entity(ActorFilms.class);  // 自动映射到 POJO
​
// 流式响应
chatClient.prompt()
    .user("写一首关于 Java 的诗")
    .stream()
    .content()
    .subscribe(System.out::print);
3.2.3 Advisor 机制深度解析

Advisor 是 Spring AI 最强大的扩展点:

java 复制代码
// Advisor 基础接口
public interface CallAdvisor extends Advisor {
    ChatClientRequest before(ChatClientRequest request, CallAdvisorChain chain);
    ChatClientResponse after(ChatClientResponse response, CallAdvisorChain chain);
}
​
// 核心 Advisor 实现
​
// 1. 聊天记忆 Advisor
public class MessageChatMemoryAdvisor implements CallAdvisor {
    private final ChatMemory chatMemory;  // 内存存储
    private final String conversationId;  // 会话ID
    
    @Override
    public ChatClientRequest before(ChatClientRequest request, CallAdvisorChain chain) {
        // 1. 加载历史消息
        List<Message> history = chatMemory.get(conversationId, 10);
        // 2. 将历史添加到请求
        return request.mutate()
            .messages(history)
            .build();
    }
    
    @Override
    public ChatClientResponse after(ChatClientResponse response, CallAdvisorChain chain) {
        // 3. 保存新消息到内存
        chatMemory.add(conversationId, response.getResult().getOutput());
        return response;
    }
}
​
// 2. RAG Advisor
public class QuestionAnswerAdvisor implements CallAdvisor {
    private final VectorStore vectorStore;
    private final SearchRequest searchRequest;
    
    @Override
    public ChatClientRequest before(ChatClientRequest request, CallAdvisorChain chain) {
        // 1. 将用户问题向量化
        String userText = request.prompt().getUserMessage().getText();
        // 2. 检索相关文档
        List<Document> documents = vectorStore.similaritySearch(
            SearchRequest.query(userText).withTopK(5)
        );
        // 3. 将文档注入系统提示
        String context = documents.stream()
            .map(Document::getText)
            .collect(Collectors.joining("\n"));
        
        return request.mutate()
            .system(s -> s.text("基于以下上下文回答:\n" + context))
            .build();
    }
}

Advisor 执行链

复制代码

3.3 spring-ai-vector-store 模块

向量存储是 RAG 应用的基础设施。

3.3.1 VectorStore 接口设计
java 复制代码
public interface VectorStore extends DocumentWriter, VectorStoreRetriever {
    
    // 写入文档(自动向量化)
    void add(List<Document> documents);
    
    // 根据 ID 删除
    void delete(List<String> idList);
    
    // 根据过滤条件删除
    void delete(Filter.Expression filterExpression);
    
    // 相似度搜索
    List<Document> similaritySearch(SearchRequest request);
    
    // Builder 模式支持
    interface Builder<T extends Builder<T>> {
        T observationRegistry(ObservationRegistry registry);
        T batchingStrategy(BatchingStrategy strategy);
        VectorStore build();
    }
}
3.3.2 搜索请求构建
java 复制代码
SearchRequest request = SearchRequest.builder()
    .query("Spring Security 认证流程")     // 查询文本
    .topK(5)                               // 返回前5个结果
    .similarityThreshold(0.7)              // 相似度阈值
    .filterExpression("category == 'tech' && year >= 2023")  // 元数据过滤
    .build();
​
List<Document> results = vectorStore.similaritySearch(request);
3.3.3 过滤器表达式

Spring AI 提供了 SQL 风格的过滤器表达式:

复制代码
// 支持的运算符
- 比较:==、!=、>、>=、<、<=
- 逻辑:AND、OR、NOT
- 集合:IN、NIN
​
// 示例
"country == 'USA' AND year >= 2020"
"category IN ['tech', 'science']"
"NOT (author == 'unknown')"
"price > 100 AND (category == 'book' OR category == 'ebook')"

实现原理:使用 ANTLR4 解析表达式并转换为各数据库的查询语法。

3.3.4 SimpleVectorStore 实现

内存级向量存储,适合测试:

java 复制代码
public class SimpleVectorStore extends AbstractObservationVectorStore {
    private final Map<String, SimpleVectorStoreContent> store = new ConcurrentHashMap<>();
    
    @Override
    public void doAdd(List<Document> documents) {
        for (Document doc : documents) {
            float[] embedding = embeddingModel.embed(doc);
            store.put(doc.getId(), new SimpleVectorStoreContent(
                doc.getId(),
                doc.getText(),
                doc.getMetadata(),
                embedding
            ));
        }
    }
    
    @Override
    public List<Document> doSimilaritySearch(SearchRequest request) {
        float[] queryEmbedding = embeddingModel.embed(request.getQuery());
        
        return store.values().stream()
            .map(content -> new AbstractMap.SimpleEntry<>(
                content, 
                calculateCosineSimilarity(queryEmbedding, content.getEmbedding())
            ))
            .filter(entry -> entry.getValue() >= request.getSimilarityThreshold())
            .sorted(Map.Entry.<SimpleVectorStoreContent, Double>comparingByValue().reversed())
            .limit(request.getTopK())
            .map(entry -> new Document(
                entry.getKey().getId(),
                entry.getKey().getText(),
                entry.getKey().getMetadata()
            ))
            .collect(Collectors.toList());
    }
}

3.4 spring-ai-commons 模块

包含所有模块共享的基础组件。

3.4.1 Document 类
java 复制代码
public class Document {
    private final String id;                    // 唯一标识
    private final String text;                  // 文本内容
    private final Media media;                  // 媒体内容(多模态)
    private final Map<String, Object> metadata; // 元数据
    private final Double score;                 // 相似度分数
    
    // 支持文本或媒体,但不能同时存在
    public boolean isText() { return text != null; }
    public boolean isMedia() { return media != null; }
}
3.4.2 内容转换器
java 复制代码
// 结构化输出转换
public interface StructuredOutputConverter<T> {
    String getFormat();           // 告诉模型输出格式
    T convert(String text);       // 解析模型输出
}
​
// Bean 输出转换器 - 自动映射到 POJO
public class BeanOutputConverter<T> implements StructuredOutputConverter<T> {
    private final Class<T> targetClass;
    private final ObjectMapper objectMapper;
    
    @Override
    public String getFormat() {
        // 生成 JSON Schema 提示模型
        return JsonSchemaGenerator.generateFor(targetClass);
    }
    
    @Override
    public T convert(String text) {
        return objectMapper.readValue(text, targetClass);
    }
}
​
// 使用示例
BeanOutputConverter<ActorFilms> converter = 
    new BeanOutputConverter<>(ActorFilms.class);
    
String jsonResponse = chatClient.prompt()
    .user(u -> u.text("列出 Tom Hanks 的电影"))
    .call()
    .content();
    
ActorFilms result = converter.convert(jsonResponse);

4. 模型集成层

4.1 模型实现架构

每个模型提供商的实现都遵循统一架构:

复制代码

4.2 OpenAI 实现详解

4.2.1 OpenAiApi - 底层 HTTP 客户端
java 复制代码
public class OpenAiApi {
    private final RestClient restClient;
    
    // 聊天完成 API
    public ResponseEntity<ChatCompletion> chatCompletionEntity(
            ChatCompletionRequest request,
            MultiValueMap<String, String> additionalHttpHeaders) {
        
        return restClient.post()
            .uri("/v1/chat/completions")
            .headers(headers -> headers.addAll(additionalHttpHeaders))
            .body(request)
            .retrieve()
            .toEntity(ChatCompletion.class);
    }
    
    // 流式响应
    public Flux<ChatCompletionChunk> chatCompletionStream(
            ChatCompletionRequest request) {
        
        return webClient.post()
            .uri("/v1/chat/completions")
            .bodyValue(request)
            .retrieve()
            .bodyToFlux(ChatCompletionChunk.class);
    }
}
​
// 请求/响应 DTO
public record ChatCompletionRequest(
    String model,
    List<ChatCompletionMessage> messages,
    Double temperature,
    Integer maxTokens,
    List<FunctionTool> tools,
    ResponseFormat responseFormat
) {}
​
public record ChatCompletion(
    String id,
    List<Choice> choices,
    Usage usage
) {
    public record Choice(
        int index,
        ChatCompletionMessage message,
        String finishReason
    ) {}
}
4.2.2 OpenAiChatModel - 高层封装
java 复制代码
public class OpenAiChatModel implements ChatModel {
    private final OpenAiApi openAiApi;
    private final OpenAiChatOptions defaultOptions;
    private final ToolCallingManager toolCallingManager;
    private final RetryTemplate retryTemplate;
    private final ObservationRegistry observationRegistry;
    
    @Override
    public ChatResponse call(Prompt prompt) {
        // 1. 合并默认选项和运行时选项
        Prompt requestPrompt = buildRequestPrompt(prompt);
        
        // 2. 创建观测上下文
        ChatModelObservationContext context = ChatModelObservationContext.builder()
            .prompt(requestPrompt)
            .provider(OpenAiApiConstants.PROVIDER_NAME)
            .build();
        
        // 3. 使用 Observation 包装调用
        return ChatModelObservationDocumentation.CHAT_MODEL_OPERATION
            .observation(observationConvention, DEFAULT_OBSERVATION_CONVENTION,
                        () -> context, observationRegistry)
            .observe(() -> {
                // 4. 执行重试逻辑
                ResponseEntity<ChatCompletion> response = retryTemplate.execute(
                    ctx -> openAiApi.chatCompletionEntity(
                        createRequest(requestPrompt, false),
                        getAdditionalHttpHeaders(requestPrompt)
                    )
                );
                
                // 5. 处理工具调用
                ChatCompletion completion = response.getBody();
                if (hasToolCalls(completion)) {
                    return handleToolCalls(requestPrompt, completion);
                }
                
                // 6. 转换为统一响应格式
                return toChatResponse(response);
            });
    }
    
    // 流式响应实现
    @Override
    public Flux<ChatResponse> stream(Prompt prompt) {
        ChatCompletionRequest request = createRequest(buildRequestPrompt(prompt), true);
        
        return openAiApi.chatCompletionStream(request)
            .map(this::toChatResponseChunk)
            .concatMap(response -> {
                // 聚合流式响应
                if (isComplete(response)) {
                    return Flux.just(response);
                }
                return Flux.just(response);
            });
    }
}

4.3 智谱 AI (ZhiPuAI) 实现

智谱 AI 是国内主流的大模型提供商,Spring AI 提供了完整支持。

4.3.1 实现结构
java 复制代码
// 与 OpenAI 结构类似,但适配智谱 API
public class ZhiPuAiChatModel implements ChatModel {
    private final ZhiPuAiApi zhiPuAiApi;
    private final ZhiPuAiChatOptions defaultOptions;
    
    @Override
    public ChatResponse call(Prompt prompt) {
        ZhiPuAiApi.ChatCompletionRequest request = createRequest(prompt);
        
        ResponseEntity<ZhiPuAiApi.ChatCompletion> response = 
            retryTemplate.execute(ctx -> zhiPuAiApi.chatCompletionEntity(request));
            
        return toChatResponse(response.getBody());
    }
}
​
// 智谱特有选项
public class ZhiPuAiChatOptions implements ChatOptions {
    private String model;           // 模型名称:glm-4、glm-4-flash 等
    private Double temperature;     // 温度参数
    private Integer maxTokens;      // 最大 token 数
    private Boolean stream;         // 是否流式
    private List<FunctionCallback> tools;  // 工具列表
}

4.4 其他模型支持

Spring AI 1.1.4 支持的模型提供商:

提供商 模块 支持功能
OpenAI spring-ai-openai 聊天、嵌入、图像、语音、审核
Azure OpenAI spring-ai-azure-openai 聊天、嵌入、图像
智谱 AI spring-ai-zhipuai 聊天、嵌入、图像
Anthropic spring-ai-anthropic 聊天
Mistral AI spring-ai-mistral-ai 聊天、嵌入
Ollama spring-ai-ollama 聊天、嵌入
HuggingFace spring-ai-huggingface 嵌入
Google Vertex AI spring-ai-vertex-ai-gemini 聊天、嵌入
Amazon Bedrock spring-ai-bedrock 聊天、嵌入
DeepSeek spring-ai-deepseek 聊天
MiniMax spring-ai-minimax 聊天、嵌入
... ... ...

5. 向量存储系统

5.1 支持的向量数据库

Spring AI 支持 19 种向量数据库:

复制代码
关系型数据库扩展:
- PostgreSQL + pgvector
- MariaDB
- Oracle
​
专用向量数据库:
- Milvus / Zilliz
- Pinecone
- Qdrant
- Weaviate
- Chroma
​
通用数据库向量扩展:
- Elasticsearch
- OpenSearch
- Redis
- MongoDB Atlas
- Neo4j
- Cassandra
- Azure Cosmos DB
​
云服务:
- Azure AI Search
- Couchbase
- GemFire
- Typesense
- HANA DB

5.2 PGVector 实现详解

PostgreSQL + pgvector 是最流行的向量存储方案:

java 复制代码
public class PgVectorStore extends AbstractObservationVectorStore {
    private final JdbcTemplate jdbcTemplate;
    private final int dimensions;
    private final PgDistanceType distanceType;
    private final boolean initializeSchema;
    
    @Override
    public void doAdd(List<Document> documents) {
        for (Document document : documents) {
            float[] embedding = embeddingModel.embed(document);
            
            jdbcTemplate.update(
                "INSERT INTO vector_store (id, content, metadata, embedding) " +
                "VALUES (?, ?, ?::jsonb, ?) " +
                "ON CONFLICT (id) DO UPDATE SET " +
                "content = EXCLUDED.content, " +
                "metadata = EXCLUDED.metadata, " +
                "embedding = EXCLUDED.embedding",
                document.getId(),
                document.getText(),
                toJson(document.getMetadata()),
                toPgVector(embedding)
            );
        }
    }
    
    @Override
    public List<Document> doSimilaritySearch(SearchRequest request) {
        float[] queryEmbedding = embeddingModel.embed(request.getQuery());
        
        String sql = String.format(
            "SELECT id, content, metadata, embedding %s as distance " +
            "FROM vector_store " +
            "WHERE embedding %s ?::vector " +
            "%s" +  // 过滤条件
            "ORDER BY embedding %s ?::vector " +
            "LIMIT ?",
            distanceType.getOperator(),
            distanceType.getOperator(),
            buildFilterClause(request.getFilterExpression()),
            distanceType.getOperator()
        );
        
        return jdbcTemplate.query(sql, documentRowMapper,
            toPgVector(queryEmbedding),
            toPgVector(queryEmbedding),
            request.getTopK()
        );
    }
}

5.3 Milvus 实现

java 复制代码
public class MilvusVectorStore extends AbstractObservationVectorStore {
    private final MilvusServiceClient milvusClient;
    private final String collectionName;
    
    @Override
    public void doAdd(List<Document> documents) {
        List<String> ids = new ArrayList<>();
        List<String> contents = new ArrayList<>();
        List<JSONObject> metadata = new ArrayList<>();
        List<List<Float>> vectors = new ArrayList<>();
        
        for (Document doc : documents) {
            ids.add(doc.getId());
            contents.add(doc.getText());
            metadata.add(new JSONObject(doc.getMetadata()));
            vectors.add(toList(embeddingModel.embed(doc)));
        }
        
        milvusClient.insert(InsertParam.newBuilder()
            .withCollectionName(collectionName)
            .withFields(List.of(
                new InsertParam.Field("id", ids),
                new InsertParam.Field("content", contents),
                new InsertParam.Field("metadata", metadata),
                new InsertParam.Field("embedding", vectors)
            ))
            .build()
        );
    }
}

6. RAG 检索增强生成

6.1 RAG 架构设计

Spring AI 的 RAG 实现遵循模块化和可扩展原则:

复制代码

6.2 RetrievalAugmentationAdvisor

这是 RAG 的核心实现类:

java 复制代码
public final class RetrievalAugmentationAdvisor implements BaseAdvisor {
    private final List<QueryTransformer> queryTransformers;
    private final QueryExpander queryExpander;
    private final DocumentRetriever documentRetriever;
    private final DocumentJoiner documentJoiner;
    private final List<DocumentPostProcessor> documentPostProcessors;
    private final QueryAugmenter queryAugmenter;
    
    @Override
    public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
        // 0. 创建 Query 对象
        Query originalQuery = Query.builder()
            .text(request.prompt().getUserMessage().getText())
            .history(request.prompt().getInstructions())
            .build();
        
        // 1. 查询转换(如:翻译、压缩历史)
        Query transformedQuery = originalQuery;
        for (var transformer : queryTransformers) {
            transformedQuery = transformer.apply(transformedQuery);
        }
        
        // 2. 查询扩展(如:生成多个相关查询)
        List<Query> expandedQueries = queryExpander != null 
            ? queryExpander.expand(transformedQuery)
            : List.of(transformedQuery);
        
        // 3. 并行检索文档
        Map<Query, List<List<Document>>> documentsForQuery = expandedQueries.stream()
            .map(query -> CompletableFuture.supplyAsync(
                () -> getDocumentsForQuery(query), taskExecutor))
            .toList()
            .stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> List.of(entry.getValue())));
        
        // 4. 合并文档
        List<Document> documents = documentJoiner.join(documentsForQuery);
        
        // 5. 后处理(如:重排序、去重)
        for (var processor : documentPostProcessors) {
            documents = processor.process(originalQuery, documents);
        }
        
        // 6. 查询增强(将文档注入提示)
        Query augmentedQuery = queryAugmenter.augment(originalQuery, documents);
        
        // 7. 更新请求
        return request.mutate()
            .prompt(request.prompt().augmentUserMessage(augmentedQuery.text()))
            .context(context -> context.put(DOCUMENT_CONTEXT, documents))
            .build();
    }
}

6.3 查询转换器 (QueryTransformer)

java 复制代码
// 查询转换器接口
public interface QueryTransformer extends Function<Query, Query> {}
​
// 1. 重写查询 - 优化问题表达
public class RewriteQueryTransformer implements QueryTransformer {
    private final ChatClient chatClient;
    
    @Override
    public Query apply(Query query) {
        String rewritten = chatClient.prompt()
            .system("重写以下查询,使其更清晰、更具体")
            .user(query.text())
            .call()
            .content();
        return query.mutate().text(rewritten).build();
    }
}
​
// 2. 翻译查询 - 支持多语言
public class TranslationQueryTransformer implements QueryTransformer {
    private final ChatClient chatClient;
    private final String targetLanguage;
    
    @Override
    public Query apply(Query query) {
        String translated = chatClient.prompt()
            .system("将查询翻译成" + targetLanguage)
            .user(query.text())
            .call()
            .content();
        return query.mutate().text(translated).build();
    }
}
​
// 3. 压缩历史 - 长对话优化
public class CompressionQueryTransformer implements QueryTransformer {
    @Override
    public Query apply(Query query) {
        // 压缩对话历史,保留关键信息
        List<Message> compressedHistory = compressHistory(query.history());
        return query.mutate().history(compressedHistory).build();
    }
}

6.4 文档检索器 (DocumentRetriever)

java 复制代码
// 基于向量存储的检索器
public class VectorStoreDocumentRetriever implements DocumentRetriever {
    private final VectorStore vectorStore;
    private final SearchRequest searchRequest;
    
    @Override
    public List<Document> retrieve(Query query) {
        SearchRequest request = SearchRequest.builder()
            .query(query.text())
            .topK(searchRequest.getTopK())
            .similarityThreshold(searchRequest.getSimilarityThreshold())
            .filterExpression(searchRequest.getFilterExpression())
            .build();
        
        return vectorStore.similaritySearch(request);
    }
}

6.5 查询增强器 (QueryAugmenter)

java 复制代码
// 上下文查询增强器
public class ContextualQueryAugmenter implements QueryAugmenter {
    @Override
    public Query augment(Query query, List<Document> documents) {
        if (documents.isEmpty()) {
            return query;  // 无文档时不增强
        }
        
        String context = documents.stream()
            .map(doc -> String.format("[Document ID: %s]\n%s", doc.getId(), doc.getText()))
            .collect(Collectors.joining("\n\n"));
        
        String augmentedText = String.format("""
            基于以下上下文信息回答问题:
            
            %s
            
            问题:%s
            
            如果上下文中没有相关信息,请说明你不知道。
            """, context, query.text());
        
        return query.mutate().text(augmentedText).build();
    }
}

7. MCP 模型上下文协议

7.1 MCP 概述

Model Context Protocol (MCP) 是 Anthropic 推出的开放协议,用于标准化 AI 模型与外部工具、数据源的集成。

7.2 MCP 架构

复制代码

7.3 MCP 核心组件

java 复制代码
// MCP 工具回调
public class SyncMcpToolCallback implements ToolCallback {
    private final McpSyncClient mcpClient;
    private final Tool tool;
    
    @Override
    public ToolDefinition getToolDefinition() {
        return ToolDefinition.builder()
            .name(tool.name())
            .description(tool.description())
            .inputSchema(tool.inputSchema())
            .build();
    }
    
    @Override
    public String call(String toolInput) {
        CallToolResult result = mcpClient.callTool(
            new CallToolRequest(tool.name(), parseJson(toolInput))
        );
        return serializeResult(result);
    }
}
​
// 异步版本
public class AsyncMcpToolCallback implements ToolCallback {
    private final McpAsyncClient mcpClient;
    
    @Override
    public String call(String toolInput) {
        // 阻塞等待异步结果
        return mcpClient.callTool(request)
            .block()
            .toString();
    }
}

7.4 MCP 注解支持

Spring AI 提供了基于注解的 MCP 工具定义:

java 复制代码
@Component
public class WeatherTools {
    
    @Tool(description = "获取指定城市的天气信息")
    public WeatherInfo getWeather(
            @ToolParam(description = "城市名称,如:北京") String city,
            @ToolParam(description = "日期,格式:yyyy-MM-dd") String date) {
        // 实现逻辑
        return weatherService.fetch(city, date);
    }
}

8. 工具调用机制

8.1 工具调用架构

复制代码

8.2 工具定义与实现

java 复制代码
// 方式1:使用 Function
FunctionToolCallback.builder("getWeather", (WeatherRequest request) -> {
    return weatherService.getWeather(request.city(), request.date());
})
.description("获取城市天气")
.inputSchema(WeatherRequest.class)
.build();
​
// 方式2:使用方法引用
Method method = WeatherService.class.getMethod("getWeather", String.class, String.class);
MethodToolCallback.builder(method, weatherService)
    .description("获取城市天气")
    .build();
​
// 方式3:Spring Bean 自动发现
@Bean
public ToolCallbackProvider weatherTools(WeatherService service) {
    return MethodToolCallbackProvider.builder()
        .toolObjects(service)
        .build();
}

8.3 ToolCallingManager 实现

java 复制代码
public class DefaultToolCallingManager implements ToolCallingManager {
    private final ToolCallbackResolver toolCallbackResolver;
    private final ToolExecutionExceptionProcessor exceptionProcessor;
    
    @Override
    public ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse) {
        AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
        
        List<ToolResponseMessage> toolResponseMessages = new ArrayList<>();
        
        for (ToolCall toolCall : assistantMessage.getToolCalls()) {
            try {
                // 1. 解析工具调用
                String toolName = toolCall.name();
                String toolInput = toolCall.arguments();
                
                // 2. 查找工具
                ToolCallback toolCallback = toolCallbackResolver.resolve(toolName);
                if (toolCallback == null) {
                    throw new IllegalArgumentException("Tool not found: " + toolName);
                }
                
                // 3. 执行工具
                String result = toolCallback.call(toolInput);
                
                // 4. 构造工具响应
                toolResponseMessages.add(new ToolResponseMessage(
                    result, toolName, toolCall.id()
                ));
                
            } catch (Exception e) {
                // 5. 异常处理
                String errorResult = exceptionProcessor.process(e);
                toolResponseMessages.add(new ToolResponseMessage(
                    errorResult, toolCall.name(), toolCall.id()
                ));
            }
        }
        
        return ToolExecutionResult.builder()
            .prompt(prompt)  // 包含原对话 + 工具响应
            .build();
    }
}

9. Spring Boot 自动配置

9.1 自动配置架构

Spring AI 为每个模型和向量存储提供独立的自动配置模块:

复制代码
auto-configurations/
├── models/
│   ├── spring-ai-autoconfigure-model-openai
│   ├── spring-ai-autoconfigure-model-zhipuai
│   └── ...
├── vector-stores/
│   ├── spring-ai-autoconfigure-vector-store-pgvector
│   ├── spring-ai-autoconfigure-vector-store-milvus
│   └── ...
└── mcp/
    ├── spring-ai-autoconfigure-mcp-client-common
    └── spring-ai-autoconfigure-mcp-server-common

9.2 OpenAI 自动配置示例

java 复制代码
@Configuration
@ConditionalOnClass(OpenAiApi.class)
@EnableConfigurationProperties(OpenAiChatProperties.class)
public class OpenAiAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public OpenAiApi openAiApi(OpenAiConnectionProperties connectionProperties) {
        return OpenAiApi.builder()
            .apiKey(connectionProperties.getApiKey())
            .baseUrl(connectionProperties.getBaseUrl())
            .build();
    }
    
    @Bean
    @ConditionalOnMissingBean
    public OpenAiChatModel openAiChatModel(
            OpenAiApi openAiApi,
            OpenAiChatProperties chatProperties,
            ToolCallingManager toolCallingManager,
            ObservationRegistry observationRegistry) {
        
        return new OpenAiChatModel(
            openAiApi,
            chatProperties.getOptions(),
            toolCallingManager,
            RetryUtils.DEFAULT_RETRY_TEMPLATE,
            observationRegistry
        );
    }
}
​
// 配置属性
@ConfigurationProperties("spring.ai.openai")
public class OpenAiChatProperties {
    private String apiKey;
    private String baseUrl = "https://api.openai.com";
    private ChatOptions options = new ChatOptions();
}

9.3 Starter 模块

Starter 模块将自动配置和依赖整合:

XML 复制代码
<!-- spring-ai-starter-model-openai/pom.xml -->
<dependencies>
    <!-- 自动配置 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-autoconfigure-model-openai</artifactId>
    </dependency>
    <!-- 核心实现 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai</artifactId>
    </dependency>
    <!-- Spring Boot 自动配置支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
</dependencies>

9.4 应用配置示例

bash 复制代码
# application.yml
spring:
  ai:
    # OpenAI 配置
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com
      chat:
        options:
          model: gpt-4
          temperature: 0.7
          max-tokens: 2000
    
    # 智谱 AI 配置
    zhipuai:
      api-key: ${ZHIPUAI_API_KEY}
      chat:
        options:
          model: glm-4
          temperature: 0.7
    
    # 向量存储配置
    vectorstore:
      pgvector:
        index-type: hnsw
        distance-type: cosine_distance
        dimensions: 1536
        initialize-schema: true

10. 最佳实践与设计模式

10.1 推荐项目结构

复制代码
my-spring-ai-app/
├── src/main/java/com/example/ai/
│   ├── config/
│   │   ├── AIConfig.java          # AI 模型配置
│   │   └── VectorStoreConfig.java  # 向量存储配置
│   ├── controller/
│   │   └── ChatController.java     # REST API
│   ├── service/
│   │   ├── ChatService.java        # 聊天服务
│   │   ├── RAGService.java         # RAG 服务
│   │   └── EmbeddingService.java   # 嵌入服务
│   ├── tools/
│   │   └── WeatherTools.java       # 工具定义
│   └── advisor/
│       └── CustomAdvisor.java      # 自定义 Advisor
├── src/main/resources/
│   ├── application.yml
│   └── prompts/                   # 提示模板
│       ├── system-prompt.st
│       └── rag-context.st
└── pom.xml

10.2 配置类最佳实践

java 复制代码
@Configuration
public class AIConfig {
    
    @Bean
    public ChatClient chatClient(ChatModel chatModel) {
        return ChatClient.builder(chatModel)
            .defaultSystem("你是一个专业的技术助手")
            .defaultOptions(ChatOptions.builder()
                .temperature(0.7)
                .maxTokens(2000)
                .build())
            .build();
    }
    
    @Bean
    public VectorStore vectorStore(
            EmbeddingModel embeddingModel,
            JdbcTemplate jdbcTemplate) {
        return PgVectorStore.builder(embeddingModel)
            .jdbcTemplate(jdbcTemplate)
            .dimensions(1536)
            .initializeSchema(true)
            .build();
    }
}

10.3 RAG 完整示例

java 复制代码
@Service
public class RAGService {
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    
    public String chatWithDocuments(String query) {
        return chatClient.prompt()
            .advisors(new QuestionAnswerAdvisor(
                vectorStore,
                SearchRequest.defaults().withTopK(5)
            ))
            .user(query)
            .call()
            .content();
    }
}
​
// 更复杂的 RAG 配置
@Bean
public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor(
        VectorStore vectorStore,
        ChatClient chatClient) {
    
    return RetrievalAugmentationAdvisor.builder()
        // 查询转换
        .queryTransformers(new TranslationQueryTransformer(chatClient, "zh"))
        // 查询扩展
        .queryExpander(new MultiQueryExpander(chatClient, 3))
        // 文档检索
        .documentRetriever(VectorStoreDocumentRetriever.builder()
            .vectorStore(vectorStore)
            .searchRequest(SearchRequest.defaults().withTopK(5))
            .build())
        // 查询增强
        .queryAugmenter(ContextualQueryAugmenter.builder()
            .promptTemplate("基于以下内容回答:\n\n{context}\n\n问题:{query}")
            .build())
        .build();
}

10.4 错误处理与重试

java 复制代码
@Configuration
public class RetryConfig {
    
    @Bean
    public RetryTemplate aiRetryTemplate() {
        return RetryTemplate.builder()
            .maxAttempts(3)
            .fixedBackoff(1000)
            .retryOn(TransientAiException.class)
            .build();
    }
}
​
@Service
public class RobustChatService {
    private final ChatClient chatClient;
    private final RetryTemplate retryTemplate;
    
    public String chatWithRetry(String message) {
        return retryTemplate.execute(context -> {
            try {
                return chatClient.prompt()
                    .user(message)
                    .call()
                    .content();
            } catch (Exception e) {
                // 判断是否为可重试错误
                if (isTransientError(e)) {
                    throw new TransientAiException(e);
                }
                throw e;
            }
        });
    }
}

10.5 观测与监控

java 复制代码
@Configuration
public class ObservationConfig {
    
    @Bean
    public ChatClientObservationConvention customObservationConvention() {
        return context -> {
            // 自定义观测标签
            return KeyValues.of(
                KeyValue.of("ai.application", "my-app"),
                KeyValue.of("ai.environment", "production")
            );
        };
    }
}
​
// 使用 Micrometer 观测
chatClient.prompt()
    .observationRegistry(observationRegistry)
    .user("Hello")
    .call();

总结

Spring AI 1.1.4 是一个设计精良、功能丰富的 AI 应用开发框架。其核心优势包括:

  1. 统一的 API 抽象:支持 20+ 模型提供商的切换,代码可移植性强

  2. 模块化架构:各组件松耦合,可按需使用

  3. Spring 原生集成:充分利用 Spring Boot 的自动配置和依赖注入

  4. 强大的扩展机制:Advisor 模式提供了灵活的扩展点

  5. 完整的 RAG 支持:从文档处理到检索增强的完整链路

  6. 企业级特性:内置重试、观测、监控等企业级功能

通过深入理解其架构设计和源码实现,开发者可以更好地利用 Spring AI 构建高质量的 AI 应用。


参考资料

相关推荐
pupudawang3 小时前
使用 Logback 的最佳实践:`logback.xml` 与 `logback-spring.xml` 的区别与用法
xml·spring·logback
是Smoky呢3 小时前
springAI+向量数据库(SimpleVectorStore)+RAG深度理解
spring·aigc·ai编程
常利兵4 小时前
Spring Boot 牵手Spring AI,玩转DeepSeek大模型
人工智能·spring boot·spring
Thomas.Sir4 小时前
第六章:RAG知识库开发之【深入浅出RAG使用效果评估:从指标到实践】
人工智能·python·ai·rag·效果评估
星如雨グッ!(๑•̀ㅂ•́)و✧5 小时前
Spring WebFlux中DataBufferLimitException异常的解决方案
java·后端·spring
心勤则明5 小时前
使用 Spring AI Alibaba MCP 结合 Nacos 实现企业级智能体应用
java·人工智能·spring
blxr_5 小时前
Spring AI
数据库·人工智能·spring
Chan165 小时前
SpringAI:RAG 最佳实践与调优
java·spring boot·ai·java-ee·intellij-idea·rag·springai