# AI 客服系统 - 部署与运维文档

**版本**: v1.0 | **更新日期**: 2026-02-28

---

## 目录

1. [系统架构](#系统架构)
2. [快速部署](#快速部署)
3. [启动方式](#启动方式)
4. [生产环境部署](#生产环境部署)
5. [多进程架构](#多进程架构)
6. [API 接口文档](#api-接口文档)
7. [触发条件详解](#触发条件详解)
8. [数据库](#数据库)
9. [配置说明](#配置说明)
10. [监控与日志](#监控与日志)
11. [故障排查](#故障排查)

---

## 系统架构

```
┌─────────────┐      ┌──────────────┐      ┌─────────────┐
│  天网服务器  │ ───→ │  AI 客服 API  │ ───→ │  企业微信   │
│  (公网 IP)   │      │ (127.0.0.1:6060)│    │  (轻简软件)  │
└─────────────┘      └──────────────┘      └─────────────┘
       ↑                     │
       └─────────────────────┘
                      ┌──────────────┐
                      │   SQLite     │
                      │  任务数据库   │
                      └──────────────┘
```

### 核心组件

| 组件 | 地址 | 说明 |
|------|------|------|
| AI 客服 HTTP API | `http://127.0.0.1:6060` | 接收天网任务 |
| 天网服务器 | 公网 IP | 任务调度中心 |
| 轻简软件 | `ws://127.0.0.1:9528` | 企业微信连接 |
| 任务数据库 | SQLite 本地存储 | 任务持久化 |

---

## 快速部署

### 步骤 1：环境检查

```bash
python3 --version  # 需要 3.8+
cd /root/ai_customer_service/ai_cs
pip3 install -r requirements.txt
```

### 步骤 2：启动服务

```bash
cd /root/ai_customer_service/ai_cs

# 前台运行（测试用）
python3 run.py --api-only

# 后台运行（生产用）
nohup python3 run.py --api-only > /tmp/tianwang.log 2>&1 &
```

### 步骤 3：验证

```bash
curl http://localhost:6060/api/health
# 预期: {"code":200,"data":{"service":"ai-cs-tianwang-bridge",...},"message":"OK"}
```

---

## 启动方式

统一入口 `run.py`，通过参数切换模式：

```bash
# 仅 HTTP API（天网简化版，推荐）
python3 run.py --api-only

# 完整版（HTTP API + WebSocket + AI Agent）
python3 run.py --tianwang

# WebSocket 客服模式（默认）
python3 run.py

# 多进程模式
python3 run.py --multi --workers 4

# 不启用 AI Agent
python3 run.py --no-agent

# 指定 HTTP 端口
python3 run.py --api-only --port 8080
```

---

## 生产环境部署

### 方式 1：systemd 服务（推荐）

```bash
cat > /etc/systemd/system/ai-cs-tianwang.service << 'SERVICE'
[Unit]
Description=AI Customer Service with Tianwang
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root/ai_customer_service/ai_cs
ExecStart=/usr/bin/python3 run.py --api-only
Restart=always
RestartSec=10
LimitNOFILE=65535
Environment="HTTP_API_PORT=6060"
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ai-cs-tianwang

[Install]
WantedBy=multi-user.target
SERVICE

systemctl daemon-reload
systemctl enable ai-cs-tianwang
systemctl start ai-cs-tianwang
systemctl status ai-cs-tianwang
journalctl -u ai-cs-tianwang -f
```

### 方式 2：Docker 部署

```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 6060
CMD ["python3", "run.py", "--api-only"]
```

```bash
docker build -t ai-cs-tianwang .
docker run -d \
  --name ai-cs \
  -p 6060:6060 \
  -v /root/ai_customer_service/ai_cs/db:/app/db \
  --restart unless-stopped \
  ai-cs-tianwang
```

### 方式 3：后台运行（简单场景）

```bash
nohup python3 run.py --api-only > /tmp/tianwang.log 2>&1 &
ps aux | grep "run.py"
tail -f /tmp/tianwang.log
pkill -f "run.py"  # 停止
```

---

## 多进程架构

### 架构说明

```
单进程（默认）                 多进程（可选）
┌─────────────────┐           ┌─────────┐  ┌─────────┐  ┌─────────┐
│ Python 进程     │           │进程 1    │  │进程 2    │  │进程 3    │
│ asyncio Loop    │           │客户 A,B  │  │客户 C,D  │  │客户 E,F  │
│ 所有客户 + Agent │           └─────────┘  └─────────┘  └─────────┘
└─────────────────┘
```

### 使用方法

```bash
# 多进程模式（默认 CPU 核心数）
python3 run.py --multi

# 指定进程数
python3 run.py --multi --workers 4

# 或使用专用启动器
python3 scripts/multi_process_launcher.py --workers 4
```

### 分片算法

客户按 `acc_id:from_id` 的 MD5 hash 值分配到不同进程，同一客户始终在同一进程。

### 性能对比

| 指标 | 单进程 | 多进程 (4 核) |
|------|--------|-------------|
| 并发客户数 | ~50 | ~200 |
| CPU 使用率 | 25% | 80% |
| 故障影响 | 全局 | 局部 |

---

## API 接口文档

### 1. 接收任务

**POST** `/api/task/receive`

```bash
curl -X POST http://localhost:6060/api/task/receive \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "TASK_20260227_001",
    "type": "send_file_after_reply",
    "customer": {"id": "customer_123", "name": "小明"},
    "trigger": {
      "type": "specified_customer_reply",
      "customer_id": "customer_123",
      "customer_name": "小明",
      "keyword": "好的",
      "exact_match": false
    },
    "action": {"type": "send_message", "message": "这是您要的文件"},
    "priority": "normal",
    "timeout_hours": 24,
    "created_by": "设计师 lz"
  }'
```

**响应**:
```json
{"code": 200, "message": "任务接收成功", "data": {"task_id": "TASK_20260227_001", "status": "pending"}}
```

### 2. 查询任务状态

**GET** `/api/task/status/:task_id`

```bash
curl http://localhost:6060/api/task/status/TASK_20260227_001
```

### 3. 取消任务

**POST** `/api/task/cancel`

```bash
curl -X POST http://localhost:6060/api/task/cancel \
  -H "Content-Type: application/json" \
  -d '{"task_id": "TASK_20260227_001", "reason": "客户取消订单"}'
```

### 4. 任务列表

**GET** `/api/task/list`

参数: `customer_id`(可选)、`status`(可选)、`page`(默认1)、`page_size`(默认20)

```bash
curl "http://localhost:6060/api/task/list?status=pending&page=1&page_size=10"
```

### 5. 健康检查

**GET** `/api/health`

```bash
curl http://localhost:6060/api/health
```

---

## 触发条件详解

### 1. specified_customer_reply（推荐）

指定客户回复指定内容时触发。

```json
{
  "trigger": {
    "type": "specified_customer_reply",
    "customer_id": "customer_123",
    "customer_name": "小明",
    "keyword": "好的",
    "exact_match": false
  }
}
```

| 字段 | 必填 | 说明 |
|------|------|------|
| `customer_id` | 是 | 指定客户 ID |
| `customer_name` | 否 | 指定客户名称 |
| `keyword` | 是 | 回复关键词 |
| `exact_match` | 否 | 是否精确匹配（默认 false）|

**exact_match 说明**:
- `false`: 消息**包含**关键词即触发（"好的谢谢" 匹配 "好的"）
- `true`: 消息**完全等于**关键词才触发

**匹配逻辑**:
```
客户发送消息 → 检查客户 ID → 检查客户名称(可选) → 检查关键词 → 触发
```

### 2. customer_reply

任意客户回复指定内容。

```json
{"trigger": {"type": "customer_reply", "keyword": "好的"}}
```

### 3. customer_keyword

任意客户说某关键词（支持多个）。

```json
{"trigger": {"type": "customer_keyword", "keywords": ["好的", "可以", "行"]}}
```

### 4. customer_payment

客户付款时触发。

```json
{"trigger": {"type": "customer_payment", "keywords": ["已付款", "拍下了"]}}
```

### 5. time_reach

到达指定时间触发。

```json
{"trigger": {"type": "time_reach", "time": "2026-02-28 09:00:00"}}
```

---

## 数据库

### 天网任务数据库

路径: `db/task_db/tasks.db`

```sql
CREATE TABLE tasks (
    task_id TEXT PRIMARY KEY,
    specified_customer_id TEXT,
    specified_customer_name TEXT,
    type TEXT NOT NULL,
    customer_name TEXT,
    customer_id TEXT,
    trigger_type TEXT,
    trigger_keyword TEXT,
    trigger_keywords TEXT,
    action_type TEXT,
    action_file_url TEXT,
    action_message TEXT,
    priority TEXT DEFAULT 'normal',
    timeout_hours INTEGER DEFAULT 24,
    status TEXT DEFAULT 'pending',
    retry_count INTEGER DEFAULT 0,
    max_retry INTEGER DEFAULT 3,
    created_at TEXT,
    created_by TEXT,
    triggered_at TEXT,
    completed_at TEXT,
    error_message TEXT,
    result TEXT
);
```

**任务状态流转**: `pending → waiting → running → completed / failed`

### 图片任务数据库

路径: `db/image_tasks.db`（详见 **项目功能汇总.md - 图片任务数据库**）

---

## 配置说明

### 环境变量

文件: `.env.tianwang`

```bash
AI_CS_HOST=127.0.0.1
AI_CS_PORT=6060
AI_CS_API_URL=http://127.0.0.1:6060
TIANWANG_CALLBACK_URL=http://127.0.0.1:6060/api/task/callback
```

### 天网回调配置

在 `core/task_scheduler.py` 中修改回调 URL:

```python
await client.post('http://tianwang-server/api/task/callback', json={...})
```

### 端口说明

| 端口 | 用途 |
|------|------|
| 6060 | HTTP API 服务器 |
| 9528 | 轻简软件 WebSocket（外部）|

**防火墙**:
```bash
firewall-cmd --add-port=6060/tcp --permanent && firewall-cmd --reload
```

---

## 监控与日志

### 查看进程状态

```bash
ps aux | grep "run.py"
netstat -tlnp | grep 6060
systemctl status ai-cs-tianwang  # systemd 方式
```

### 查看日志

```bash
tail -f /tmp/tianwang.log                              # 文件方式
journalctl -u ai-cs-tianwang -f                        # systemd 方式
grep "任务" /tmp/tianwang.log                           # 搜索任务日志
grep "派单" /tmp/tianwang.log                           # 搜索派单日志
grep "转接人工" /tmp/tianwang.log                       # 搜索转接日志
```

### 查看数据库

```bash
sqlite3 /root/ai_customer_service/ai_cs/db/task_db/tasks.db

SELECT task_id, type, status, created_at FROM tasks ORDER BY created_at DESC LIMIT 10;
SELECT * FROM tasks WHERE status='pending';
SELECT task_id, error_message FROM tasks WHERE status='failed';
SELECT status, COUNT(*) as count FROM tasks GROUP BY status;
.exit
```

---

## 故障排查

### API 无法访问

```bash
ps aux | grep "run.py"               # 检查进程
netstat -tlnp | grep 6060           # 检查端口
pkill -f "run.py"                    # 停止
nohup python3 run.py --api-only > /tmp/tianwang.log 2>&1 &
tail -f /tmp/tianwang.log            # 查看日志
```

### 任务接收失败（500 错误）

```bash
tail -f /tmp/tianwang.log | grep "ERROR"
sqlite3 db/task_db/tasks.db ".schema tasks"   # 检查数据库
# 如果数据库损坏：rm db/task_db/tasks.db 然后重启（自动重建）
```

### 任务未触发

```bash
curl http://localhost:6060/api/task/status/TASK_ID   # 检查状态
grep "任务触发" /tmp/tianwang.log                     # 查看触发日志
# 确认客户消息包含触发关键词
```

### 内存占用过高

```bash
ps aux | grep run_tianwang | awk '{print $6/1024 " MB"}'
# 建议每天定时重启
crontab -e
# 添加: 0 3 * * * pkill -f "run.py" && sleep 2 && nohup python3 /root/ai_customer_service/ai_cs/run.py --api-only > /tmp/tianwang.log 2>&1 &
```

### Worker 进程退出（多进程模式）

```bash
journalctl -u ai-cs-multi -f | grep "Worker.*退出"
systemctl restart ai-cs-multi
```

---

## 文件位置速查

| 文件 | 路径 |
|------|------|
| 启动脚本 | `run.py`（通过 `--api-only` / `--tianwang` 切换模式）|
| HTTP API | `api/http_server.py` |
| 任务调度 | `core/task_scheduler.py` |
| 数据模型 | `db/task_db/task_model.py` |
| 配置文件 | `.env.tianwang` |
| 日志文件 | `/tmp/tianwang.log` |
| 任务数据库 | `db/task_db/tasks.db` |

---

## 快速参考

```
┌─────────────────────────────────────────────┐
│  AI 客服 API - 快速参考                      │
├─────────────────────────────────────────────┤
│ 地址：http://localhost:6060                  │
│                                             │
│ POST /api/task/receive    - 接收任务        │
│ GET  /api/task/status/:id - 查询状态        │
│ POST /api/task/cancel     - 取消任务        │
│ GET  /api/task/list       - 任务列表        │
│ GET  /api/health          - 健康检查        │
│                                             │
│ 启动：python3 run.py --api-only             │
│ 日志：tail -f /tmp/tianwang.log             │
│ 数据库：sqlite3 db/task_db/tasks.db         │
└─────────────────────────────────────────────┘
```
