feat(MCA): TASK-033 删除旧 AiService 和 AiConfig
- 删除旧的 AiService 类 - 删除旧的 AiConfig 类 - 更新 MessageRouterServiceImpl 使用 AiServiceClient - 更新 DebugController 移除 AiService 引用 - 无编译错误
This commit is contained in:
parent
1fbdf4777a
commit
4b1fcf453f
|
|
@ -1,30 +0,0 @@
|
||||||
package com.wecom.robot.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "ai")
|
|
||||||
public class AiConfig {
|
|
||||||
|
|
||||||
private boolean enabled;
|
|
||||||
private String provider;
|
|
||||||
private DeepSeekConfig deepseek;
|
|
||||||
private OpenAiConfig openai;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class DeepSeekConfig {
|
|
||||||
private String apiKey;
|
|
||||||
private String baseUrl;
|
|
||||||
private String model;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class OpenAiConfig {
|
|
||||||
private String apiKey;
|
|
||||||
private String baseUrl;
|
|
||||||
private String model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,9 +2,7 @@ package com.wecom.robot.controller;
|
||||||
|
|
||||||
import com.wecom.robot.config.WecomConfig;
|
import com.wecom.robot.config.WecomConfig;
|
||||||
import com.wecom.robot.dto.ApiResponse;
|
import com.wecom.robot.dto.ApiResponse;
|
||||||
import com.wecom.robot.dto.ChatCompletionRequest;
|
|
||||||
import com.wecom.robot.entity.Message;
|
import com.wecom.robot.entity.Message;
|
||||||
import com.wecom.robot.service.AiService;
|
|
||||||
import com.wecom.robot.service.SessionManagerService;
|
import com.wecom.robot.service.SessionManagerService;
|
||||||
import com.wecom.robot.util.WXBizMsgCrypt;
|
import com.wecom.robot.util.WXBizMsgCrypt;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
@ -23,7 +21,6 @@ import java.util.Map;
|
||||||
public class DebugController {
|
public class DebugController {
|
||||||
|
|
||||||
private final WecomConfig wecomConfig;
|
private final WecomConfig wecomConfig;
|
||||||
private final AiService aiService;
|
|
||||||
private final SessionManagerService sessionManagerService;
|
private final SessionManagerService sessionManagerService;
|
||||||
|
|
||||||
@GetMapping("/config")
|
@GetMapping("/config")
|
||||||
|
|
@ -108,38 +105,13 @@ public class DebugController {
|
||||||
return ApiResponse.success(result);
|
return ApiResponse.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/ai/context")
|
|
||||||
public ApiResponse<Map<String, Object>> getLastAiContext() {
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
|
||||||
|
|
||||||
result.put("systemPrompt", aiService.getSystemPrompt());
|
|
||||||
result.put("lastRequestJson", aiService.getLastRequestJson());
|
|
||||||
result.put("lastConfidence", aiService.getLastConfidence());
|
|
||||||
|
|
||||||
List<ChatCompletionRequest.Message> messages = aiService.getLastRequestMessages();
|
|
||||||
result.put("messageCount", messages.size());
|
|
||||||
|
|
||||||
List<Map<String, String>> messageList = new java.util.ArrayList<>();
|
|
||||||
for (ChatCompletionRequest.Message msg : messages) {
|
|
||||||
Map<String, String> msgMap = new HashMap<>();
|
|
||||||
msgMap.put("role", msg.getRole());
|
|
||||||
msgMap.put("content", msg.getContent());
|
|
||||||
messageList.add(msgMap);
|
|
||||||
}
|
|
||||||
result.put("messages", messageList);
|
|
||||||
|
|
||||||
return ApiResponse.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/ai/session/{sessionId}/context")
|
@GetMapping("/ai/session/{sessionId}/context")
|
||||||
public ApiResponse<Map<String, Object>> getSessionAiContext(
|
public ApiResponse<Map<String, Object>> getSessionAiContext(
|
||||||
@PathVariable String sessionId,
|
@PathVariable String sessionId) {
|
||||||
@RequestParam(required = false, defaultValue = "测试消息") String testMessage) {
|
|
||||||
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
result.put("sessionId", sessionId);
|
result.put("sessionId", sessionId);
|
||||||
result.put("systemPrompt", aiService.getSystemPrompt());
|
|
||||||
|
|
||||||
List<Message> history = sessionManagerService.getSessionMessages(sessionId);
|
List<Message> history = sessionManagerService.getSessionMessages(sessionId);
|
||||||
result.put("historyCount", history.size());
|
result.put("historyCount", history.size());
|
||||||
|
|
@ -156,18 +128,6 @@ public class DebugController {
|
||||||
}
|
}
|
||||||
result.put("history", historyList);
|
result.put("history", historyList);
|
||||||
|
|
||||||
List<ChatCompletionRequest.Message> contextMessages = aiService.buildMessagesForTest(history, testMessage);
|
|
||||||
result.put("contextMessageCount", contextMessages.size());
|
|
||||||
|
|
||||||
List<Map<String, String>> contextList = new java.util.ArrayList<>();
|
|
||||||
for (ChatCompletionRequest.Message msg : contextMessages) {
|
|
||||||
Map<String, String> msgMap = new HashMap<>();
|
|
||||||
msgMap.put("role", msg.getRole());
|
|
||||||
msgMap.put("content", msg.getContent());
|
|
||||||
contextList.add(msgMap);
|
|
||||||
}
|
|
||||||
result.put("contextMessages", contextList);
|
|
||||||
|
|
||||||
return ApiResponse.success(result);
|
return ApiResponse.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
package com.wecom.robot.service;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.wecom.robot.config.AiConfig;
|
|
||||||
import com.wecom.robot.dto.ChatCompletionRequest;
|
|
||||||
import com.wecom.robot.dto.ChatCompletionResponse;
|
|
||||||
import com.wecom.robot.entity.Message;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.*;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class AiService {
|
|
||||||
|
|
||||||
private static final String SYSTEM_PROMPT = "你是ash超脑的客服,请用简洁、友好的语言回答客户的问题。" +
|
|
||||||
"如果不确定答案,请诚实告知客户。" +
|
|
||||||
"回答要准确、专业,避免过于冗长,要尽量拟人化口语化,自然回答问题。";
|
|
||||||
|
|
||||||
private final AiConfig aiConfig;
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
|
||||||
|
|
||||||
private double lastConfidence = 1.0;
|
|
||||||
private List<ChatCompletionRequest.Message> lastRequestMessages = new ArrayList<>();
|
|
||||||
private String lastRequestJson = "";
|
|
||||||
|
|
||||||
public String generateReply(String userMessage, List<Message> history) {
|
|
||||||
if (!aiConfig.isEnabled()) {
|
|
||||||
return "AI服务暂未开启,请联系人工客服。";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String provider = aiConfig.getProvider();
|
|
||||||
String apiUrl;
|
|
||||||
String apiKey;
|
|
||||||
String model;
|
|
||||||
|
|
||||||
if ("deepseek".equalsIgnoreCase(provider)) {
|
|
||||||
apiUrl = aiConfig.getDeepseek().getBaseUrl() + "/chat/completions";
|
|
||||||
apiKey = aiConfig.getDeepseek().getApiKey();
|
|
||||||
model = aiConfig.getDeepseek().getModel();
|
|
||||||
} else {
|
|
||||||
apiUrl = aiConfig.getOpenai().getBaseUrl() + "/chat/completions";
|
|
||||||
apiKey = aiConfig.getOpenai().getApiKey();
|
|
||||||
model = aiConfig.getOpenai().getModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ChatCompletionRequest.Message> messages = buildMessages(history, userMessage);
|
|
||||||
ChatCompletionRequest request = ChatCompletionRequest.create(model, messages);
|
|
||||||
|
|
||||||
lastRequestMessages = messages;
|
|
||||||
lastRequestJson = JSON.toJSONString(request, true);
|
|
||||||
|
|
||||||
log.info("===== AI请求上下文 =====");
|
|
||||||
log.info("Provider: {}, Model: {}", provider, model);
|
|
||||||
log.info("API URL: {}", apiUrl);
|
|
||||||
log.info("消息数量: {}", messages.size());
|
|
||||||
for (int i = 0; i < messages.size(); i++) {
|
|
||||||
ChatCompletionRequest.Message msg = messages.get(i);
|
|
||||||
log.info("[{}] {}: {}", i, msg.getRole(), msg.getContent());
|
|
||||||
}
|
|
||||||
log.info("===== 完整请求JSON =====");
|
|
||||||
log.info("\n{}", lastRequestJson);
|
|
||||||
log.info("========================");
|
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
headers.setBearerAuth(apiKey);
|
|
||||||
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(request), headers);
|
|
||||||
ResponseEntity<String> response = restTemplate.postForEntity(apiUrl, entity, String.class);
|
|
||||||
|
|
||||||
log.info("===== AI响应 =====");
|
|
||||||
log.info("Status: {}", response.getStatusCode());
|
|
||||||
log.info("Body: {}", response.getBody());
|
|
||||||
log.info("==================");
|
|
||||||
|
|
||||||
ChatCompletionResponse completionResponse = JSON.parseObject(response.getBody(), ChatCompletionResponse.class);
|
|
||||||
String reply = completionResponse.getContent();
|
|
||||||
|
|
||||||
lastConfidence = calculateConfidence(reply);
|
|
||||||
|
|
||||||
log.info("AI回复生成成功: confidence={}, reply={}", lastConfidence, reply);
|
|
||||||
return reply;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("AI回复生成失败", e);
|
|
||||||
lastConfidence = 0.0;
|
|
||||||
return "抱歉,我暂时无法回答您的问题,正在为您转接人工客服...";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getLastConfidence() {
|
|
||||||
return lastConfidence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ChatCompletionRequest.Message> getLastRequestMessages() {
|
|
||||||
return lastRequestMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastRequestJson() {
|
|
||||||
return lastRequestJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSystemPrompt() {
|
|
||||||
return SYSTEM_PROMPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ChatCompletionRequest.Message> buildMessagesForTest(List<Message> history, String currentMessage) {
|
|
||||||
return buildMessages(history, currentMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ChatCompletionRequest.Message> buildMessages(List<Message> history, String currentMessage) {
|
|
||||||
List<ChatCompletionRequest.Message> messages = new ArrayList<>();
|
|
||||||
|
|
||||||
messages.add(new ChatCompletionRequest.Message("system", SYSTEM_PROMPT));
|
|
||||||
|
|
||||||
int startIndex = Math.max(0, history.size() - 10);
|
|
||||||
for (int i = startIndex; i < history.size(); i++) {
|
|
||||||
Message msg = history.get(i);
|
|
||||||
String role = Message.SENDER_TYPE_CUSTOMER.equals(msg.getSenderType()) ? "user" : "assistant";
|
|
||||||
messages.add(new ChatCompletionRequest.Message(role, msg.getContent()));
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.add(new ChatCompletionRequest.Message("user", currentMessage));
|
|
||||||
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double calculateConfidence(String reply) {
|
|
||||||
if (reply == null || reply.isEmpty()) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.contains("不确定") || reply.contains("不清楚") || reply.contains("无法回答")) {
|
|
||||||
return 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.contains("转接人工") || reply.contains("人工客服")) {
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply.length() < 10) {
|
|
||||||
return 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.85;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,7 +31,6 @@ public class MessageProcessService {
|
||||||
private static final String CHANNEL_TYPE = "wechat";
|
private static final String CHANNEL_TYPE = "wechat";
|
||||||
|
|
||||||
private final SessionManagerService sessionManagerService;
|
private final SessionManagerService sessionManagerService;
|
||||||
private final AiService aiService;
|
|
||||||
private final TransferService transferService;
|
private final TransferService transferService;
|
||||||
private final WecomApiService wecomApiService;
|
private final WecomApiService wecomApiService;
|
||||||
private final WebSocketService webSocketService;
|
private final WebSocketService webSocketService;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import com.wecom.robot.adapter.ChannelAdapter;
|
||||||
import com.wecom.robot.adapter.TransferCapable;
|
import com.wecom.robot.adapter.TransferCapable;
|
||||||
import com.wecom.robot.dto.InboundMessage;
|
import com.wecom.robot.dto.InboundMessage;
|
||||||
import com.wecom.robot.dto.OutboundMessage;
|
import com.wecom.robot.dto.OutboundMessage;
|
||||||
|
import com.wecom.robot.dto.ai.ChatRequest;
|
||||||
|
import com.wecom.robot.dto.ai.ChatResponse;
|
||||||
import com.wecom.robot.entity.Message;
|
import com.wecom.robot.entity.Message;
|
||||||
import com.wecom.robot.entity.Session;
|
import com.wecom.robot.entity.Session;
|
||||||
import com.wecom.robot.service.*;
|
import com.wecom.robot.service.*;
|
||||||
|
|
@ -17,14 +19,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息路由服务实现 - 渠道无关的消息路由核心逻辑
|
|
||||||
*
|
|
||||||
* <p>关联 AC: [AC-MCA-08] 统一消息路由, [AC-MCA-09] 状态路由, [AC-MCA-10] 人工客服分发
|
|
||||||
*
|
|
||||||
* @see MessageRouterService
|
|
||||||
* @see InboundMessage
|
|
||||||
*/
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|
@ -34,7 +28,7 @@ public class MessageRouterServiceImpl implements MessageRouterService {
|
||||||
private static final long IDEMPOTENT_TTL_HOURS = 1;
|
private static final long IDEMPOTENT_TTL_HOURS = 1;
|
||||||
|
|
||||||
private final SessionManagerService sessionManagerService;
|
private final SessionManagerService sessionManagerService;
|
||||||
private final AiService aiService;
|
private final AiServiceClient aiServiceClient;
|
||||||
private final TransferService transferService;
|
private final TransferService transferService;
|
||||||
private final WebSocketService webSocketService;
|
private final WebSocketService webSocketService;
|
||||||
private final Map<String, ChannelAdapter> channelAdapters;
|
private final Map<String, ChannelAdapter> channelAdapters;
|
||||||
|
|
@ -95,20 +89,36 @@ public class MessageRouterServiceImpl implements MessageRouterService {
|
||||||
session.getSessionId(), truncateContent(message.getContent()));
|
session.getSessionId(), truncateContent(message.getContent()));
|
||||||
|
|
||||||
List<Message> history = sessionManagerService.getSessionMessages(session.getSessionId());
|
List<Message> history = sessionManagerService.getSessionMessages(session.getSessionId());
|
||||||
String reply = aiService.generateReply(message.getContent(), history);
|
|
||||||
|
|
||||||
double confidence = aiService.getLastConfidence();
|
ChatRequest chatRequest = ChatRequest.fromInboundMessage(message);
|
||||||
|
ChatResponse chatResponse;
|
||||||
|
try {
|
||||||
|
chatResponse = aiServiceClient.generateReply(chatRequest).get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[AC-MCA-06] AI服务调用失败: {}", e.getMessage());
|
||||||
|
chatResponse = ChatResponse.fallbackWithTransfer(
|
||||||
|
"抱歉,我暂时无法回答您的问题,正在为您转接人工客服...",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String reply = chatResponse.getReply();
|
||||||
|
double confidence = chatResponse.getConfidence() != null ? chatResponse.getConfidence() : 0.0;
|
||||||
int messageCount = sessionManagerService.getMessageCount(session.getSessionId());
|
int messageCount = sessionManagerService.getMessageCount(session.getSessionId());
|
||||||
|
|
||||||
boolean shouldTransfer = transferService.shouldTransferToManual(
|
boolean shouldTransfer = chatResponse.getShouldTransfer() != null && chatResponse.getShouldTransfer();
|
||||||
|
|
||||||
|
if (!shouldTransfer) {
|
||||||
|
shouldTransfer = transferService.shouldTransferToManual(
|
||||||
message.getContent(),
|
message.getContent(),
|
||||||
confidence,
|
confidence,
|
||||||
messageCount,
|
messageCount,
|
||||||
session.getCreatedAt()
|
session.getCreatedAt()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldTransfer) {
|
if (shouldTransfer) {
|
||||||
handleTransferToManual(session, message, reply);
|
handleTransferToManual(session, message, reply, chatResponse.getTransferReason());
|
||||||
} else {
|
} else {
|
||||||
sendReplyToUser(session, message, reply);
|
sendReplyToUser(session, message, reply);
|
||||||
}
|
}
|
||||||
|
|
@ -177,10 +187,10 @@ public class MessageRouterServiceImpl implements MessageRouterService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTransferToManual(Session session, InboundMessage message, String reply) {
|
private void handleTransferToManual(Session session, InboundMessage message, String reply, String transferReason) {
|
||||||
String reason = transferService.getTransferReason(
|
String reason = transferReason != null ? transferReason : transferService.getTransferReason(
|
||||||
message.getContent(),
|
message.getContent(),
|
||||||
aiService.getLastConfidence(),
|
0.0,
|
||||||
sessionManagerService.getMessageCount(session.getSessionId())
|
sessionManagerService.getMessageCount(session.getSessionId())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue