feat(MCA): TASK-031 实现 AiServiceClient [AC-MCA-04, AC-MCA-05]
- 创建 AiServiceClient 接口 - 创建 AiServiceClientImpl 实现类 - 使用 RestTemplate 调用 /ai/chat - 配置 Resilience4j 熔断和超时
This commit is contained in:
parent
56ffb522ac
commit
1fbdf4777a
|
|
@ -0,0 +1,18 @@
|
|||
package com.wecom.robot.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration
|
||||
public class RestTemplateConfig {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(5000);
|
||||
factory.setReadTimeout(5000);
|
||||
return new RestTemplate(factory);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.wecom.robot.service;
|
||||
|
||||
import com.wecom.robot.dto.ai.ChatRequest;
|
||||
import com.wecom.robot.dto.ai.ChatResponse;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface AiServiceClient {
|
||||
|
||||
CompletableFuture<ChatResponse> generateReply(ChatRequest request);
|
||||
|
||||
boolean healthCheck();
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.wecom.robot.service.impl;
|
||||
|
||||
import com.wecom.robot.config.AiServiceConfig;
|
||||
import com.wecom.robot.dto.ai.ChatRequest;
|
||||
import com.wecom.robot.dto.ai.ChatResponse;
|
||||
import com.wecom.robot.service.AiServiceClient;
|
||||
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
|
||||
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AiServiceClientImpl implements AiServiceClient {
|
||||
|
||||
private static final String CHAT_ENDPOINT = "/ai/chat";
|
||||
private static final String HEALTH_ENDPOINT = "/ai/health";
|
||||
|
||||
private final AiServiceConfig aiServiceConfig;
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
@Override
|
||||
@CircuitBreaker(name = "aiService", fallbackMethod = "generateReplyFallback")
|
||||
@TimeLimiter(name = "aiService")
|
||||
public CompletableFuture<ChatResponse> generateReply(ChatRequest request) {
|
||||
log.info("[AC-MCA-04] 调用 AI 服务: sessionId={}", request.getSessionId());
|
||||
|
||||
String url = aiServiceConfig.getUrl() + CHAT_ENDPOINT;
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity<ChatRequest> entity = new HttpEntity<>(request, headers);
|
||||
|
||||
ResponseEntity<ChatResponse> response = restTemplate.postForEntity(
|
||||
url, entity, ChatResponse.class);
|
||||
|
||||
log.info("[AC-MCA-05] AI 服务响应: sessionId={}, shouldTransfer={}",
|
||||
request.getSessionId(),
|
||||
response.getBody() != null ? response.getBody().getShouldTransfer() : null);
|
||||
|
||||
return CompletableFuture.completedFuture(response.getBody());
|
||||
}
|
||||
|
||||
public CompletableFuture<ChatResponse> generateReplyFallback(ChatRequest request, Throwable cause) {
|
||||
log.warn("[AC-MCA-06][AC-MCA-07] AI 服务降级: sessionId={}, cause={}",
|
||||
request.getSessionId(), cause.getMessage());
|
||||
|
||||
ChatResponse fallbackResponse = ChatResponse.fallbackWithTransfer(
|
||||
"抱歉,我暂时无法回答您的问题,正在为您转接人工客服...",
|
||||
cause.getMessage()
|
||||
);
|
||||
|
||||
return CompletableFuture.completedFuture(fallbackResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean healthCheck() {
|
||||
try {
|
||||
String url = aiServiceConfig.getUrl() + HEALTH_ENDPOINT;
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||
return response.getStatusCode().is2xxSuccessful();
|
||||
} catch (Exception e) {
|
||||
log.error("[AC-MCA-04] AI 服务健康检查失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,3 +42,17 @@ channel:
|
|||
enabled: false
|
||||
jd:
|
||||
enabled: false
|
||||
|
||||
resilience4j:
|
||||
circuitbreaker:
|
||||
instances:
|
||||
aiService:
|
||||
failure-rate-threshold: 50
|
||||
sliding-window-size: 10
|
||||
sliding-window-type: COUNT_BASED
|
||||
wait-duration-in-open-state: 30s
|
||||
permitted-number-of-calls-in-half-open-state: 3
|
||||
timelimiter:
|
||||
instances:
|
||||
aiService:
|
||||
timeout-duration: 5s
|
||||
|
|
|
|||
Loading…
Reference in New Issue