取代或辅助人工,自动分析新提交的工单内容(文本描述),准确判断其问题类别(Classification)和紧急程度(Sentiment Analysis),并自动分配给最合适的处理团队或工程师。
微服务架构设计:
- 工单接入服务 (Ticket Ingestion Service):接收来自Web前端、邮件或其他渠道的新工单。
- 智能分析服务 (AI Analysis Service):负责调用大模型API对工单内容进行分析。
- 路由决策服务 (Routing Decision Service):根据分析结果和执行规则,决定分配给谁。
- 工单管理服务 (Ticket Management Service):负责工单的持久化、状态更新和分配操作。
- 消息队列 (Message Queue, e.g. RabbitMQ/Kafka):用于服务间的异步通信,解耦并提高可靠性
技术栈选型:
- Java框架: Spring Boot + Spring Cloud Stream (用于消息队列集成)
- 大模型API: OpenAI GPT-4 / GPT-3.5-Turbo 或 Azure OpenAI(企业级首选,因其合规性和安全性更佳) 或 本地部署的Mistral/Mixtral模型。
- 消息队列: RabbitMQ
- 数据库: PostgreSQL (存储工单信息、分析结果、分配记录)
- 向量数据库 (可选,用于高级RAG): Redis with RedisStack (RedisSearch)
- 开发工具: LangChain4j (极大简化LLM集成代码)
一、主要依赖
xml
<!-- LangChain4j for OpenAI -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>0.28.0</version> <!-- 请使用最新版本 -->
</dependency>
<!-- 如果你用Azure OpenAI -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-azure-open-ai</artifactId>
<version>0.28.0</version>
</dependency>
二、创建工单实体和分析结果实体
java
@Entity
public class Ticket {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Column(columnDefinition = "TEXT")
private String description; // 工单详细描述,这是给LLM分析的核心内容
private String submitterEmail;
private LocalDateTime createdAt;
private String status; // e.g., "NEW", "ANALYZING", "ASSIGNED", "CLOSED"
private String assignedTeam; // 被分配到的团队,e.g., "NETWORK", "DATABASE", "BILLING"
// ... getters and setters
}
@Entity
public class TicketAnalysis {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long ticketId;
private String category; // LLM分析出的类别,e.g., "硬件故障", "软件bug", "账户问题"
private String urgency; // LLM分析出的紧急程度,e.g., "高", "中", "低"
private String suggestedTeam; // LLM建议分配的团队
@Column(columnDefinition = "TEXT")
private String reasoning; // LLM做出判断的推理过程,用于审计和调试
private LocalDateTime analyzedAt;
// ... getters and setters
}
三、实现工单接入服务(创建)---发送---监听
java
@RestController
@RequestMapping("/api/tickets")
public class TicketController {
@Autowired
private TicketService ticketService;
@PostMapping
public ResponseEntity<Ticket> createTicket(@RequestBody Ticket ticket) {
ticket.setStatus("NEW");
ticket.setCreatedAt(LocalDateTime.now());
Ticket savedTicket = ticketService.save(ticket);
// 发送消息到消息队列,触发后续分析
ticketService.notifyNewTicket(savedTicket);
return ResponseEntity.ok(savedTicket);
}
}
java
@Service
@EnableBinding(Source.class) // Spring Cloud Stream 旧版注解,新版本可用函数式方式
public class TicketService {
@Autowired
private Source source;
public void notifyNewTicket(Ticket ticket) {
source.output().send(MessageBuilder.withPayload(ticket.getId()).build());
}
}
java
@Service
@EnableBinding(Sink.class)
public class TicketAnalysisListener {
@Autowired
private TicketAnalysisService analysisService;
@StreamListener(Sink.INPUT)
public void handleNewTicket(Long ticketId) {
analysisService.analyzeAndRouteTicket(ticketId);
}
}
四、构建核心------智能分析服务
①、LLM客户端
yml
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: "gpt-3.5-turbo" # 或者 "gpt-4"
temperature: 0.0 # 越低输出越确定
max-tokens: 500
②、设计Prompt
设计一个结构化的Prompt是成功的关键。它需要明确指令、格式和示例。
③、实现分析服务
java
@Service
public class TicketAnalysisService {
@Autowired
private TicketRepository ticketRepository;
@Autowired
private TicketAnalysisRepository analysisRepository;
@Autowired
private RoutingDecisionService routingService;
// 注入LangChain4j的OpenAiChatModel
private final OpenAiChatModel chatModel;
public TicketAnalysisService(OpenAiChatModel chatModel) {
this.chatModel = chatModel;
}
@Transactional
public void analyzeAndRouteTicket(Long ticketId) {
Ticket ticket = ticketRepository.findById(ticketId)
.orElseThrow(() -> new RuntimeException("Ticket not found: " + ticketId));
// 更新状态为分析中
ticket.setStatus("ANALYZING");
ticketRepository.save(ticket);
// 构建Prompt
String prompt = """
你是一个资深的IT支持专家。请分析以下工单描述,并严格按照JSON格式输出分析结果。
工单标题: %s
工单描述: %s
请执行以下步骤:
1. **分类**:判断问题属于哪个类别("NETWORK", "SERVER", "DATABASE", "APPLICATION", "BILLING", "ACCOUNT", "OTHER")。
2. **紧急程度**:判断紧急程度("HIGH", "MEDIUM", "LOW")。依据:是否影响大量用户、是否导致业务完全中断、用户情绪是否激动。
3. **建议分配团队**:根据分类,建议应分配给哪个团队处理。
4. **推理**:用一句话简要说明你的推理原因。
输出格式必须是以下JSON,不要有任何其他文字:
{
"category": "分类结果",
"urgency": "紧急程度",
"suggestedTeam": "建议团队",
"reasoning": "你的推理"
}
""".formatted(ticket.getTitle(), ticket.getDescription());
// 调用LLM
String aiResponse = chatModel.generate(prompt);
// 解析LLM的JSON响应 (这里需要简单的JSON解析)
TicketAnalysis analysis = parseAiResponse(aiResponse);
analysis.setTicketId(ticketId);
analysis.setAnalyzedAt(LocalDateTime.now());
analysisRepository.save(analysis);
// 将分析结果传递给路由决策服务
routingService.makeRoutingDecision(ticketId, analysis);
}
private TicketAnalysis parseAiResponse(String jsonResponse) {
// 使用Jackson或Gson解析JSON字符串到TicketAnalysis对象
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(jsonResponse, TicketAnalysis.class);
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to parse AI response", e);
}
}
}
④、实现路由决策服务
决策服务可以包含简单的规则引擎,例如即使LLM建议分配给"NETWORK"团队,但如果紧急程度为"HIGH",则可能直接分配给"NETWORK_ON_CALL"团队。
java
@Service
public class RoutingDecisionService {
@Autowired
private TicketRepository ticketRepository;
public void makeRoutingDecision(Long ticketId, TicketAnalysis analysis) {
Ticket ticket = ticketRepository.findById(ticketId).orElseThrow();
String finalTeam = analysis.getSuggestedTeam();
// 示例:简单的规则覆盖
if ("HIGH".equals(analysis.getUrgency()) && "NETWORK".equals(finalTeam)) {
finalTeam = "NETWORK_ON_CALL"; // 网络团队 on-call 小组
}
if ("BILLING".equals(finalTeam) && analysis.getReasoning().toLowerCase().contains("refund")) {
finalTeam = "BILLING_SUPERVISOR"; // 退款问题需要主管处理
}
// 执行分配
ticket.setAssignedTeam(finalTeam);
ticket.setStatus("ASSIGNED");
ticketRepository.save(ticket);
// TODO: 这里可以触发邮件或通知,告知团队有新工单分配
System.out.println("Ticket #" + ticketId + " assigned to team: " + finalTeam);
}
}