# 天璇 (TianXuan) 故障诊断手册

> 常见问题排查指南。使用 `scripts/diagnose_compare.py` 进行跨机日志对比诊断。

---

## 目录

1. [启动问题](#1-启动问题)
2. [数据加载问题](#2-数据加载问题)
3. [聚类问题](#3-聚类问题)
4. [UMAP 问题](#4-umap-问题)
5. [数据库问题](#5-数据库问题)
6. [LLM 集成问题](#6-llm-集成问题)
7. [前端问题](#7-前端问题)
8. [跨机一致性问题](#8-跨机一致性问题)
9. [性能问题](#9-性能问题)
10. [诊断工具使用](#10-诊断工具使用)

---

## 1. 启动问题

### 1.1 `config` 模块找不到

**症状**: `ModuleNotFoundError: No module named 'config'`

**原因**: Python 路径未包含项目根目录。

**解决**:
```bat
:: 在项目根目录下运行
set PYTHONUTF8=1
chcp 65001
start /B runtime\python\python.exe manage.py runserver
```

### 1.2 首次启动无数据库

**症状**: `OperationalError: no such table`

**解决**:
```bat
runtime\python\python.exe manage.py migrate
```

`wsgi.py` 已包含 SQLite 启动自修复逻辑, 自动创建缺失的数据库文件。

### 1.3 端口被占用

**症状**: `Error: [WinError 10048] 通常每个套接字地址只允许使用一次`

**解决**:
```bat
:: 查占用进程
netstat -ano | findstr :8000
:: 改端口 (config.yaml)
server:
  port: 8080
```

### 1.4 残留进程未清理

**症状**: 前一次启动后进程未终止, 再次启动端口占用

**解决**:
```bat
:: 检查 .server_pid 文件
type .server_pid
:: 强制终止
taskkill /PID <pid> /F
del .server_pid
```

---

## 2. 数据加载问题

### 2.1 Schema 不匹配 (多文件列名不一致)

**症状**: `ValueError: schema mismatch` 或列名不一致时报错

**诊断**:
```bash
runtime\python\python.exe scripts\column_survey.py --csv "data/*.csv"
```

**解决**:
- 方案 A: 设置 `schema_strict=False` (默认), 自动并集合并, 缺失列填 null
- 方案 B: 调用 `repair_schema` MCP 工具 — 自动对齐列名 (大小写合并、下划线/连字符规范化)
- 方案 C: 在 `config.yaml` 中通过 `columns` 映射手动统一列名

### 2.2 CSV 编码问题 (乱码)

**症状**: 中文列名或数据出现乱码、`UnicodeDecodeError`

**诊断**:
```bash
:: 检查文件编码
runtime\python\python.exe -c "
with open('data/your.csv', 'rb') as f:
    print(f.read(10).hex())
"
```

**解决**:
- BOM 标记: 系统自动检测 BOM → UTF-8/UTF-16LE/UTF-16BE
- 无 BOM: 默认 UTF-8, 可手动指定 `encoding="latin-1"` 或 `encoding="gbk"`
- 所有命令加 `chcp 65001` + `set PYTHONUTF8=1`

### 2.3 `+` 号字符串无法解析为数字

**症状**: `"+"` 在数值列中导致 `cannot cast to Float64`

**解决**: 已在 `_coerce_to_float()` 中修复 — `"+"` / `"-"` / 空白 / `"N/A"` 等伪值在聚合前自动转为 null。日志标记 `[CLEAN] numeric coercion applied`。

### 2.4 列类型检测错误 (IP 列被识别为 String)

**症状**: 某列应为 IPv4 但被检测为 STRING

**诊断**:
```bash
:: 在 MCP 中调用
validate_data(dataset_id="ds_...")
```

**解决**:
- 在 `config.yaml` 中手动指定: `columns: { src_ip: ipv4, dst_ip: ipv4 }`
- 配置优先级: config → 值优先检测 → 名称推断 → STRING 回退

### 2.5 ZIP 文件解压失败

**症状**: 上传 ZIP 文件后无数据

**解决**: 检查 ZIP 内文件是否为 `.csv` 格式。系统仅自动解压 ZIP 中的 CSV 文件。

---

## 3. 聚类问题

### 3.1 聚类返回 0 个簇或全噪声

**症状**: `n_clusters=0` 或所有标签为 -1 (HDBSCAN 噪声)

**诊断**:
```python
diagnose_clustering(dataset_id="...", cluster_result_id="...")
```
输出包含: 特征方差分析、相关矩阵、稀疏性检查、参数建议。

**常见原因与解决**:

| 原因 | 诊断信号 | 解决 |
|------|---------|------|
| 样本太少 | n < 3 | 检查数据加载是否成功; 增大数据量 |
| min_cluster_size 太大 | 日志中 min_cluster_size > n/2 | 系统已自动调整为 n//20, 如仍失败手动降低 |
| 全零方差特征 | 方差 < 1e-10 | 系统已自动过滤零方差列; 检查特征选择是否合理 |
| 特征高度相关 | Pearson > 0.95 | 系统已自动去相关; 仍有问题则减少特征数 |
| 数据全是 NaN | 日志 all-NaN columns dropped | 检查数据源; 增加样本量 |

### 3.2 "mean on str" 错误

**症状**: `TypeError: can't convert type 'str' to numerator/denominator`

**原因**: 跨机 dtype 推断不一致 (一台推断为 Float, 另一台为 String)

**解决**: 已在 `tools/entities.py::_handle_build_entity_profiles` 的聚合参数构建中修复 — 聚合前检查 dtype, 非数值列自动 cast。`_coerce_to_float()` 兜底。

### 3.3 KMeans 簇数与预期不符

**症状**: KMeans 产生的簇数与 `n_clusters` 参数不一致

**原因**: MiniBatchKMeans 在大数据集上可能产生少于预期的簇

**解决**:
```python
# 尝试 HDBSCAN (自动确定 k)
run_clustering(dataset_id="...", cluster_columns=[...], algorithm="hdbscan")
# 或增大 n_clusters
run_clustering(..., algorithm="kmeans", params={"n_clusters": 5})
```

---

## 4. UMAP 问题

### 4.1 UMAP 嵌入失败 (`[UMAP_ERR]`)

**症状**: 日志中出现 `[UMAP_ERR]` 但流程继续 (UMAP 计算失败不影响核心分析)

**常见原因**:
- 数据量过大 (>100K): 系统已实现训练 10K + 批量变换 1K 批次
- 全 NaN 列: UMAP 前已有 StandardScaler + `np.nan_to_num`
- 内存不足: UMAP 需要额外内存

**解决**:
```bash
:: 检查 stderr
runtime\python\python.exe manage.py run_pipeline data/*.csv 2> umap_err.log
```

### 4.2 UMAP 坐标全为 0

**症状**: EntityProfile 的 embedding_x/y 全为 0.0

**原因**: UMAP 计算过程中异常被 `try/except` 捕获, 静默回退

**解决**:
- 检查 stderr 是否有 `[UMAP_ERR]` 日志
- 确认 `umap-learn` 包已安装: `runtime\python\python.exe -c "import umap; print(umap.__version__)"`
- 减少数据量重试

### 4.3 TruncatedSVD 降维导致聚类结果变化

**症状**: 特征 >50 维时聚类结果与预期不同

**原因**: SVD 降维会损失信息 (保留前 50 个主成分)

**解决**:
- 手动选择更少的基础特征 (<50 个), 避免触发 SVD 降维
- 通过 `cluster_columns` 参数精确控制输入特征列

---

## 5. 数据库问题

### 5.1 SQLite 锁 (`[DB_LOCKED]`)

**症状**: 日志中出现 `[DB_LOCKED]` 警告

**说明**: 系统已内置 `retry_on_lock` 装饰器 (3 次重试, 指数退避)。SQLite WAL 模式下读写并发性良好。

**解决**:
- 减少并发写入 (多个 Django 进程同时写)
- 增大超时: `sqlite3_db.config(busy_timeout=5000)`
- 检查是否有未关闭的长时间事务

### 5.2 ClusterFeature 表无数据 (`db_saved=False`)

**症状**: `extract_features` 返回 `db_saved=False`

**诊断**:
```bash
runtime\python\python.exe scripts\debug_db.py
```

**常见原因**:
- Django ORM sync_to_async 包装缺失 (已在 `tools/features.py` 中修复)
- AnalysisRun 记录未找到 (csv_glob 匹配失败)
- 权限问题 (SQLite 文件只读)

### 5.3 EntityProfile 表无 embedding 坐标

**症状**: EntityProfile 记录存在但 embedding_x/y 为 null

**原因**: UMAP 计算失败 (见 4.1)

---

## 6. LLM 集成问题

### 6.1 400 错误

**症状**: LLM 返回 HTTP 400

**原因**: API 地址错误 / Key 无效 / 模型名错误

**诊断**: 配置页 → 填写 LLM 配置 → 点击「测试连通性」

**解决**:
1. 确认 `base_url` 格式: `https://api.openai.com/v1` (注意末尾的 /v1)
2. 确认 `api_key` 无多余空格
3. 确认 `model` 名称与 API 支持的一致

### 6.2 超时

**症状**: 日志中 `latency_ms` 很高, LLM 步骤无响应

**解决**:
- 增大 `max_tokens` (config.yaml)
- 检查网络延迟
- 32B 模型推理慢: 系统已设置 90s 超时, 如仍不足可增加

### 6.3 工具调用失败

**症状**: `[TOOL]` 日志后出现错误

**诊断**:
```bash
:: 查看完整 LLM 交互日志
type logs\tianxuan.log | findstr "[TOOL] [LLM]"
```

**解决**:
- 检查工具返回的错误信息
- LLM 可能生成了格式错误的工具调用 JSON → 重试
- 重复调用检测: orchestrator 会自动跳过重复的工具调用

### 6.4 分析结果为空

**症状**: LLM 完成但无聚类结果

**常见原因**:
- 实体检测失败 → 手动指定 `entity_columns`
- 数据量太小 → 增大样本
- 实体列检测到非 IP 列 → 通过 `entity_columns` 强制指定

---

## 7. 前端问题

### 7.1 Canvas 散点图不显示

**症状**: 聚类概览页空白

**诊断**:
```bash
:: 检查浏览器控制台 (F12)
:: 常见错误: "Cannot read properties of undefined"
```

**解决**:
- 确认聚类已完成 (检查 AnalysisRun.status == 'completed')
- 确认有 UMAP/PCA 坐标数据 (EntityProfile.embedding_x 非 null)
- 清除浏览器缓存 (Ctrl+F5)

### 7.2 3D 地球空白

**症状**: `/globe/` 页面渲染为空白

**原因**:
- WebGL2 不可用 (核显驱动过旧或浏览器不支持)
- Three.js 未加载 (检查 Network tab, 603KB 的 three.min.js)
- 地球贴图未加载 (1.4MB earth_atmos_2048.jpg)

**解决**:
- 确认浏览器支持 WebGL2: 访问 `chrome://gpu` 检查 WebGL2 状态
- 确认 `static/tianxuan/three.min.js` 和 `earth_atmos_2048.jpg` 存在
- 数据中优先使用 `src_latitude/src_longitude` 列, 无则 GeoIP 回退
- 确保 GeoIP 数据文件 `data/geoip_data.txt` 存在

### 7.3 地理分布图空白

**症状**: 聚类概览页的地理分布 Canvas 不显示

**原因**: 数据中无经纬度信息且 GeoIP 查询失败

**解决**: 确保 GeoIP 数据库 `data/geoip_data.txt` 存在且格式正确。GeoIP 仅支持离线查询, 无网络依赖。

---

## 8. 跨机一致性问题

### 8.1 核心诊断流程

```bat
:: 两台机器各自运行管道, 保存日志
del logs\tianxuan.log
runtime\python\python.exe manage.py run_pipeline data\complex_test.csv
copy logs\tianxuan.log log_%COMPUTERNAME%.txt

:: 对比
runtime\python\python.exe scripts\diagnose_compare.py log_MACHINE_A.txt log_MACHINE_B.txt
```

首个 `[DIFF]` 行就是问题根源。

### 8.2 常见跨机差异

| 差异类型 | 日志标记 | 根因 | 检查 |
|---------|---------|------|------|
| 列类型不同 | `[LOAD_SCHEMA]` | Polars 版本不一致 或 PYTHONUTF8 未生效 | `polars.__version__`, `sys.flags.utf8_mode` |
| 关键词匹配不同 | `[FIND_COL]` | frozenset 哈希随机性 | 已通过 tuple 替代 frozenset 修复 |
| 聚合结果不同 | `[CLUSTER_INPUT]` | random_state 不一致 或 StandardScaler 差异 | 确认 random_state=42, sklearn 版本一致 |
| 编码问题 | `UnicodeDecodeError` | 系统编码不一致 | `sys.getdefaultencoding()`, `sys.getfilesystemencoding()` |
| dtype 推断不同 | `Utf8 vs Float64` | Polars 推断漂移 | 已通过类型安全聚合 + `_coerce_to_float` 防护 |

### 8.3 运行时自检脚本

```bash
:: 在两台机器上分别运行, 对比输出
runtime\python\python.exe -c "
import sys, polars, numpy, sklearn
print(f'Python: {sys.version}')
print(f'Polars: {polars.__version__}')
print(f'NumPy: {numpy.__version__}')
print(f'sklearn: {sklearn.__version__}')
print(f'defaultencoding: {sys.getdefaultencoding()}')
print(f'fsencoding: {sys.getfilesystemencoding()}')
print(f'utf8_mode: {sys.flags.utf8_mode}')
print(f'hashseed: {sys.flags.hash_randomization}')
"
```

### 8.4 已知已修复的跨机问题

| 问题 | 修复方案 | 代码位置 |
|------|---------|---------|
| "mean on str" | frozenset → tuple + 类型安全聚合 | tools/entities.py, ip_clustering.py |
| 编码漂移 | PYTHONUTF8=1 | run.bat |
| DB 特征不保存 | sync_to_async 包装 | tools/features.py |
| 图表依赖缺失 | 纯 Canvas 2D | 全部图表 |
| 聚类结果随机 | random_state=42 | tools/clustering.py, run_pipeline.py |

---

## 9. 性能问题

### 9.1 大数据集 OOM

**症状**: 内存不足导致进程崩溃

**系统已实现的防护**:
- 可用内存 < 2GB → 自动降采样 50K (psutil 检测)
- 样本 > 100K → 采样 100K
- 样本 > 50K → 采样 50K
- MiniBatchKMeans 替代 KMeans (batch_size=1024)
- SVD 降维 (>50 特征 → 50)
- UMAP 训练 10K + 批量变换 1K 批次
- Polars LazyFrame + streaming 惰性执行

**手动优化**:
```python
# 在 load_data 或 run_clustering 时降采样
load_data(csv_glob="data/*.csv")
# → 后续 run_clustering 会自动降采样
# 或使用 filter_and_cluster 先过滤再聚类
```

### 9.2 SQLite 写入慢

**症状**: DB 持久化耗时较长

**解决**:
- WAL 模式已开启 (synchronous=NORMAL)
- batch_size=1000 批量写入 (bulk_create)
- 增大 cache_size: SQLite PRAGMA cache_size=20000 (20MB)
- 临时目录移到 SSD

### 9.3 UMAP 计算慢

**症状**: extract_features 步骤耗时过长

**说明**: UMAP 计算分为训练 (≤10K 样本) + 批量变换 (1K 批次), 已是最优方案。

**如需加速**: 减小 `MAX_UMAP_TRAIN` (`tools/features.py` 中的硬编码常量, 默认 10000)。

---

## 10. 诊断工具使用

### 10.1 MCP 诊断工具链

```
问题 → validate_data (数据质量) → explore_distributions (分布检查) → find_outliers (异常值)
→ diagnose_clustering (聚类诊断) → compare_datasets (处理前后对比) → export_debug_sample (导出样本)
```

所有诊断工具位于 `tools/diagnostics.py`。

### 10.2 列结构调查

```bash
runtime\python\python.exe scripts\column_survey.py --csv "data/*.csv"
# 输出: 每个 CSV 的列名/类型/空值率/分布
```

### 10.3 DB 持久化调试

```bash
runtime\python\python.exe scripts\debug_db.py
# 期望: n_features=30 db_saved=True
```

### 10.4 跨机日志对比

```bash
runtime\python\python.exe scripts\diagnose_compare.py log_machine_a.txt log_machine_b.txt
# 输出: 首个差异行的内容 (两侧对比)
```

### 10.5 关键日志标记汇总

| 标记 | 文件 | 含义 |
|------|------|------|
| `[LOAD]` | data_loader.py | CSV 加载完成 |
| `[LOAD_SCHEMA]` | data_loader.py | 每列推断类型 (最重要!) |
| `[CLEAN]` | data_loader.py | 清洗操作 |
| `[VALIDATE]` | data_validator.py | 数据校验 |
| `[FIND_COL]` | tools/entities.py | 实体列关键词匹配 |
| `[CLUSTER_INPUT]` | tools/clustering.py | 聚类输入形状 |
| `[CLUSTER_SCALE]` | tools/clustering.py | StandardScaler |
| `[SCORE]` | tools/entities.py | 自适应评分权重 |
| `[UMAP_ERR]` | tools/features.py | UMAP 异常 |
| `[DB_SAVE_ERROR]` | tools/features.py | DB 持久化失败 |
| `[DB_LOCKED]` | db_utils.py | SQLite 锁重试 |
| `[LLM]` | llm_orchestrator.py | LLM 调用 |
| `[TOOL]` | llm_orchestrator.py | LLM 调用工具 |

---

> **相关文档**: `AGENTS.md` (架构/配置/操作流程), `docs/工作流.md` (完整分析流水线)
