---
doc_id: service-session-spec
title: 用戶進線 Session 過程規格說明書
description: Aile ServiceSession 模型、會話生命週期、機器人接待、轉人工分配、結束流程、定時任務與統計規格，供開發團隊參考。
slug: /specifications/service-session-spec
product: Aile
category: specification
audience:
  - developer
  - architect
  - qa
visibility: public
status: published
version: 1.0.0
owner: aile-platform
updated_at: 2026-06-13
tags:
  - Aile
  - ServiceSession
  - ServiceNumber
  - 規格說明書
rendered_html: /rendered/specifications/service-session-spec/
download: true
sidebar_position: 9
---

# 用戶進線 Session 過程規格說明書

**版本：** v1.0  
**最後更新：** 2026-06-13  
**服務範圍：** `aile-service-tenant`（核心）、`aile-service-room`（協同）  

---

## 1. 概述

用戶進線 Session（ServiceSession）是 Aile 客服系統的核心會話管理機制。每當客戶透過 LINE 私聊或其他渠道向服務號發起對話時，系統會建立一條 ServiceSession 記錄，追蹤從機器人接待到人工服務的完整生命週期。

### 1.1 核心概念

| 概念 | 說明 |
|------|------|
| **ServiceSession** | 一次客戶進線的完整會話記錄 |
| **Session 狀態** | 9 種狀態：RobotActive → DistributeActive → AgentActive → ... → End |
| **機器人接待** | 客戶進線後首先由機器人（AI 助手）接待 |
| **轉人工** | 客戶請求或系統判定需要轉接人工客服 |
| **分配策略** | 基於員工權重（RoomWeight）的自動分配 |

---

## 2. ServiceSessionModel（會話持久化模型）

### 2.1 資料結構

MongoDB 集合：`aile.tenant.servicenumber.session`

```java
// aile-api/aile-tenant-api/.../model/servicenumber/ServiceSessionModel.java
@Document("aile.tenant.servicenumber.session")
@CompoundIndexes({
    @CompoundIndex(name = "serviceNumberId", def = "{'serviceNumberId': 1}"),
    @CompoundIndex(name = "roomId_1_updateTime_1", def = "{'roomId': 1, 'updateTime': 1}"),
    @CompoundIndex(name = "roomId_1_channel_1_updateTime_1", def = "{'roomId': 1, 'channel': 1, 'updateTime': 1}"),
    @CompoundIndex(name = "gwSessionId_1", def = "{'gwSessionId': 1}"),
    @CompoundIndex(name = "serviceNumberId_1_status_1", def = "{'serviceNumberId': 1, 'status': 1}"),
    @CompoundIndex(name = "serviceNumberId_1_status_1_agentId_1", def = "{'serviceNumberId': 1, 'status': 1, 'agentId': 1}"),
    @CompoundIndex(name = "agentId_1_status_1", def = "{'agentId': 1, 'status': 1}"),
    @CompoundIndex(name = "serviceNumberId_1_scopeId_1", def = "{'serviceNumberId': 1, 'scopeId': 1}"),
    @CompoundIndex(name = "status_1_activeTime_1", def = "{'status': 1, 'activeTime': 1}"),
    @CompoundIndex(name = "status_1_distributeTime_1", def = "{'status': 1, 'distributeTime': 1}"),
    @CompoundIndex(name = "serviceNumberId_1_startTime_1", def = "{'serviceNumberId': 1, 'startTime': 1}")
})
public class ServiceSessionModel extends BaseModel {
    String tenantId;                   // 租戶 ID
    String serviceNumberId;            // 服務號 ID
    ServiceNumberType serviceNumberType; // 服務號類型
    String roomId;                     // 聊天室 ID
    String accountId;                  // 帳號 ID
    String customerId;                 // 客戶（聯繫人）ID
    String scopeId;                    // 客戶渠道 scopeId
    String agentId;                    // 接待客服的 memberId
    String gwSessionId;                // Gateway 側的 session ID
    ServiceSessionStatus status;       // 會話狀態
    Channel channel;                   // 進線渠道（Line / WhatsApp 等）
    Long startTime;                    // 會話開始時間
    Long activeTime;                   // 最近活躍時間
    Long endTime;                      // 會話結束時間
    Long distributeTime;               // 人工分配時間
    Long robotActiveTime;              // 機器人開始接待時間
    Long robotStopTime;                // 機器人接待結束時間
    Long timeoutTime;                  // 超時時間
    // 滿意度
    Integer satisfactionScore;         // 滿意度評分
    String satisfactionComment;        // 滿意度備註
}
```

---

## 3. Session 生命週期狀態機

### 3.1 狀態定義

```java
// aile-api/aile-tenant-api/.../enums/ServiceSessionStatus.java
public enum ServiceSessionStatus {
    RobotActive,       // 機器人服務中
    RobotStop,         // 機器人服務結束
    DistributeActive,  // 轉人工，剛進件（等待分配）
    AgentActive,       // 客服人員服務中
    AgentStop,         // 客服人員服務結束
    CustomerStop,      // 客戶主動結束
    Timeout,           // 服務超時結束
    NoWorkTimeStop,    // 非上班時間結束
    Deleted            // 標記刪除
}
```

### 3.2 狀態轉換圖

```
客戶進線
  │
  ▼
RobotActive ──────────────────────────────────────┐
  │                                                │
  ├──→ RobotStop（機器人主動結束）                   │
  │                                                │
  ├──→ DistributeActive（轉人工）                    │
  │       │                                        │
  │       ├──→ AgentActive（分配成功）               │
  │       │       │                                │
  │       │       ├──→ AgentStop（客服結束）          │
  │       │       ├──→ CustomerStop（客戶結束）       │
  │       │       └──→ Timeout（超時）               │
  │       │                                        │
  │       └──→ NoWorkTimeStop（非工作時間）           │
  │                                                │
  ├──→ CustomerStop（客戶主動結束）                   │
  ├──→ Timeout（超時）                               │
  └──→ NoWorkTimeStop（非工作時間）                   │
                                                    │
  (所有結束狀態可被標記為 Deleted) ◄──────────────────┘
```

### 3.3 活躍狀態判斷

```java
// 以下三個狀態為「活躍中」
activeStatus = [RobotActive, DistributeActive, AgentActive]

// 「主要活躍」（人工相關）
isMainActive() → DistributeActive || AgentActive

// 「已離線」
isOffline() → RobotStop || AgentStop || CustomerStop || Timeout || NoWorkTimeStop || Deleted
```

---

## 4. ServiceSessionService（會話服務接口）

位置：`aile-service/aile-service-tenant/.../service/servicenumber/ServiceSessionService.java`

### 4.1 核心方法

| 方法 | 說明 | 狀態變更 |
|------|------|----------|
| `start(dto)` | 客戶進線，開始新會話 | → RobotActive |
| `startRobotActive(model)` | 啟動機器人接待 | → RobotActive |
| `stopRobotService(model)` | 停止機器人接待 | RobotActive → RobotStop |
| `warningRobotService(model)` | 機器人接待預警 | RobotActive（不變） |
| `startDistributeService(model, context)` | 轉人工分配 | → DistributeActive |
| `agentStartService(dto, employeeId)` | 客服接起 | DistributeActive → AgentActive |
| `agentStopService(dto)` | 客服結束 | AgentActive → AgentStop |
| `customerStopService(dto)` | 客戶結束 | RobotActive/AgentActive → CustomerStop |
| `timeout(model)` | 超時結束 | 活躍狀態 → Timeout |
| `agentSwitchRobot(dto)` | 客服轉機器人 | AgentActive → RobotActive |
| `transfer(model, memberId)` | 轉接給其他客服 | AgentActive → AgentActive（更換 agentId） |
| `refreshSession(dto)` | 刷新會話活躍時間 | 更新 activeTime |
| `ownerStopService(model)` | 管理員強制結束 | 任意活躍 → AgentStop |
| `getLastSession(roomId)` | 查詢最近一次會話 | - |

### 4.2 分配上下文

```java
// aile-service/aile-service-tenant/.../service/servicenumber/dto/ServiceSessionDistributeContext.java
public class ServiceSessionDistributeContext {
    String serviceNumberId;
    String roomId;
    String employeeId;          // 指定客服（選填，不指定則自動分配）
    RoomWeightEventCode eventCode; // 分配事件碼
    boolean checkWorkTime;      // 是否檢查工作時間
}
```

---

## 5. 會話啟動流程

### 5.1 客戶進線

```
Gateway Webhook（LINE 私聊消息）
  │
  └── aile-service-tenant (GatewayController)
        │
        ├── 解析 Webhook：提取 sender.code、to.code、message
        ├── 查找/建立 TenantContactModel（聯繫人）
        ├── 查找/建立 ServiceNumberScopeModel（渠道關聯）
        ├── 查找/建立 Services Room（私聊聊天室）
        │
        ├── ServiceSessionService.start(startDto)
        │     ├── 檢查是否已有活躍會話（同一 roomId + channel）
        │     │     ├── 有 → 刷新現有會話（refreshSession）
        │     │     └── 無 → 建立新會話
        │     ├── status = RobotActive
        │     └── 記錄 startTime、robotActiveTime
        │
        ├── 消息寫入 Services Room
        │
        └── 觸發助手管線（AssistantTriggerPublishService）
              └── 若無助手或助手不匹配 → 直接轉人工
```

### 5.2 機器人接待結束

```
客戶發送特定關鍵詞（如「轉人工」）或系統規則觸發
  │
  └── ServiceSessionService.stopRobotService(session)
        ├── status: RobotActive → RobotStop
        ├── 記錄 robotStopTime
        └── 可選：自動觸發 startDistributeService
```

---

## 6. 轉人工分配流程

### 6.1 分配觸發

轉人工有三種觸發方式：

| 方式 | 觸發條件 |
|------|----------|
| 客戶請求 | 客戶發送「轉人工」等關鍵詞 |
| 機器人無法處理 | AI 助手判斷需轉人工（返回特定信號） |
| 系統規則 | 無助手配置的服務號，直接轉人工 |

### 6.2 分配邏輯

```
ServiceSessionService.startDistributeService(session, context)
  │
  ├── 檢查工作時間（context.checkWorkTime = true）
  │     ├── 非工作時間 → status = NoWorkTimeStop → return null
  │     └── 工作時間 → 繼續
  │
  ├── 若指定 employeeId（指定客服）
  │     └── 查詢該客服是否在線且可接待
  │
  ├── 若未指定（自動分配）
  │     └── 基於 RoomWeight 系統自動選擇最合適的客服
  │           ├── 查詢該服務號的在線客服列表
  │           ├── 依權重排序（空閒度、技能匹配、接待數量等）
  │           └── 選擇權重最高的客服
  │
  ├── status: RobotActive → DistributeActive（若需等待）或直接 → AgentActive
  ├── 記錄 distributeTime
  │
  └── 發送分配通知（Socket.IO / PubSub）
```

### 6.3 客服接起

```
ServiceSessionService.agentStartService(dto, employeeId)
  │
  ├── 驗證 employeeId 是否為分配目標
  ├── status: DistributeActive → AgentActive
  ├── 記錄 agentId
  └── 發送會話開始消息（AgentStartMessageEvent）
```

---

## 7. 會話結束流程

### 7.1 客服結束

```
客服點擊「結束會話」
  │
  └── ServiceSessionService.agentStopService(dto)
        ├── status: AgentActive → AgentStop
        ├── 記錄 endTime
        └── 發送 AgentStopMessageEvent
```

### 7.2 客戶結束

```
客戶發送結束信號或 Gateway 推送 ServiceEnd 事件
  │
  └── ServiceSessionService.customerStopService(dto)
        ├── status: RobotActive/AgentActive → CustomerStop
        ├── 記錄 endTime
        └── 清除活躍會話緩存
```

### 7.3 超時結束

```
SessionTimeoutScheduleTask（定時掃描）
  │
  └── 掃描 activeTime 超過配置閾值的活躍會話
        ├── status → Timeout
        └── 發送 SessionTimeoutEvent
```

---

## 8. 定時任務

### 8.1 會話超時

| 任務 | 位置 | 說明 |
|------|------|------|
| `SessionTimeoutScheduleTask` | `aile-service-tenant/.../task/` | 定時掃描超時會話 |
| `OnceSessionTimeoutTask` | `aile-service-tenant/.../task/` | 單次超時處理 |

### 8.2 會話空閒

| 任務 | 位置 | 說明 |
|------|------|------|
| `SessionIdleScheduleTask` | `aile-service-tenant/.../task/` | 掃描空閒過久的會話 |
| `OnceSessionIdleTask` | `aile-service-tenant/.../task/` | 單次空閒處理 |

### 8.3 自動轉接

| 任務 | 位置 | 說明 |
|------|------|------|
| `OwnerAutoTransferScheduleTask` | `aile-service-tenant/.../task/` | 客服離線自動轉接 |
| `OnceOwnerAutoTransferTask` | `aile-service-tenant/.../task/` | 單次自動轉接處理 |

### 8.4 自動結束

| 任務 | 位置 | 說明 |
|------|------|------|
| `OwnerAutoStopScheduleTask` | `aile-service-tenant/.../task/` | 客服離線自動結束會話 |
| `OnceOwnerAutoStopTask` | `aile-service-tenant/.../task/` | 單次自動結束處理 |

---

## 9. 會話統計

### 9.1 統計接口

路由：`/servicenumber/session/statistics`

| 維度 | 說明 |
|------|------|
| 按服務號 | 每個服務號的會話總數、活躍數、結束數 |
| 按時間 | 按月/按日統計會話趨勢 |
| 按客服 | 每個客服的接待量、平均處理時間 |
| 按機器人 | 機器人接待比例、轉人工率 |

### 9.2 統計資料結構

```java
// aile-api/aile-tenant-api/.../vo/servicenumber/statistics/ServiceSessionStatisticsVO.java
public class ServiceSessionStatisticsVO {
    long totalCount;           // 總會話數
    long activeCount;          // 活躍會話數
    long robotActiveCount;     // 機器人接待數
    long agentActiveCount;    // 人工接待數
    long endedCount;          // 已結束數
    long timeoutCount;        // 超時數
    double avgHandleTime;     // 平均處理時間（秒）
    double robotRatio;        // 機器人處理比例
    double transferRatio;     // 轉人工比例
}
```

---

## 10. 會話通知機制

### 10.1 通知事件

位置：`aile-service/aile-service-tenant/.../notice/session/`

| 事件類 | 觸發時機 |
|--------|----------|
| `SessionRobotActiveEvent` | 機器人開始接待 |
| `SessionRobotStopEvent` | 機器人接待結束 |
| `SessionRobotWarningEvent` | 機器人接待預警 |
| `SessionDistributeActiveEvent` | 進入分配佇列 |
| `SessionAgentActiveEvent` | 客服接起 |
| `SessionAgentStopEvent` | 客服結束 |
| `SessionTimeoutEvent` | 會話超時 |

### 10.2 會話消息

位置：`aile-service/aile-service-tenant/.../session/message/`

| 事件 | 說明 |
|------|------|
| `SessionStartMessageEvent` | 會話開始卡片消息 |
| `RobotActiveMessageEvent` | 機器人接待中卡片消息 |
| `RobotStopMessageEvent` | 機器人接待結束消息 |
| `AgentStartMessageEvent` | 人工客服接入消息 |
| `AgentStopMessageEvent` | 人工客服結束消息 |
| `TimeoutMessageEvent` | 會話超時消息 |

---

## 11. 滿意度評價

### 11.1 評價服務

位置：`aile-service/aile-service-tenant/.../service/servicenumber/SatisfactionSurveyService.java`

```
會話結束（AgentStop / CustomerStop）
  │
  └── SatisfactionSurveyService.sendSurvey(session)
        ├── 向客戶推送滿意度評價卡片
        ├── 客戶評分 → 記錄 satisfactionScore
        └── 客戶可選填評論 → 記錄 satisfactionComment
```

---

## 12. 與其他模組的協作

| 模組 | 互動方式 | 說明 |
|------|----------|------|
| Room 服務 | Feign（`ServiceSessionFeign`） | 刷新會話、檢查房間狀態 |
| Gateway | Webhook 事件 | 接收 ServiceStart/ServiceEnd 事件 |
| 助手 | PubSub + Feign | 機器人接待階段的助手觸發 |
| 配額 | 配額檢查 | 會話建立時檢查配額 |
| 進線原因 | `ServiceInboundReasonSessionService` | 會話關聯進線原因 |
| Saga | `ProcessServiceSessionMergeStep` | 客戶合併時的會話處理 |

---

## 13. 關鍵檔案索引

| 層級 | 檔案 | 說明 |
|------|------|------|
| API Model | `aile-api/aile-tenant-api/.../model/servicenumber/ServiceSessionModel.java` | 會話持久化模型 |
| API Enum | `aile-api/aile-tenant-api/.../enums/ServiceSessionStatus.java` | 會話狀態枚舉 |
| Service | `aile-service/aile-service-tenant/.../service/servicenumber/ServiceSessionService.java` | 會話服務接口 |
| Service Impl | `aile-service/aile-service-tenant/.../service/servicenumber/impl/ServiceSessionServiceImpl.java` | 會話服務實現 |
| Controller | `aile-service/aile-service-tenant/.../controller/servicenumber/ServiceSessionController.java` | 會話 API |
| DTO | `aile-service/aile-service-tenant/.../service/servicenumber/dto/ServiceSessionDistributeContext.java` | 分配上下文 |
| 通知 | `aile-service/aile-service-tenant/.../notice/session/SessionNoticeUtil.java` | 會話通知工具 |
| 通知事件 | `aile-service/aile-service-tenant/.../notice/session/event/*.java` | 各類通知事件 |
| 消息事件 | `aile-service/aile-service-tenant/.../session/message/*.java` | 會話消息事件 |
| 消息工具 | `aile-service/aile-service-tenant/.../session/SessionMessageUtil.java` | 會話消息工具 |
| 定時任務 | `aile-service/aile-service-tenant/.../task/SessionTimeoutScheduleTask.java` | 超時掃描 |
| 定時任務 | `aile-service/aile-service-tenant/.../task/SessionIdleScheduleTask.java` | 空閒掃描 |
| 定時任務 | `aile-service/aile-service-tenant/.../task/OwnerAutoTransferScheduleTask.java` | 自動轉接 |
| 定時任務 | `aile-service/aile-service-tenant/.../task/OwnerAutoStopScheduleTask.java` | 自動結束 |
| 滿意度 | `aile-service/aile-service-tenant/.../service/servicenumber/SatisfactionSurveyService.java` | 滿意度評價 |
| Saga | `aile-service/aile-service-tenant/.../saga/step/ProcessServiceSessionMergeStep.java` | Saga 會話合併 |
| Gateway 事件 | `aile-service/aile-service-tenant/.../gateway/factory/strategy/impl/ServiceStartEventImpl.java` | Gateway 開始事件 |
| Gateway 事件 | `aile-service/aile-service-tenant/.../gateway/factory/strategy/impl/ServiceEndEventImpl.java` | Gateway 結束事件 |
