380 lines
9.5 KiB
Markdown
380 lines
9.5 KiB
Markdown
# 大模型接口更换指导文档
|
||
|
||
## 概述
|
||
|
||
当前系统使用Spring AI框架集成OpenAI API,本文档详细说明如何更换为其他大模型提供商或自部署模型。
|
||
|
||
## 当前架构分析
|
||
|
||
### 现有集成方式
|
||
|
||
系统在 `ChatService.java:39` 中注入 `ChatClient`,通过Spring AI的统一接口调用大模型:
|
||
|
||
```java
|
||
// 当前实现方式
|
||
private final ChatClient chatClient;
|
||
|
||
@Autowired
|
||
public ChatService(ChatClient.Builder builder,
|
||
ConversationMapper conversationMapper,
|
||
MessageMapper messageMapper) {
|
||
this.chatClient = builder.build();
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 关键调用点
|
||
|
||
1. **流式调用** (`ChatService.java:71-75`):
|
||
```java
|
||
Flux<String> flux = chatClient
|
||
.prompt()
|
||
.user(request.getMessage())
|
||
.stream()
|
||
.content();
|
||
```
|
||
|
||
2. **普通调用** (`ChatService.java:234-238`):
|
||
```java
|
||
private String generateAIResponse(ChatRequest request) {
|
||
// 目前是模拟实现,需要改为真实调用
|
||
return "这是AI的回复内容,模拟生成。";
|
||
}
|
||
```
|
||
|
||
## 更换方案
|
||
|
||
### 方案一: 使用Spring AI支持的其他模型
|
||
|
||
Spring AI支持多种模型提供商,只需修改配置和依赖即可。
|
||
|
||
#### 1.1 更换为Azure OpenAI
|
||
|
||
**步骤1**: 修改 `pom.xml` 依赖
|
||
```xml
|
||
<!-- 移除现有OpenAI依赖 -->
|
||
<!-- <dependency>
|
||
<groupId>org.springframework.ai</groupId>
|
||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||
<version>1.0.0-M6</version>
|
||
</dependency> -->
|
||
|
||
<!-- 添加Azure OpenAI依赖 -->
|
||
<dependency>
|
||
<groupId>org.springframework.ai</groupId>
|
||
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
|
||
<version>1.0.0-M6</version>
|
||
</dependency>
|
||
```
|
||
|
||
**步骤2**: 修改 `application.yml` 配置
|
||
```yaml
|
||
spring:
|
||
ai:
|
||
azure:
|
||
openai:
|
||
api-key: ${AZURE_OPENAI_API_KEY}
|
||
endpoint: ${AZURE_OPENAI_ENDPOINT}
|
||
chat:
|
||
options:
|
||
deployment-name: gpt-4o-mini
|
||
temperature: 0.7
|
||
```
|
||
|
||
**步骤3**: 无需修改Java代码,Spring AI会自动适配
|
||
|
||
#### 1.2 更换为Anthropic Claude
|
||
|
||
**步骤1**: 修改依赖
|
||
```xml
|
||
<dependency>
|
||
<groupId>org.springframework.ai</groupId>
|
||
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
|
||
<version>1.0.0-M6</version>
|
||
</dependency>
|
||
```
|
||
|
||
**步骤2**: 修改配置
|
||
```yaml
|
||
spring:
|
||
ai:
|
||
anthropic:
|
||
api-key: ${ANTHROPIC_API_KEY}
|
||
chat:
|
||
options:
|
||
model: claude-3-sonnet-20240229
|
||
max-tokens: 1000
|
||
```
|
||
|
||
#### 1.3 更换为本地Ollama
|
||
|
||
**步骤1**: 修改依赖
|
||
```xml
|
||
<dependency>
|
||
<groupId>org.springframework.ai</groupId>
|
||
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
|
||
<version>1.0.0-M6</version>
|
||
</dependency>
|
||
```
|
||
|
||
**步骤2**: 修改配置
|
||
```yaml
|
||
spring:
|
||
ai:
|
||
ollama:
|
||
base-url: http://localhost:11434
|
||
chat:
|
||
options:
|
||
model: llama2
|
||
temperature: 0.7
|
||
```
|
||
|
||
### 方案二: 集成阿里云通义千问
|
||
|
||
由于Spring AI暂不直接支持通义千问,需要自定义实现。
|
||
|
||
**步骤1**: 添加HTTP客户端依赖
|
||
```xml
|
||
<dependency>
|
||
<groupId>com.alibaba.cloud</groupId>
|
||
<artifactId>alibabacloud-dashscope-sdk-java</artifactId>
|
||
<version>2.14.0</version>
|
||
</dependency>
|
||
```
|
||
|
||
**步骤2**: 创建通义千问服务类
|
||
```java
|
||
// 新建文件: src/main/java/com/yundage/chat/service/QianWenService.java
|
||
@Service
|
||
public class QianWenService {
|
||
|
||
@Value("${dashscope.api-key}")
|
||
private String apiKey;
|
||
|
||
public String generateResponse(String prompt) {
|
||
// 实现通义千问API调用逻辑
|
||
Generation gen = new Generation();
|
||
gen.setApiKey(apiKey);
|
||
|
||
GenerationParam param = GenerationParam.builder()
|
||
.model("qwen-turbo")
|
||
.prompt(prompt)
|
||
.build();
|
||
|
||
GenerationResult result = gen.call(param);
|
||
return result.getOutput().getText();
|
||
}
|
||
|
||
public Flux<String> generateStreamResponse(String prompt) {
|
||
// 实现流式响应
|
||
return Flux.create(sink -> {
|
||
// 流式调用逻辑
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
**步骤3**: 修改 `ChatService.java`
|
||
```java
|
||
@Service
|
||
public class ChatService {
|
||
|
||
// 添加注入
|
||
@Autowired
|
||
private QianWenService qianWenService;
|
||
|
||
// 修改普通调用方法
|
||
private String generateAIResponse(ChatRequest request) {
|
||
return qianWenService.generateResponse(request.getMessage());
|
||
}
|
||
|
||
// 修改流式调用方法
|
||
public SseEmitter processChatStream(ChatRequest request, User user) {
|
||
// ...
|
||
Flux<String> flux = qianWenService.generateStreamResponse(request.getMessage());
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
**步骤4**: 添加配置
|
||
```yaml
|
||
dashscope:
|
||
api-key: ${DASHSCOPE_API_KEY}
|
||
```
|
||
|
||
### 方案三: 集成百度文心一言
|
||
|
||
**步骤1**: 添加百度AI SDK
|
||
```xml
|
||
<dependency>
|
||
<groupId>com.baidubce</groupId>
|
||
<artifactId>qianfan</artifactId>
|
||
<version>0.2.5</version>
|
||
</dependency>
|
||
```
|
||
|
||
**步骤2**: 创建文心一言服务
|
||
```java
|
||
// 新建文件: src/main/java/com/yundage/chat/service/ErnieService.java
|
||
@Service
|
||
public class ErnieService {
|
||
|
||
@Value("${baidu.api-key}")
|
||
private String apiKey;
|
||
|
||
@Value("${baidu.secret-key}")
|
||
private String secretKey;
|
||
|
||
public String generateResponse(String prompt) {
|
||
ChatCompletion chatCompletion = new ChatCompletion();
|
||
chatCompletion.setAccessKey(apiKey);
|
||
chatCompletion.setSecretKey(secretKey);
|
||
|
||
List<ChatCompletionMessage> messages = new ArrayList<>();
|
||
messages.add(ChatCompletionMessage.builder()
|
||
.role("user")
|
||
.content(prompt)
|
||
.build());
|
||
|
||
ChatCompletionRequest request = ChatCompletionRequest.builder()
|
||
.model("ERNIE-Bot-turbo")
|
||
.messages(messages)
|
||
.build();
|
||
|
||
ChatCompletionResponse response = chatCompletion.create(request);
|
||
return response.getResult();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 方案四: 完全自定义HTTP客户端
|
||
|
||
适用于任何提供HTTP API的大模型服务。
|
||
|
||
**步骤1**: 创建通用AI客户端接口
|
||
```java
|
||
// 新建文件: src/main/java/com/yundage/chat/service/ai/AIService.java
|
||
public interface AIService {
|
||
String generateResponse(String prompt);
|
||
Flux<String> generateStreamResponse(String prompt);
|
||
}
|
||
```
|
||
|
||
**步骤2**: 实现具体的AI服务
|
||
```java
|
||
// 新建文件: src/main/java/com/yundage/chat/service/ai/CustomAIService.java
|
||
@Service
|
||
public class CustomAIService implements AIService {
|
||
|
||
@Autowired
|
||
private RestTemplate restTemplate;
|
||
|
||
@Value("${custom.ai.api-url}")
|
||
private String apiUrl;
|
||
|
||
@Value("${custom.ai.api-key}")
|
||
private String apiKey;
|
||
|
||
@Override
|
||
public String generateResponse(String prompt) {
|
||
HttpHeaders headers = new HttpHeaders();
|
||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||
headers.setBearerAuth(apiKey);
|
||
|
||
Map<String, Object> requestBody = Map.of(
|
||
"model", "custom-model",
|
||
"messages", List.of(Map.of("role", "user", "content", prompt))
|
||
);
|
||
|
||
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
|
||
|
||
ResponseEntity<Map> response = restTemplate.postForEntity(apiUrl, request, Map.class);
|
||
|
||
// 解析响应并返回内容
|
||
return extractContentFromResponse(response.getBody());
|
||
}
|
||
|
||
@Override
|
||
public Flux<String> generateStreamResponse(String prompt) {
|
||
// 实现Server-Sent Events或WebSocket流式调用
|
||
return Flux.create(sink -> {
|
||
// 流式调用实现
|
||
});
|
||
}
|
||
|
||
private String extractContentFromResponse(Map<String, Object> response) {
|
||
// 根据API响应格式解析内容
|
||
return "";
|
||
}
|
||
}
|
||
```
|
||
|
||
## 更换建议和注意事项
|
||
|
||
### 1. 性能考虑
|
||
|
||
- **延迟**: 不同模型服务的响应延迟差异较大
|
||
- **并发**: 评估新服务的并发处理能力
|
||
- **限流**: 实现客户端限流避免触发API限制
|
||
|
||
### 2. 成本优化
|
||
|
||
- **Token计费**: 不同服务的计费方式差异较大
|
||
- **缓存策略**: 对相同问题实现响应缓存
|
||
- **模型选择**: 根据业务场景选择合适规模的模型
|
||
|
||
### 3. 质量保证
|
||
|
||
- **A/B测试**: 同时运行新旧模型对比效果
|
||
- **回退机制**: 新模型出现问题时能快速回退
|
||
- **监控告警**: 监控响应质量和错误率
|
||
|
||
### 4. 配置管理
|
||
|
||
建议将所有AI相关配置外化到环境变量:
|
||
|
||
```yaml
|
||
# application.yml
|
||
ai:
|
||
provider: ${AI_PROVIDER:openai}
|
||
openai:
|
||
api-key: ${OPENAI_API_KEY}
|
||
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
|
||
azure:
|
||
api-key: ${AZURE_API_KEY}
|
||
endpoint: ${AZURE_ENDPOINT}
|
||
custom:
|
||
api-url: ${CUSTOM_AI_URL}
|
||
api-key: ${CUSTOM_AI_KEY}
|
||
```
|
||
|
||
### 5. 数据安全
|
||
|
||
- **数据加密**: 确保API调用使用HTTPS
|
||
- **敏感信息**: 避免在日志中记录用户输入内容
|
||
- **访问控制**: 限制AI服务的网络访问权限
|
||
|
||
## 测试验证
|
||
|
||
更换模型后需要进行充分测试:
|
||
|
||
1. **功能测试**: 验证基本问答功能正常
|
||
2. **流式测试**: 确认流式输出工作正常
|
||
3. **错误处理**: 测试各种异常情况的处理
|
||
4. **性能测试**: 验证响应时间和并发能力
|
||
5. **集成测试**: 端到端功能验证
|
||
|
||
## 总结
|
||
|
||
根据具体需求选择合适的更换方案:
|
||
|
||
- **简单迁移**: 选择方案一,使用Spring AI支持的其他模型
|
||
- **成本优化**: 选择方案二或三,使用国内模型服务
|
||
- **深度定制**: 选择方案四,完全自定义实现
|
||
|
||
建议采用渐进式迁移,先在测试环境验证,确认无误后再部署到生产环境。
|
||
|
||
---
|
||
|
||
*更新时间: 2025-07-28* |