ai-robot-channel/spec/ai-robot/design.md

33 KiB
Raw Blame History

feature_id title status version owners last_updated
MCA 多渠道适配主框架架构设计 draft 0.2.0
architect
backend
2026-02-24

多渠道适配主框架架构设计design.md

1. 系统架构

1.1 整体架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                              外部系统                                         │
├─────────────────┬─────────────────┬─────────────────┬───────────────────────┤
│   企业微信 API   │    抖音 API     │    京东 API     │      前端工作台        │
└────────┬────────┴────────┬────────┴────────┬────────┴──────────┬────────────┘
         │                 │                 │                    │
         ▼                 ▼                 ▼                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                          Java 主框架 (Spring Boot)                           │
├─────────────────────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                     入口层 (Controller Layer)                        │    │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐               │    │
│  │  │WecomCallback │  │DouyinCallback│  │  JdCallback  │  (预留)       │    │
│  │  │  Controller  │  │  Controller  │  │  Controller  │               │    │
│  │  └──────┬───────┘  └──────────────┘  └──────────────┘               │    │
│  │         │                                                            │    │
│  │         │ 验签/解密/解析 → InboundMessage                            │    │
│  │         ▼                                                            │    │
│  └─────────┼───────────────────────────────────────────────────────────┘    │
│            │                                                                 │
│            ▼                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                     消息路由层 (Message Router)                      │    │
│  │  ┌──────────────────────────────────────────────────────────────┐   │    │
│  │  │              MessageRouterService (渠道无关)                  │   │    │
│  │  │  - processInboundMessage(InboundMessage)                     │   │    │
│  │  │  - routeBySessionState(Session, InboundMessage)              │   │    │
│  │  │  - dispatchToAiService(Session, InboundMessage)              │   │    │
│  │  │  - dispatchToManualCs(Session, InboundMessage)               │   │    │
│  │  └──────────────────────────────────────────────────────────────┘   │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                    │                                         │
│                                    ▼                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                        渠道适配层 (Channel Adapter)                  │    │
│  │  ┌──────────────────────────────────────────────────────────────┐   │    │
│  │  │              ChannelAdapter 接口 (核心能力)                   │   │    │
│  │  │  - getChannelType()                                          │   │    │
│  │  │  - sendMessage(OutboundMessage)                              │   │    │
│  │  └──────────────────────────────────────────────────────────────┘   │    │
│  │  ┌──────────────────────────────────────────────────────────────┐   │    │
│  │  │              可选能力接口 (Optional Capabilities)             │   │    │
│  │  │  - ServiceStateCapable  - TransferCapable  - MessageSyncCapable│   │    │
│  │  └──────────────────────────────────────────────────────────────┘   │    │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐               │    │
│  │  │ WeChatAdapter│  │DouyinAdapter │  │  JdAdapter   │  (预留)       │    │
│  │  │  (已实现)     │  │   (预留)      │  │   (预留)     │               │    │
│  │  └──────────────┘  └──────────────┘  └──────────────┘               │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                    │                                         │
│          ┌─────────────────────────┼─────────────────────────┐              │
│          ▼                         ▼                         ▼              │
│  ┌──────────────┐     ┌──────────────────────┐     ┌──────────────┐        │
│  │ AI 服务客户端 │     │   会话管理层          │     │ WebSocket 服务│        │
│  │AiServiceClient│     │SessionManagerService │     │WebSocketService│       │
│  └──────┬───────┘     └──────────────────────┘     └──────────────┘        │
│         │                                                                   │
└─────────┼───────────────────────────────────────────────────────────────────┘
          │ HTTP
          ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                        Python AI 服务 (独立部署)                             │
├─────────────────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                       │
│  │ OpenAI Client│  │DeepSeek Client│  │  其他模型    │                       │
│  └──────┬───────┘  └──────┬───────┘  └──────────────┘                       │
│         │                 │                                                  │
│         ▼                 ▼                                                  │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                      AI 服务核心逻辑                                  │    │
│  │  - /ai/chat      生成 AI 回复                                        │    │
│  │  - /ai/health    健康检查                                            │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 模块职责

模块 职责 关联 AC
入口层 接收渠道回调,验签/解密/解析,转换为统一的 InboundMessage AC-MCA-08
消息路由层 渠道无关的消息路由,根据会话状态分发到 AI 或人工 AC-MCA-08 ~ AC-MCA-10
渠道适配层 封装各渠道 API 差异,提供统一的消息发送接口 AC-MCA-01 ~ AC-MCA-03
AI 服务客户端 调用 Python AI 服务,处理超时/降级 AC-MCA-04 ~ AC-MCA-07
会话管理层 管理会话生命周期、状态变更、消息持久化 AC-MCA-11 ~ AC-MCA-12
WebSocket 服务 实时推送消息到人工客服工作台 AC-MCA-10
Python AI 服务 AI 模型推理、置信度评估、转人工建议 AC-MCA-04 ~ AC-MCA-05

2. 统一消息模型

2.1 入站消息 (InboundMessage)

@Data
public class InboundMessage {
    private String channelType;           // 渠道类型: wechat/douyin/jd
    private String channelMessageId;      // 渠道原始消息ID (用于幂等)
    private String sessionKey;            // 会话标识 (customerId + kfId 组合)
    private String customerId;            // 客户ID
    private String kfId;                  // 客服账号ID
    private String sender;                // 发送者标识
    private String content;               // 消息内容 (统一字段名)
    private String msgType;               // 消息类型: text/image/voice 等
    private String rawPayload;            // 原始消息体 (JSON/XML)
    private Long timestamp;               // 消息时间戳
    private SignatureInfo signatureInfo;  // 签名信息
    private Map<String, Object> metadata; // 扩展元数据
}

@Data
public class SignatureInfo {
    private String signature;             // 签名值
    private String timestamp;             // 签名时间戳
    private String nonce;                 // 随机数
    private String algorithm;             // 签名算法 (可选)
}

2.2 出站消息 (OutboundMessage)

@Data
public class OutboundMessage {
    private String channelType;           // 渠道类型
    private String receiver;              // 接收者ID (customerId)
    private String kfId;                  // 客服账号ID
    private String content;               // 消息内容
    private String msgType;               // 消息类型
    private Map<String, Object> metadata; // 扩展元数据
}

2.3 字段映射策略

重要:内部统一使用 content 字段名,与 AI 服务契约 (currentMessage) 的映射在 AiServiceClient 层处理。

内部字段 AI 服务契约字段 映射位置
InboundMessage.content ChatRequest.currentMessage AiServiceClient.generateReply()
InboundMessage.sessionKey ChatRequest.sessionId AiServiceClient.generateReply()
InboundMessage.channelType ChatRequest.channelType AiServiceClient.generateReply()
public ChatRequest toChatRequest(InboundMessage msg, List<Message> history) {
    ChatRequest request = new ChatRequest();
    request.setSessionId(msg.getSessionKey());
    request.setCurrentMessage(msg.getContent());  // content → currentMessage
    request.setChannelType(msg.getChannelType());
    request.setHistory(history);
    return request;
}

3. 核心接口设计

3.1 渠道适配器接口

// 核心能力接口(所有渠道必须实现)
public interface ChannelAdapter {
    String getChannelType();
    void sendMessage(OutboundMessage message);
}

// 可选能力接口:服务状态管理
public interface ServiceStateCapable {
    ServiceState getServiceState(String kfId, String customerId);
    boolean transServiceState(String kfId, String customerId, int newState, String servicerId);
}

// 可选能力接口:转人工
public interface TransferCapable {
    boolean transferToPool(String kfId, String customerId);
    boolean transferToManual(String kfId, String customerId, String servicerId);
}

// 可选能力接口:消息同步
public interface MessageSyncCapable {
    SyncMsgResponse syncMessages(String kfId, String cursor);
}

3.2 消息路由服务接口

public interface MessageRouterService {
    void processInboundMessage(InboundMessage message);
    void routeBySessionState(Session session, InboundMessage message);
    void dispatchToAiService(Session session, InboundMessage message);
    void dispatchToManualCs(Session session, InboundMessage message);
    void dispatchToPendingPool(Session session, InboundMessage message);
}

3.3 AI 服务客户端接口

public interface AiServiceClient {
    ChatResponse generateReply(ChatRequest request);
    boolean healthCheck();
}

4. 核心流程

4.1 消息处理主流程(渠道无关)

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│ 渠道回调入口      │────▶│ 验签/解密/解析    │────▶│ 构建 InboundMessage│
│ (Controller)     │     │ (渠道专属逻辑)    │     │ (统一消息模型)    │
└──────────────────┘     └────────┬─────────┘     └──────────────────┘
                                  │
                                  ▼
                     ┌──────────────────┐
                     │ MessageRouter    │
                     │ processInbound   │
                     │ Message()        │
                     └────────┬─────────┘
                              │
                              ▼
                     ┌──────────────────┐
                     │ 幂等检查 (msgId)  │
                     │ Redis SETNX      │
                     └────────┬─────────┘
                              │
                              ▼
                     ┌──────────────────┐
                     │ 获取/创建会话     │
                     │ SessionManager   │
                     └────────┬─────────┘
                              │
                              ▼
                     ┌──────────────────┐
                     │ 获取渠道服务状态  │
                     │ (可选能力检测)    │
                     └────────┬─────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
        ┌──────────┐   ┌──────────┐   ┌──────────┐
        │ AI 状态   │   │ POOL 状态 │   │MANUAL 状态│
        │          │   │          │   │          │
        └────┬─────┘   └────┬─────┘   └────┬─────┘
             │              │              │
             ▼              ▼              ▼
     ┌──────────────┐ ┌──────────┐ ┌──────────────┐
     │dispatchTo    │ │dispatchTo│ │dispatchTo    │
     │ AiService    │ │PendingPool│ │ ManualCs     │
     └──────┬───────┘ └──────────┘ └──────────────┘
            │
            ▼
     ┌──────────────┐
     │ 判断是否转人工│
     │shouldTransfer│
     └──────┬───────┘
            │
    ┌───────┴───────┐
    ▼               ▼
┌───────┐    ┌──────────────┐
│发送回复│    │ 转入待接入池  │
│给用户  │    │ TransferCapable│
└───────┘    └──────────────┘

4.2 AI 服务调用流程

┌──────────────────┐
│ 构造 ChatRequest │
│ sessionId        │
│ currentMessage   │←── content 映射
│ channelType      │
│ history (可选)   │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐     ┌──────────────────┐
│ HTTP POST        │────▶│ Python AI 服务    │
│ /ai/chat         │     │ 超时: 5s          │
└────────┬─────────┘     └────────┬─────────┘
         │                        │
         │         ┌──────────────┼──────────────┐
         │         ▼              ▼              ▼
         │   ┌──────────┐  ┌──────────┐  ┌──────────┐
         │   │ 成功响应  │  │ 超时/失败 │  │ 服务不可用│
         │   │ 200 OK   │  │ Timeout  │  │ 503      │
         │   └────┬─────┘  └────┬─────┘  └────┬─────┘
         │        │             │             │
         │        ▼             ▼             ▼
         │   ┌──────────┐  ┌──────────────────────┐
         │   │ 返回回复  │  │ 降级处理              │
         │   │ reply    │  │ 返回固定回复          │
         │   │confidence│  │ "正在转接人工客服..." │
         │   │shouldTransfer│ └──────────┬───────────┘
         │   └──────────┘              │
         │                             ▼
         │                      ┌──────────────┐
         │                      │ 触发转人工    │
         │                      │ TransferCapable│
         │                      └──────────────┘
         │
         ▼
┌──────────────────┐
│ 处理响应         │
│ - 保存消息       │
│ - 发送给用户     │
│ - 判断转人工     │
└──────────────────┘

5. 数据模型

5.1 实体关系图

┌──────────────────┐       ┌──────────────────┐
│     Session      │       │     Message      │
├──────────────────┤       ├──────────────────┤
│ sessionId (PK)   │──────▶│ msgId (PK)       │
│ customerId       │  1:N  │ sessionId (FK)   │
│ kfId             │       │ senderType       │
│ channelType (新) │       │ senderId         │
│ status           │       │ content          │
│ wxServiceState   │       │ msgType          │
│ manualCsId       │       │ rawData          │
│ createdAt        │       │ createdAt        │
│ updatedAt        │       └──────────────────┘
└──────────────────┘
         │
         │ 1:N
         ▼
┌──────────────────┐
│   TransferLog    │
├──────────────────┤
│ id (PK)          │
│ sessionId (FK)   │
│ triggerReason    │
│ triggerTime      │
│ acceptedCsId     │
│ acceptedTime     │
└──────────────────┘

5.2 数据库变更

口径说明:本次仅做最小 schema 变更,新增 channel_type 字段,默认值为 wechat;可通过在线 DDL 方式执行;不涉及数据迁移。符合 requirements.md 中"仅增加渠道类型字段,不进行大规模迁移"的范围约定。

表名 变更类型 变更内容
session 新增字段 channel_type VARCHAR(20) DEFAULT 'wechat'

DDL 示例

ALTER TABLE session ADD COLUMN channel_type VARCHAR(20) DEFAULT 'wechat' 
COMMENT '渠道类型: wechat/douyin/jd';

5.3 Redis 缓存结构

Key 模式 类型 说明 TTL
wecom:access_token String 微信 access_token 7200s - 300s
wecom:cursor:{openKfId} String 消息同步游标 永久
session:status:{sessionId} String 会话状态缓存 24h
session:msg_count:{sessionId} String 消息计数 24h
idempotent:{msgId} String 消息幂等键 1h

6. 跨模块调用策略

6.1 AI 服务调用

配置项 说明
超时时间 5 秒 连接 + 读取总超时
重试次数 0 不重试,直接降级
熔断阈值 5 次/分钟 连续失败 5 次触发熔断
熔断时间 30 秒 熔断后等待时间
降级策略 返回固定回复 + 转人工 见下方降级逻辑

6.2 熔断器选型

选型决策:使用 Resilience4j 作为熔断器实现,与 Spring Boot 2.7 兼容。

方案 说明
Resilience4j 推荐。轻量级,支持断路器、限流、重试,与 Spring Boot 2.7 兼容良好
最小实现 仅做 timeout + fallback不做熔断不推荐与 requirements 不一致)

熔断状态存储

  • 单实例内存存储CircuitBreakerRegistry
  • 多实例:可扩展为 Redis 存储(通过 Resilience4j + Redis 实现)

依赖配置

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>2.1.0</version>
</dependency>

6.3 降级逻辑

@Service
public class AiServiceClientImpl implements AiServiceClient {
    
    @CircuitBreaker(name = "aiService", fallbackMethod = "fallback")
    @TimeLimiter(name = "aiService")
    public ChatResponse generateReply(ChatRequest request) {
        // HTTP 调用 Python AI 服务
    }
    
    public ChatResponse fallback(ChatRequest request, Throwable cause) {
        log.warn("AI 服务降级: sessionId={}, cause={}", 
                 request.getSessionId(), cause.getMessage());
        
        ChatResponse response = new ChatResponse();
        response.setReply("抱歉,我暂时无法回答您的问题,正在为您转接人工客服...");
        response.setConfidence(0.0);
        response.setShouldTransfer(true);
        return response;
    }
}

6.4 错误映射

AI 服务错误 主框架处理 用户感知
200 OK 正常处理 返回 AI 回复
400 Bad Request 记录日志,降级 转人工
500 Internal Error 记录日志,降级 转人工
503 Service Unavailable 记录日志,降级 转人工
Timeout 记录日志,降级 转人工
Connection Refused 触发熔断,降级 转人工

7. 消息幂等性设计

7.1 幂等键

  • 使用 InboundMessage.channelMessageId 作为幂等键
  • 微信渠道:使用微信返回的 msgId
  • 其他渠道:使用渠道返回的消息 ID 或生成唯一 ID

7.2 幂等处理流程

┌──────────────────┐
│ 收到消息         │
│ channelMessageId │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐     ┌──────────────────┐
│ Redis 检查       │────▶│ Key 不存在        │
│ idempotent:{msgId}│    │ 继续处理          │
└────────┬─────────┘     └────────┬─────────┘
         │                        │
         ▼                        ▼
┌──────────────────┐     ┌──────────────────┐
│ Key 已存在       │     │ 设置 Key (TTL 1h)│
│ 跳过处理         │     │ 处理消息          │
└──────────────────┘     └──────────────────┘

7.3 实现代码

public boolean processMessageIdempotent(String channelMessageId, Runnable processor) {
    String key = "idempotent:" + channelMessageId;
    Boolean absent = redisTemplate.opsForValue()
            .setIfAbsent(key, "1", 1, TimeUnit.HOURS);
    
    if (Boolean.TRUE.equals(absent)) {
        processor.run();
        return true;
    }
    
    log.info("重复消息,跳过处理: channelMessageId={}", channelMessageId);
    return false;
}

8. 配置管理

8.1 新增配置项

# application.yml 新增配置
ai-service:
  url: http://ai-service:8080
  timeout: 5000

resilience4j:
  circuitbreaker:
    instances:
      aiService:
        failure-rate-threshold: 50
        sliding-window-size: 10
        sliding-window-type: COUNT_BASED
        wait-duration-in-open-state: 30s
        permitted-number-of-calls-in-half-open-state: 3
  timelimiter:
    instances:
      aiService:
        timeout-duration: 5s

channel:
  default: wechat
  adapters:
    wechat:
      enabled: true
    douyin:
      enabled: false
    jd:
      enabled: false

8.2 配置类

@Data
@Component
@ConfigurationProperties(prefix = "ai-service")
public class AiServiceConfig {
    private String url;
    private int timeout = 5000;
}

@Data
@Component
@ConfigurationProperties(prefix = "channel")
public class ChannelConfig {
    private String default;
    private Map<String, AdapterConfig> adapters;
    
    @Data
    public static class AdapterConfig {
        private boolean enabled;
    }
}

9. 部署架构

9.1 部署拓扑

┌─────────────────────────────────────────────────────────────┐
│                        负载均衡器                            │
└─────────────────────────────┬───────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
        ┌──────────┐   ┌──────────┐   ┌──────────┐
        │ Java 主  │   │ Java 主  │   │ Java 主  │
        │ 框架实例1│   │ 框架实例2│   │ 框架实例3│
        └────┬─────┘   └────┬─────┘   └────┬─────┘
             │              │              │
             └──────────────┼──────────────┘
                            │
         ┌──────────────────┼──────────────────┐
         ▼                  ▼                  ▼
   ┌──────────┐      ┌──────────┐      ┌──────────┐
   │  Redis   │      │  MySQL   │      │Python AI │
   │ (Cluster)│      │ (Master) │      │  服务    │
   └──────────┘      └──────────┘      └──────────┘

9.2 服务依赖

服务 依赖关系 健康检查
Java 主框架 依赖 Redis, MySQL, Python AI /actuator/health
Python AI 服务 无外部依赖 /ai/health

10. 安全设计

10.1 渠道回调鉴权

渠道 鉴权方式 验证逻辑
微信 msg_signature + timestamp + nonce 沿用现有 WeCom 官方验签/解密方案(复用现有 WXBizMsgCrypt 实现)
抖音 X-Signature + X-Timestamp 待实现
京东 signature + timestamp 待实现

说明:微信回调验签/加解密使用企业微信官方方案,具体算法细节封装在现有 WXBizMsgCrypt 类中,不在本设计文档展开。

10.2 内部服务鉴权

  • Java 主框架 → Python AI 服务:内网调用,无需鉴权(可扩展为 mTLS
  • WebSocket 连接:路径参数 {csId} 标识身份(可扩展为 Token 验证)

11. 监控与告警

说明本节为后续演进预留MVP 阶段可暂不实现。

11.1 关键指标

指标 类型 说明
ai.service.latency Histogram AI 服务调用延迟
ai.service.error.rate Counter AI 服务错误率
ai.service.circuit.breaker.open Gauge 熔断器状态
message.process.count Counter 消息处理数量
message.idempotent.skip Counter 幂等跳过数量
session.active.count Gauge 活跃会话数

11.2 告警规则

规则 条件 级别
AI 服务不可用 连续失败 5 次 Critical
AI 服务延迟过高 P99 > 3s Warning
熔断器触发 circuit.breaker.open = 1 Critical