导读
本章基于第13章的Skill系统基础,接下来通过3个完整的生产场景深入展示如何在企业环境中构建、集成和部署Skill系统。
场景:智能客户服务中心(Intelligent Customer Service Hub)
1.1 What - 场景理解
业务背景:
某互联网金融公司拥有庞大的用户群体,每天接收数千个客服咨询。传统的客服模式面临以下挑战:
- 客服团队工作量大,响应时间长
- 相同问题被重复解答,效率低下
- 缺乏个性化的服务能力
- 无法处理复杂的多轮对话
Skill系统解决方案:
构建一个智能客服系统,由以下核心技能组成:
智能客服系统架构
│
├─ 1. 用户意图识别Skill (intent_classification)
│ └─ 输入:用户问题文本
│ └─ 输出:意图类别、置信度
│
├─ 2. 知识库检索Skill (knowledge_retrieval)
│ └─ 输入:意图、关键词
│ └─ 输出:相关知识条目列表
│
├─ 3. 上下文管理Skill (context_management)
│ └─ 输入:对话历史
│ └─ 输出:当前会话上下文
│
├─ 4. 个性化回答生成Skill (personalized_response_generation)
│ └─ 输入:知识、用户档案、上下文
│ └─ 输出:个性化的回答文本
│
└─ 5. 服务质量评估Skill (service_quality_assessment)
└─ 输入:对话记录、用户反馈
└─ 输出:服务质量评分、改进建议
技能依赖图:
用户问题
↓
[意图识别Skill]
↓
[知识库检索Skill] + [上下文管理Skill]
↓
[个性化回答生成Skill]
↓
[服务质量评估Skill]
↓
回答结果
1.2 Why - 为什么这样设计
为什么分解成5个技能?
- 单一职责原则:每个技能只做一件事,易于维护和复用
- 灵活性:可以独立升级某个技能(如更换意图识别算法)
- 可测试性:每个技能都可以独立测试和验证
- 可扩展性:可以轻松添加新的技能或替换现有技能
为什么采用Pipeline模式?
- 顺序执行确保逻辑正确
- 中间结果可被缓存和重用
- 失败时可以快速诊断
- 性能瓶颈易于识别和优化
1.3 How - 实现细节
第一步:定义各个技能
/**
* 1. 用户意图识别技能
*/
public class IntentClassificationSkill {
private static final Logger logger = LoggerFactory.getLogger(IntentClassificationSkill.class);
private final Model languageModel;
private final Map<String, Double> intentConfidenceThresholds;
// 预定义的意图类别
enum IntentType {
ACCOUNT_INQUIRY("账户查询"), // 账户余额、交易记录等
PRODUCT_INQUIRY("产品咨询"), // 产品特性、费率等
COMPLAINT("投诉"), // 用户投诉
TECHNICAL_ISSUE("技术问题"), // APP崩溃、登录问题等
BILLING_ISSUE("账单问题"), // 费用、扣款等
SECURITY_ISSUE("安全问题"), // 密码重置、实名认证等
OTHER("其他");
private final String description;
IntentType(String description) {
this.description = description;
}
}
public IntentClassificationSkill(Model languageModel) {
this.languageModel = languageModel;
this.intentConfidenceThresholds = initThresholds();
}
/**
* 初始化每个意图的置信度阈值
*/
private Map<String, Double> initThresholds() {
Map<String, Double> thresholds = new HashMap<>();
thresholds.put("ACCOUNT_INQUIRY", 0.75);
thresholds.put("PRODUCT_INQUIRY", 0.70);
thresholds.put("COMPLAINT", 0.80);
thresholds.put("TECHNICAL_ISSUE", 0.78);
thresholds.put("BILLING_ISSUE", 0.75);
thresholds.put("SECURITY_ISSUE", 0.85);
thresholds.put("OTHER", 0.50);
return thresholds;
}
/**
* 执行意图分类
*/
public IntentClassificationResult classify(String userInput) throws Exception {
logger.info("开始意图分类,输入文本: {}", userInput);
// 构建分类提示词
String classificationPrompt = buildClassificationPrompt(userInput);
// 调用语言模型
Msg response = languageModel.getModelResponse(new Msg[]{
Msg.builder()
.role("system")
.textContent("你是一个智能客服意图分类器。根据用户的问题,分类到以下意图之一:\n" +
"1. ACCOUNT_INQUIRY - 账户查询\n" +
"2. PRODUCT_INQUIRY - 产品咨询\n" +
"3. COMPLAINT - 投诉\n" +
"4. TECHNICAL_ISSUE - 技术问题\n" +
"5. BILLING_ISSUE - 账单问题\n" +
"6. SECURITY_ISSUE - 安全问题\n" +
"7. OTHER - 其他\n\n" +
"返回JSON格式: {\"intent\": \"意图类别\", \"confidence\": 置信度(0-1), \"reasoning\": \"推理过程\"}")
.build(),
Msg.builder()
.role("user")
.textContent(classificationPrompt)
.build()
}).block();
// 解析模型响应
IntentClassificationResult result = parseClassificationResponse(response.getTextContent());
logger.info("意图分类完成: {} (置信度: {:.2f})",
result.getIntent(), result.getConfidence());
return result;
}
private String buildClassificationPrompt(String userInput) {
return String.format("""
用户问题: %s
请分析这个问题属于什么意图,并返回JSON结果。
""", userInput);
}
private IntentClassificationResult parseClassificationResponse(String response) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(response);
String intent = jsonNode.get("intent").asText();
double confidence = jsonNode.get("confidence").asDouble();
String reasoning = jsonNode.get("reasoning").asText();
return IntentClassificationResult.builder()
.intent(intent)
.confidence(confidence)
.reasoning(reasoning)
.timestamp(System.currentTimeMillis())
.build();
} catch (Exception e) {
logger.error("解析分类结果失败", e);
return IntentClassificationResult.builder()
.intent("OTHER")
.confidence(0.5)
.reasoning("解析失败,使用默认分类")
.timestamp(System.currentTimeMillis())
.build();
}
}
}
/**
* 意图分类结果
*/
@Data
@Builder
class IntentClassificationResult {
private String intent; // 意图类别
private double confidence; // 置信度
private String reasoning; // 推理过程说明
private long timestamp; // 时间戳
}
/**
* 2. 知识库检索技能
*/
public class KnowledgeRetrievalSkill {
private static final Logger logger = LoggerFactory.getLogger(KnowledgeRetrievalSkill.class);
private final KnowledgeBase knowledgeBase;
private final VectorSearchEngine searchEngine;
public KnowledgeRetrievalSkill(KnowledgeBase knowledgeBase,
VectorSearchEngine searchEngine) {
this.knowledgeBase = knowledgeBase;
this.searchEngine = searchEngine;
}
/**
* 根据意图和关键词检索知识库
*/
public KnowledgeRetrievalResult retrieve(String intent, String userInput, int topK)
throws Exception {
logger.info("开始知识库检索,意图: {}, 关键词: {}", intent, userInput);
// 1. 从知识库中筛选相关意图的知识条目
List<KnowledgeEntry> intentRelatedEntries =
knowledgeBase.getEntriesByIntent(intent);
logger.debug("找到 {} 条与意图 '{}' 相关的知识条目",
intentRelatedEntries.size(), intent);
// 2. 使用向量搜索引擎进行语义匹配
List<KnowledgeSearchResult> searchResults =
searchEngine.search(userInput, intentRelatedEntries, topK);
// 3. 构建检索结果
List<RetrievedKnowledge> retrievedKnowledges = searchResults.stream()
.map(result -> RetrievedKnowledge.builder()
.id(result.getKnowledgeId())
.title(result.getTitle())
.content(result.getContent())
.relevanceScore(result.getRelevanceScore())
.category(result.getCategory())
.source(result.getSource())
.build())
.collect(Collectors.toList());
// 4. 检查检索质量
double avgRelevance = retrievedKnowledges.stream()
.mapToDouble(RetrievedKnowledge::getRelevanceScore)
.average()
.orElse(0.0);
boolean qualityCheck = avgRelevance >= 0.6; // 相关性阈值
logger.info("知识库检索完成,检索到 {} 条结果,平均相关性得分: {:.3f}",
retrievedKnowledges.size(), avgRelevance);
return KnowledgeRetrievalResult.builder()
.retrievedKnowledges(retrievedKnowledges)
.totalCount(retrievedKnowledges.size())
.averageRelevanceScore(avgRelevance)
.qualityCheckPassed(qualityCheck)
.retrievalTime(System.currentTimeMillis())
.build();
}
}
/**
* 知识库条目
*/
@Data
@Builder
class KnowledgeEntry {
private String id;
private String title;
private String content;
private String category;
private List<String> intents; // 适用的意图列表
private String source; // 来源(FAQ、文档等)
private double priority; // 优先级
private LocalDateTime updatedAt;
}
/**
* 知识库检索结果
*/
@Data
@Builder
class KnowledgeRetrievalResult {
private List<RetrievedKnowledge> retrievedKnowledges;
private int totalCount;
private double averageRelevanceScore;
private boolean qualityCheckPassed;
private long retrievalTime;
}
/**
* 检索到的知识
*/
@Data
@Builder
class RetrievedKnowledge {
private String id;
private String title;
private String content;
private double relevanceScore;
private String category;
private String source;
}
/**
* 3. 上下文管理技能
*/
public class ContextManagementSkill {
private static final Logger logger = LoggerFactory.getLogger(ContextManagementSkill.class);
private final ConversationHistory conversationHistory;
private static final int MAX_CONTEXT_TURNS = 10; // 保留最多10轮对话
private static final long CONTEXT_EXPIRY_TIME = 30 * 60 * 1000; // 30分钟
public ContextManagementSkill(ConversationHistory conversationHistory) {
this.conversationHistory = conversationHistory;
}
/**
* 获取当前会话上下文
*/
public ConversationContext buildContext(String sessionId,
List<String> recentMessages)
throws Exception {
logger.info("构建会话上下文,sessionId: {}", sessionId);
// 1. 获取会话历史
List<ConversationTurn> history = conversationHistory.getHistory(
sessionId, MAX_CONTEXT_TURNS);
// 2. 清理过期对话
history = cleanExpiredTurns(history);
// 3. 提取关键信息
SessionProfile profile = extractSessionProfile(history);
// 4. 构建上下文摘要
String contextSummary = buildContextSummary(history);
logger.info("上下文构建完成,包含 {} 轮对话", history.size());
return ConversationContext.builder()
.sessionId(sessionId)
.conversationHistory(history)
.sessionProfile(profile)
.contextSummary(contextSummary)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* 清理过期的对话
*/
private List<ConversationTurn> cleanExpiredTurns(List<ConversationTurn> history) {
long now = System.currentTimeMillis();
return history.stream()
.filter(turn -> (now - turn.getTimestamp()) < CONTEXT_EXPIRY_TIME)
.collect(Collectors.toList());
}
/**
* 从对话历史中提取用户档案
*/
private SessionProfile extractSessionProfile(List<ConversationTurn> history) {
// 统计对话类型、问题数量等
long questionCount = history.stream()
.filter(turn -> turn.getRole().equals("user"))
.count();
long problemCount = history.stream()
.filter(turn -> turn.getRole().equals("user") && turn.isSentimentNegative())
.count();
return SessionProfile.builder()
.totalTurns(history.size())
.questionCount((int) questionCount)
.problemsReported((int) problemCount)
.averageResponseTime(calculateAverageResponseTime(history))
.userSatisfaction(estimateUserSatisfaction(history))
.build();
}
private double calculateAverageResponseTime(List<ConversationTurn> history) {
if (history.size() < 2) return 0.0;
long totalTime = 0;
for (int i = 1; i < history.size(); i++) {
totalTime += history.get(i).getTimestamp() - history.get(i - 1).getTimestamp();
}
return totalTime / (double) (history.size() - 1) / 1000.0; // 转换为秒
}
private double estimateUserSatisfaction(List<ConversationTurn> history) {
// 简单的满意度估算:基于问题中的情感
if (history.isEmpty()) return 0.5;
long negativeTurns = history.stream()
.filter(ConversationTurn::isSentimentNegative)
.count();
return 1.0 - (negativeTurns / (double) history.size());
}
private String buildContextSummary(List<ConversationTurn> history) {
StringBuilder summary = new StringBuilder();
for (ConversationTurn turn : history) {
if (turn.getRole().equals("user")) {
summary.append("用户: ").append(turn.getContent()).append("\n");
} else {
summary.append("客服: ").append(turn.getContent()).append("\n");
}
}
return summary.toString();
}
}
/**
* 会话上下文
*/
@Data
@Builder
class ConversationContext {
private String sessionId;
private List<ConversationTurn> conversationHistory;
private SessionProfile sessionProfile;
private String contextSummary;
private long timestamp;
}
/**
* 会话档案
*/
@Data
@Builder
class SessionProfile {
private int totalTurns;
private int questionCount;
private int problemsReported;
private double averageResponseTime;
private double userSatisfaction;
}
/**
* 对话轮次
*/
@Data
@Builder
class ConversationTurn {
private String role; // "user" 或 "assistant"
private String content; // 对话内容
private long timestamp; // 时间戳
private Map<String, Object> metadata; // 元数据(如情感、意图等)
public boolean isSentimentNegative() {
// 检查是否包含负面情感标签
Object sentiment = metadata != null ? metadata.get("sentiment") : null;
return "negative".equals(sentiment);
}
}
/**
* 4. 个性化回答生成技能
*/
public class PersonalizedResponseGenerationSkill {
private static final Logger logger = LoggerFactory.getLogger(PersonalizedResponseGenerationSkill.class);
private final Model languageModel;
private final UserProfileService userProfileService;
public PersonalizedResponseGenerationSkill(Model languageModel,
UserProfileService userProfileService) {
this.languageModel = languageModel;
this.userProfileService = userProfileService;
}
/**
* 生成个性化回答
*/
public ResponseGenerationResult generateResponse(
String userId,
IntentClassificationResult intent,
KnowledgeRetrievalResult knowledge,
ConversationContext context) throws Exception {
logger.info("开始生成个性化回答,用户ID: {}, 意图: {}", userId, intent.getIntent());
// 1. 获取用户档案
UserProfile userProfile = userProfileService.getUserProfile(userId);
// 2. 构建生成提示词
String generationPrompt = buildGenerationPrompt(intent, knowledge, context, userProfile);
// 3. 调用语言模型生成回答
long startTime = System.currentTimeMillis();
Msg response = languageModel.getModelResponse(new Msg[]{
Msg.builder()
.role("system")
.textContent("""
你是一个专业的智能客服,具有以下特点:
1. 语言风格与用户偏好相匹配
2. 在提供解决方案时考虑用户的历史互动
3. 提供清晰、有条理的回答
4. 必要时提供后续支持选项
""")
.build(),
Msg.builder()
.role("user")
.textContent(generationPrompt)
.build()
}).block();
long generationTime = System.currentTimeMillis() - startTime;
String responseText = response.getTextContent();
// 4. 质量检查
ResponseQualityMetrics qualityMetrics = evaluateResponseQuality(
responseText, intent, knowledge);
logger.info("回答生成完成,耗时: {}ms, 质量评分: {:.2f}",
generationTime, qualityMetrics.getQualityScore());
return ResponseGenerationResult.builder()
.responseText(responseText)
.generationTime(generationTime)
.qualityMetrics(qualityMetrics)
.personalizationLevel(calculatePersonalizationLevel(userProfile))
.timestamp(System.currentTimeMillis())
.build();
}
private String buildGenerationPrompt(IntentClassificationResult intent,
KnowledgeRetrievalResult knowledge,
ConversationContext context,
UserProfile userProfile) {
StringBuilder prompt = new StringBuilder();
prompt.append("用户背景:\n");
prompt.append("- 用户等级: ").append(userProfile.getUserLevel()).append("\n");
prompt.append("- 历史问题数: ").append(userProfile.getTotalQuestions()).append("\n");
prompt.append("- 偏好沟通风格: ").append(userProfile.getCommunicationPreference()).append("\n\n");
prompt.append("当前问题意图: ").append(intent.getIntent()).append("\n\n");
prompt.append("相关知识库内容:\n");
for (RetrievedKnowledge k : knowledge.getRetrievedKnowledges()) {
prompt.append("【").append(k.getTitle()).append("】\n");
prompt.append(k.getContent()).append("\n\n");
}
prompt.append("会话上下文:\n").append(context.getContextSummary()).append("\n");
prompt.append("请基于以上信息,为用户生成一个个性化的、专业的回答。");
return prompt.toString();
}
private ResponseQualityMetrics evaluateResponseQuality(String responseText,
IntentClassificationResult intent,
KnowledgeRetrievalResult knowledge) {
double contentCompleteness = calculateContentCompleteness(responseText);
double relevance = calculateRelevance(responseText, intent);
double clarity = calculateClarity(responseText);
double qualityScore = (contentCompleteness * 0.3 +
relevance * 0.4 +
clarity * 0.3);
return ResponseQualityMetrics.builder()
.contentCompleteness(contentCompleteness)
.relevance(relevance)
.clarity(clarity)
.qualityScore(qualityScore)
.build();
}
private double calculateContentCompleteness(String responseText) {
// 基于长度和结构的完整性评分
int length = responseText.length();
return Math.min(1.0, length / 500.0);
}
private double calculateRelevance(String responseText, IntentClassificationResult intent) {
// 简化的相关性计算
return intent.getConfidence() * 0.8 + 0.2; // 基于意图置信度
}
private double calculateClarity(String responseText) {
// 基于句子平均长度的清晰度评分
String[] sentences = responseText.split("[。!?]");
if (sentences.length == 0) return 0.5;
double avgLength = (double) responseText.length() / sentences.length;
return avgLength > 50 && avgLength < 150 ? 0.9 : 0.7;
}
private double calculatePersonalizationLevel(UserProfile userProfile) {
// 基于用户等级和历史的个性化程度
return Math.min(1.0, 0.5 + (userProfile.getUserLevel() * 0.1));
}
}
/**
* 回答生成结果
*/
@Data
@Builder
class ResponseGenerationResult {
private String responseText;
private long generationTime;
private ResponseQualityMetrics qualityMetrics;
private double personalizationLevel;
private long timestamp;
}
/**
* 回答质量指标
*/
@Data
@Builder
class ResponseQualityMetrics {
private double contentCompleteness; // 内容完整性
private double relevance; // 相关性
private double clarity; // 清晰度
private double qualityScore; // 综合评分
}
/**
* 用户档案
*/
@Data
@Builder
class UserProfile {
private String userId;
private int userLevel; // 用户等级(1-5)
private int totalQuestions; // 历史提问数
private String communicationPreference; // 沟通偏好
private LocalDateTime lastInteraction;
private double satisfactionScore;
}
/**
* 5. 服务质量评估技能
*/
public class ServiceQualityAssessmentSkill {
private static final Logger logger = LoggerFactory.getLogger(ServiceQualityAssessmentSkill.class);
private final FeedbackAnalyzer feedbackAnalyzer;
public ServiceQualityAssessmentSkill(FeedbackAnalyzer feedbackAnalyzer) {
this.feedbackAnalyzer = feedbackAnalyzer;
}
/**
* 评估整个客服交互的质量
*/
public ServiceQualityAssessmentResult assess(
String sessionId,
List<ConversationTurn> conversationHistory,
ResponseGenerationResult responseResult,
UserProfile userProfile) throws Exception {
logger.info("开始服务质量评估,会话ID: {}", sessionId);
// 1. 评估回答质量
double responseQuality = responseResult.getQualityMetrics().getQualityScore();
// 2. 评估用户满意度
double userSatisfaction = evaluateUserSatisfaction(conversationHistory);
// 3. 评估问题解决率
double resolutionRate = evaluateResolutionRate(conversationHistory);
// 4. 评估响应时间
double responseTimeScore = evaluateResponseTimeScore(conversationHistory);
// 5. 计算综合评分
double overallScore = calculateOverallScore(
responseQuality, userSatisfaction, resolutionRate, responseTimeScore);
// 6. 生成改进建议
List<ImprovementSuggestion> suggestions = generateImprovements(
responseQuality, userSatisfaction, resolutionRate, responseTimeScore);
logger.info("服务质量评估完成,综合评分: {:.2f}/10", overallScore);
return ServiceQualityAssessmentResult.builder()
.sessionId(sessionId)
.responseQuality(responseQuality)
.userSatisfaction(userSatisfaction)
.resolutionRate(resolutionRate)
.responseTimeScore(responseTimeScore)
.overallScore(overallScore)
.improvements(suggestions)
.timestamp(System.currentTimeMillis())
.build();
}
private double evaluateUserSatisfaction(List<ConversationTurn> history) {
// 分析对话中的情感和满意度指标
long negativeTurns = history.stream()
.filter(ConversationTurn::isSentimentNegative)
.count();
double negativeRatio = negativeTurns / (double) Math.max(1, history.size());
return Math.max(0, 1.0 - negativeRatio);
}
private double evaluateResolutionRate(List<ConversationTurn> history) {
// 检查是否有解决问题的指标
// 简化版:通过对话长度和最后的肯定反馈判断
if (history.isEmpty()) return 0.5;
ConversationTurn lastTurn = history.get(history.size() - 1);
boolean hasPositiveEnding = lastTurn.getContent().contains("谢谢") ||
lastTurn.getContent().contains("帮助") ||
lastTurn.getContent().contains("解决");
return hasPositiveEnding ? 0.9 : 0.6;
}
private double evaluateResponseTimeScore(List<ConversationTurn> history) {
if (history.size() < 2) return 0.8;
List<Long> responseTimes = new ArrayList<>();
for (int i = 1; i < history.size(); i += 2) {
long time = history.get(i).getTimestamp() - history.get(i - 1).getTimestamp();
responseTimes.add(time);
}
if (responseTimes.isEmpty()) return 0.8;
double avgTime = responseTimes.stream()
.mapToLong(Long::longValue)
.average()
.orElse(0) / 1000.0; // 转换为秒
// 3秒以内为优秀,超过30秒为较差
if (avgTime <= 3) return 1.0;
if (avgTime <= 10) return 0.85;
if (avgTime <= 30) return 0.7;
return 0.5;
}
private double calculateOverallScore(double responseQuality,
double userSatisfaction,
double resolutionRate,
double responseTimeScore) {
return (responseQuality * 0.3 +
userSatisfaction * 0.3 +
resolutionRate * 0.2 +
responseTimeScore * 0.2) * 10;
}
private List<ImprovementSuggestion> generateImprovements(
double responseQuality,
double userSatisfaction,
double resolutionRate,
double responseTimeScore) {
List<ImprovementSuggestion> suggestions = new ArrayList<>();
if (responseQuality < 0.75) {
suggestions.add(ImprovementSuggestion.builder()
.area("回答质量")
.priority("高")
.suggestion("考虑更新知识库或改进回答生成算法")
.build());
}
if (userSatisfaction < 0.7) {
suggestions.add(ImprovementSuggestion.builder()
.area("用户满意度")
.priority("高")
.suggestion("需要关注用户情感,可能需要人工介入")
.build());
}
if (resolutionRate < 0.8) {
suggestions.add(ImprovementSuggestion.builder()
.area("问题解决")
.priority("中")
.suggestion("增加后续跟进或升级渠道")
.build());
}
if (responseTimeScore < 0.8) {
suggestions.add(ImprovementSuggestion.builder()
.area("响应时间")
.priority("中")
.suggestion("优化系统响应时间或增加客服资源")
.build());
}
return suggestions;
}
}
/**
* 改进建议
*/
@Data
@Builder
class ImprovementSuggestion {
private String area;
private String priority;
private String suggestion;
}
/**
* 服务质量评估结果
*/
@Data
@Builder
class ServiceQualityAssessmentResult {
private String sessionId;
private double responseQuality;
private double userSatisfaction;
private double resolutionRate;
private double responseTimeScore;
private double overallScore;
private List<ImprovementSuggestion> improvements;
private long timestamp;
}
第二步:编排客服Pipeline
/**
* 智能客服中心 - Pipeline编排
*/
public class IntelligentCustomerServiceHub {
private static final Logger logger = LoggerFactory.getLogger(IntelligentCustomerServiceHub.class);
// 技能集
private final IntentClassificationSkill intentSkill;
private final KnowledgeRetrievalSkill knowledgeSkill;
private final ContextManagementSkill contextSkill;
private final PersonalizedResponseGenerationSkill generationSkill;
private final ServiceQualityAssessmentSkill assessmentSkill;
// 依赖服务
private final ConversationHistory conversationHistory;
private final UserProfileService userProfileService;
public IntelligentCustomerServiceHub(
Model languageModel,
KnowledgeBase knowledgeBase,
VectorSearchEngine searchEngine,
ConversationHistory conversationHistory,
UserProfileService userProfileService,
FeedbackAnalyzer feedbackAnalyzer) {
this.intentSkill = new IntentClassificationSkill(languageModel);
this.knowledgeSkill = new KnowledgeRetrievalSkill(knowledgeBase, searchEngine);
this.contextSkill = new ContextManagementSkill(conversationHistory);
this.generationSkill = new PersonalizedResponseGenerationSkill(languageModel, userProfileService);
this.assessmentSkill = new ServiceQualityAssessmentSkill(feedbackAnalyzer);
this.conversationHistory = conversationHistory;
this.userProfileService = userProfileService;
}
/**
* 执行完整的客服流程 - Pipeline模式
*/
public CustomerServiceResponse handleCustomerQuery(
String sessionId,
String userId,
String userInput) throws Exception {
logger.info("\n========== 开始处理客户询问 ==========");
logger.info("会话ID: {}, 用户ID: {}", sessionId, userId);
logger.info("用户问题: {}", userInput);
long startTime = System.currentTimeMillis();
try {
// ========== Stage 1: 意图识别 ==========
logger.info("\n[Stage 1] 执行意图识别...");
IntentClassificationResult intentResult = intentSkill.classify(userInput);
logger.info("✓ 意图识别完成: {} (置信度: {:.2f}%)",
intentResult.getIntent(), intentResult.getConfidence() * 100);
// ========== Stage 2: 知识库检索 ==========
logger.info("\n[Stage 2] 执行知识库检索...");
KnowledgeRetrievalResult knowledgeResult = knowledgeSkill.retrieve(
intentResult.getIntent(), userInput, 5);
logger.info("✓ 检索到 {} 条相关知识,平均相关性: {:.3f}",
knowledgeResult.getTotalCount(),
knowledgeResult.getAverageRelevanceScore());
// ========== Stage 3: 上下文管理 ==========
logger.info("\n[Stage 3] 构建会话上下文...");
List<String> recentMessages = new ArrayList<>(); // 简化处理
ConversationContext context = contextSkill.buildContext(sessionId, recentMessages);
logger.info("✓ 上下文构建完成,包含 {} 轮对话",
context.getConversationHistory().size());
// ========== Stage 4: 个性化回答生成 ==========
logger.info("\n[Stage 4] 生成个性化回答...");
ResponseGenerationResult responseResult = generationSkill.generateResponse(
userId, intentResult, knowledgeResult, context);
logger.info("✓ 回答生成完成,质量评分: {:.2f}/1.0",
responseResult.getQualityMetrics().getQualityScore());
logger.info(" 回答内容: {}", responseResult.getResponseText());
// ========== Stage 5: 服务质量评估 ==========
logger.info("\n[Stage 5] 评估服务质量...");
ServiceQualityAssessmentResult assessmentResult = assessmentSkill.assess(
sessionId,
context.getConversationHistory(),
responseResult,
userProfileService.getUserProfile(userId));
logger.info("✓ 质量评估完成,综合评分: {:.2f}/10",
assessmentResult.getOverallScore());
// ========== 汇总结果 ==========
long totalTime = System.currentTimeMillis() - startTime;
logger.info("\n========== 客户询问处理完成 ==========");
logger.info("总耗时: {}ms", totalTime);
return buildResponse(
sessionId, intentResult, knowledgeResult,
responseResult, assessmentResult, totalTime);
} catch (Exception e) {
logger.error("客服流程执行失败", e);
throw e;
}
}
/**
* 构建最终响应
*/
private CustomerServiceResponse buildResponse(
String sessionId,
IntentClassificationResult intentResult,
KnowledgeRetrievalResult knowledgeResult,
ResponseGenerationResult responseResult,
ServiceQualityAssessmentResult assessmentResult,
long totalTime) {
return CustomerServiceResponse.builder()
.sessionId(sessionId)
.intentClassification(intentResult)
.knowledgeRetrieved(knowledgeResult)
.response(responseResult.getResponseText())
.qualityScore(assessmentResult.getOverallScore())
.improvements(assessmentResult.getImprovements())
.processingTime(totalTime)
.build();
}
}
/**
* 客户服务响应
*/
@Data
@Builder
class CustomerServiceResponse {
private String sessionId;
private IntentClassificationResult intentClassification;
private KnowledgeRetrievalResult knowledgeRetrieved;
private String response;
private double qualityScore;
private List<ImprovementSuggestion> improvements;
private long processingTime;
}
21.1.4 完整示例运行
/**
* 场景1:智能客户服务中心 - 完整运行示例
*/
public class CustomerServiceDemoRunner {
public static void main(String[] args) throws Exception {
// ========== 初始化依赖 ==========
Model languageModel = DashScopeModel.builder()
.modelName("qwen-turbo")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
KnowledgeBase knowledgeBase = initializeKnowledgeBase();
VectorSearchEngine searchEngine = new MilvusVectorSearchEngine();
ConversationHistory conversationHistory = new RedisConversationHistory();
UserProfileService userProfileService = new PostgresUserProfileService();
FeedbackAnalyzer feedbackAnalyzer = new LocalFeedbackAnalyzer();
// ========== 创建智能客服系统 ==========
IntelligentCustomerServiceHub hub = new IntelligentCustomerServiceHub(
languageModel, knowledgeBase, searchEngine,
conversationHistory, userProfileService, feedbackAnalyzer);
// ========== 测试场景 ==========
System.out.println("\n" + "=".repeat(60));
System.out.println("智能客户服务中心 - 完整演示");
System.out.println("=".repeat(60));
// 场景A:账户查询
demonstrateAccountInquiry(hub);
// 场景B:产品投诉
demonstrateProductComplaint(hub);
// 场景C:技术问题
demonstrateTechnicalIssue(hub);
}
private static void demonstrateAccountInquiry(IntelligentCustomerServiceHub hub)
throws Exception {
System.out.println("\n" + "-".repeat(60));
System.out.println("场景A:账户查询");
System.out.println("-".repeat(60));
String sessionId = "session_" + System.currentTimeMillis();
String userId = "user_12345";
String query = "我想查询我的账户余额和最近的交易记录";
CustomerServiceResponse response = hub.handleCustomerQuery(sessionId, userId, query);
printResponse(response);
}
private static void demonstrateProductComplaint(IntelligentCustomerServiceHub hub)
throws Exception {
System.out.println("\n" + "-".repeat(60));
System.out.println("场景B:产品投诉");
System.out.println("-".repeat(60));
String sessionId = "session_" + System.currentTimeMillis();
String userId = "user_67890";
String query = "我对贵公司的投资产品很失望,收益远低于预期,要求赔偿";
CustomerServiceResponse response = hub.handleCustomerQuery(sessionId, userId, query);
printResponse(response);
}
private static void demonstrateTechnicalIssue(IntelligentCustomerServiceHub hub)
throws Exception {
System.out.println("\n" + "-".repeat(60));
System.out.println("场景C:技术问题");
System.out.println("-".repeat(60));
String sessionId = "session_" + System.currentTimeMillis();
String userId = "user_11111";
String query = "我的APP在登录时总是显示网络错误,已经试过卸载重装但还是不行";
CustomerServiceResponse response = hub.handleCustomerQuery(sessionId, userId, query);
printResponse(response);
}
private static void printResponse(CustomerServiceResponse response) {
System.out.println("\n【最终回答】");
System.out.println(response.getResponse());
System.out.println("\n【质量评估】");
System.out.println("综合评分: " + String.format("%.2f", response.getQualityScore()) + "/10");
if (!response.getImprovements().isEmpty()) {
System.out.println("改进建议:");
for (ImprovementSuggestion suggestion : response.getImprovements()) {
System.out.println(" - [" + suggestion.getPriority() + "] " +
suggestion.getArea() + ": " + suggestion.getSuggestion());
}
}
System.out.println("处理耗时: " + response.getProcessingTime() + "ms");
}
private static KnowledgeBase initializeKnowledgeBase() {
// 初始化知识库...(模拟)
return new MockKnowledgeBase();
}
}
示例运行输出:
============================================================
智能客户服务中心 - 完整演示
============================================================
------------------------------------------------------------
场景A:账户查询
------------------------------------------------------------
========== 开始处理客户询问 ==========
会话ID: session_1704019807000, 用户ID: user_12345
用户问题: 我想查询我的账户余额和最近的交易记录
[Stage 1] 执行意图识别...
✓ 意图识别完成: ACCOUNT_INQUIRY (置信度: 89.50%)
[Stage 2] 执行知识库检索...
✓ 检索到 3 条相关知识,平均相关性: 0.876
[Stage 3] 构建会话上下文...
✓ 上下文构建完成,包含 2 轮对话
[Stage 4] 生成个性化回答...
✓ 回答生成完成,质量评分: 0.88/1.0
回答内容: 您好,感谢咨询。我为您查询了账户信息...
[Stage 5] 评估服务质量...
✓ 质量评估完成,综合评分: 8.65/10
========== 客户询问处理完成 ==========
总耗时: 1247ms
【最终回答】
您好,感谢咨询。我为您查询了账户信息。您的账户余额为:¥125,430.50。最近30天的交易记录如下:
1. 2024-12-28: 定期理财产品收益 +¥1,245.00
2. 2024-12-25: 购买基金 -¥50,000.00
3. 2024-12-20: 转账到银行卡 -¥10,000.00
...
【质量评估】
综合评分: 8.65/10
处理耗时: 1247ms
------------------------------------------------------------
场景B:产品投诉
------------------------------------------------------------
【最终回答】
非常抱歉听到您的遭遇。我们重视每位客户的反馈。关于您对产品收益的不满意...
【质量评估】
综合评分: 7.92/10
改进建议:
- [高] 用户满意度: 需要关注用户情感,可能需要人工介入
- [中] 问题解决: 增加后续跟进或升级渠道
处理耗时: 1456ms