# 天璇 (TianXuan) 分析工作流

> 从原始 TLS 流 CSV 到实体画像、聚类结果、区分特征、UMAP 可视化的完整流水线文档。当前版本 v3.0。

---

## 目录

1. [工具总览](#1-工具总览)
2. [标准分析流程](#2-标准分析流程)
3. [数据准备与加载](#3-数据准备与加载)
4. [类型检测与数据校验](#4-类型检测与数据校验)
5. [实体识别与聚合](#5-实体识别与聚合)
6. [自适应评分](#6-自适应评分)
7. [聚类分析](#7-聚类分析)
8. [特征提取与 UMAP 嵌入](#8-特征提取与-umap-嵌入)
9. [可视化](#9-可视化)
10. [LLM 集成](#10-llm-集成)
11. [手动分析工作流](#11-手动分析工作流)
12. [跨机部署](#12-跨机部署)

---

## 1. 工具总览

系统现有 **30 个 MCP 工具**, 分四层, 实现于 `analysis/tools/` 包的 14 个 handler 模块。完整列表见 [AGENTS.md](../AGENTS.md) 中的「30 MCP Tools」表。

**标准分析链 (`load_data → filter_data → profile_data → build_entity_profiles → compute_scores → run_clustering → extract_features`)** 覆盖从 CSV 加载到 UMAP 可视化的全流程。LLM 自动模式由 `tianxuan/llm_orchestrator.py` 驱动, 策略式提示词: 先 profile 了解数据 → 根据数据决策下一步 → 失败自动调诊断工具 → 最终中文总结。

### 降维方案: UMAP + TruncatedSVD

| 方法 | 用途 | 触发条件 | 代码位置 |
|------|------|---------|------------|
| **UMAP** (n_components=2) | 实体 2D 嵌入可视化, 存入 EntityProfile 表 (embedding_x/y) | `extract_features` 执行时自动计算 | `tools/features.py::_handle_extract_features` |
| **TruncatedSVD** (n_components=50) | 聚类前高维特征降维 (>50 维时) | `run_clustering` / `filter_and_cluster` 执行时 | `tools/clustering.py::_handle_run_clustering` |
| **TruncatedSVD** (n_components=1) | 自适应评分权重学习 (SVD 第一分量 loading) | `compute_scores` 被调用时 | `tools/entities.py::_add_adaptive_scores` |
| **PCA-2D** (legacy) | 前端 cluster_overview 散点图 (Canvas 绘制) | CLI pipeline 步骤 6 | `views/pipeline.py` / `run_pipeline.py` |

**距离计算**: `analysis/distance.py` 提供 IP 子网距离、地理距离 (Haversine)、Levenshtein、Hamming、FFT 相位距离。`compute_distance_matrix` 工具额外允许 LLM 编写 Python 距离函数体 (签名 `def distance_fn(row: dict) -> float:`), 在受限命名空间 (math, numpy) 中逐行执行, 用于现有工具无法表达的一次性度量。

---

## 2. 标准分析流程

```
load_data → profile_data → build_entity_profiles → compute_scores → run_clustering → extract_features
```

### 2.1 加载数据 (`load_data`)

```python
load_data(
    csv_glob="data/*.csv",         # glob 支持递归 **/*.csv
    schema_strict=False,            # 自动并集合并, 缺失列填 null
    recursive=False,
    encoding="utf-8",
)
# 返回: dataset_id, schema, row_count, file_count, memory_mb
```

实现: `tools/load_data.py::_handle_load_data` → `data_loader.py::load_csv_directory` (BOM 检测、编码回退、schema 容错合并)。

### 2.2 了解数据 (`profile_data`)

```python
profile_data(dataset_id="ds_...", sample_size=1000)
# 返回: 列类型/统计/空值率/相关性矩阵 (自动截断 64KB)
```

实现: `tools/profile.py::_handle_profile_data` → `data_profiler.py` 列统计 + 相关性矩阵计算。

### 2.3 构建实体画像 (`build_entity_profiles`)

```python
build_entity_profiles(
    dataset_id="ds_...",
    auto_detect=True,              # 自动检测 IP/SNI/host/MAC/domain 列
    # 或手动指定:
    # entity_columns=["src_ip", "dst_ip"]  # 多列复合键
)
# 返回: dataset_id (entity_前缀), entity_columns, n_entities, n_features
```

实现: `tools/entities.py::_handle_build_entity_profiles`, 融合了原 entity_detector (列检测) 和 entity_aggregator (聚合) 的逻辑。

### 2.4 计算异常分数 (`compute_scores`)

```python
compute_scores(dataset_id="entity_ds_...")
# 内部流程:
# 1. 采样 10K 行 → TruncatedSVD(n_components=1) 学习特征权重
# 2. 加权求和 → proxy_score (0-1)
# 3. IQR 阈值 → risk_level (normal/watch/suspicious/critical)
# 4. 复合 → threat_score
```

实现: `tools/entities.py::_handle_compute_scores` + `_add_adaptive_scores`。

### 2.5 聚类分析 (`run_clustering`)

```python
run_clustering(
    dataset_id="entity_ds_...",
    cluster_columns=["flow_count", "unique_dst_ips", ...],  # 或自动选数值列
    algorithm="hdbscan",           # 或 "kmeans"
    random_state=42,
)
```

预处理链: 列过滤 → NaN 填充 (列均值) → StandardScaler → 方差过滤 (< 1e-10) → 相关过滤 (> 0.95 Pearson) → **TruncatedSVD (>50 特征时降维至 50)** → 聚类

实现: `tools/clustering.py::_handle_run_clustering`。

### 2.6 提取特征 (`extract_features`)

```python
extract_features(
    dataset_id="entity_ds_...",
    cluster_result_id="clust_...",
    method="zscore",               # 或 "anova"
    top_k=10,
)
```

执行: Z-Score/ANOVA 特征重要性 → **UMAP-2D 嵌入** (训练 10K 样本, 批量变换 1K 批次) → EntityProfile 表存储坐标 → ClusterFeature 表存储区分特征。

实现: `tools/features.py::_handle_extract_features` + `_save_features_to_db`。

---

## 3. 数据准备与加载

### 3.1 CSV 格式要求

| 要求 | 说明 |
|------|------|
| 分隔符 | 逗号 `,` (默认), 支持自定义 |
| 文件扩展名 | `.csv` |
| 多文件 | glob 通配符、`**/*.csv` 递归扫描、自动合并 |
| 压缩包 | `.zip` 文件自动解压 (上传界面) |
| 文件数量 | 无硬性限制 (Polars `diagonal_relaxed` 合并) |

### 3.2 编码支持

| 编码 | BOM | 自动检测 |
|------|-----|---------|
| UTF-8 (推荐) | 无 / `EF BB BF` | 默认 |
| UTF-8 with BOM | `EF BB BF` | 自动 |
| UTF-16LE | `FF FE` | 自动 |
| UTF-16BE | `FE FF` | 自动 |

> **生产建议**: 始终使用 UTF-8 无 BOM 编码。`run.bat` 已内置 `PYTHONUTF8=1`。

### 3.3 Schema 容错

| 模式 | 行为 |
|------|------|
| `schema_strict: false` (默认) | 自动并集合并, 缺失列填 null |
| `schema_strict: true` | 列名不一致时报 ValueError |

实现: `data_loader.py::load_csv_directory` 中的 `diagonal_relaxed` 合并策略。

---

## 4. 类型检测与数据校验

### 4.1 值优先类型检测

`analysis/type_classifier.py` 实现六阶段类型推断:

```
配置指定 (config.yaml columns section) → 值采样检测 (85%+ 合规即判定)
    → 名称推断 (下划线分词关键词匹配) → STRING 回退
```

支持类型: MAC, PORT, IPv4, URL, HEX, ENUM, LAT_LON, BOOL_ENUM, TIMESTAMP, INT, FLOAT, STRING。

### 4.2 数据校验

`analysis/data_validator.py::validate()` 检查: 列类型矛盾、缺失率 (>50% 高风险)、异常值 (Z-score > 5 比例)、枚举分布、IPv4 有效性。

### 4.3 自动清洗

在 `load_csv_directory()` 中自动执行: BOOL_ENUM 标准化 (`"+"` → True, `""` → null)、HEX 列添加 `hex_pairs_count` 辅助列、通用数值清洗 (`_coerce_to_float` 处理 `+`/`-`/空白/N/A 等伪值)。

---

## 5. 实体识别与聚合

### 5.1 实体列检测

`tools/entities.py::_handle_build_entity_profiles` 中的自动检测逻辑 (合并了原 `entity_detector.py` 的功能):

- **关键词匹配**: 列名下划线分词后匹配 `_ENTITY_KEYWORDS` 集合 (IP, SNI, host, MAC, domain, user, id, name, ...)
- **数据类型判断**: IPv4 列、ENUM 列自动纳入候选
- **唯一值比率**: 高唯一率 (>50%) 加权, 极高唯一率 (>90%) 惩罚
- **空值惩罚**: 高空值率 (>50%) 大幅降权
- **多列复合键**: 多个 IP 列 (src_ip + dst_ip) 自动组合为复合实体键

### 5.2 IP 子网聚合

对 `DataType.IPv4` 列自动生成子网 (如 `192.168.1.0/24`), `unique_24_networks` 反映网络分布广度。`config.yaml` 可配置子网掩码列表。

实现: `ip_clustering.py::ip_to_subnet` 和 `apply_subnet_aggregation`。

### 5.3 类型感知聚合

数据类型到聚合函数的映射位于 `tools/entities.py`:

| 数据类型 | 聚合函数 |
|---------|---------|
| INT | mean, sum |
| FLOAT | mean |
| ENUM | mode |
| HEX | hex 对均值 |
| URL | 唯一域名数 |
| IPv4 | 子网多样性 |
| LAT_LON | mean |
| TIMESTAMP | min, max |

---

## 6. 自适应评分

`tools/entities.py::_add_adaptive_scores()`:

1. 采样 ≤10K 行
2. **TruncatedSVD(n_components=1)** 学习特征权重 (第一分量 loading 的绝对值归一化)
3. 全量加权求和 → `proxy_score` (0-1), `modern_tls_rate` 取反
4. IQR 阈值: q75 + 1.5×IQR → suspicious, q75 + 3.0×IQR → critical
5. 从数据分布自动推断, 无人工阈值

---

## 7. 聚类分析

### 7.1 算法选择

| 算法 | 适用场景 |
|------|---------|
| HDBSCAN (默认) | 未知簇数、存在噪声点、自动确定 k |
| KMeans (MiniBatch) | 已知簇数、球形分布、大数据集快速收敛 |

### 7.2 预处理链

1. 列过滤 → 2. 全 NaN 列丢弃 → 3. 列均值填充 NaN → 4. StandardScaler → 5. 方差过滤 (< 1e-10) → 6. 相关过滤 (> 0.95) → 7. **TruncatedSVD (>50 维时)** → 8. min_cluster_size 自适应 (n//20) → 9. 聚类

实现: `tools/clustering.py::_handle_run_clustering`。

### 7.3 低内存保护

可用内存 < 2GB 时自动降采样到 50K 行。样本数 > 100K 时采样 100K。样本数 > 50K 时采样 50K。

### 7.4 质量评估

| 指标 | 范围 | 说明 |
|------|------|------|
| Silhouette Score | [-1, 1] | >0.5 良好, >0.7 优秀 |
| Davies-Bouldin Index | [0, +∞) | 越低越好 |
| Calinski-Harabasz Score | [0, +∞) | 越高越好 |
| Noise Ratio | [0, 1] | HDBSCAN 噪声点比例 |

实现: `tools/evaluate.py::_handle_evaluate_clustering`。

---

## 8. 特征提取与 UMAP 嵌入

### 8.1 Z-Score 方法

`(μ_cluster − μ_global) / σ_global` — 簇中心 vs 全局均值的标准差偏离。

### 8.2 UMAP-2D 嵌入

在 `extract_features` 执行时自动计算 (`tools/features.py`):
- **训练**: 采样 ≤10K 行 → StandardScaler → UMAP(n_components=2, n_neighbors=15, min_dist=0.1)
- **批量变换**: 1K 行批次 → 全量数据坐标
- **持久化**: `EntityProfile` 表的 `embedding_x` / `embedding_y` 字段
- **用途**: 前端散点图 (cluster_overview.html Canvas 2D 渲染, 按聚类着色)

### 8.3 区分特征解读

| 分数范围 | 含义 |
|---------|------|
| \|Z\| < 1.0 | 无明显区分力 |
| 1.0 ≤ \|Z\| < 2.0 | 中等区分力 |
| \|Z\| ≥ 2.0 | **强区分特征** (Web 界面颜色高亮) |

---

## 9. 可视化

### 9.1 聚类概览 (`/clusters/<display_id>/`)

Canvas 2D 绘制的 UMAP/PCA 散点图 (实体在二维嵌入空间的分布) + 地理分布图 + Silhouette 柱状对比。点颜色按聚类标签区分。

### 9.2 3D 地球 (`/globe/`)

Three.js 绘制: TLS 流量弧线 (v1.3 蓝/v1.2 粉/其他 青)、弧线高度自适应距离、鼠标拖拽旋转、滚轮缩放 (3-30)、经纬线 (10° 间隔)、177 国境线、脉冲动画 (背面剔除, 不穿透地球)、多数据源叠加复选框。

### 9.3 实体画像 (`/entity/<display_id>/`)

聚合特征展示 + Z-Score 簇偏离量 + Canvas 单点散点图。

---

## 10. LLM 集成

### 10.1 API 配置

通过 `config/config.yaml` 或 Web 配置页面设置:

```yaml
llm:
  enabled: true
  base_url: "https://api.openai.com/v1"
  api_key: "sk-..."
  model: "deepseek-v4-flash"
  max_tokens: 2048
  temperature: 0.1
```

支持 OpenAI 兼容 API (OpenAI / Azure / Ollama / vLLM / LM Studio)。

### 10.2 32B 模型优化

`tianxuan/llm_orchestrator.py` 中的优化: Step Guidance (每步提示下一步)、工具结果截断 (1200 chars)、超时 90s、最大步数 15、中文一行工具描述、`_truncate_response()` 自动将返回压缩到 64KB 以内。

### 10.3 日志标记

| 标记 | 含义 |
|------|------|
| `[LLM]` | LLM 调用 (model, latency_ms) |
| `[LLM REQUEST]` | 请求内容 (缩减后) |
| `[LLM RESPONSE]` | 响应状态 |
| `[TOOL]` | LLM 调用的工具名 |
| `[SCORE]` | 自适应评分参数 (权重/阈值) |
| `[CLUSTER_INPUT]` | 聚类输入 (行数/列数/特征列) |
| `[CLUSTER_SCALE]` | StandardScaler 状态 |
| `[UMAP_ERR]` | UMAP 计算异常 |
| `[DB_SAVE_ERROR]` | DB 持久化失败 |
| `[DB_LOCKED]` | SQLite 锁重试 |

---

## 11. 手动分析工作流

手动分析页面 (`templates/tianxuan/manual.html`) 为**工作流构建器**:

1. 用户添加/移除/重排分析步骤
2. 每步选择 MCP 工具并填写参数
3. 方案可保存/加载/删除 (JSON 文件, 存储于 `.omo/plans/`)
4. 支持单步执行或全部自动串行执行
5. 每步执行结果实时显示在步骤下方

后端实现: `views/manual.py::manual_page` (页面渲染) + `views/manual.py::manual_run_analysis` (执行引擎)。

---

## 12. 跨机部署

### 12.1 运行时验证

```bash
# 两台机器各自执行
runtime\python\python.exe manage.py run_pipeline data\complex_test.csv
# 对比日志
runtime\python\python.exe scripts\diagnose_compare.py log_a.txt log_b.txt
```

### 12.2 跨机一致性检查清单

```bash
runtime\python\python.exe --version
runtime\python\python.exe -c "import sys; print(sys.getdefaultencoding(), sys.getfilesystemencoding())"
runtime\python\python.exe -c "import polars; print(polars.__version__)"
runtime\python\python.exe -c "import numpy, sklearn; print(numpy.__version__, sklearn.__version__)"
```

### 12.3 关键架构决策 (已修复的跨机问题)

| 决策 | 原因 |
|------|------|
| tuple 替代 frozenset | PYTHONHASHSEED 差异导致迭代顺序不确定 |
| PYTHONUTF8=1 | 跨机编码一致性 |
| sync_to_async ORM | async 上下文中的 Django ORM 安全调用 |
| 纯 Canvas 图表 | 零外部 JS 依赖, 离线可用 |
| 上传目录隔离 (%APPDATA%) | 与项目路径无关, 跨机部署路径不一致 |
| min_cluster_size 自适应 (n//20) | 数据量差异不影响聚类结果 |
| random_state=42 | 所有随机操作固定种子 |

### 12.4 故障诊断流程

```
出现跨机差异
  ├─ Step 1: 收集两台机器的 logs/tianxuan.log
  ├─ Step 2: diagnose_compare.py 对比, 找首个 [DIFF]
  ├─ Step 3: 判断差异类型
  │   ├─ [LOAD_SCHEMA] 列类型不同 → 检查 Polars 版本/PYTHONUTF8
  │   ├─ [FIND_COL] 关键词匹配不同 → tuple 修复已应用
  │   └─ [CLUSTER_INPUT] 聚类结果不同 → 检查 random_state/StandardScaler
  └─ Step 4: 归档诊断信息 → 诊断报告_%COMPUTERNAME%.txt
```

---

## 附录: 模块历史

> **simple_analysis 模块**: 原独立 Django app (`/simple/` 路由) 提供简化的上传→筛选→Leaflet 地图工作流。在 beta-clean 分支重构中已删除, 独立维护于 master 分支。当前版本不再包含此模块。

---

> **更多技术细节**: 请参阅 `AGENTS.md` 了解完整配置、架构决策和操作流程。
