# 天璇 (TianXuan) — TLS 流数据分析与实体画像系统

基于 Polars + scikit-learn + Three.js 的 TLS 流数据分析工具链。支持 CSV 批量导入、自动实体检测、多维聚合、聚类分析、特征提取、**3D 地球流量可视化**。提供 Django Web 操作界面和 MCP 协议接口，支持 32B 大语言模型编排分析流程。**全离线运行**，所有 JS 库/地图贴图/GeoIP 数据库均已内嵌。

---

## 目录

1. [系统概述](#1-系统概述)
2. [快速开始](#2-快速开始)
3. [用户指南](#3-用户指南)
4. [页面功能说明](#4-页面功能说明)
5. [CLI 管道](#5-cli-管道)
6. [MCP 工具文档](#6-mcp-工具文档)
7. [测试](#7-测试)
8. [项目结构](#8-项目结构)
9. [常见问题](#9-常见问题)

---

## 1. 系统概述

### 1.1 解决的问题

企业网络中 TLS 流量通常以 CSV 形式导出（每行一条流记录），数据量大、列名不统一、缺乏标签。本系统提供一条从原始 CSV 到实体画像的自动化分析流水线：

```
CSV 文件 → 上传/加载 → 自动检测实体列 → 按实体聚合特征
→ 实体级聚类 → 提取每簇区分特征 → Web 可视化 / MCP 接口
```

### 1.2 核心能力

| 模块 | 功能说明 |
|------|---------|
| **数据加载** | 多文件合并、BOM 自动检测、跨文件 schema 容错、递归 `**/*.csv`、中文路径支持 |
| **实体检测** | 基于列名关键词 + 唯一值比率 + 数据类型的三维打分，自动推荐实体列（如 `src_ip`、`sni`、`user`） |
| **实体聚合** | 按实体分组计算流统计、目标多样性、TLS 特征、协议特征、时间模式、地理位置（经纬度） |
| **IP 子网聚合** | 支持 /24 和 /28 子网掩码，同一子网下所有 IP 合并为一个实体节点 |
| **多列复合键** | 支持 `(src_ip, dst_ip)` 等多列组合作为实体标识 |
| **聚类分析** | HDBSCAN（自动确定簇数）/ KMeans，零样本自动降级，Silhouette / Davies-Bouldin 质量评估 |
| **特征提取** | Z-Score / ANOVA 方法计算每个聚类的区分性特征 |
| **3D 地球** | 基于 Three.js 的 TLS 流量弧线可视化，多数据源叠加，经纬线网格，国境线轮廓 |
| **地理可视化** | PCA 散点图 + Canvas 原生渲染（无外部 JS 依赖） |
| **LLM 集成** | OpenAI 兼容 API、LLM 自动编排分析流程（profile → 实体 → 聚类 → 特征） |
| **Web 界面** | CSV 上传拖拽、手动分步分析向导、LLM 自动分析、配置管理、运行记录查看 |
| **MCP 协议** | 12 个 JSON-RPC 工具，供外部 LLM 编排调用 |
| **便携运行时** | 项目内置 Python 3.12 运行时（593MB），零系统依赖，`run.bat` 双击即用 |

### 1.3 技术栈

| 组件 | 技术选型 |
|------|---------|
| **后端框架** | Django 4.2 (SQLite WAL) |
| **数据处理** | Polars 1.42.1 (LazyFrame 延迟计算 + streaming) |
| **机器学习** | scikit-learn (StandardScaler, HDBSCAN, KMeans, PCA) |
| **MCP 协议** | Python MCP SDK (stdio 传输) |
| **前端 3D** | Three.js (603KB, 离线) |
| **前端图表** | 纯 Canvas 2D API 原生绘制 |
| **配置** | Pydantic + YAML |
| **LLM 接口** | OpenAI chat/completions 兼容 API |
| **运行时** | 嵌入式 Python 3.12 (Win7 兼容版 adang1345) |

---

## 2. 快速开始

### 2.1 用户模式（无需预装 Python）

```bat
1. 解压项目文件夹到任意目录
2. 双击 run.bat
3. 等待命令行显示 "Starting TianXuan..."
4. 浏览器自动打开 http://127.0.0.1:8000/
5. 点击「上传数据」→ 选择 CSV 文件 → 上传 → 等待预处理完成
6. 进入「手动分析」→ 选择数据集 → 配置参数 → 运行分析
7. 查看结果：聚类概览、簇详情、实体画像、地球分布图
```

### 2.2 开发者模式

```bash
# 初始化数据库
runtime\python\python.exe manage.py migrate

# 生成测试数据
runtime\python\python.exe scripts\gen_test_data.py --rows 1000

# 启动开发服务器
runtime\python\python.exe manage.py runserver

# 浏览器打开 http://127.0.0.1:8000/
```

### 2.3 脚本一览

| 脚本 | 功能 |
|------|------|
| `run.bat` | 启动 Django Web 界面（:8000），自动打开浏览器 |
| `shell.bat` | 打开 Django Shell（Python 交互式环境） |

### 2.4 一键分析管道

```bash
# 加载 CSV → 自动检测实体 → 聚合 → 聚类 → 特征提取 → 写入数据库
runtime\python\python.exe manage.py run_pipeline "data/input.csv"

# 指定聚类算法
runtime\python\python.exe manage.py run_pipeline "data/*.csv" --algo kmeans

# 手动指定实体列（跳过自动检测）
runtime\python\python.exe manage.py run_pipeline "data/*.csv" --entity-col src_ip

# 导出结果
runtime\python\python.exe manage.py run_pipeline "data/*.csv" --output ./results/
```

输出示例：
```
[1/5] 加载 CSV: data/test_flows.csv → 500 rows, 1 files, 0.2 MB
[2/5] 检测实体列 → 自动检测: src_ip (共 6 候选)
[3/5] 实体聚合 → 50 个实体, 18 维特征
[4/5] 聚类 (hdbscan) → 2 个簇, 噪声比 0.24, Silhouette: 0.2557
[5/5] 特征提取 → 30 个特征已保存到数据库
*** 分析完成! Run ID: #1
```

---

## 3. 用户指南

### 3.1 上传数据

1. 点击导航栏「上传数据」
2. 拖拽 CSV 文件到虚线区域，或点击选择文件
3. 支持多文件上传，自动拼接相同 schema 的文件
4. 支持 `schema_strict=false` 模式（默认）：不同列名的文件会自动合并，缺失列填 null
5. 支持 `.zip` 压缩包自动解压
6. 上传后自动在后台进行预处理（加载 → 检测实体列 → 聚合），完成后状态变为 `ready`
7. 进度条实时显示处理状态

**数据格式要求**：
- 每行一条 TLS 流记录
- 建议包含列：`src_ip`、`dst_ip`、`proto`、`bytes_sent`、`bytes_rev`、`duration`、`packets` 等
- 可选地理列：`latitude` / `lat` / `y` 和 `longitude` / `lon` / `lng` / `x`（自动识别）
- 可选时间列：`timestamp` / `ts` / `time`（自动识别）

### 3.2 手动分析

3 步向导完成分析：

**Step 1 - 选择数据集**：从已预处理完成的数据集中选择一个（显示行数、已检测的实体列）

**Step 2 - 配置参数**：
- 聚类算法：HDBSCAN（自动确定簇数，推荐）/ KMeans（需预设 k 值）
- 最小簇大小（min_cluster_size）：默认 5，数据不足时自动降级

**Step 3 - 确认运行**：回顾配置，点击「开始分析」。后台自动完成聚类 + 特征提取，完成后跳转到结果页。

### 3.3 LLM 自动分析

需要先在「配置」页面设置 LLM 的 base_url 和 API Key：

1. 进入「LLM 分析」页面
2. 选择一个已预处理的数据集
3. 点击「开始自动分析」
4. 后端 LLM 编排器会自动调用 profile → build_entity_profiles → run_clustering → extract_features
5. 进度条实时显示当前步骤

### 3.4 查看结果

#### 运行详情页
- 总流数、实体数、簇数 摘要卡片
- 簇列表：每个簇的大小、占比、Silhouette 分数

#### 聚类概览页
- **PCA 散点图**：实体在二维主成分空间中的分布，颜色区分聚类
- **地理分布图**：实体在地理坐标上的分布（需 CSV 包含经纬度列），支持缺失值
- 每个簇的详情卡片：Top 5 区分特征

#### 簇详情页
- 特征表：每列的均值、标准差、中位数、区分度分数（Top 50）
- 实体列表：该簇包含的实体（Top 50），可点击查看详情

#### 实体画像页
- 实体标识、所属簇
- 聚合特征值和相对簇均值的偏离（Z-score）
- 偏差显著的特征以颜色高亮（|Z| > 2）

#### 3D 地球页
- Three.js 3D 地球，TLS 流量弧线连接源目 IP
- 弧线颜色标识 TLS 版本（TLSv1.3 蓝 / v1.2 粉 / 其他青）
- 鼠标拖拽旋转、滚轮缩放
- 经纬线网格 + 国境线轮廓
- 多数据源叠加复选框
- 脉冲光点动画（背面剔除）

---

## 4. 页面功能说明

| 页面 | 路由 | 功能 |
|------|------|------|
| **首页** | `/` | 最近运行记录概览 |
| **上传数据** | `/upload/` | 拖拽上传 CSV，自动预处理 |
| **手动分析** | `/analyze/manual/` | 3 步向导：选数据→设参数→运行 |
| **LLM 分析** | `/analyze/auto/` | LLM 自动编排分析流程 |
| **运行记录** | `/runs/` | 所有分析运行列表 |
| **运行详情** | `/runs/<id>/` | 单次运行摘要 + 簇列表 |
| **聚类概览** | `/clusters/<run_id>/` | PCA 散点图 + 每簇区分特征 |
| **簇详情** | `/clusters/<run_id>/<label>/` | 特征表 + 实体列表 |
| **实体画像** | `/entities/<id>/` | 单实体特征 + 簇偏离 |
| **3D 地球** | `/globe/` | Three.js 流量弧线可视化 |
| **配置** | `/config/` | 系统配置编辑 + LLM 测试 |
| **日志** | `/logs/` | 运行日志查看 |

---

## 5. CLI 管道

```bash
# 完整管道（HDBSCAN 默认）
runtime\python\python.exe manage.py run_pipeline data/complex_test.csv

# 指定 KMeans
runtime\python\python.exe manage.py run_pipeline data/*.csv --algo kmeans

# 手动指定实体列
runtime\python\python.exe manage.py run_pipeline data/*.csv --entity-col src_ip

# 设置子网聚合掩码
runtime\python\python.exe manage.py run_pipeline data/*.csv --subnet-masks 24 28
```

---

## 6. MCP 工具文档

### 6.1 工具总览

系统通过 MCP (Model Context Protocol) 暴露 12 个工具，支持 LLM 以 JSON-RPC 方式编排调用。

| # | 工具名 | 功能 | 必需参数 |
|---|--------|------|----------|
| 1 | `load_data` | 加载 CSV 文件（支持 glob、递归、schema 容错） | `csv_glob` |
| 2 | `profile_data` | 数据集概要统计 + 相关性矩阵 | `dataset_id` |
| 3 | `filter_data` | 按条件过滤（12 操作符 + AND/OR） | `dataset_id`, `filters` |
| 4 | `preprocess_data` | 预处理（标准化/编码/填充） | `dataset_id`, `columns` |
| 5 | `run_clustering` | 执行聚类（HDBSCAN/KMeans，带质量评估） | `dataset_id`, `cluster_columns` |
| 6 | `evaluate_clustering` | 评估聚类质量（Silhouette/DB/CH） | `cluster_result_id`, `dataset_id` |
| 7 | `extract_features` | 提取各聚类区分特征（Z-Score/ANOVA） | `dataset_id`, `cluster_result_id` |
| 8 | `export_results` | 导出结果到磁盘（CSV/Parquet/JSON） | `result_id`, `output_path` |
| 9 | `list_datasets` | 列出所有活跃数据集 | 无 |
| 10 | `drop_dataset` | 删除数据集释放内存 | `dataset_id` |
| 11 | `clone_dataset` | 浅拷贝数据集（不复制数据） | `dataset_id` |
| 12 | `build_entity_profiles` | 自动检测实体列 + 聚合画像 | `dataset_id` |

### 6.2 响应约定

- 成功时返回 JSON 对象，含 `truncated: false`
- 超过阈值时自动截断，设置 `truncated: true` + `omitted_columns`
- 错误时返回 `{ "error": "描述", "truncated": false }`
- 所有响应通过 `TextContent` 包装返回

### 6.3 JSON-RPC 调用示例

```
→ {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"load_data","arguments":{"csv_glob":"data/*.csv"}}}
← {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"dataset_id\":\"ds_...\",\"row_count\":500}"}]}}

→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"build_entity_profiles","arguments":{"dataset_id":"ds_...","auto_detect":true}}}
← {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"entity_dataset_id\":\"entity_...\",\"entity_count\":50,\"entity_column_used\":\"src_ip\"}"}]}}
```

---

## 7. 测试

```bash
# 运行全部测试
runtime\python\python.exe -m pytest tests -q

# 运行特定测试文件
runtime\python\python.exe -m pytest tests/test_entity.py -v

# 运行端到端测试
runtime\python\python.exe -m pytest tests/test_e2e.py -v
```

### 生成测试数据
```bash
# 简单数据
runtime\python\python.exe scripts\gen_test_data.py --rows 1000

# Globe 模式（IP 在真实 GeoIP 范围内，弧线可见）
runtime\python\python.exe scripts\gen_test_data.py --globe

# 复杂数据（5000 行 24 列含 55% 缺失）
runtime\python\python.exe scripts\gen_complex_test.py --rows 5000
```

### 列结构调查
```bash
# 统计各 CSV 文件的列名、类型、分布
runtime\python\python.exe scripts\column_survey.py --csv "data/*.csv"
```

---

## 8. 项目结构

```
tianxuan/
├── tianxuan/                 # Django 项目配置
│   ├── settings.py           # Django 配置（数据库、中间件）
│   ├── urls.py               # 根路由
│   └── llm_orchestrator.py   # LLM 编排后端（tool_calls 循环）
│
├── analysis/                 # 核心分析模块（Django app）
│   ├── data_loader.py        # CSV 加载、BOM 检测、schema 容错、递归 glob
│   ├── data_profiler.py      # 数据集概要统计与相关性矩阵
│   ├── entity_detector.py    # 实体列自动检测（关键词 + unique_ratio 打分）
│   ├── entity_aggregator.py  # 实体聚合（流→实体画像），含 IP 子网聚合
│   ├── type_classifier.py    # 值优先类型检测（MAC/端口/IPv4/URL/HEX/ENUM/LAT_LON）
│   ├── data_validator.py     # 列校验（缺失率/异常值/IP有效性）
│   ├── geoip.py              # GeoIP 经纬度查询
│   ├── session_store.py      # 线程安全内存会话存储（Singleton + RLock）
│   ├── tool_registry.py      # 12 个 MCP 工具定义 + 异步处理函数
│   ├── mcp_server.py         # MCP stdio 服务器
│   ├── views.py              # 所有 Django 视图
│   ├── urls.py               # 16 条 URL 路由
│   ├── models.py             # ORM 模型
│   └── management/commands/
│       ├── start_mcp.py      # manage.py start_mcp
│       └── run_pipeline.py   # manage.py run_pipeline（一键 CLI 管道）
│
├── config/
│   ├── config.yaml           # 配置文件（自动生成，带注释）
│   └── loader.py             # Pydantic 配置加载器
│
├── templates/tianxuan/       # 11 个页面模板
├── static/tianxuan/          # Three.js + 地球贴图 + 国境线
├── runtime/python/           # 便携 Python 3.12 运行时（593MB）
├── tests/                    # 53 个测试 (pytest)
├── scripts/                  # 工具脚本
├── docs/                     # 文档
├── run.bat                   # 用户启动脚本（双击即用）
└── manage.py                 # Django 管理入口
```

---

## 9. 常见问题

### Q1: 双击 run.bat 后浏览器没打开？
A: 手动打开浏览器访问 `http://127.0.0.1:8000/`。如果也无法访问，检查命令行是否有报错。

### Q2: 压缩时提示 `db.sqlite3-wal 被占用`？
A: 有残留的 Python 进程持有 SQLite 连接。运行以下命令后重试：
```powershell
Get-Process python -ErrorAction SilentlyContinue | Stop-Process -Force
Remove-Item db.sqlite3-wal, db.sqlite3-shm -Force -ErrorAction SilentlyContinue
```

### Q3: 地图不显示？
A: CSV 需包含 lat/lon 列（列名含 `lat`/`latitude`/`lon`/`longitude`/`lng` 自动识别），缺失值不显示。页面会提示跳过的数量。

### Q4: 上传 CSV 后显示 "处理失败"？
A: 在运行详情页查看错误消息。常见原因：
- CSV 编码不是 UTF-8
- 所有列都是非数值类型（无法聚类，返回 0 簇）
- 数据量太小（< 3 条实体记录，HDBSCAN 自动跳过）

### Q5: 如何配置 LLM？
A: 导航到「配置」页面，填写 base_url 和 API Key，点击「测试连通性」验证。支持 OpenAI 兼容的任何 API。

### Q6: 支持哪些 CSV 编码？
A: 自动检测 UTF-8 BOM、UTF-16LE BOM、UTF-16BE BOM。无 BOM 时默认 UTF-8。中文路径完全支持。

### Q7: 不同 CSV 文件的列名不一致怎么办？
A: 默认 `schema_strict=false`，系统自动取所有文件的列名并集，缺失列填 null。如需严格模式，在配置中将 `schema_strict` 改为 `true`。

### Q8: 项目太大，如何缩小？
```powershell
Remove-Item -Recurse *.pyc, __pycache__ -Force
Remove-Item db.sqlite3-wal, db.sqlite3-shm -Force -ErrorAction SilentlyContinue
```

---

## 10. 增量更新（部署到离线机）

天璇支持**增量更新**，只需将变更代码打包成小 zip 包，复制到离线机双击 `update.bat` 即可完成更新，无需每次传输整个项目（1.5GB）。

### 10.1 首次部署

在离线机上第一次部署时，需要完成数据库迁移：

```bat
:: 确保数据库在 %APPDATA%/TianXuan/ 下
runtime\python\python.exe scripts\migrate_db_to_appdata.py

:: 初始化数据库表
runtime\python\python.exe manage.py migrate

:: 导入 TLS 引用数据
runtime\python\python.exe manage.py import_tlsdb
```

> 如果之前已在使用天璇，`migrate_db_to_appdata.py` 会自动将已有 `db.sqlite3` 复制到新位置。

### 10.2 开发机：构建更新包

在**开发机**上完成代码修改并提交后：

```bash
# 确保工作树干净（无未提交变更）
git status

# 构建增量更新包
python scripts/build_update.py
```

脚本会自动：
1. 检测当前 git tag 与最近一次 tag 之间的文件变更
2. 计算每个文件的 SHA256 校验和
3. 打包为 `tianxuan_update_<旧版本>-<新版本>.zip`
4. 更新 `VERSION` 文件
5. 如果检测到依赖变更，会输出提示信息

**输出示例**：
```
==================================================
  天璇 增量更新包构建工具
==================================================

当前 VERSION: v1.0.0
最新 git tag: v1.0

变更文件: 5 个修改/新增, 1 个删除

==================================================
✅ 增量更新包构建完成！
  包: tianxuan_update_v1.0-v1.1.zip
  大小: 0.05 MB
  从: v1.0
  到: v1.1
  文件数: 5
  删除: 1
==================================================
```

### 10.3 离线机：应用更新

在**离线机**上：

1. 将 `tianxuan_update_*.zip` 复制到天璇项目目录（与 `run.bat` 同目录）
2. **双击 `update.bat`**（或拖拽 zip 到 `update.bat` 上）
3. 等待更新完成
4. 关闭窗口，重新双击 `run.bat` 启动新版本

更新脚本会自动：
1. ✅ 验证更新包完整性（SHA256 校验）
2. ✅ 备份当前配置（`config/config.yaml`）
3. ✅ 删除废弃文件
4. ✅ 覆盖更新文件
5. ✅ 智能合并配置（保留你的设置，仅增加新配置项）
6. ✅ 清理 Python 缓存
7. ✅ 运行数据库迁移
8. ✅ 更新版本号

### 10.4 回滚

如果更新后出现问题：

```
双击 rollback.bat
→ 输入 y 确认回滚
→ 等待恢复完成
→ 重新双击 run.bat 启动旧版本
```

回滚会从 `%APPDATA%/TianXuan/backups/` 恢复最近一次备份。

### 10.5 依赖变更时的特殊处理

当 `pyproject.toml` 或 `requirements.txt` 变更时（即添加/更新了 Python 依赖），构建脚本会输出警告：

```
⚠️  依赖已变更！请手动将 runtime/ 目录同步到离线机
```

此时需要额外步骤：

1. 在开发机上将 `runtime/` 目录**完整压缩**（约 645MB）
2. 复制到离线机，覆盖 `runtime/` 目录
3. 或者使用差异更新：仅覆盖变更的包目录（`runtime/python/Lib/site-packages/`）

> 依赖变更是低频操作（通常只在添加新功能时需要），所以这不会影响日常的代码增量更新。

### 10.6 文件说明

| 文件 | 用途 | 需要 git 跟踪？ |
|------|------|----------------|
| `VERSION` | 记录当前版本号 | ✅ 是 |
| `scripts/build_update.py` | 开发机：构建增量包 | ✅ 是 |
| `scripts/apply_update.py` | 离线机：应用更新 | ✅ 是 |
| `scripts/merge_config.py` | 合并用户配置与源码配置 | ✅ 是 |
| `scripts/migrate_db_to_appdata.py` | 首次迁移数据库到 APPDATA | ✅ 是 |
| `scripts/version_utils.py` | 版本工具函数 | ✅ 是 |
| `update.bat` | 离线机双击入口 | ✅ 是 |
| `rollback.bat` | 回滚入口 | ✅ 是 |
| `analysis/appdata.py` | APPDATA 路径共享模块 | ✅ 是 |
| `.update_cache/runtime_snapshot.json` | 运行时依赖快照（自动生成）| ❌ 否 |
| `RUNTIME_CHANGED.txt` | 依赖变更提示（自动生成）| ❌ 否 |

### 10.7 目录结构变化

更新系统将用户数据与项目代码分离：

```
项目目录（可安全覆盖）              用户数据目录（永不覆盖）
天璇/                              %APPDATA%/TianXuan/
├── analysis/          ← 代码       ├── db.sqlite3        ← 数据库
├── config/config.yaml ← 配置       ├── data/uploads/     ← 上传的 CSV
├── runtime/           ← 运行时      ├── .session_store.json
├── templates/         ← 模板        └── backups/          ← 更新备份
├── static/            ← 静态资源
├── scripts/           ← 工具脚本
├── update.bat         ← 更新入口
└── VERSION            ← 版本号
```


```
