找回密码
 立即注册
首页 业界区 业界 Spring AI 代码分析(三)--集成LLM

Spring AI 代码分析(三)--集成LLM

能杜孱 2025-11-20 22:50:01
大模型集成实现分析

请关注微信公众号:阿呆-bot
1. 工程结构概览

Spring AI 支持多种大模型提供商,每个提供商都有独立的实现模块。虽然实现细节不同,但它们都遵循统一的抽象模式。下面我们来看看主要的模型实现:
  1. models/
  2. ├── spring-ai-openai/          # OpenAI 实现
  3. │   ├── OpenAiChatModel.java
  4. │   ├── OpenAiEmbeddingModel.java
  5. │   └── api/                   # 底层 API 客户端
  6. │       └── OpenAiApi.java
  7. ├── spring-ai-deepseek/        # DeepSeek 实现
  8. │   ├── DeepSeekChatModel.java
  9. │   └── api/
  10. │       └── DeepSeekApi.java
  11. ├── spring-ai-oci-genai/       # Oracle OCI GenAI 实现
  12. │   ├── OCICohereChatModel.java
  13. │   └── OCIEmbeddingModel.java
  14. └── spring-ai-transformers/     # 本地 Transformer 模型
  15.     └── TransformersEmbeddingModel.java
复制代码
2. 通用实现模式

所有大模型实现都遵循相同的模式:

  • 实现核心接口:实现 ChatModel 或 EmbeddingModel
  • 底层 API 客户端:封装提供商的 HTTP API
  • 选项管理:每个模型有自己的 Options 类
  • 密钥管理:通过 ApiKey 接口管理认证
  • 重试机制:集成 Spring Retry
  • 观察性:集成 Micrometer
3. 实现模式关系图

1.png

4. 密钥管理机制

4.1 ApiKey 接口设计

Spring AI 使用 ApiKey 接口统一管理所有模型的密钥:
  1. public interface ApiKey {
  2.     String getValue();  // 获取当前有效的密钥
  3. }
复制代码
这个设计的巧妙之处在于:

  • 支持静态密钥:SimpleApiKey 直接存储密钥
  • 支持动态刷新:可以实现自动刷新的密钥(比如 GCP 的短期密钥)
  • 类型安全:所有模型都使用相同的接口
4.2 密钥使用方式

在 API 客户端中,密钥通过 HTTP Header 传递:
  1. // OpenAiApi 中的密钥使用
  2. this.restClient = restClientBuilder.clone()
  3.     .baseUrl(baseUrl)
  4.     .defaultRequest(requestHeadersSpec -> {
  5.         if (!(apiKey instanceof NoopApiKey)) {
  6.             requestHeadersSpec.header(HttpHeaders.AUTHORIZATION,
  7.                 "Bearer " + apiKey.getValue());
  8.         }
  9.     })
  10.     .build();
复制代码
每次请求都会调用 apiKey.getValue(),这样如果密钥需要刷新,实现类可以在内部处理。
4.3 密钥配置方式

密钥可以通过多种方式配置:
方式一:配置文件
  1. spring.ai.openai.api-key=${OPENAI_API_KEY}
复制代码
方式二:环境变量
  1. export OPENAI_API_KEY=sk-xxx
复制代码
方式三:程序化配置
  1. OpenAiApi api = OpenAiApi.builder()
  2.     .apiKey(new SimpleApiKey("sk-xxx"))
  3.     .build();
复制代码
5. 具体实现分析

5.1 OpenAI 实现

OpenAI 的实现是最完整的,支持同步和流式调用:
  1. public class OpenAiChatModel implements ChatModel {
  2.     private final OpenAiApi openAiApi;
  3.     private final OpenAiChatOptions defaultOptions;
  4.     private final RetryTemplate retryTemplate;
  5.     private final ToolCallingManager toolCallingManager;
  6.    
  7.     @Override
  8.     public ChatResponse call(Prompt prompt) {
  9.         // 1. 构建请求 Prompt(处理工具调用)
  10.         Prompt requestPrompt = buildRequestPrompt(prompt);
  11.         
  12.         // 2. 调用底层 API
  13.         ResponseEntity<ChatCompletion> response = retryTemplate.execute(
  14.             ctx -> openAiApi.chatCompletion(toRequest(requestPrompt))
  15.         );
  16.         
  17.         // 3. 转换响应
  18.         return toChatResponse(response);
  19.     }
  20.    
  21.     @Override
  22.     public Flux<ChatResponse> stream(Prompt prompt) {
  23.         // 流式调用类似,但返回 Flux
  24.         return openAiApi.chatCompletionStream(toRequest(prompt))
  25.             .map(this::toChatResponse);
  26.     }
  27. }
复制代码
特点

  • 完整的工具调用支持
  • 支持流式响应
  • 完善的错误处理和重试
  • 支持多模态(图像、音频)
5.2 DeepSeek 实现

DeepSeek 的实现与 OpenAI 类似,但更简洁:
  1. public class DeepSeekChatModel implements ChatModel {
  2.     private final DeepSeekApi deepSeekApi;
  3.     private final DeepSeekChatOptions defaultOptions;
  4.    
  5.     @Override
  6.     public ChatResponse call(Prompt prompt) {
  7.         Prompt requestPrompt = buildRequestPrompt(prompt);
  8.         ChatModelObservationContext context = ChatModelObservationContext.builder()
  9.             .prompt(requestPrompt)
  10.             .provider("DEEPSEEK")
  11.             .build();
  12.         
  13.         return ChatModelObservationDocumentation.CHAT_MODEL_OPERATION
  14.             .observation(...)
  15.             .observe(() -> {
  16.                 ResponseEntity<ChatCompletion> response =
  17.                     deepSeekApi.chatCompletion(toRequest(requestPrompt));
  18.                 return toChatResponse(response);
  19.             });
  20.     }
  21. }
复制代码
特点

  • 结构清晰,代码简洁
  • 支持观察性(Micrometer)
  • 支持工具调用
5.3 OCI GenAI 实现

OCI 的实现使用了 Oracle 的官方 SDK:
  1. public class OCICohereChatModel implements ChatModel {
  2.     private final GenerativeAiInference genAi;  // OCI SDK 客户端
  3.     private final OCICohereChatOptions defaultOptions;
  4.    
  5.     @Override
  6.     public ChatResponse call(Prompt prompt) {
  7.         // 使用 OCI SDK 调用
  8.         ChatRequest request = toCohereChatRequest(prompt, options);
  9.         ChatResponse ociResponse = this.genAi.chat(request);
  10.         return toGenerations(ociResponse, options);
  11.     }
  12. }
复制代码
特点

  • 使用官方 OCI SDK
  • 需要配置 compartment 和 serving mode
  • 支持 Cohere 模型
5.4 Transformers 实现(本地模型)

Transformers 实现比较特殊,它不调用远程 API,而是在本地运行 ONNX 模型:
  1. public class TransformersEmbeddingModel extends AbstractEmbeddingModel {
  2.     private OrtSession session;  // ONNX Runtime 会话
  3.     private HuggingFaceTokenizer tokenizer;
  4.    
  5.     @Override
  6.     public EmbeddingResponse call(EmbeddingRequest request) {
  7.         // 1. Tokenize 输入文本
  8.         Encoding encoding = tokenizer.encode(request.getInstructions());
  9.         
  10.         // 2. 运行 ONNX 模型
  11.         OnnxTensor inputTensor = OnnxTensor.createTensor(
  12.             ortEnvironment,
  13.             encoding.getIds()
  14.         );
  15.         OrtSession.Result result = session.run(
  16.             Map.of("input_ids", inputTensor)
  17.         );
  18.         
  19.         // 3. 提取嵌入向量
  20.         float[] embedding = extractEmbedding(result);
  21.         
  22.         return new EmbeddingResponse(List.of(new Embedding(embedding)));
  23.     }
  24. }
复制代码
特点

  • 完全本地运行:不需要 API 密钥
  • 使用 ONNX Runtime:高性能推理引擎
  • 支持 GPU 加速:可以配置 GPU 推理
  • 模型缓存:自动下载和缓存模型文件
6. 实现对比分析

特性OpenAIDeepSeekOCITransformersAPI 类型REST APIREST APIOCI SDK本地 ONNX密钥管理ApiKey 接口ApiKey 接口OCI 认证无需密钥流式支持✅✅❌❌工具调用✅✅✅N/A多模态✅❌❌N/A重试机制✅✅✅N/A观察性✅✅✅✅7. 关键实现细节

7.1 请求构建模式

所有实现都遵循相同的请求构建模式:
  1. // 1. 合并默认选项和运行时选项
  2. ChatOptions requestOptions = ModelOptionsUtils.merge(
  3.     prompt.getOptions(),
  4.     this.defaultOptions,
  5.     ChatOptions.class
  6. );
  7. // 2. 转换为提供商特定的请求对象
  8. ProviderRequest providerRequest = toProviderRequest(prompt, requestOptions);
  9. // 3. 调用底层 API
  10. ProviderResponse providerResponse = apiClient.call(providerRequest);
  11. // 4. 转换为 Spring AI 响应
  12. ChatResponse chatResponse = toChatResponse(providerResponse);
复制代码
7.2 工具调用处理

支持工具调用的模型(如 OpenAI、DeepSeek)都实现了类似的工具调用流程:
  1. // 1. 解析工具定义
  2. List<ToolDefinition> toolDefinitions =
  3.     toolCallingManager.resolveToolDefinitions(options);
  4. // 2. 将工具定义添加到请求中
  5. request.setTools(toolDefinitions);
  6. // 3. 调用模型
  7. ChatResponse response = apiClient.call(request);
  8. // 4. 检查是否有工具调用请求
  9. if (response.hasToolCalls()) {
  10.     // 5. 执行工具调用
  11.     ToolExecutionResult toolResult =
  12.         toolCallingManager.executeToolCalls(prompt, response);
  13.    
  14.     // 6. 将工具结果作为新的 Prompt 再次调用
  15.     return call(new Prompt(toolResult.getConversationHistory()));
  16. }
复制代码
7.3 流式处理实现

流式处理使用 Reactor 的 Flux:
  1. @Override
  2. public Flux<ChatResponse> stream(Prompt prompt) {
  3.     return webClient.post()
  4.         .uri("/v1/chat/completions")
  5.         .bodyValue(toRequest(prompt))
  6.         .retrieve()
  7.         .bodyToFlux(ServerSentEvent.class)
  8.         .filter(event -> !"[DONE]".equals(event.data()))
  9.         .map(this::toChatResponse);
  10. }
复制代码
8. 外部依赖

不同实现的依赖差异:
8.1 OpenAI/DeepSeek


  • Spring Web:RestClient 和 WebClient
  • Jackson:JSON 处理
  • Spring Retry:重试机制
8.2 OCI GenAI


  • OCI SDK:Oracle 官方 SDK
  • Spring Web:HTTP 客户端(如果需要)
8.3 Transformers


  • ONNX Runtime:ONNX 模型推理
  • DJL:Deep Java Library(Tokenizer)
  • 无网络依赖:完全本地运行
9. 工程总结

Spring AI 的大模型集成实现有几个亮点:
统一抽象,灵活实现。所有模型都实现相同的接口(ChatModel、EmbeddingModel),但底层实现可以完全不同。这种设计让用户可以轻松切换模型,而不需要改业务代码。今天用 OpenAI,明天想换 DeepSeek?改个配置就行。
密钥管理统一化。通过 ApiKey 接口,所有模型使用相同的密钥管理方式。这简化了配置,也为未来的动态密钥刷新提供了扩展点。想从配置中心动态获取密钥?实现 ApiKey 接口就行。
选项合并机制。ModelOptionsUtils.merge() 提供了灵活的选项合并机制,支持默认选项和运行时选项的合并,让配置既灵活又简单。默认配置在 application.yml,运行时可以动态调整。
观察性内置。所有实现都集成了 Micrometer,提供了完善的指标和追踪能力。这对于生产环境非常重要,可以监控模型调用次数、延迟、错误率等。
本地模型支持。Transformers 实现展示了如何在本地运行模型,这对于数据隐私要求高的场景非常有价值。数据不出本地,完全可控。
总的来说,Spring AI 的大模型集成实现既统一又灵活。统一的接口让代码简洁,灵活的实现让每个提供商都能发挥自己的优势。这种设计让 Spring AI 能够支持 20+ 种不同的模型提供商,同时保持代码的可维护性。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册