简介:本文详细介绍如何将Spring AI框架与DeepSeek大模型结合,通过代码示例和架构设计,帮助开发者快速构建AI驱动的智能应用。
Spring AI作为Spring生态的AI扩展框架,为Java开发者提供了标准化的AI服务抽象层。其核心优势在于:
AiClient
接口屏蔽不同AI服务商的差异,支持OpenAI、Ollama等模型的无缝切换DeepSeek作为开源大模型,其R1版本在数学推理和代码生成方面表现突出。两者结合可实现:
<!-- Maven配置示例 -->
<dependencies>
<!-- Spring AI核心模块 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
<version>0.8.0</version>
</dependency>
<!-- DeepSeek适配器(需自行实现或使用社区版本) -->
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-ai-deepseek</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 可选:响应式支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-reactor</artifactId>
<version>0.8.0</version>
</dependency>
</dependencies>
public class DeepSeekAiClient implements AiClient {
private final RestTemplate restTemplate;
private final String apiUrl;
private final String apiKey;
public DeepSeekAiClient(String apiUrl, String apiKey) {
this.apiUrl = apiUrl;
this.apiKey = apiKey;
this.restTemplate = new RestTemplateBuilder()
.setConnectTimeout(Duration.ofSeconds(10))
.setReadTimeout(Duration.ofSeconds(30))
.build();
}
@Override
public ChatResponse chat(ChatRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(apiKey);
Map<String, Object> body = Map.of(
"model", "deepseek-r1",
"messages", request.getMessages(),
"temperature", 0.7,
"max_tokens", 2000
);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
ResponseEntity<Map<String, Object>> response = restTemplate.postForEntity(
apiUrl + "/v1/chat/completions",
entity,
Map.class
);
Map<String, Object> responseBody = response.getBody();
String content = (String) ((Map) responseBody.get("choices")).get("message").get("content");
return ChatResponse.builder()
.content(content)
.build();
}
}
@Configuration
public class DeepSeekAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public AiClient deepSeekAiClient(
@Value("${spring.ai.deepseek.api-url}") String apiUrl,
@Value("${spring.ai.deepseek.api-key}") String apiKey) {
return new DeepSeekAiClient(apiUrl, apiKey);
}
@Bean
public ChatEndpoint chatEndpoint(AiClient aiClient) {
return new ChatEndpoint(aiClient);
}
}
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatEndpoint chatEndpoint;
public ChatController(ChatEndpoint chatEndpoint) {
this.chatEndpoint = chatEndpoint;
}
@PostMapping
public Mono<ChatResponse> chat(
@RequestBody ChatRequest request,
@RequestParam(defaultValue = "0.7") float temperature) {
// 添加系统指令增强上下文理解
Message systemMessage = Message.system(
"你是一个专业的企业助手,使用Markdown格式回答"
);
ChatRequest enhancedRequest = ChatRequest.builder()
.messages(Stream.concat(
Stream.of(systemMessage),
request.getMessages().stream()
).toList())
.temperature(temperature)
.build();
return chatEndpoint.call(enhancedRequest);
}
}
public class CodeGenerator {
private final AiClient aiClient;
public CodeGenerator(AiClient aiClient) {
this.aiClient = aiClient;
}
public String generateCode(String requirements, String framework) {
Message prompt = Message.user(String.format(
"用%s实现以下功能:\n%s\n要求:\n1. 代码结构清晰\n2. 添加必要注释\n3. 包含单元测试",
framework, requirements
));
ChatRequest request = ChatRequest.builder()
.messages(List.of(prompt))
.model("deepseek-code")
.build();
ChatResponse response = aiClient.chat(request);
return response.getContent();
}
}
@Configuration
public class HttpClientConfig {
@Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(20);
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(30000)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(config)
.build();
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
@Component
public class ChatCache {
private final Cache<String, String> cache;
public ChatCache() {
this.cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofHours(1))
.build();
}
public String getCachedResponse(String promptHash) {
return cache.getIfPresent(promptHash);
}
public void putResponse(String promptHash, String response) {
cache.put(promptHash, response);
}
}
public class DataEncryptor {
private final SecretKey secretKey;
private final Cipher cipher;
public DataEncryptor(String secret) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
this.secretKey = new SecretKeySpec(secret.getBytes(), "AES");
this.cipher = Cipher.getInstance("AES/GCM/NoPadding");
}
public String encrypt(String data) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV();
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(
Stream.concat(
Arrays.stream(iv),
Arrays.stream(encrypted)
).toArray()
);
}
}
@Aspect
@Component
public class AuditAspect {
private final AuditLogRepository logRepository;
public AuditAspect(AuditLogRepository logRepository) {
this.logRepository = logRepository;
}
@Around("@annotation(Auditable)")
public Object logAiCall(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - startTime;
AuditLog log = new AuditLog();
log.setOperation(joinPoint.getSignature().getName());
log.setDuration(duration);
log.setTimestamp(Instant.now());
// 获取请求参数中的敏感信息(需根据实际实现调整)
Object[] args = joinPoint.getArgs();
if (args.length > 0 && args[0] instanceof ChatRequest) {
ChatRequest request = (ChatRequest) args[0];
log.setPrompt(request.getMessages().get(0).getContent());
}
logRepository.save(log);
return result;
}
}
# deployment.yaml示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-ai-deepseek
spec:
replicas: 3
selector:
matchLabels:
app: spring-ai
template:
metadata:
labels:
app: spring-ai
spec:
containers:
- name: app
image: my-registry/spring-ai-deepseek:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_AI_DEEPSEEK_API_URL
valueFrom:
secretKeyRef:
name: deepseek-secrets
key: api-url
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
@Configuration
public class MetricsConfig {
@Bean
public MicrometerCollectorRegistry micrometerRegistry() {
return new MicrometerCollectorRegistry(
Metrics.globalRegistry,
Tag.of("service", "spring-ai-deepseek")
);
}
@Bean
public Timer aiCallTimer() {
return Timer.builder("ai.call.duration")
.description("AI调用耗时")
.tags("model", "deepseek-r1")
.register(Metrics.globalRegistry);
}
}
@Retryable(value = {RestClientException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000))
public ChatResponse retryableChat(ChatRequest request) {
return aiClient.chat(request);
}
public class ModelRouter {
private final Map<String, AiClient> clients;
public ModelRouter(List<AiClient> clients) {
this.clients = clients.stream()
.collect(Collectors.toMap(
client -> {
// 通过反射或其他方式获取模型名称
try {
return (String) client.getClass()
.getMethod("getModelName")
.invoke(client);
} catch (Exception e) {
return "unknown";
}
},
Function.identity()
));
}
public AiClient getClient(String modelName) {
return clients.getOrDefault(
modelName.toLowerCase(),
clients.get("default")
);
}
}
本教程完整展示了Spring AI与DeepSeek的集成方案,覆盖了从基础环境搭建到高级功能实现的完整流程。实际开发中建议:
未来发展方向包括:
通过这种架构设计,企业可以快速构建具备AI能力的智能应用,同时保持系统的可扩展性和可维护性。