2026-06-11 11:37:38 +08:00
|
|
|
|
package com.company.agentfoundation.agent;
|
2026-06-08 09:37:35 +08:00
|
|
|
|
|
|
|
|
|
|
import com.company.agentfoundation.domain.ChatRequest;
|
|
|
|
|
|
import com.company.agentfoundation.domain.ChatResponse;
|
2026-06-12 09:56:34 +08:00
|
|
|
|
import com.company.agentfoundation.directory.EmployeeAccountMapping;
|
|
|
|
|
|
import com.company.agentfoundation.directory.EmployeeDirectoryResponse;
|
|
|
|
|
|
import com.company.agentfoundation.directory.EmployeeDirectoryService;
|
2026-06-08 09:37:35 +08:00
|
|
|
|
import com.company.agentfoundation.security.AgentContext;
|
|
|
|
|
|
import com.company.agentfoundation.service.ChatService;
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
@Service
|
|
|
|
|
|
public class AgentOrchestratorService {
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(AgentOrchestratorService.class);
|
|
|
|
|
|
|
|
|
|
|
|
private final IntentRecognitionService intentRecognitionService;
|
|
|
|
|
|
private final OperationReportService operationReportService;
|
|
|
|
|
|
private final ChatService chatService;
|
2026-06-12 09:56:34 +08:00
|
|
|
|
private final EmployeeDirectoryService employeeDirectoryService;
|
2026-06-08 09:37:35 +08:00
|
|
|
|
|
|
|
|
|
|
public AgentOrchestratorService(
|
|
|
|
|
|
IntentRecognitionService intentRecognitionService,
|
|
|
|
|
|
OperationReportService operationReportService,
|
2026-06-12 09:56:34 +08:00
|
|
|
|
ChatService chatService,
|
|
|
|
|
|
EmployeeDirectoryService employeeDirectoryService
|
2026-06-08 09:37:35 +08:00
|
|
|
|
) {
|
|
|
|
|
|
this.intentRecognitionService = intentRecognitionService;
|
|
|
|
|
|
this.operationReportService = operationReportService;
|
|
|
|
|
|
this.chatService = chatService;
|
2026-06-12 09:56:34 +08:00
|
|
|
|
this.employeeDirectoryService = employeeDirectoryService;
|
2026-06-08 09:37:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public String handleMessage(String agentId, String fromUser, String userText) {
|
|
|
|
|
|
AgentIntent intent = intentRecognitionService.recognize(agentId, userText);
|
2026-06-11 11:31:49 +08:00
|
|
|
|
log.info("agent orchestrator route fromUser={} intent={} group={}", fromUser, intent.code(), intent.mcpGroup());
|
2026-06-08 09:37:35 +08:00
|
|
|
|
if (intent != AgentIntent.GENERAL_CHAT) {
|
2026-06-12 09:56:34 +08:00
|
|
|
|
return appendDirectoryInfo(
|
|
|
|
|
|
toWecomText(operationReportService.handle(intent, AgentRequestContext.of(agentId, fromUser, userText))),
|
|
|
|
|
|
fromUser
|
|
|
|
|
|
);
|
2026-06-08 09:37:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ChatRequest request = new ChatRequest(
|
|
|
|
|
|
null,
|
|
|
|
|
|
List.of(
|
|
|
|
|
|
new ChatRequest.Message("system", "You are an enterprise CRM assistant. Reply concisely in Chinese."),
|
|
|
|
|
|
new ChatRequest.Message("user", userText)
|
|
|
|
|
|
),
|
|
|
|
|
|
0.3
|
|
|
|
|
|
);
|
|
|
|
|
|
ChatResponse response = chatService.chat(new AgentContext(agentId), request);
|
2026-06-12 09:56:34 +08:00
|
|
|
|
return appendDirectoryInfo(response.content(), fromUser);
|
2026-06-08 09:37:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String toWecomText(AgentCapabilityResponse response) {
|
|
|
|
|
|
return """
|
|
|
|
|
|
\u3010%s\u3011
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
\u80fd\u529b\u5206\u7ec4\uff1a%s
|
|
|
|
|
|
\u80fd\u529b\u7f16\u7801\uff1a%s
|
|
|
|
|
|
\u6570\u636e\u6e90\uff1a%s
|
|
|
|
|
|
\u72b6\u6001\uff1a%s
|
|
|
|
|
|
""".formatted(
|
|
|
|
|
|
response.title(),
|
|
|
|
|
|
response.message(),
|
|
|
|
|
|
response.mcpGroup(),
|
|
|
|
|
|
response.intentCode(),
|
|
|
|
|
|
String.join("\u3001", response.dataSources()),
|
|
|
|
|
|
response.status()
|
|
|
|
|
|
).trim();
|
|
|
|
|
|
}
|
2026-06-12 09:56:34 +08:00
|
|
|
|
|
|
|
|
|
|
private String appendDirectoryInfo(String reply, String wecomUserId) {
|
|
|
|
|
|
String text = reply == null || reply.isBlank() ? "" : reply.trim();
|
|
|
|
|
|
return text + "\n\n" + buildDirectoryInfo(wecomUserId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String buildDirectoryInfo(String wecomUserId) {
|
|
|
|
|
|
if (wecomUserId == null || wecomUserId.isBlank()) {
|
|
|
|
|
|
return "【身份信息】\n企业微信账号:未获取\n学邦账号:未匹配\n部门:未匹配\n身份:未匹配";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
return employeeDirectoryService.findByWecomUserId(wecomUserId)
|
|
|
|
|
|
.map(this::formatDirectoryInfo)
|
|
|
|
|
|
.orElse("""
|
|
|
|
|
|
【身份信息】
|
|
|
|
|
|
企业微信账号:%s
|
|
|
|
|
|
学邦账号:未匹配
|
|
|
|
|
|
部门:未匹配
|
|
|
|
|
|
身份:未匹配
|
|
|
|
|
|
""".formatted(wecomUserId).trim());
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.warn("employee directory lookup failed wecomUserId={} err={}", wecomUserId, e.getMessage());
|
|
|
|
|
|
return """
|
|
|
|
|
|
【身份信息】
|
|
|
|
|
|
企业微信账号:%s
|
|
|
|
|
|
学邦账号:查询失败
|
|
|
|
|
|
部门:查询失败
|
|
|
|
|
|
身份:查询失败
|
|
|
|
|
|
""".formatted(wecomUserId).trim();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String formatDirectoryInfo(EmployeeDirectoryResponse response) {
|
|
|
|
|
|
EmployeeAccountMapping account = response.account();
|
|
|
|
|
|
String department = firstNotBlank(account.xuebangPrimaryOrg(), account.wecomDepartmentPath(), "未匹配");
|
|
|
|
|
|
String xuebangAccount = firstNotBlank(account.xuebangAccount(), "未匹配");
|
|
|
|
|
|
String roleName = firstNotBlank(account.primaryRoleName(), "未匹配");
|
|
|
|
|
|
String roleCode = firstNotBlank(account.primaryRoleCode(), "未匹配");
|
|
|
|
|
|
String scopeType = firstNotBlank(account.dataScopeType(), "未匹配");
|
|
|
|
|
|
String roleLevel = account.roleLevel() == null ? "未匹配" : account.roleLevel().toString();
|
|
|
|
|
|
|
|
|
|
|
|
return """
|
|
|
|
|
|
【身份信息】
|
|
|
|
|
|
企业微信账号:%s
|
|
|
|
|
|
学邦账号:%s
|
|
|
|
|
|
部门:%s
|
|
|
|
|
|
身份:%s(%s,级别%s,范围%s)
|
|
|
|
|
|
""".formatted(account.wecomUserId(), xuebangAccount, department, roleName, roleCode, roleLevel, scopeType).trim();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String firstNotBlank(String... values) {
|
|
|
|
|
|
for (String value : values) {
|
|
|
|
|
|
if (value != null && !value.isBlank()) {
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
2026-06-08 09:37:35 +08:00
|
|
|
|
}
|