阿里开源AgentScope多智能体框架解析系列(十四)第14章:企业级Skill系统-智能客户服务中心

6 阅读14分钟

导读

本章基于第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个技能?

  1. 单一职责原则:每个技能只做一件事,易于维护和复用
  2. 灵活性:可以独立升级某个技能(如更换意图识别算法)
  3. 可测试性:每个技能都可以独立测试和验证
  4. 可扩展性:可以轻松添加新的技能或替换现有技能

为什么采用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