feat(ssa): Complete T-test end-to-end testing with 9 bug fixes - Phase 1 core 85% complete. R service: missing value auto-filter. Backend: error handling, variable matching, dynamic filename. Frontend: module activation, session isolation, error propagation. Full flow verified.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
# AIclinicalresearch 系统当前状态与开发指南
|
||||
|
||||
> **文档版本:** v5.3
|
||||
> **文档版本:** v5.5
|
||||
> **创建日期:** 2025-11-28
|
||||
> **维护者:** 开发团队
|
||||
> **最后更新:** 2026-02-18
|
||||
> **最后更新:** 2026-02-19
|
||||
> **🎉 重大里程碑:**
|
||||
> - **2026-02-18:SSA MVP 开发计划 v1.3 完成!** Brain-Hand架构 + 统计护栏 + HITL + 10工具MVP,准予启动开发
|
||||
> - **🆕 2026-02-19:SSA T 检验端到端测试通过!** 完整流程验证 + 9 个 Bug 修复 + Phase 1 核心完成 85%
|
||||
> - **2026-02-19:SSA Week 1 开发完成!** R Docker 镜像构建成功 + 后端/前端骨架 + 规范对齐
|
||||
> - **2026-02-18:SSA MVP 开发计划 v1.5 完成!** Brain-Hand架构 + 统计护栏 + HITL + 专家配置体系
|
||||
> - **2026-02-18:RVW V2.0 Week 3 完成!** 统计验证扩展 + 负号归一化 + 文件格式提示 + 用户体验优化
|
||||
> - **2026-02-18:RVW V2.0 Skills 架构完成!** Skills 核心框架 + 3个 Skill 实现 + ReviewWorker 改造
|
||||
> - **2026-02-17:RVW V2.0 "数据侦探" Day 6 完成!** L2统计验证器 + L2.5一致性取证(SE三角验证、SD>Mean)
|
||||
@@ -20,14 +22,14 @@
|
||||
> - **2026-01-24:Protocol Agent 框架完成!** 可复用Agent框架+5阶段对话流程
|
||||
> - **2026-01-22:OSS 存储集成完成!** 阿里云 OSS 正式接入平台基础层
|
||||
>
|
||||
> **最新进展(RVW V2.0 Week 3 完成 2026-02-18):**
|
||||
> - ✅ **负号归一化**:6 种 Unicode 负号变体支持,防止 float() 崩溃
|
||||
> - ✅ **T 检验验证增强**:智能样本量提取 + subrow 精确高亮
|
||||
> - ✅ **SE 三角/CI-P 验证增强**:多行单元格 subrow 支持
|
||||
> - ✅ **前端翻译映射更新**:6 种新 IssueType 中文翻译
|
||||
> - ✅ **文件格式提示**:PDF/.doc 上传时提示无法数据验证
|
||||
> - ✅ **Skills 核心框架**:types、registry、executor、profile、context
|
||||
> - ✅ **3 个 Skill 实现**:DataForensics、Editorial、Methodology
|
||||
> **🆕 最新进展(SSA T 检验端到端测试通过 2026-02-19):**
|
||||
> - ✅ **🎉 完整流程验证**:数据上传 → 计划生成 → 分析执行 → 结果展示 → 代码下载
|
||||
> - ✅ **R 服务 Bug 修复**:缺失值自动过滤,解决分组变量 3 组问题
|
||||
> - ✅ **类型推断优化**:0/1 数字列正确识别为分类变量
|
||||
> - ✅ **错误处理增强**:R 服务错误信息正确传递给前端显示
|
||||
> - ✅ **文件名动态生成**:`{toolName}_{dataName}_{MMDD}_{HHmm}.R`
|
||||
> - ✅ **前端模块激活**:智能统计分析入口可用
|
||||
> - ✅ **用户会话隔离**:不同用户数据正确隔离
|
||||
>
|
||||
> **部署状态:** ✅ 生产环境运行中 | 公网地址:http://8.140.53.236/
|
||||
> **REDCap 状态:** ✅ 生产环境运行中 | 地址:https://redcap.xunzhengyixue.com/
|
||||
@@ -68,7 +70,7 @@
|
||||
| **ASL** | AI智能文献 | 文献筛选、Meta分析、证据图谱 | ⭐⭐⭐⭐⭐ | 🎉 **智能检索MVP完成(60%)** - DeepSearch集成 | **P0** |
|
||||
| **DC** | 数据清洗整理 | ETL + 医学NER(百万行级数据) | ⭐⭐⭐⭐⭐ | ✅ **Tool B完成 + Tool C 99%(异步架构+性能优化-99%+多指标转换+7大功能)** | **P0** |
|
||||
| **IIT** | IIT Manager Agent | AI驱动IIT研究助手 - 双脑架构+REDCap集成 | ⭐⭐⭐⭐⭐ | 🎉 **事件级质控V3.1完成(设计100%,代码60%)** | **P0** |
|
||||
| **SSA** | 智能统计分析 | Brain-Hand架构 + 统计护栏 + HITL + 10工具MVP | ⭐⭐⭐⭐⭐ | 🚀 **MVP计划v1.3完成(设计100%,开发0%)** - 准予启动开发 | **P1** |
|
||||
| **SSA** | 智能统计分析 | Brain-Hand架构 + 统计护栏 + HITL + 10工具MVP | ⭐⭐⭐⭐⭐ | 🎉 **T检验端到端通过(设计100%,开发85%)** - Phase 1 核心完成 | **P1** |
|
||||
| **ST** | 统计分析工具 | 100+轻量化统计工具 | ⭐⭐⭐⭐ | 📋 规划中 | P2 |
|
||||
| **RVW** | 稿件审查系统 | 方法学评估 + 🆕数据侦探(L1/L2/L2.5验证)+ Skills架构 + Word导出 | ⭐⭐⭐⭐ | 🚀 **V2.0 Week3完成(85%)** - 统计验证扩展+负号归一化+文件格式提示+用户体验优化 | P1 |
|
||||
| **ADMIN** | 运营管理端 | Prompt管理、租户管理、用户管理、运营监控、系统知识库 | ⭐⭐⭐⭐⭐ | 🎉 **Phase 4.6完成(88%)** - Prompt知识库集成+动态注入 | **P0** |
|
||||
@@ -92,6 +94,8 @@
|
||||
│ • EmbeddingService (text-embedding-v4) │
|
||||
│ • VectorSearchService (多查询+Rerank) │
|
||||
│ • QueryRewriter (DeepSeek V3 查询理解) │
|
||||
│ 🆕 R统计引擎:ssa-r-statistics:1.0.1 Docker ✅ │
|
||||
│ • plumber API | 统计护栏 | 预签名URL | 非特权用户 │
|
||||
│ 前端:Chat组件V2(Ant Design X)🆕 ✅ │
|
||||
│ AIStreamChat | ThinkingBlock | useAIStream Hook │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
@@ -132,7 +136,7 @@
|
||||
- PostgreSQL 15 (Docker: pgvector/pgvector:pg15)
|
||||
- **pgvector 0.8.1** ✅ 2026-01-19 新增(向量数据库扩展,支持 RAG)
|
||||
- **pg_bigm 1.2** ✅ 2026-01-24 新增(中日韩全文搜索,10-100倍性能提升)
|
||||
- **13个Schema隔离**(platform/aia/pkb/asl/dc/iit/ssa/st/rvw/admin/common/capability/ekb ✅ 2026-01-21新增)
|
||||
- **14个Schema隔离**(platform/aia/pkb/asl/dc/iit/ssa/ssa_schema🆕/st/rvw/admin/common/capability/ekb)
|
||||
|
||||
**云原生部署**:
|
||||
- 阿里云 SAE (Serverless 应用引擎)
|
||||
@@ -151,9 +155,9 @@
|
||||
|
||||
---
|
||||
|
||||
## 🚀 当前开发状态(2026-02-08)
|
||||
## 🚀 当前开发状态(2026-02-19)
|
||||
|
||||
### 🎉 最新进展:IIT 实时质控系统完成 + UI 优化计划制定(2026-02-08)
|
||||
### 🎉 最新进展:SSA Week 1 开发完成 + R Docker 构建成功(2026-02-19)
|
||||
|
||||
#### ✅ 实时质控系统 + 管理端批量操作 + 质控驾驶舱设计
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
| **文档处理** | `extraction_service/` | ✅ 🆕 | pymupdf4llm PDF→Markdown |
|
||||
| **认证授权** | `common/auth/` | ✅ | JWT认证 + 权限控制 |
|
||||
| **Prompt管理** | `common/prompt/` | ✅ | 动态Prompt配置 |
|
||||
| **🆕R统计引擎** | `r-statistics-service/` | ✅ | Docker化R统计服务(plumber) |
|
||||
|
||||
### 前端通用能力
|
||||
|
||||
|
||||
580
docs/02-通用能力层/06-R统计引擎/01-R统计引擎架构与部署指南.md
Normal file
580
docs/02-通用能力层/06-R统计引擎/01-R统计引擎架构与部署指南.md
Normal file
@@ -0,0 +1,580 @@
|
||||
# R 统计引擎架构与部署指南
|
||||
|
||||
> **版本:** v1.0
|
||||
> **创建日期:** 2026-02-19
|
||||
> **维护者:** SSA-Pro 开发团队
|
||||
> **状态:** ✅ 生产就绪
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [概述](#1-概述)
|
||||
2. [架构设计](#2-架构设计)
|
||||
3. [Docker 镜像构建](#3-docker-镜像构建)
|
||||
4. [部署指南](#4-部署指南)
|
||||
5. [API 参考](#5-api-参考)
|
||||
6. [开发指南](#6-开发指南)
|
||||
7. [运维指南](#7-运维指南)
|
||||
8. [常见问题](#8-常见问题)
|
||||
|
||||
---
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 什么是 R 统计引擎
|
||||
|
||||
R 统计引擎是平台的**专用统计计算服务**,基于 Docker 容器化部署,提供:
|
||||
|
||||
- 🧮 **严谨的统计分析能力**(T 检验、方差分析、回归等)
|
||||
- 🛡️ **统计护栏**(正态性检验、方差齐性检验等)
|
||||
- 📊 **可视化输出**(Base64 编码的图表)
|
||||
- 📝 **可复现代码生成**(APA 格式的 R 脚本)
|
||||
|
||||
### 1.2 定位
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 业务模块层 │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ SSA-Pro │ │ 其他 │ │ 其他 │ │
|
||||
│ │ 智能统计 │ │ 模块 │ │ 模块 │ │
|
||||
│ └────┬────┘ └─────────┘ └─────────┘ │
|
||||
├───────┼─────────────────────────────────────────────────────┤
|
||||
│ ▼ 通用能力层 │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ R 统计引擎 (Docker) │ │
|
||||
│ │ • /health 健康检查 │ │
|
||||
│ │ • /api/v1/tools 工具列表 │ │
|
||||
│ │ • /api/v1/skills 技能执行 │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.3 技术栈
|
||||
|
||||
| 组件 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| R | 4.3.3 | 统计计算核心 |
|
||||
| plumber | 1.2.1 | REST API 框架 |
|
||||
| ggplot2 | 最新 | 数据可视化 |
|
||||
| car | 3.1-2 | 高级统计检验 |
|
||||
| dplyr/tidyr | 最新 | 数据处理 |
|
||||
| Docker | 24+ | 容器化部署 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 Brain-Hand 模型
|
||||
|
||||
R 统计引擎采用 **Brain-Hand 分离架构**:
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Node.js │ │ R Docker │
|
||||
│ (Brain) │ │ (Hand) │
|
||||
├──────────────────┤ ├──────────────────┤
|
||||
│ • 业务逻辑 │ HTTP │ • 统计计算 │
|
||||
│ • 认证鉴权 │ ───────> │ • 数据处理 │
|
||||
│ • OSS 签名 │ │ • 图表生成 │
|
||||
│ • 结果解释 │ <─────── │ • 代码生成 │
|
||||
└──────────────────┘ JSON └──────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 数据传输协议
|
||||
|
||||
支持两种数据传输方式:
|
||||
|
||||
| 方式 | 条件 | 字段 |
|
||||
|------|------|------|
|
||||
| **inline** | 数据 < 2MB | `data_source.data` (JSON) |
|
||||
| **oss** | 数据 >= 2MB | `data_source.oss_url` (预签名 URL) |
|
||||
|
||||
```json
|
||||
// 方式 1: inline
|
||||
{
|
||||
"data_source": {
|
||||
"type": "inline",
|
||||
"data": [{"group": "A", "value": 10}, ...]
|
||||
}
|
||||
}
|
||||
|
||||
// 方式 2: oss (预签名 URL)
|
||||
{
|
||||
"data_source": {
|
||||
"type": "oss",
|
||||
"oss_url": "https://bucket.oss.com/data.csv?signature=xxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 安全设计
|
||||
|
||||
| 安全措施 | 实现方式 |
|
||||
|----------|----------|
|
||||
| 非特权用户 | `USER appuser` |
|
||||
| 路径遍历防护 | `tool_code` 正则白名单 `^[A-Z][A-Z0-9_]*$` |
|
||||
| OSS 密钥隔离 | Node.js 生成预签名 URL,R 无需持有密钥 |
|
||||
| 健康检查 | Docker HEALTHCHECK |
|
||||
|
||||
---
|
||||
|
||||
## 3. Docker 镜像构建
|
||||
|
||||
### 3.1 完整 Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM rocker/r-ver:4.3
|
||||
|
||||
LABEL maintainer="dev-team@aiclinicalresearch.com"
|
||||
LABEL version="1.0.1"
|
||||
LABEL description="SSA-Pro R Statistics Service"
|
||||
|
||||
# 安装系统依赖(包括 R 包编译所需的库)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libcurl4-openssl-dev \
|
||||
libssl-dev \
|
||||
libxml2-dev \
|
||||
libsodium-dev \
|
||||
zlib1g-dev \
|
||||
libnlopt-dev \
|
||||
liblapack-dev \
|
||||
libblas-dev \
|
||||
gfortran \
|
||||
pkg-config \
|
||||
cmake \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 直接安装 R 包
|
||||
RUN R -e "install.packages(c( \
|
||||
'plumber', \
|
||||
'jsonlite', \
|
||||
'ggplot2', \
|
||||
'glue', \
|
||||
'dplyr', \
|
||||
'tidyr', \
|
||||
'base64enc', \
|
||||
'yaml', \
|
||||
'car', \
|
||||
'httr' \
|
||||
), repos='https://cloud.r-project.org/', Ncpus=2)"
|
||||
|
||||
# 安全加固:创建非特权用户
|
||||
RUN useradd -m -s /bin/bash appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制应用代码
|
||||
COPY plumber.R plumber.R
|
||||
COPY utils/ utils/
|
||||
COPY tools/ tools/
|
||||
COPY tests/ tests/
|
||||
|
||||
# 设置目录权限
|
||||
RUN chown -R appuser:appuser /app
|
||||
|
||||
# 切换到非特权用户
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
# 环境变量
|
||||
ENV DEV_MODE="false"
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
|
||||
# 启动服务
|
||||
CMD ["R", "-e", "plumber::plumb('plumber.R')$run(host='0.0.0.0', port=8080)"]
|
||||
```
|
||||
|
||||
### 3.2 系统依赖说明
|
||||
|
||||
| 依赖包 | 用途 |
|
||||
|--------|------|
|
||||
| `libcurl4-openssl-dev` | httr 包(HTTP 请求) |
|
||||
| `libssl-dev` | openssl 包(加密) |
|
||||
| `libxml2-dev` | xml2 包(XML 解析) |
|
||||
| `libsodium-dev` | sodium 包(加密) |
|
||||
| `zlib1g-dev` | httpuv 包(Web 服务器) |
|
||||
| `libnlopt-dev` | nloptr 包(优化算法) |
|
||||
| `liblapack-dev` | 线性代数计算 |
|
||||
| `libblas-dev` | 基础线性代数 |
|
||||
| `gfortran` | Fortran 编译器(部分 R 包需要) |
|
||||
| `cmake` | nloptr 包构建 |
|
||||
| `curl` | 健康检查 |
|
||||
|
||||
### 3.3 构建命令
|
||||
|
||||
```bash
|
||||
# 本地构建
|
||||
cd r-statistics-service
|
||||
docker build -t ssa-r-statistics:1.0.1 .
|
||||
|
||||
# 查看镜像
|
||||
docker images ssa-r-statistics
|
||||
|
||||
# 预期输出
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
ssa-r-statistics 1.0.1 xxxxxxxxxxxx x minutes ago 1.81GB
|
||||
```
|
||||
|
||||
### 3.4 构建时间参考
|
||||
|
||||
| 阶段 | 耗时 |
|
||||
|------|------|
|
||||
| 基础镜像下载 | ~2 分钟(首次) |
|
||||
| 系统依赖安装 | ~1 分钟 |
|
||||
| R 包安装 | ~6 分钟 |
|
||||
| **总计** | **~9 分钟** |
|
||||
|
||||
---
|
||||
|
||||
## 4. 部署指南
|
||||
|
||||
### 4.1 开发环境
|
||||
|
||||
使用 docker-compose:
|
||||
|
||||
```yaml
|
||||
# r-statistics-service/docker-compose.yml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
ssa-r-service:
|
||||
build: .
|
||||
container_name: ssa-r-statistics
|
||||
ports:
|
||||
- "8082:8080" # 主机8082 → 容器8080(REDCap占用8080/8081)
|
||||
environment:
|
||||
- DEV_MODE=true
|
||||
volumes:
|
||||
# 开发环境挂载:支持热重载
|
||||
- ./tools:/app/tools
|
||||
- ./utils:/app/utils
|
||||
- ./tests:/app/tests
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"] # 容器内部仍是8080
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
```
|
||||
|
||||
启动命令:
|
||||
```bash
|
||||
cd r-statistics-service
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 4.2 生产环境 (SAE)
|
||||
|
||||
```yaml
|
||||
# SAE 配置
|
||||
容器镜像: registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.1
|
||||
实例规格: 2 vCPU, 4 GB
|
||||
最小实例: 1
|
||||
最大实例: 5
|
||||
端口: 8080
|
||||
|
||||
环境变量:
|
||||
DEV_MODE: "false"
|
||||
```
|
||||
|
||||
### 4.3 环境变量
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `DEV_MODE` | `false` | 开发模式(启用热重载,每次请求重新加载工具脚本) |
|
||||
|
||||
> **说明**:开发环境和生产环境都使用真实 OSS,无需 Mock 数据。
|
||||
> - 开发环境:`ai-clinical-data-dev` bucket
|
||||
> - 生产环境:`ai-clinical-data` bucket
|
||||
|
||||
### 4.4 端口配置
|
||||
|
||||
| 环境 | 主机端口 | 容器端口 | 说明 |
|
||||
|------|----------|----------|------|
|
||||
| **开发环境** | 8082 | 8080 | 避免与 REDCap 8080/8081 冲突 |
|
||||
| **生产环境 (SAE)** | 8080 | 8080 | 云端无端口冲突 |
|
||||
|
||||
> **注意**:Node.js 后端通过 `R_SERVICE_URL` 环境变量配置 R 服务地址,默认值为 `http://localhost:8082`。
|
||||
|
||||
---
|
||||
|
||||
## 5. API 参考
|
||||
|
||||
### 5.1 健康检查
|
||||
|
||||
```http
|
||||
GET /health
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"timestamp": "2026-02-19 08:00:00",
|
||||
"version": "1.0.1",
|
||||
"dev_mode": true,
|
||||
"tools_loaded": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 工具列表
|
||||
|
||||
```http
|
||||
GET /api/v1/tools
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"tools": ["t_test_ind", "anova_oneway"],
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 执行技能
|
||||
|
||||
```http
|
||||
POST /api/v1/skills/{tool_code}
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"data_source": {
|
||||
"type": "inline",
|
||||
"data": [...]
|
||||
},
|
||||
"params": {
|
||||
"group_var": "group",
|
||||
"value_var": "value"
|
||||
},
|
||||
"guardrails": {
|
||||
"check_normality": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "分析完成",
|
||||
"warnings": null,
|
||||
"results": {
|
||||
"method": "Welch Two Sample t-test",
|
||||
"statistic": -5.196,
|
||||
"df": 5.98,
|
||||
"p_value": 0.002,
|
||||
"p_value_fmt": "p = .002"
|
||||
},
|
||||
"plots": ["data:image/png;base64,..."],
|
||||
"trace_log": [...],
|
||||
"reproducible_code": "..."
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"error_code": "E001",
|
||||
"error_type": "business",
|
||||
"message": "列名 'xxx' 在数据中不存在",
|
||||
"user_hint": "请检查变量名是否拼写正确"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 开发指南
|
||||
|
||||
### 6.1 添加新工具
|
||||
|
||||
1. 在 `tools/` 目录创建 R 脚本:
|
||||
|
||||
```r
|
||||
# tools/my_analysis.R
|
||||
|
||||
#' @tool_code ST_MY_ANALYSIS
|
||||
#' @name 我的分析工具
|
||||
#' @version 1.0.0
|
||||
|
||||
# 统一入口函数
|
||||
run_analysis <- function(input) {
|
||||
# 加载数据
|
||||
df <- load_input_data(input)
|
||||
|
||||
# 参数
|
||||
p <- input$params
|
||||
|
||||
# 护栏检查
|
||||
# ...
|
||||
|
||||
# 核心计算
|
||||
# ...
|
||||
|
||||
# 返回结果
|
||||
return(list(
|
||||
status = "success",
|
||||
message = "分析完成",
|
||||
results = list(...)
|
||||
))
|
||||
}
|
||||
```
|
||||
|
||||
2. 重启服务(开发模式无需重启)
|
||||
|
||||
3. 测试:
|
||||
```bash
|
||||
curl -X POST http://localhost:8082/api/v1/skills/ST_MY_ANALYSIS \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data_source": {...}, "params": {...}}'
|
||||
```
|
||||
|
||||
### 6.2 工具命名规范
|
||||
|
||||
| 项目 | 规范 |
|
||||
|------|------|
|
||||
| 文件名 | 小写下划线:`t_test_ind.R` |
|
||||
| tool_code | 大写下划线:`ST_T_TEST_IND` |
|
||||
| 入口函数 | 固定名称:`run_analysis` |
|
||||
|
||||
### 6.3 结果格式规范
|
||||
|
||||
```r
|
||||
return(list(
|
||||
status = "success" | "error" | "blocked",
|
||||
message = "...",
|
||||
warnings = c("...") | NULL,
|
||||
results = list(
|
||||
# 统计结果
|
||||
),
|
||||
plots = list(
|
||||
"data:image/png;base64,..."
|
||||
),
|
||||
trace_log = c("..."),
|
||||
reproducible_code = "..."
|
||||
))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 运维指南
|
||||
|
||||
### 7.1 日志查看
|
||||
|
||||
```bash
|
||||
# 实时日志
|
||||
docker logs -f ssa-r-statistics
|
||||
|
||||
# 最近 100 行
|
||||
docker logs --tail 100 ssa-r-statistics
|
||||
```
|
||||
|
||||
### 7.2 性能监控
|
||||
|
||||
```bash
|
||||
# 容器资源使用
|
||||
docker stats ssa-r-statistics
|
||||
```
|
||||
|
||||
### 7.3 重启服务
|
||||
|
||||
```bash
|
||||
# 开发环境
|
||||
docker-compose restart
|
||||
|
||||
# 生产环境 (SAE)
|
||||
通过 SAE 控制台重启实例
|
||||
```
|
||||
|
||||
### 7.4 镜像更新
|
||||
|
||||
```bash
|
||||
# 1. 构建新镜像
|
||||
docker build -t ssa-r-statistics:1.0.2 .
|
||||
|
||||
# 2. 推送到镜像仓库
|
||||
docker tag ssa-r-statistics:1.0.2 registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.2
|
||||
docker push registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.2
|
||||
|
||||
# 3. 更新 SAE 部署
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 常见问题
|
||||
|
||||
### Q1: 构建时 httpuv 安装失败
|
||||
|
||||
**错误:** `fatal error: zlib.h: No such file or directory`
|
||||
|
||||
**解决:** 添加 `zlib1g-dev` 到系统依赖
|
||||
|
||||
### Q2: 构建时 nloptr 安装失败
|
||||
|
||||
**错误:** `CMAKE NOT FOUND`
|
||||
|
||||
**解决:** 添加 `cmake` 到系统依赖
|
||||
|
||||
### Q3: /tmp 权限问题
|
||||
|
||||
**错误:** `cannot open file '/tmp/Rtmpxxx': No such file or directory`
|
||||
|
||||
**解决:** 不要在启动命令中清理 /tmp
|
||||
|
||||
### Q4: DEV_MODE 热重载不生效
|
||||
|
||||
**原因:** 没有挂载 volumes
|
||||
|
||||
**解决:**
|
||||
```yaml
|
||||
volumes:
|
||||
- ./tools:/app/tools
|
||||
```
|
||||
|
||||
### Q5: 容器启动后无法访问
|
||||
|
||||
**检查:**
|
||||
1. 端口映射是否正确
|
||||
2. 健康检查是否通过
|
||||
3. 查看容器日志
|
||||
|
||||
---
|
||||
|
||||
## 附录:文件结构
|
||||
|
||||
```
|
||||
r-statistics-service/
|
||||
├── Dockerfile # 生产镜像定义
|
||||
├── docker-compose.yml # 开发环境编排
|
||||
├── renv.lock # R 包版本锁定(备用)
|
||||
├── .Rprofile # R 启动配置(备用)
|
||||
├── plumber.R # API 入口
|
||||
├── utils/
|
||||
│ ├── data_loader.R # 数据加载(预签名 URL)
|
||||
│ ├── guardrails.R # 统计护栏
|
||||
│ ├── error_codes.R # 错误映射
|
||||
│ └── result_formatter.R # 结果格式化
|
||||
├── tools/
|
||||
│ └── t_test_ind.R # 独立样本 T 检验
|
||||
├── tests/
|
||||
│ └── fixtures/
|
||||
│ └── normal_data.csv # 测试数据
|
||||
├── metadata/ # 工具元数据(预留)
|
||||
└── templates/ # 解释模板(预留)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
@@ -1,17 +1,33 @@
|
||||
# SSA智能统计分析模块 - 当前状态与开发指南
|
||||
|
||||
> **文档版本:** v1.0
|
||||
> **文档版本:** v1.5
|
||||
> **创建日期:** 2026-02-18
|
||||
> **最后更新:** 2026-02-18
|
||||
> **最后更新:** 2026-02-19
|
||||
> **维护者:** 开发团队
|
||||
> **当前状态:** 📋 **MVP 开发计划 v1.3 完成,准予启动开发**
|
||||
> **当前状态:** 🎉 **T 检验端到端测试通过!MVP Phase 1 核心完成 85%**
|
||||
> **文档目的:** 快速了解SSA模块状态,为新AI助手提供上下文
|
||||
>
|
||||
> **🎉 里程碑(2026-02-18):**
|
||||
> - ✅ **PRD 完成**:SSA-Pro 严谨型智能统计分析模块需求定义
|
||||
> - ✅ **架构设计 V4 完成**:Brain-Hand 双层架构 + 统计护栏 + HITL 人机协同
|
||||
> - ✅ **MVP 开发计划 v1.3 完成**:通过 3 轮团队评审,准予启动开发
|
||||
> - ✅ **MVP 开发计划 v1.5 完成**:通过 5 轮评审,纳入完整专家配置体系
|
||||
> - ✅ **5 份开发文档完成**:总览、任务清单、R服务指南、后端指南、前端指南
|
||||
>
|
||||
> **🎉 T 检验端到端测试通过(2026-02-19):**
|
||||
> - ✅ **🎉 完整流程验证**:数据上传 → 计划生成 → 分析执行 → 结果展示 → 代码下载
|
||||
> - ✅ **R 服务 Bug 修复**:缺失值自动过滤,解决分组变量 3 组问题
|
||||
> - ✅ **类型推断优化**:0/1 数字列正确识别为分类变量
|
||||
> - ✅ **错误处理增强**:R 服务错误信息正确传递给前端
|
||||
> - ✅ **文件名动态生成**:`{toolName}_{dataName}_{MMDD}_{HHmm}.R`
|
||||
> - ✅ **前端模块激活**:智能统计分析入口可用
|
||||
> - ✅ **用户会话隔离**:不同用户数据正确隔离
|
||||
>
|
||||
> **🆕 v1.5 新增特性(专家配置体系):**
|
||||
> - 🆕 **统计决策表**:(Goal, Y, X, Design) 四维匹配精准选工具,替代简单 RAG
|
||||
> - 🆕 **R 代码库**:支持上传 100+ 成熟 R 脚本,统一 `run_analysis()` 入口
|
||||
> - 🆕 **参数映射配置**:JSON Key → R 参数名可配置
|
||||
> - 🆕 **护栏规则链**:支持 Block / Warn / Switch 三种 Action
|
||||
> - 🆕 **结果解读模板**:"填空题"式的论文级结论生成
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +42,7 @@
|
||||
| **商业价值** | ⭐⭐⭐⭐⭐ 极高 |
|
||||
| **独立性** | ⭐⭐⭐⭐ 高(可独立使用,也可与其他模块协同) |
|
||||
| **目标用户** | 临床研究人员、生物统计师 |
|
||||
| **开发状态** | 📋 **MVP 开发计划完成,准备启动开发** |
|
||||
| **开发状态** | 🚀 **MVP Phase 1 开发中(Week 1 完成 ~80%)** |
|
||||
|
||||
### 核心目标
|
||||
|
||||
@@ -42,8 +58,9 @@
|
||||
#### 核心AI能力(规划中)
|
||||
|
||||
1. **智能规划(Planner)**
|
||||
- RAG 工具检索:根据用户意图召回最适合的统计方法
|
||||
- 参数映射:将自然语言映射为统计参数
|
||||
- 🆕 **决策表匹配**:(Goal, Y, X, Design) 四维精准选工具
|
||||
- RAG 工具检索:作为决策表的兜底方案
|
||||
- 参数映射:将自然语言映射为统计参数(可配置)
|
||||
- 统计分析计划(SAP)生成
|
||||
|
||||
2. **统计护栏(Guardrails)**
|
||||
@@ -51,6 +68,7 @@
|
||||
- 方差齐性检验(Levene)
|
||||
- 样本量检验
|
||||
- 大样本优化(N > 5000 抽样检验)
|
||||
- 🆕 **护栏 Action**:Block(阻止) / Warn(警告) / Switch(切换方法)
|
||||
|
||||
3. **人机协同(HITL)**
|
||||
- Plan Card:用户确认/修改分析计划
|
||||
@@ -62,6 +80,19 @@
|
||||
- 自动注入依赖安装脚本
|
||||
- APA 格式化输出(p_value_fmt)
|
||||
|
||||
5. **🆕 咨询模式**
|
||||
- 无数据对话:用户只描述研究设计
|
||||
- SAP 文档生成:结构化统计分析计划
|
||||
- 多格式导出:Word/Markdown
|
||||
|
||||
6. **🆕 配置中台(专家知识库)**
|
||||
- 🆕 **统计决策表**:Goal + Y + X + Design → Tool 映射
|
||||
- 🆕 **R 代码库**:100+ 成熟脚本上传,统一 `run_analysis()` 入口
|
||||
- 🆕 **参数映射**:JSON Key → R 参数名 + 校验规则
|
||||
- 🆕 **护栏规则链**:Check → Threshold → Action (Block/Warn/Switch)
|
||||
- 🆕 **结果解读模板**:"填空题"式论文级结论
|
||||
- Excel 配置导入 + 热加载 + 配置校验
|
||||
|
||||
#### MVP 工具清单(10个)
|
||||
|
||||
| 工具代码 | 工具名称 | 适用场景 |
|
||||
@@ -81,28 +112,30 @@
|
||||
|
||||
## 🏗️ 架构设计
|
||||
|
||||
### Brain-Hand 双层架构
|
||||
### Brain-Hand 双层架构 + 配置中台
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 用户界面 (Frontend) │
|
||||
│ DataUploader | PlanCard | ExecutionTrace | ResultCard │
|
||||
│ 🆕 ModeSwitch | DataUploader | PlanCard | ResultCard │
|
||||
│ ↓ 智能分析 ↓ 咨询模式 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Brain Layer (Node.js) │
|
||||
│ Planner (Brain/大脑) - Node.js │
|
||||
│ ┌─────────────────────────────────────────────────────┐│
|
||||
│ │ DataParserService: 数据解析 → Schema 提取 ││
|
||||
│ │ ToolRetrievalService: RAG 工具检索 ││
|
||||
│ │ PlannerService: LLM 规划 + 参数映射 ││
|
||||
│ │ RClientService: R 服务调用(混合数据协议) ││
|
||||
│ │ PlannerService: LLM 规划(有数据) ││
|
||||
│ │ 🆕 ConsultService: 无数据咨询 ││
|
||||
│ │ 🆕 SAPGeneratorService: SAP 文档生成 ││
|
||||
│ │ CriticService: 结果解读(流式) ││
|
||||
│ └─────────────────────────────────────────────────────┘│
|
||||
│ 📌 只看 Schema(无真实数据) │
|
||||
│ 📌 只看 Schema,支持有数据/无数据两种模式 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
↓ (仅智能分析模式)
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Hand Layer (R Docker) │
|
||||
│ Executor (Hand/四肢) - R Docker │
|
||||
│ ┌─────────────────────────────────────────────────────┐│
|
||||
│ │ data_loader.R: 混合数据协议(inline/OSS) ││
|
||||
│ │ guardrails.R: 统计护栏(正态/方差齐性/样本量) ││
|
||||
@@ -111,6 +144,16 @@
|
||||
│ │ error_codes.R: 结构化错误码 ││
|
||||
│ └─────────────────────────────────────────────────────┘│
|
||||
│ 📌 操作真实数据 + 生成可复现代码 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
▲
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 🆕 配置中台 (Config Center) │
|
||||
│ ┌─────────────────────────────────────────────────────┐│
|
||||
│ │ ConfigLoaderService: Excel 配置加载 ││
|
||||
│ │ ConfigValidatorService: 配置校验 ││
|
||||
│ │ ConfigCacheService: 配置缓存 + 热加载 ││
|
||||
│ └─────────────────────────────────────────────────────┘│
|
||||
│ 📌 统计专家可配置,系统动态加载 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -128,14 +171,23 @@
|
||||
|
||||
## 📋 开发进度
|
||||
|
||||
| Phase | 任务 | 状态 | 计划日期 |
|
||||
| Phase | 任务 | 状态 | 完成日期 |
|
||||
|-------|------|------|---------|
|
||||
| Phase 0 | 需求分析与架构设计 | ✅ 已完成 | 2026-02-18 |
|
||||
| Phase 0 | MVP 开发计划 v1.0 → v1.3 | ✅ 已完成 | 2026-02-18 |
|
||||
| Phase 1 | 骨架搭建(T检验端到端) | 📋 待开始 | - |
|
||||
| Phase 2 | 智能与交互(RAG + HITL) | 📋 待开始 | - |
|
||||
| Phase 3 | 打磨与调试 | 📋 待开始 | - |
|
||||
| **总计** | - | **设计 100%,开发 0%** | - |
|
||||
| Phase 0 | MVP 开发计划 v1.0 → v1.6 | ✅ 已完成 | 2026-02-19 |
|
||||
| Phase 1 | 骨架搭建 + 配置中台 | 🎉 **核心完成 85%** | 2026-02-19 |
|
||||
| Phase 2 | 智能规划 + 咨询模式 | 📋 待开始 | - |
|
||||
| Phase 3 | 完善与联调 | 📋 待开始 | - |
|
||||
| **总计** | 106 个任务 | **完成 38 项(36%)** | - |
|
||||
|
||||
### 🎉 Phase 1 已完成核心功能
|
||||
|
||||
| 组件 | 完成项 | 状态 |
|
||||
|------|--------|------|
|
||||
| **R 服务** | T 检验、错误码、护栏、预签名 URL、缺失值处理 | ✅ 100% |
|
||||
| **后端** | 路由、RClientService、DataParserService、代码下载 | ✅ 83% |
|
||||
| **前端** | 页面框架、数据上传、结果展示、代码下载、模块注册 | ✅ 100% |
|
||||
| **配置中台** | 数据库表、热加载 API | 🔄 18% |
|
||||
|
||||
### 开发计划文档
|
||||
|
||||
@@ -154,6 +206,7 @@
|
||||
| v1.0 | `06-开发记录/SSA-Pro 方案深度审查与风险评估报告.md` | 需修订 | 2026-02-18 |
|
||||
| v1.1 | `06-开发记录/SSA-Pro 方案深度审查与风险评估报告 V2.0.md` | 需修订 | 2026-02-18 |
|
||||
| v1.2 | `06-开发记录/SSA-Pro V1.2 终极审查与发令报告V3.0.md` | 🟢 通过 | 2026-02-18 |
|
||||
| v1.4 | 🆕 纳入双引擎 + 咨询模式 + 配置中台 | 🟢 通过 | 2026-02-18 |
|
||||
|
||||
---
|
||||
|
||||
@@ -250,6 +303,8 @@ docs/03-业务模块/SSA-智能统计分析/
|
||||
|
||||
### API 接口预览
|
||||
|
||||
#### 智能分析模式
|
||||
|
||||
```http
|
||||
### 创建会话
|
||||
POST http://localhost:3001/api/v1/ssa/sessions
|
||||
@@ -270,6 +325,39 @@ Content-Type: application/json
|
||||
GET http://localhost:3001/api/v1/ssa/sessions/{sessionId}/result
|
||||
```
|
||||
|
||||
#### 🆕 咨询模式
|
||||
|
||||
```http
|
||||
### 创建咨询会话(无数据)
|
||||
POST http://localhost:3001/api/v1/ssa/consult
|
||||
|
||||
### 咨询对话
|
||||
POST http://localhost:3001/api/v1/ssa/consult/{sessionId}/chat
|
||||
Content-Type: application/json
|
||||
{"message": "我有一个双臂 RCT 研究,想比较主要终点..."}
|
||||
|
||||
### 生成 SAP 文档
|
||||
POST http://localhost:3001/api/v1/ssa/consult/{sessionId}/generate-sap
|
||||
|
||||
### 下载 SAP
|
||||
GET http://localhost:3001/api/v1/ssa/consult/{sessionId}/download-sap?format=word
|
||||
```
|
||||
|
||||
#### 🆕 配置中台
|
||||
|
||||
```http
|
||||
### 导入 Excel 配置
|
||||
POST http://localhost:3001/api/v1/ssa/config/import
|
||||
Content-Type: multipart/form-data
|
||||
# file: config.xlsx
|
||||
|
||||
### 热加载配置
|
||||
POST http://localhost:3001/api/v1/ssa/config/reload
|
||||
|
||||
### 获取工具列表
|
||||
GET http://localhost:3001/api/v1/ssa/config/tools
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
@@ -277,10 +365,13 @@ GET http://localhost:3001/api/v1/ssa/sessions/{sessionId}/result
|
||||
### 对新AI助手
|
||||
|
||||
1. ✅ **设计文档已完成**:开发前请先阅读架构设计V4
|
||||
2. ✅ **开发计划v1.3已审批**:遵循5份开发文档进行开发
|
||||
3. ⚠️ **Brain-Hand 隔离**:Node.js 只看 Schema,R 操作真实数据
|
||||
4. ⚠️ **混合数据协议**:< 2MB inline,2-20MB OSS
|
||||
5. ⚠️ **代码模板同步**:修改 Wrapper 逻辑时必须同步更新 templates/
|
||||
2. ✅ **开发计划v1.4已审批**:遵循5份开发文档进行开发
|
||||
3. ⚠️ **Planner/Executor 分离**:代码目录按 planner/executor 组织
|
||||
4. ⚠️ **Brain-Hand 隔离**:Node.js 只看 Schema,R 操作真实数据
|
||||
5. ⚠️ **支持无数据模式**:咨询模式下 Planner 可独立工作
|
||||
6. ⚠️ **配置外置**:工具定义从 Excel 加载,不硬编码
|
||||
7. ⚠️ **混合数据协议**:< 2MB inline,2-20MB OSS
|
||||
8. ⚠️ **代码模板同步**:修改 Wrapper 逻辑时必须同步更新 templates/
|
||||
|
||||
### 风险与应对
|
||||
|
||||
@@ -300,7 +391,7 @@ GET http://localhost:3001/api/v1/ssa/sessions/{sessionId}/result
|
||||
|
||||
### MVP 阶段(当前)
|
||||
|
||||
- [ ] Phase 1:骨架搭建(T检验端到端跑通)
|
||||
- [x] Phase 1:骨架搭建(T检验端到端跑通)✅ 2026-02-19
|
||||
- [ ] Phase 2:智能与交互(RAG + HITL + 10工具)
|
||||
- [ ] Phase 3:打磨与调试(性能优化 + Bug修复)
|
||||
|
||||
@@ -313,7 +404,7 @@ GET http://localhost:3001/api/v1/ssa/sessions/{sessionId}/result
|
||||
|
||||
---
|
||||
|
||||
**文档版本:** v1.0
|
||||
**最后更新:** 2026-02-18
|
||||
**当前状态:** 📋 MVP 开发计划 v1.3 完成,准予启动开发
|
||||
**下一步:** Phase 1 骨架搭建
|
||||
**文档版本:** v1.5
|
||||
**最后更新:** 2026-02-19
|
||||
**当前状态:** 🎉 T 检验端到端测试通过,Phase 1 核心完成 85%
|
||||
**下一步:** Phase 2 智能规划 + 更多统计方法(或完善配置中台)
|
||||
|
||||
128
docs/03-业务模块/SSA-智能统计分析/00-系统设计/Planner 统计分析计划与配置映射.md
Normal file
128
docs/03-业务模块/SSA-智能统计分析/00-系统设计/Planner 统计分析计划与配置映射.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# **专家视角:统计分析计划 (SAP) 的解构与配置映射**
|
||||
|
||||
**文档版本:** v1.0
|
||||
|
||||
**创建日期:** 2026-02-18
|
||||
|
||||
**核心议题:** 从医学统计专家的视角,重新定义 Planner 的规划逻辑与 Admin 的配置要素。
|
||||
|
||||
## **1\. 统计专家的“问诊”逻辑 (The Statistician's Mindset)**
|
||||
|
||||
当医生拿着数据来找我(统计专家)时,我脑子里的思维路径是这样的:
|
||||
|
||||
### **第一步:明确研究目的 (Objective)**
|
||||
|
||||
* **专家会问**:你是要描述现状?比较差异?探索关联?还是预测未来?
|
||||
* **系统映射**:**意图识别配置**。
|
||||
* *Config*: 关键词映射表("影响因素" \-\> 回归分析;"疗效对比" \-\> 差异检验)。
|
||||
|
||||
### **第二步:明确数据特征 (Data Characteristics)**
|
||||
|
||||
* **专家会问**:你的结局变量(Y)是什么类型的?(连续/分类/生存时间)你的分组变量(X)是几组?数据是独立采样的,还是同一个病人前后的对比(配对)?
|
||||
* **系统映射**:**变量角色定义**。
|
||||
* *Config*: 工具的适用数据类型约束(如:ST\_T\_TEST\_IND 要求 Y=Numeric, X=Categorical(2 levels), Design=Independent)。
|
||||
|
||||
### **第三步:制定分析策略 (Strategy)**
|
||||
|
||||
* **专家会想**:既然是比较两组连续变量,先看正态性。如果正态,用 T 检验;如果不正态,用 Wilcoxon。最后还要画个图直观展示。
|
||||
* **系统映射**:**决策树与组合配置**。
|
||||
* *Config*: 不仅仅配置“一个工具”,而是配置 **"标准分析流 (SOP)"**。
|
||||
|
||||
## **2\. 一份标准的 SAP 包括什么? (Anatomy of SAP)**
|
||||
|
||||
Planner 生成的不仅仅是一个 Tool Code,而应该是一份完整的**作战地图**。
|
||||
|
||||
### **2.1 SAP 的核心要素**
|
||||
|
||||
1. **分析集定义 (Analysis Set)**:全分析集 (FAS) 还是符合方案集 (PPS)?(MVP 阶段默认全数据)。
|
||||
2. **变量操作 (Data Manipulation)**:需要计算 BMI 吗?需要把年龄分段吗?
|
||||
3. **描述性统计 (Descriptive)**:基线表怎么做?(连续变量算 Mean±SD,分类变量算 N(%))。
|
||||
4. **推断性统计 (Inference)**:核心假设检验方法(方法论 \+ 假设前提)。
|
||||
5. **图表规划 (Visualization)**:用什么图展示结果最直观?
|
||||
|
||||
### **2.2 我们的 Planner 应该输出什么?**
|
||||
|
||||
用户看到的“预习卡片”,本质上就是 SAP 的摘要版:
|
||||
|
||||
**🎯 统计分析计划**
|
||||
|
||||
1. **研究假设**:男性与女性的血糖水平存在差异。
|
||||
2. **数据清洗**:剔除 GLU 为空的样本;自动计算 BMI \= Weight/Height^2。
|
||||
3. **统计方法**:
|
||||
* 优先使用 **独立样本 T 检验**。
|
||||
* **前置条件**:需满足正态性(Shapiro-Wilk P \> 0.05)。
|
||||
* **替代方案**:若不满足,转为 **Mann-Whitney U 检验**。
|
||||
4. **图表展示**:分组箱线图 (Boxplot) 叠加散点。
|
||||
|
||||
## **3\. 这种视角下,后台需要配置什么? (Config Requirements)**
|
||||
|
||||
我们要配置的不是“API 参数”,而是\*\*“统计学家的知识图谱”\*\*。我们需要在 Excel 中增加这几列:
|
||||
|
||||
### **3.1 决策逻辑配置 (Decision Logic)**
|
||||
|
||||
这是 Planner 的核心。专家需要定义:
|
||||
|
||||
| 配置项 | 含义 | 示例 (T检验) |
|
||||
| :---- | :---- | :---- |
|
||||
| **Goal\_Type** | 分析目的 | Difference (差异比较) |
|
||||
| **Y\_Type** | 因变量类型 | Continuous (连续数值) |
|
||||
| **X\_Type** | 自变量类型 | Categorical\_2 (二分类) |
|
||||
| **Design\_Type** | 设计类型 | Independent (独立) |
|
||||
| **Pre\_Conditions** | 前置假设 | Normality, Homogeneity |
|
||||
|
||||
**Planner 的逻辑**:
|
||||
|
||||
用户输入 \-\> 提取 (Goal, X, Y) \-\> **查配置表匹配** \-\> 命中 ST\_T\_TEST\_IND。
|
||||
|
||||
### **3.2 完整分析流配置 (Analysis Flow)**
|
||||
|
||||
一个工具往往伴随着一套动作。专家需要定义“套餐”:
|
||||
|
||||
| 配置项 | 含义 | 示例 |
|
||||
| :---- | :---- | :---- |
|
||||
| **Main\_Method** | 主方法 | t.test |
|
||||
| **Desc\_Method** | 描述方法 | mean\_sd (均值标准差) |
|
||||
| **Plot\_Type** | 推荐图表 | boxplot \+ jitter |
|
||||
| **Alt\_Method** | 替代方法 | wilcox.test (非参数) |
|
||||
|
||||
### **3.3 结果解读模板 (Narrative Template)**
|
||||
|
||||
专家要教 AI 怎么写论文里的“结果”部分。
|
||||
|
||||
* **配置内容**:
|
||||
"本研究共纳入 {{n}} 例样本。{{group\_col}} 各组间 {{val\_col}} 的差异 {{significance}} (t={{statistic}}, P={{p\_value}})。如图 1 所示,{{high\_group}} 的数值显著高于 {{low\_group}}。"
|
||||
|
||||
## **4\. 对架构的深层影响**
|
||||
|
||||
您的质疑直接推动了 **Config Center (配置中台)** 的升维。
|
||||
|
||||
1. **Planner 变重了**:它不能只做简单的 RAG 检索。它需要内置一个**轻量级的推理机**(基于专家配置的决策表),来模拟专家“看病”的过程。
|
||||
2. **Executor 变纯粹了**:它只需要忠实地执行 SAP 中的指令(包括主方法、替代方法、画图)。
|
||||
3. **Excel 配置表变复杂了**:我们需要设计一个更结构化的 Excel,让专家能把这些逻辑填进去。
|
||||
|
||||
### **新版 Excel 配置结构预览**
|
||||
|
||||
**Sheet: Knowledge\_Graph (知识图谱)**
|
||||
|
||||
* Scenario\_ID: 场景代码 (如 DIFF\_NUM\_2GRP\_IND)
|
||||
* User\_Intent: 用户意图 (差异比较)
|
||||
* Data\_Pattern: 数据特征 (Y=数值, X=2分类, 独立)
|
||||
* Rec\_Tool\_Code: 推荐工具 (ST\_T\_TEST\_IND)
|
||||
|
||||
**Sheet: Tool\_Definition (工具定义)**
|
||||
|
||||
* Tool\_Code: ST\_T\_TEST\_IND
|
||||
* Workflow: \[Check\_Normality, Check\_Variance, Run\_Test, Plot\_Box\] (定义一连串动作)
|
||||
* Report\_Template: 结果解释模板...
|
||||
|
||||
## **5\. 总结**
|
||||
|
||||
您是对的。**统计分析规划(Planner)的核心不是“检索”,而是“匹配”和“决策”。**
|
||||
|
||||
我们需要了解用户的:
|
||||
|
||||
1. **目的** (差异/相关/预测)
|
||||
2. **变量类型** (数值/分类/等级)
|
||||
3. **实验设计** (独立/配对/随访)
|
||||
|
||||
**我们的系统配置,必须围绕这三个维度展开。** 只有这样,SSA-Pro 才能生成一份让医生信服的 SAP,而不仅仅是扔给用户一个 T 检验代码。
|
||||
120
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Executor_专家配置要素.md
Normal file
120
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Executor_专家配置要素.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# **SSA-Executor 专家配置要素清单 (Configuration Specs)**
|
||||
|
||||
**文档版本:** v1.0
|
||||
|
||||
**创建日期:** 2026-02-18
|
||||
|
||||
**核心目标:** 定义统计专家需要在“配置中心”为每个 R 工具录入的详细信息。
|
||||
|
||||
**隐喻:** 如果 R 代码是“药方”,这个配置单就是“药品说明书”。
|
||||
|
||||
## **1\. 基础元数据 (Identity)**
|
||||
|
||||
*给这个 R 脚本一个系统内唯一的身份。*
|
||||
|
||||
| 配置项 | 说明 | 示例 |
|
||||
| :---- | :---- | :---- |
|
||||
| **Tool Code** | 唯一标识符 (Primary Key) | ST\_T\_TEST\_IND |
|
||||
| **Tool Name** | 显示名称 | 独立样本 T 检验 |
|
||||
| **Version** | 版本号 | v1.0.2 (用于回滚) |
|
||||
| **R Script File** | **上传文件** | t\_test\_ind.R (专家直接上传脚本) |
|
||||
| **Entry Function** | 入口函数名 | run\_analysis |
|
||||
|
||||
## **2\. 输入参数映射 (Input Contract)**
|
||||
|
||||
*告诉 Executor:这个 R 脚本需要什么原料?*
|
||||
|
||||
| 参数名 (JSON Key) | R 函数参数名 | 数据类型 | 校验规则 (Validator) | 默认值 |
|
||||
| :---- | :---- | :---- | :---- | :---- |
|
||||
| group\_col | group\_var | String | Must be column name | \- |
|
||||
| val\_col | value\_var | String | Must be numeric column | \- |
|
||||
| conf\_level | conf\_level | Float | 0.90 \- 0.99 | 0.95 |
|
||||
| alternative | alt | String | "two.sided", "less", "greater" | "two.sided" |
|
||||
|
||||
## **3\. 统计护栏配置 (Guardrails Config) ⭐ 核心**
|
||||
|
||||
*告诉 Executor:在跑核心代码前,先做什么体检?*
|
||||
|
||||
**配置模式:** 规则链 (Rule Chain)
|
||||
|
||||
1. **检查项 (Check)**: Shapiro-Wilk Normality Test
|
||||
* **目标变量**: val\_col (按 group\_col 分组)
|
||||
* **阈值 (Threshold)**: P \< 0.05
|
||||
* **失败动作 (Action)**:
|
||||
* \[ \] **Block**: 报错并终止 ("数据不正态,无法计算")
|
||||
* \[ \] **Warn**: 继续执行,但在结果中标记警告
|
||||
* \[x\] **Switch**: 自动切换到工具 ST\_WILCOXON (非参数检验)
|
||||
2. **检查项 (Check)**: Sample Size
|
||||
* **规则**: Min(N) \< 3
|
||||
* **失败动作**: **Block** ("样本量太少,无法计算")
|
||||
|
||||
## **4\. 输出结果定义 (Output Definition)**
|
||||
|
||||
*告诉 Executor:跑完代码后,要给用户看什么?*
|
||||
|
||||
### **4.1 结构化数据 (Table)**
|
||||
|
||||
定义返回的三线表里包含哪些指标。
|
||||
|
||||
* **指标 1**: Statistic (t值 / F值)
|
||||
* **指标 2**: P-Value (保留 3 位小数,\<0.001 显示为 "\<0.001")
|
||||
* **指标 3**: Mean ± SD (描述性统计)
|
||||
* **指标 4**: CI (95%) (置信区间)
|
||||
|
||||
### **4.2 图表配置 (Visualization)**
|
||||
|
||||
定义 R 脚本生成的图表规范(ggplot2 模板)。
|
||||
|
||||
* **图表类型**: Boxplot with Jitter (箱线图+散点)
|
||||
* **X 轴映射**: group\_col
|
||||
* **Y 轴映射**: val\_col
|
||||
* **配色方案**: Nature / Lancet (期刊风格)
|
||||
* **其它元素**: 是否标注 P 值?(Yes/No)
|
||||
|
||||
### **4.3 智能解读模板 (Narrative Template)**
|
||||
|
||||
这是给 AI (Critic) 参考的“填空题”,或者是 R 直接生成的结论。
|
||||
|
||||
* **模板**:"本研究纳入 {{N}} 例样本。{{group\_col}} 各组间 {{val\_col}} 的差异 **{{significance\_text}}** (t={{statistic}}, P={{p\_value}})。具体而言,{{high\_group}} 的均值 ({{mean\_1}}) 显著高于 {{low\_group}} ({{mean\_2}})。"
|
||||
|
||||
## **5\. 代码交付配置 (Code Handover)**
|
||||
|
||||
*告诉 Executor:用户点击“下载代码”时,给他什么?*
|
||||
|
||||
这是一个 **glue 字符串模板**,用于生成可复现的 R 代码。
|
||||
|
||||
\# 模板示例
|
||||
library(ggplot2)
|
||||
library(stats)
|
||||
|
||||
\# 1\. 读取数据
|
||||
data \<- read.csv("your\_data.csv")
|
||||
|
||||
\# 2\. 统计检验
|
||||
res \<- t.test({{val\_col}} \~ {{group\_col}}, data=data, var.equal={{var\_equal}})
|
||||
print(res)
|
||||
|
||||
\# 3\. 绘图
|
||||
ggplot(data, aes(x={{group\_col}}, y={{val\_col}})) \+
|
||||
geom\_boxplot(fill="\#3C5488") \+
|
||||
theme\_bw() \+
|
||||
labs(title="Difference Analysis")
|
||||
|
||||
## **6\. 环境依赖 (Dependencies)**
|
||||
|
||||
*告诉 Executor:运行这个脚本需要装什么包?*
|
||||
|
||||
* **Packages**: ggplot2, dplyr, car, ggpubr
|
||||
* **System Libs**: libcairo2 (如果涉及特殊绘图)
|
||||
|
||||
## **7\. 总结:专家的工作流**
|
||||
|
||||
统计学专家在“配置中心”要做的事情就是:
|
||||
|
||||
1. **上传** 写好的 t\_test.R。
|
||||
2. **勾选** 这个脚本需要的输入参数(列名)。
|
||||
3. **设置** 护栏(P \< 0.05 切换 Wilcoxon)。
|
||||
4. **粘贴** 代码模板(供用户下载)。
|
||||
5. **预览** 这一套配置是否能跑通测试数据。
|
||||
|
||||
**这才是真正的“专家协同”。**
|
||||
228
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Pro_v2.0_双引擎架构版 V2.1.md
Normal file
228
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Pro_v2.0_双引擎架构版 V2.1.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# **PRD: SSA-Pro 智能统计分析 (v2.0 双引擎架构版)**
|
||||
|
||||
**文档状态:** v2.1 (Optimized for User Scenarios)
|
||||
|
||||
**发布日期:** 2026-02-18
|
||||
|
||||
**文档密级:** 内部绝密
|
||||
|
||||
**核心变更:** \> 1\. 重构业务流程,确立“智能分析(混合模式)”为主流程。
|
||||
|
||||
2\. 明确“执行模式”为“标准化复用”场景,而非手动填参。
|
||||
|
||||
3\. 强化“专家配置”在架构中的核心地位。
|
||||
|
||||
## **1\. 核心变革说明 (Executive Summary)**
|
||||
|
||||
**致研发团队:为什么要进行这次架构升级?**
|
||||
|
||||
经过前几轮的技术验证与业务推演,我们发现原有的“上传-\>规划-\>执行”一条龙模式存在两个致命的业务死角:
|
||||
|
||||
1. **用户意图模糊**:用户往往不知道自己要做什么(如“帮我分析一下”),直接跑代码会报错或产生无意义结果。
|
||||
2. **统计专家缺位**:护栏规则硬编码在代码里,统计专家无法维护,导致系统缺乏“灵魂”。
|
||||
|
||||
因此,我们将架构解耦为**两个独立子系统**,通过编排满足不同场景:
|
||||
|
||||
* **Planner(大脑)**:负责陪聊、澄清意图、生成方案。**(独立上线,无需数据)**
|
||||
* **Executor(四肢)**:负责接收明确指令、跑数、出结果。**(复用之前的 R 开发成果)**
|
||||
|
||||
**架构拆分与用户体验的关系:**
|
||||
|
||||
架构上的拆分(Planner/Executor)是为了技术上的解耦和复用,但在用户体验端,对于最常见的“智能分析”场景,我们将这两者**无缝串联**,给用户提供“一站式”体验。
|
||||
|
||||
## **2\. 研发背景与业务价值**
|
||||
|
||||
### **2.1 用户真实痛点**
|
||||
|
||||
* **场景 A (无数据)**:医生在写基金本子,还没收病人,但他急需一份《统计学分析计划书》来填表。原方案不支持此场景。
|
||||
* **场景 B (数据脏)**:医生上传的 Excel 列名全是中文,且有特殊字符。原方案直接跑 R 会崩溃。
|
||||
* **场景 C (隐私顾虑)**:医生不敢把数据上传到云端,但又想知道该用什么统计方法。
|
||||
|
||||
### **2.2 产品解决方案:双引擎 \+ 配置中台**
|
||||
|
||||
1. **独立咨询 (SSA-Planner)**:无需上传数据,通过多轮对话澄清意图,输出专业的 SAP (分析计划)。
|
||||
2. **独立计算 (SSA-Executor)**:用户确认方案后,再上传数据,一键执行计算,交付代码。
|
||||
3. **专家协同 (Config Center)**:统计专家通过 Excel 配置规则,系统动态加载,不再硬编码。
|
||||
|
||||
### **2.3 商业价值**
|
||||
|
||||
* **降低门槛**:用户不用传数据就能体验 AI 能力(Planner),极大地提高了转化率。
|
||||
* **数据安全**:实现了逻辑(云端)与数据(本地/隔离)的彻底解耦。
|
||||
|
||||
## **3\. 系统架构与模块定义**
|
||||
|
||||
### **3.1 总体架构图**
|
||||
|
||||
graph TD
|
||||
subgraph "用户触点"
|
||||
Chat\[前端 Chat 界面\]
|
||||
end
|
||||
|
||||
subgraph "Module A: 智能规划师 (SSA-Planner)"
|
||||
Intent\[意图识别引擎\]
|
||||
Clarify\[澄清引导模块\]
|
||||
GenSAP\[SAP 生成模块\]
|
||||
end
|
||||
|
||||
subgraph "Module B: 智能执行器 (SSA-Executor)"
|
||||
API\[Executor API\]
|
||||
R\_Core\[R Docker 容器\]
|
||||
Guard\[统计护栏\]
|
||||
end
|
||||
|
||||
subgraph "Module C: 统计配置中台 (Admin)"
|
||||
Meta\[元数据管理\]
|
||||
Rules\[规则引擎\]
|
||||
Templates\[代码模板\]
|
||||
end
|
||||
|
||||
Chat \--"1. 咨询/方案"--\> Intent
|
||||
Intent \<--\> Clarify
|
||||
Intent \--\> GenSAP
|
||||
|
||||
Chat \--"2. 执行/计算"--\> API
|
||||
API \--\> R\_Core
|
||||
|
||||
Meta \-.-\> Intent
|
||||
Rules \-.-\> Guard
|
||||
|
||||
### **3.2 模块功能详述**
|
||||
|
||||
#### **🧩 模块 A:SSA-Planner (智能规划师)**
|
||||
|
||||
* **定位**:纯 NLP 应用,不涉及 R 计算。
|
||||
* **输入**:自然语言 \+ (可选) 数据 Schema。
|
||||
* **核心能力**:
|
||||
* **意图澄清**:当用户指令模糊时,主动反问("您是想做差异分析还是相关性分析?")。
|
||||
* **方案生成**:检索 RAG 库,生成结构化的 JSON 计划和 Markdown 报告。
|
||||
* **交付物**:《统计分析计划书》 (PDF/Word)。
|
||||
|
||||
#### **🧩 模块 B:SSA-Executor (智能执行器)**
|
||||
|
||||
* **定位**:纯计算服务,无状态 API。
|
||||
* **输入**:skill\_code \+ params \+ data\_source。
|
||||
* **核心能力**:
|
||||
* **混合数据加载**:支持 JSON 和 OSS 数据源。
|
||||
* **护栏检查**:执行正态性、方差齐性检查。
|
||||
* **结果交付**:生成三线表、高清图、R 源码。
|
||||
* **技术备注**:**这部分完全复用原 V1.3 计划中的 R 服务开发内容。**
|
||||
* **注意**:Executor 无法直接处理用户的自然语言。必须经由 Planner 将自然语言转化为结构化参数后,才能被调用。
|
||||
|
||||
#### **🧩 模块 C:统计配置中台 (Config Center)**
|
||||
|
||||
* **定位**:专家知识注入入口。
|
||||
* **MVP 实现**:**Excel 导入工具**。
|
||||
* **配置内容**:
|
||||
* 工具定义(Name, Desc, Usage)。
|
||||
* 护栏阈值(P \< 0.05)。
|
||||
* R 代码模板(Glue Template)。
|
||||
|
||||
## **4\. 核心业务流程 (User Journey)**
|
||||
|
||||
### **流程一:智能分析模式 (Intelligent Analysis Mode) \- ⭐ 最常见场景**
|
||||
|
||||
**场景**:用户有数据,有模糊的意图(如“帮我对比一下差异”),希望一站式出结果。
|
||||
|
||||
**架构逻辑**:串联调用 Planner \-\> Executor。
|
||||
|
||||
1. **用户**:上传 data.csv 并输入:“帮我对比一下吸烟组和非吸烟组的体重差异”。
|
||||
2. **Planner**(后台隐形介入):
|
||||
* 读取 Data Schema,识别出 Group 和 Weight 列。
|
||||
* 理解用户意图("对比差异"),结合变量类型(二分类 vs 连续),推荐“独立样本 T 检验”。
|
||||
* 生成 Executor 能听懂的 JSON 参数。
|
||||
3. **交互**:系统弹出 **\[ 方案确认卡片 \]**(由 Planner 生成)。
|
||||
* *设计意图*:给用户一种“专家先审视,再执行”的安全感。
|
||||
4. **用户**:点击 **\[ 确认并执行 \]**。
|
||||
5. **Executor**:接收 Planner 的 JSON \-\> 跑 R 代码 \-\> 返回结果。
|
||||
6. **用户**:获得结果。
|
||||
|
||||
### **流程二:纯咨询模式 (Consultation Mode) \- 科研设计场景**
|
||||
|
||||
**场景**:用户还没收集数据(无数据),在写开题报告或基金标书,需要设计统计方案。
|
||||
|
||||
**架构逻辑**:仅调用 Planner。
|
||||
|
||||
1. **用户**:“我想研究阿司匹林对心血管事件的影响,该怎么设计统计?”
|
||||
2. **Planner**:检索知识库,生成《统计分析计划书 (SAP)》。
|
||||
* 包含:研究假设、变量定义、推荐方法(Cox 回归)、样本量估算建议。
|
||||
3. **用户**:下载 SAP 文档。**(流程结束)**
|
||||
|
||||
### **流程三:标准化复用模式 (Standardized Reuse Mode) \- 专家/高阶场景**
|
||||
|
||||
**场景**:
|
||||
|
||||
1. **复用**:上周生成了一个完美的 SAP,这周新数据来了,直接套用,不想再跟 AI 废话。
|
||||
2. **专家下发**:科室主任定义好了标准分析流程,存为模板,研究生直接上传数据运行。
|
||||
**架构逻辑**:跳过 Planner 推理,直接调用 Executor。
|
||||
1. **用户**:上传 new\_data.csv,并从“我的方案库”中选择“肺癌生存分析标准模板”(或加载之前的 SAP ID)。
|
||||
2. **系统**:自动校验新数据是否符合模板要求的列名(Schema Check)。
|
||||
3. **Executor**:直接读取模板参数 \-\> 跑数 \-\> 出结果。
|
||||
4. **用户**:下载结果。
|
||||
|
||||
## **5\. 接口与数据协议 (Schema)**
|
||||
|
||||
### **5.1 Planner 输出协议 (Plan JSON)**
|
||||
|
||||
这是连接 Planner 和 Executor 的契约。
|
||||
|
||||
{
|
||||
"analysis\_id": "uuid",
|
||||
"tool\_code": "ST\_T\_TEST\_IND",
|
||||
"reasoning": "因变量为连续数值,自变量为二分类...",
|
||||
"params": {
|
||||
"group\_col": "Gender",
|
||||
"val\_col": "BMI",
|
||||
"conf\_level": 0.95
|
||||
},
|
||||
"guardrails": {
|
||||
"check\_normality": true,
|
||||
"action\_on\_fail": "switch\_to\_wilcoxon"
|
||||
}
|
||||
}
|
||||
|
||||
## **6\. 实施路线图 (Updated Roadmap)**
|
||||
|
||||
基于新架构,我们将开发顺序调整为 **“Planner 先行,Executor 并行”**。
|
||||
|
||||
### **Phase 1: 智能规划师上线 (Week 1-2)**
|
||||
|
||||
* **目标**:上线“统计咨询 Chatbot”。
|
||||
* **后端**:开发 Excel 配置导入脚本;开发 Planner Service (DeepSeek)。
|
||||
* **前端**:开发咨询模式 UI。
|
||||
* **专家**:整理 Top 10 工具的 Excel 配置。
|
||||
* *注:此阶段不需要 R 服务参与。*
|
||||
|
||||
### **Phase 2: 执行器与联调 (Week 3-4)**
|
||||
|
||||
* **目标**:打通计算闭环。
|
||||
* **R 团队**:完成 Docker 封装、数据加载器 (Data Loader)、T 检验 Wrapper。
|
||||
* **后端**:对接 R API,透传 Planner 的参数。
|
||||
* **前端**:开发结果展示卡片。
|
||||
|
||||
### **Phase 3: 量产与优化 (Week 5+)**
|
||||
|
||||
* **目标**:覆盖更多工具。
|
||||
* **R 团队**:批量复制开发剩余 9 个工具。
|
||||
* **专家**:持续优化配置 Excel。
|
||||
|
||||
## **7\. 风险与应对**
|
||||
|
||||
| **风险点** | **影响** | **应对策略** |
|
||||
|
||||
| **Planner 瞎指挥** | 生成的参数 Executor 无法执行 | 引入 **Zod Schema 强校验**,参数不合法直接让 AI 重试。 |
|
||||
|
||||
| **数据列名不匹配** | R 代码报错 "Column not found" | 在 Executor 入口增加 **模糊匹配/同义词映射** 逻辑。 |
|
||||
|
||||
| **专家配置进度慢** | 阻塞 Planner 上线 | 提供标准模板,先配 1 个工具(T检验)跑通全流程。 |
|
||||
|
||||
## **8\. 结语**
|
||||
|
||||
这次架构调整不是推翻过去,而是**升维**。
|
||||
|
||||
我们保留了最核心的 **R 计算引擎 (Executor)**,它是我们的硬实力;
|
||||
|
||||
我们剥离出了 **AI 规划师 (Planner)**,它是我们的软实力;
|
||||
|
||||
我们引入了 **配置中台**,它是我们的护城河。
|
||||
|
||||
请大家基于此文档,放心开工。
|
||||
57
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Pro_架构一致性与调整分析.md
Normal file
57
docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Pro_架构一致性与调整分析.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# **SSA-Pro 架构一致性与调整分析报告**
|
||||
|
||||
**分析对象:** PRD V2.0 "智能分析模式" vs. V1.3 开发计划套件 (5文档)
|
||||
|
||||
**分析结论:** **核心逻辑完全一致,无需重构,仅需解耦接口。**
|
||||
|
||||
## **1\. 核心结论:我们绕弯路了吗?**
|
||||
|
||||
**没有。我们只是把“隐性”的逻辑“显性化”了。**
|
||||
|
||||
* **V1.3 计划(原计划)**:设计了一个“串联”系统。
|
||||
* 逻辑:用户上传 \-\> 系统规划(Planner) \-\> 系统执行(Executor) \-\> 结果
|
||||
* **现状**:这正是 PRD V2.0 中的 **“流程一:智能分析模式”**。这是用户 90% 的使用场景。
|
||||
* **V2.0 架构(新概念)**:提出了“双引擎”概念。
|
||||
* 逻辑:把上述串联系统中的 规划 和 执行 两个步骤,定义为两个可以**独立调用**的模块。
|
||||
|
||||
**结论:**
|
||||
|
||||
**V1.3 的开发计划(代码、Docker、数据库)依然是 100% 可用的基础。** 我们不需要推翻它,只需要在写代码时,注意把 Planner 和 Executor 的代码写在不同的 Service 文件里,不要写死在一个大函数里即可。
|
||||
|
||||
## **2\. 详细对比与复用策略**
|
||||
|
||||
我们来看之前的 5 个文档,看看哪些可以直接用,哪些需要微调。
|
||||
|
||||
| 原文档 | V1.3 内容 | V2.0 架构要求 | 调整建议 |
|
||||
| :---- | :---- | :---- | :---- |
|
||||
| **02-R服务开发指南** | 定义了 R Docker、Wrapper、护栏、混合数据协议。 | 需要一个独立的计算引擎。 | **无需调整 (0%)**。 R 服务本身就是 Executor,它生来就是被调用的,不关心是谁调用的。 |
|
||||
| **03-后端开发指南** | 定义了 RClientService (执行) 和 PlannerService (规划)。 | 需要 Planner 和 Executor 解耦。 | **微调接口 (10%)**。 原计划中可能有一个 runAnalysis() 函数把两步连起来写了。**调整为:** 写两个函数 plan() 和 execute(),然后在 Controller 层串联它们。 |
|
||||
| **04-前端开发指南** | 定义了 PlanCard, ExecutionTree, ResultCard。 | 需要支持“咨询模式”和“执行模式”。 | **微调路由 (10%)**。 增加一个 /consult 页面(复用 Chat 组件)。PlanCard 增加一个“仅下载方案”的按钮。 |
|
||||
| **00/01 计划任务** | 定义了开发里程碑。 | 强调 Planner 先行。 | **无需调整**。 原计划也是先做 RAG/Planner,再做 Executor。顺序本就一致。 |
|
||||
|
||||
## **3\. 为什么“双引擎”概念依然重要?(即使流程没变)**
|
||||
|
||||
既然流程一样,为什么还要提“双引擎”?是为了解决 **边界情况(Corner Cases)**:
|
||||
|
||||
1. **无数据咨询 (The "No-Data" Problem)**:
|
||||
* 如果按照旧的 V1.3 思维,代码可能会写成 if (\!file) throw Error("请上传文件")。
|
||||
* 引入“双引擎”概念后,后端代码会写成 if (\!file) return PlannerService.consult()。
|
||||
* **这就是唯一的区别:允许 Planner 独立工作。**
|
||||
2. **专家配置 (The "Config" Problem)**:
|
||||
* V1.3 计划里,工具的 Prompt 可能是写死在代码里的。
|
||||
* V2.0 强调配置中心,提醒我们把 Prompt 放到数据库里,让专家能改。
|
||||
|
||||
## **4\. 最终执行建议:如何使用现有的 5 个文档?**
|
||||
|
||||
**请直接使用之前的 5 个文档进行开发,但在实施时遵循以下 3 条“解耦原则”:**
|
||||
|
||||
1. **后端开发原则**:
|
||||
* 不要把 Planner 的逻辑和 Executor 的逻辑混在一个 Class 里。请创建 src/modules/ssa/planner/ 和 src/modules/ssa/executor/ 两个文件夹。
|
||||
2. **前端开发原则**:
|
||||
* 不要假设用户一定上传了文件。Chat 界面初始化时,允许 file 为空。
|
||||
3. **专家配置原则**:
|
||||
* 按原计划优先使用 **Excel** 导入配置。这是最快落地的方案,不需要改架构。
|
||||
|
||||
**一句话总结:**
|
||||
|
||||
**架构不需要大改。V1.3 的开发计划是稳健的。所谓的“架构调整”,只是要求开发人员在写代码时,“手起刀落”把逻辑拆得更干净一点,方便未来复用,仅此而已。**
|
||||
@@ -1,10 +1,10 @@
|
||||
# SSA-Pro MVP 开发计划总览
|
||||
|
||||
> **文档版本:** v1.3
|
||||
> **文档版本:** v1.5
|
||||
> **创建日期:** 2026-02-18
|
||||
> **最后更新:** 2026-02-18(纳入 V3.0 终极审查建议)
|
||||
> **最后更新:** 2026-02-18(纳入专家配置体系 + 决策表匹配 + R代码库)
|
||||
> **项目代号:** SSA (Smart Statistical Analysis)
|
||||
> **MVP 目标:** 打通完整闭环,上线 10 个核心统计工具
|
||||
> **MVP 目标:** 打通完整闭环,上线 10 个核心统计工具,支持咨询模式
|
||||
|
||||
---
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
| 类别 | 内容 |
|
||||
|------|------|
|
||||
| **统计工具** | 10 个高频工具(T检验、ANOVA、卡方、相关性等) |
|
||||
| **双模式支持** | 🆕 **智能分析模式**(上传数据→执行)+ **咨询模式**(无数据→SAP文档)|
|
||||
| **核心流程** | 上传数据 → AI规划 → 用户确认 → R执行 → 结果交付 |
|
||||
| **交互能力** | 计划确认卡片、执行路径树、结果展示、代码下载 |
|
||||
| **交互能力** | 计划确认卡片、执行路径树、结果展示、代码下载、🆕 SAP文档导出 |
|
||||
| **智能能力** | RAG工具检索、Planner规划、Critic结果解读 |
|
||||
| **配置中台** | 🆕 统计决策表 + R代码库 + 参数映射 + 护栏规则链 + 解读模板 |
|
||||
| **数据安全** | LLM只看Schema,R服务处理真实数据 |
|
||||
|
||||
### 1.2 不包含内容 ❌
|
||||
@@ -26,8 +28,9 @@
|
||||
|------|------|---------|
|
||||
| 50+ 工具量产 | MVP只做10个核心工具 | Phase 3 |
|
||||
| 跨模块 Skills 化 | 不实现 Global Skill Registry | V2.0 |
|
||||
| Word 报告导出 | 先实现代码下载 | Phase 3 |
|
||||
| Word 报告导出 | 先实现代码下载 + SAP 文档 | Phase 3 |
|
||||
| 大文件 OSS 传输 | MVP 限制 2MB 以内 | Phase 3 |
|
||||
| 配置管理 UI | MVP 使用 Excel 导入 | V2.0 |
|
||||
|
||||
### 1.3 MVP 工具清单(10个)
|
||||
|
||||
@@ -46,65 +49,143 @@
|
||||
|
||||
---
|
||||
|
||||
## 2. 整体架构
|
||||
## 2. 整体架构(双引擎 + 配置中台)
|
||||
|
||||
### 2.1 架构概念
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 前端 (React 19) │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 数据上传 │ │ 计划卡片 │ │ 执行路径 │ │ 结果展示 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ 用户触点 │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 智能分析模式 │ │ 咨询模式 │ │
|
||||
│ │ (上传数据+执行) │ │ (无数据,生成SAP) │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ │
|
||||
└────────────┼──────────────────────────┼─────────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Planner (大脑) - Node.js │
|
||||
│ ┌─────────┐ ┌───────────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ Rewriter│→ │🆕 决策表匹配 │→ │ Planner │→ │ Critic │ │
|
||||
│ └─────────┘ │(Goal,Y,X,Design)│ └─────────┘ └─────────┘ │
|
||||
│ └───────────────┘ │
|
||||
│ 📌 只看 Schema,四维匹配精准选工具,支持有数据/无数据 │
|
||||
└────────────────────────────┬────────────────────────────────────┘
|
||||
│ HTTP API
|
||||
┌────────────────────────────┴────────────────────────────────────┐
|
||||
│ Node.js 后端 (Brain) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ SSA Orchestrator (编排服务) │ │
|
||||
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||
│ │ │ Rewriter│→ │ RAG检索 │→ │ Planner │→ │ Critic │ │ │
|
||||
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ 只看 Schema,不看真实数据 │
|
||||
└────────────────────────────┬────────────────────────────────────┘
|
||||
│ HTTP (内网)
|
||||
┌────────────────────────────┴────────────────────────────────────┐
|
||||
│ R 统计服务 (Hand) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Plumber API Gateway │ │
|
||||
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||
│ │ │ 护栏检查 │→ │ 核心计算 │→ │ 代码生成 │ │ │
|
||||
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ 处理真实数据,网络隔离 │
|
||||
│ (仅智能分析模式)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Executor (四肢) - R Docker │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 护栏检查 │→ │ 核心计算 │→ │ 代码生成 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ 📌 处理真实数据,网络隔离 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
▲
|
||||
┌────────────────────────────┴────────────────────────────────────┐
|
||||
│ 🆕 配置中台 (Config Center) - 专家知识库 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 📊 Planner 配置 │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ 决策表: Goal_Type + Y_Type + X_Type + Design → Tool_Code ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ 🔧 Executor 配置 │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||||
│ │ R代码库: 100+ 成熟脚本 │ 参数映射 │ 护栏规则链(Block/Warn/Switch)││
|
||||
│ │ 输出定义 │ 解读模板 │ 代码交付模板 ││
|
||||
│ └─────────────────────────────────────────────────────────────┘│
|
||||
│ 📌 统计专家配置,系统动态加载,统一入口 run_analysis() │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 双模式流程
|
||||
|
||||
| 模式 | 数据要求 | 调用链 | 输出 |
|
||||
|------|---------|--------|------|
|
||||
| **智能分析** | ✅ 上传数据 | Planner → Executor | 结果 + R 代码 |
|
||||
| **统计咨询** | ❌ 无需数据 | Planner only | SAP 文档(Word) |
|
||||
|
||||
### 2.3 代码目录结构(概念显性化)
|
||||
|
||||
```
|
||||
backend/src/modules/ssa/
|
||||
├── planner/ ← Planner 职责
|
||||
│ ├── DataParserService.ts # 解析数据 Schema
|
||||
│ ├── DecisionTableService.ts # 🆕 决策表匹配 (Goal,Y,X,Design)
|
||||
│ ├── ToolRetrievalService.ts # RAG 检索(辅助)
|
||||
│ ├── PlannerService.ts # 生成分析计划(有数据)
|
||||
│ └── ConsultService.ts # 无数据咨询(生成 SAP)
|
||||
│
|
||||
├── executor/ ← Executor 职责
|
||||
│ └── RClientService.ts # 调用 R 服务
|
||||
│
|
||||
├── config/ ← 配置中台
|
||||
│ ├── DecisionTableLoader.ts # 🆕 加载统计决策表
|
||||
│ ├── RCodeLibraryService.ts # 🆕 R 代码库管理
|
||||
│ ├── ParamMappingService.ts # 🆕 参数映射配置
|
||||
│ ├── GuardrailConfigService.ts # 🆕 护栏规则链
|
||||
│ └── ConfigValidatorService.ts # 配置校验
|
||||
│
|
||||
├── routes/ # API 路由
|
||||
├── dto/ # 数据传输对象
|
||||
└── types/ # 类型定义
|
||||
```
|
||||
|
||||
### 2.4 🆕 专家配置文件结构
|
||||
|
||||
```
|
||||
config/ssa/
|
||||
├── decision_table.xlsx # 统计决策表(Planner 用)
|
||||
│ └── Sheet: Scenarios # Goal + Y + X + Design → Tool
|
||||
├── r_scripts/ # 🆕 100+ 成熟 R 脚本
|
||||
│ ├── t_test_ind.R
|
||||
│ ├── wilcoxon.R
|
||||
│ ├── anova_one.R
|
||||
│ └── ...
|
||||
├── tool_config.xlsx # 工具配置
|
||||
│ ├── Sheet: Metadata # 工具基础信息
|
||||
│ ├── Sheet: ParamMapping # JSON Key → R 参数名
|
||||
│ ├── Sheet: Guardrails # 护栏规则链
|
||||
│ ├── Sheet: OutputDef # 输出字段定义
|
||||
│ └── Sheet: Interpretation # 结果解读模板
|
||||
└── code_templates/ # 用户下载的代码模板
|
||||
├── t_test.R.template
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 里程碑与时间线
|
||||
|
||||
### Phase 1:骨架搭建(Week 1-2)
|
||||
### Phase 1:骨架搭建 + 配置中台(Week 1-2)
|
||||
|
||||
**目标:** 跑通 T 检验的 "Hello World"
|
||||
**目标:** 跑通 T 检验 + 配置中台基础 + 决策表匹配
|
||||
|
||||
| 交付物 | 验收标准 |
|
||||
|--------|---------|
|
||||
| R Docker 镜像 | 本地可运行,健康检查通过 |
|
||||
| Plumber API | POST /api/v1/skills/ST_T_TEST_IND 返回 JSON |
|
||||
| Node.js 转发 | POST /api/v1/ssa/execute 调用 R 成功 |
|
||||
| 数据库 Schema | tools_library, sessions, messages 表创建 |
|
||||
| 前端骨架 | 基础页面框架,可上传文件 |
|
||||
| 数据库 Schema | tools_library, sessions, messages, 🆕**r_code_library** 表创建 |
|
||||
| 🆕 决策表加载 | 从 Excel 加载 (Goal,Y,X,Design) → Tool 映射 |
|
||||
| 🆕 R 代码库管理 | 上传 R 脚本到数据库,统一 `run_analysis()` 入口 |
|
||||
| 🆕 参数映射配置 | JSON Key → R 参数名映射可配置 |
|
||||
| 🆕 护栏规则链 | Block/Warn/Switch 三种 Action 可配置 |
|
||||
| 🆕 配置热加载 | Admin API `/config/reload` 触发配置更新 |
|
||||
| 前端骨架 | 基础页面框架,🆕 **模式切换 Tab**(分析/咨询)|
|
||||
|
||||
### Phase 2:智能规划与交互(Week 3-4)
|
||||
### Phase 2:智能规划与咨询模式(Week 3-4)
|
||||
|
||||
**目标:** 用户可与 AI 对话,确认后执行
|
||||
**目标:** 决策表驱动规划 + 纯咨询模式双上线
|
||||
|
||||
| 交付物 | 验收标准 |
|
||||
|--------|---------|
|
||||
| RAG 检索 | 输入"两组差异"能返回 T 检验 |
|
||||
| Planner | 生成正确的参数映射 JSON |
|
||||
| 🆕 决策表匹配 | 根据 (Goal,Y,X,Design) 精准选工具,RAG 辅助 |
|
||||
| Planner(有数据) | 决策表 + Schema → 参数映射 JSON |
|
||||
| 🆕 Planner(无数据) | 决策表 + 用户描述 → SAP 文档 |
|
||||
| 🆕 SAP 文档导出 | Word/Markdown 格式下载 |
|
||||
| 🆕 结果解读模板 | 根据配置的解读模板生成论文级结论 |
|
||||
| 计划确认卡片 | 前端展示,用户可修改参数 |
|
||||
| 执行路径树 | 显示护栏检查步骤 |
|
||||
| 执行路径树 | 显示护栏检查步骤(含 Action 类型)|
|
||||
| 5 个工具 | T检验、配对T、ANOVA、卡方、相关性 |
|
||||
|
||||
### Phase 3:完善与联调(Week 5-6)
|
||||
@@ -116,22 +197,57 @@
|
||||
| Critic 解读 | 生成严谨的统计结论 |
|
||||
| 代码下载 | 用户可下载 .R 文件 |
|
||||
| 10 个工具 | 全部上线并测试通过 |
|
||||
| 端到端测试 | 10 个典型场景通过 |
|
||||
| 🆕 配置验证 | Excel 导入时校验格式/必填/唯一性 |
|
||||
| 端到端测试 | 10 个典型场景通过(含咨询模式)|
|
||||
| SAE 部署 | R 服务部署成功 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心 API 设计
|
||||
|
||||
### 4.1 会话与分析 API
|
||||
|
||||
```
|
||||
POST /api/v1/ssa/sessions # 创建会话
|
||||
POST /api/v1/ssa/sessions/:id/upload # 上传数据
|
||||
POST /api/v1/ssa/sessions/:id/plan # 生成计划(不执行)
|
||||
POST /api/v1/ssa/sessions/:id/upload # 上传数据(智能分析模式)
|
||||
POST /api/v1/ssa/sessions/:id/plan # 生成计划(有数据)
|
||||
POST /api/v1/ssa/sessions/:id/execute # 确认执行
|
||||
GET /api/v1/ssa/sessions/:id/messages # 获取消息历史
|
||||
GET /api/v1/ssa/sessions/:id/download-code # 下载代码
|
||||
```
|
||||
|
||||
### 4.2 🆕 咨询模式 API
|
||||
|
||||
```
|
||||
POST /api/v1/ssa/consult # 创建咨询会话(无数据)
|
||||
POST /api/v1/ssa/consult/:id/chat # 咨询对话(多轮)
|
||||
POST /api/v1/ssa/consult/:id/generate-sap # 生成 SAP 文档
|
||||
GET /api/v1/ssa/consult/:id/download-sap # 下载 SAP(Word/MD)
|
||||
```
|
||||
|
||||
### 4.3 🆕 配置中台 API
|
||||
|
||||
```
|
||||
# 决策表配置
|
||||
POST /api/v1/ssa/config/decision-table # 导入决策表 Excel
|
||||
GET /api/v1/ssa/config/decision-table # 获取决策表
|
||||
|
||||
# R 代码库配置
|
||||
POST /api/v1/ssa/config/r-scripts # 上传 R 脚本
|
||||
GET /api/v1/ssa/config/r-scripts # 获取脚本列表
|
||||
PUT /api/v1/ssa/config/r-scripts/:id # 更新脚本
|
||||
|
||||
# 工具配置
|
||||
POST /api/v1/ssa/config/tool-config # 导入工具配置 Excel
|
||||
GET /api/v1/ssa/config/tools # 获取工具列表
|
||||
GET /api/v1/ssa/config/tools/:code/params # 获取参数映射
|
||||
GET /api/v1/ssa/config/tools/:code/guardrails # 获取护栏规则
|
||||
|
||||
# 通用
|
||||
POST /api/v1/ssa/config/reload # 热加载所有配置(Admin)
|
||||
GET /api/v1/ssa/config/validate # 校验配置文件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 依赖与集成
|
||||
@@ -154,7 +270,9 @@ GET /api/v1/ssa/sessions/:id/download-code # 下载代码
|
||||
| R Docker 镜像 | 基于 rocker/r-ver:4.3,含 Plumber + renv |
|
||||
| R 统计服务 | SAE 新应用,**VPC 内网通信** |
|
||||
| SSA 前端模块 | `frontend-v2/src/modules/ssa/` |
|
||||
| SSA 后端模块 | `backend/src/modules/ssa/` |
|
||||
| SSA 后端模块 | `backend/src/modules/ssa/`(按 planner/executor/config 组织)|
|
||||
| 🆕 配置中台 | Excel 配置文件 + ConfigLoaderService |
|
||||
| 🆕 SAP 生成器 | ConsultService + Word 导出 |
|
||||
|
||||
### 5.3 关键配置要求
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# SSA-Pro MVP 任务清单与进度追踪
|
||||
|
||||
> **文档版本:** v1.3
|
||||
> **文档版本:** v1.6
|
||||
> **创建日期:** 2026-02-18
|
||||
> **最后更新:** 2026-02-18(纳入 V3.0 终极审查建议)
|
||||
> **最后更新:** 2026-02-19(T 检验端到端测试通过)
|
||||
> **更新频率:** 每日站会后更新
|
||||
>
|
||||
> **当前进度:** Phase 1 核心完成 ~85%,配置中台待开发
|
||||
|
||||
---
|
||||
|
||||
@@ -18,60 +20,84 @@
|
||||
|
||||
---
|
||||
|
||||
## Phase 1:骨架搭建(Week 1-2)
|
||||
## Phase 1:骨架搭建 + 配置中台(Week 1-2)
|
||||
|
||||
**里程碑目标:** T 检验 API 端到端跑通
|
||||
**里程碑目标:** T 检验 API 端到端跑通 + 配置中台基础
|
||||
|
||||
### R 服务任务
|
||||
|
||||
| 状态 | 任务 | 预估 | 备注 |
|
||||
|------|------|------|------|
|
||||
| ⬜ | 创建 `r-statistics-service/` 目录结构 | 2h | 含 templates/, fixtures/ 目录 |
|
||||
| ⬜ | 初始化 renv 并生成 `renv.lock` | 1h | **锁定包版本** |
|
||||
| ⬜ | 编写 Dockerfile(基于 rocker/r-ver:4.3) | 2h | 使用 renv::restore() |
|
||||
| ⬜ | 🆕 Dockerfile 配置 OSS 环境变量 | 1h | **ENV 注入,非硬编码** |
|
||||
| ⬜ | 安装 glue 包,创建代码模板文件 | 2h | **替代 paste0 拼接** |
|
||||
| ⬜ | 🆕 实现 `data_loader.R`(混合协议) | 3h | **支持 inline/OSS/DEV_MODE** |
|
||||
| ⬜ | 🆕 实现 `result_formatter.R`(p_value_fmt) | 1h | **APA 格式化** |
|
||||
| ⬜ | 实现 `plumber.R` 入口文件 | 2h | 健康检查 + 动态路由 |
|
||||
| ⬜ | 🆕 plumber.R 添加 Debug 模式支持 | 1h | **保留临时文件排查** |
|
||||
| ⬜ | 定义错误码枚举(error_codes.R) | 1h | **业务/系统错误分离** |
|
||||
| ⬜ | 🆕 扩展错误码映射表(map_r_error) | 1h | **R 错误 → 用户友好提示** |
|
||||
| ⬜ | 🆕 代码模板头部添加依赖安装脚本 | 0.5h | **用户本地可运行** |
|
||||
| ⬜ | 🆕 创建 `tests/fixtures/` 标准测试数据 | 2h | **normal/skewed/missing** |
|
||||
| ⬜ | 实现 T 检验 Wrapper(ST_T_TEST_IND) | 4h | 含护栏 + glue + 大样本优化 |
|
||||
| ⬜ | 本地 Docker 测试通过 | 2h | |
|
||||
| ✅ | 创建 `r-statistics-service/` 目录结构 | 2h | 含 templates/, fixtures/ 目录 |
|
||||
| ✅ | 初始化 renv 并生成 `renv.lock` | 1h | **锁定包版本** |
|
||||
| ✅ | 编写 Dockerfile(基于 rocker/r-ver:4.3) | 2h | 使用 renv::restore() |
|
||||
| ✅ | 🆕 Dockerfile 配置 OSS 环境变量 | 1h | **ENV 注入,非硬编码** |
|
||||
| ✅ | 安装 glue 包,创建代码模板文件 | 2h | **已在 T 检验中使用** |
|
||||
| ✅ | 🆕 实现 `data_loader.R`(混合协议) | 3h | **支持 inline/OSS/DEV_MODE** |
|
||||
| ✅ | 🆕 实现 `result_formatter.R`(p_value_fmt) | 1h | **APA 格式化** |
|
||||
| ✅ | 实现 `plumber.R` 入口文件 | 2h | 健康检查 + 动态路由 |
|
||||
| ✅ | 🆕 plumber.R 添加 Debug 模式支持 | 1h | **DEV_MODE 环境变量** |
|
||||
| ✅ | 定义错误码枚举(error_codes.R) | 1h | **业务/系统错误分离** |
|
||||
| ✅ | 🆕 扩展错误码映射表(map_r_error) | 1h | **R 错误 → 用户友好提示** |
|
||||
| ✅ | 🆕 代码模板头部添加依赖安装脚本 | 0.5h | **reproducible_code 中包含** |
|
||||
| ✅ | 🆕 创建 `tests/fixtures/` 标准测试数据 | 2h | **normal/skewed/missing** |
|
||||
| ✅ | 实现 T 检验 Wrapper(ST_T_TEST_IND) | 4h | 含护栏 + glue + 缺失值处理 |
|
||||
| ✅ | 本地 Docker 测试通过 | 2h | **2026-02-19 端到端测试通过** |
|
||||
|
||||
### 后端任务
|
||||
|
||||
| 状态 | 任务 | 预估 | 备注 |
|
||||
|------|------|------|------|
|
||||
| ⬜ | 创建 `backend/src/modules/ssa/` 目录结构 | 1h | |
|
||||
| ⬜ | 设计并创建数据库 Schema(Prisma) | 3h | 4张表 |
|
||||
| ⬜ | 执行 `prisma migrate dev` | 0.5h | |
|
||||
| ⬜ | 安装 json-repair 和 zod 依赖 | 0.5h | **LLM 输出容错** |
|
||||
| ⬜ | 实现 `RClientService`(调用 R 服务) | 3h | 超时 120s |
|
||||
| ⬜ | 🆕 RClientService 添加 502/504 友好处理 | 0.5h | **R 崩溃用户提示** |
|
||||
| ✅ | 创建 `backend/src/modules/ssa/` 目录结构 | 1h | **按 planner/executor/config 组织** |
|
||||
| ✅ | 设计并创建数据库 Schema(Prisma) | 3h | 9张表(含配置中台) |
|
||||
| ✅ | 执行 `prisma migrate dev` | 0.5h | 已创建迁移文件 |
|
||||
| 🔄 | 安装 json-repair 和 zod 依赖 | 0.5h | **LLM 输出容错** |
|
||||
| ✅ | 实现 `RClientService`(executor/) | 3h | 超时 120s |
|
||||
| ✅ | 🆕 RClientService 添加 502/504 友好处理 | 0.5h | **错误友好提示已实现** |
|
||||
| ⬜ | 🆕 DataParserService 分类变量隐私保护 | 1h | **稀有值 < 5 隐藏** |
|
||||
| ⬜ | 实现 `POST /api/v1/ssa/execute` 存根 | 2h | 先做转发 |
|
||||
| ⬜ | 注册路由到 `index.ts` | 0.5h | |
|
||||
| ✅ | 实现 `POST /api/v1/ssa/execute` 存根 | 2h | **完整实现,含错误处理** |
|
||||
| ✅ | 注册路由到 `index.ts` | 0.5h | |
|
||||
| ✅ | 🆕 实现 DataParserService(数据解析) | 2h | **类型推断 + 缺失值处理** |
|
||||
| ✅ | 🆕 实现分析计划生成 API | 2h | **变量智能匹配** |
|
||||
| ✅ | 🆕 实现代码下载 API | 1h | **动态文件名** |
|
||||
|
||||
### 🆕 配置中台任务
|
||||
|
||||
| 状态 | 任务 | 预估 | 备注 |
|
||||
|------|------|------|------|
|
||||
| 🔄 | 🆕 设计统计决策表 Excel 模板 | 2h | **Goal + Y + X + Design → Tool** |
|
||||
| ⬜ | 🆕 实现 `DecisionTableLoader` | 3h | **四维匹配逻辑** |
|
||||
| ✅ | 🆕 设计 R 代码库数据库表 | 1h | **r_code_library 表已创建** |
|
||||
| ⬜ | 🆕 实现 `RCodeLibraryService` | 3h | **脚本上传/版本管理** |
|
||||
| 🔄 | 🆕 定义工具配置 Excel 模板(5个Sheet) | 3h | **元数据/参数映射/护栏/输出/解读** |
|
||||
| ⬜ | 🆕 实现 `ParamMappingService` | 2h | **JSON Key → R 参数名** |
|
||||
| ⬜ | 🆕 实现 `GuardrailConfigService` | 3h | **Block/Warn/Switch 三种 Action** |
|
||||
| ⬜ | 🆕 实现 `InterpretationService` | 2h | **解读模板填空** |
|
||||
| ⬜ | 🆕 实现 `ConfigValidatorService` | 2h | **必填/格式/唯一性校验** |
|
||||
| ✅ | 🆕 实现配置热加载 API | 1h | **POST /config/reload 路由已创建** |
|
||||
| ⬜ | 🆕 上传 T 检验 R 脚本 + 配置 | 2h | **跑通完整流程** |
|
||||
|
||||
### 前端任务
|
||||
|
||||
| 状态 | 任务 | 预估 | 备注 |
|
||||
|------|------|------|------|
|
||||
| ⬜ | 创建 `frontend-v2/src/modules/ssa/` 目录结构 | 1h | |
|
||||
| ⬜ | 注册到 `moduleRegistry.ts` | 0.5h | |
|
||||
| ⬜ | 实现基础页面框架(SSAWorkspace) | 3h | 参考原型图 |
|
||||
| ⬜ | 实现左侧边栏组件 | 2h | |
|
||||
| ⬜ | 实现数据上传组件(DataUploader) | 3h | |
|
||||
| ⬜ | 构造 Mock 数据用于组件开发 | 1h | |
|
||||
| ✅ | 创建 `frontend-v2/src/modules/ssa/` 目录结构 | 1h | 含 components/hooks/stores/types |
|
||||
| ✅ | 注册到 `moduleRegistry.ts` | 0.5h | **已激活模块** |
|
||||
| ✅ | 实现基础页面框架(SSAWorkspace) | 3h | 参考原型图 |
|
||||
| ✅ | 🆕 实现模式切换 Tab(智能分析/统计咨询) | 2h | **双模式入口** |
|
||||
| ✅ | 实现左侧边栏组件 | 2h | 含数据信息展示 |
|
||||
| ✅ | 实现数据上传组件(DataUploader) | 3h | Drag & Drop |
|
||||
| ✅ | 🆕 实现结果展示组件(ResultCard + APATable) | 3h | **三线表 + 图表** |
|
||||
| ✅ | 🆕 实现执行进度组件(ExecutionTrace) | 2h | **步骤状态展示** |
|
||||
| ✅ | 🆕 实现代码下载功能 | 1h | **从后端获取文件名** |
|
||||
| ✅ | 🆕 实现 Zustand Store | 2h | **会话状态管理** |
|
||||
| ✅ | 🆕 实现 useAnalysis Hook | 2h | **上传/计划/执行/下载** |
|
||||
|
||||
---
|
||||
|
||||
## Phase 2:智能规划与交互(Week 3-4)
|
||||
## Phase 2:智能规划与咨询模式(Week 3-4)
|
||||
|
||||
**里程碑目标:** 用户可与 AI 对话,确认后执行
|
||||
**里程碑目标:** 决策表驱动规划 + 咨询模式上线
|
||||
|
||||
### R 服务任务
|
||||
|
||||
@@ -81,18 +107,27 @@
|
||||
| ⬜ | 实现单因素 ANOVA(ST_ANOVA_ONE) | 3h | |
|
||||
| ⬜ | 实现卡方检验(ST_CHI_SQUARE) | 3h | |
|
||||
| ⬜ | 实现相关性分析(ST_CORRELATION) | 3h | |
|
||||
| ⬜ | 🆕 所有 R 脚本统一 `run_analysis()` 入口 | 2h | **专家规范** |
|
||||
| ⬜ | 实现通用护栏函数(utils/guardrails.R) | 2h | |
|
||||
| ⬜ | 为 5 个工具编写元数据 YAML | 2h | |
|
||||
| ⬜ | 🆕 护栏支持 Block/Warn/Switch Action | 2h | **三种响应策略** |
|
||||
| ⬜ | 🆕 为 5 个工具上传 R 脚本 + Excel 配置 | 3h | **专家完整配置** |
|
||||
|
||||
### 后端任务
|
||||
|
||||
| 状态 | 任务 | 预估 | 备注 |
|
||||
|------|------|------|------|
|
||||
| ⬜ | 实现 `ToolRetrievalService`(RAG 检索) | 4h | 复用 VectorSearchService |
|
||||
| ⬜ | 导入 5 个工具元数据到 pgvector | 2h | |
|
||||
| ⬜ | 🆕 实现 `DecisionTableService`(planner/) | 4h | **四维匹配选工具** |
|
||||
| ⬜ | 实现 `ToolRetrievalService`(planner/) | 3h | 复用 VectorSearchService(辅助) |
|
||||
| ⬜ | 🆕 决策表 + RAG 融合策略 | 2h | **决策表优先,RAG 兜底** |
|
||||
| ⬜ | 注册 Prompt 到 capability_schema | 2h | 4 个 Prompt |
|
||||
| ⬜ | 实现 `PlannerService`(LLM 调用) | 4h | 含 json-repair + Zod 校验 |
|
||||
| ⬜ | 实现 `PlannerService`(planner/,有数据) | 4h | 含 json-repair + Zod 校验 |
|
||||
| ⬜ | 🆕 PlannerService 调用决策表匹配 | 2h | **Goal → Tool 精准匹配** |
|
||||
| ⬜ | 🆕 实现 `ConsultService`(planner/,无数据) | 4h | **基于决策表推理生成 SAP** |
|
||||
| ⬜ | 🆕 实现 `SAPGeneratorService`(SAP 文档生成) | 3h | **Markdown → Word 导出** |
|
||||
| ⬜ | 🆕 实现结果解读(InterpretationService) | 3h | **基于配置模板生成论文级结论** |
|
||||
| ⬜ | 实现 `POST /api/v1/ssa/sessions/:id/plan` | 3h | |
|
||||
| ⬜ | 🆕 实现 `POST /api/v1/ssa/consult/:id/chat` | 2h | **咨询对话** |
|
||||
| ⬜ | 🆕 实现 `POST /api/v1/ssa/consult/:id/generate-sap` | 2h | **生成 SAP** |
|
||||
| ⬜ | 实现会话管理 API(CRUD) | 3h | |
|
||||
| ⬜ | 实现 Brain-Hand 数据隔离逻辑 | 2h | Schema 给 LLM,Data 给 R |
|
||||
| ⬜ | DataParserService 增加小样本隐私保护 | 1h | N<10 时模糊化 Min/Max |
|
||||
@@ -103,9 +138,12 @@
|
||||
|------|------|------|------|
|
||||
| ⬜ | 实现 Chat 消息流组件 | 4h | 复用 AIStreamChat |
|
||||
| ⬜ | 实现计划确认卡片(PlanCard) | 4h | 参考原型图 |
|
||||
| ⬜ | 🆕 PlanCard 增加"仅下载方案"按钮 | 1h | **咨询模式** |
|
||||
| ⬜ | 实现执行路径树(ExecutionTrace) | 3h | 动画效果 |
|
||||
| ⬜ | 🆕 实现咨询模式 UI(ConsultChat) | 3h | **无数据对话** |
|
||||
| ⬜ | 🆕 实现 SAP 预览/下载组件 | 2h | **Word/MD 下载** |
|
||||
| ⬜ | 实现 API 对接(api.ts) | 2h | |
|
||||
| ⬜ | 实现 Zustand Store | 2h | |
|
||||
| ⬜ | 实现 Zustand Store | 2h | **含 mode 切换状态** |
|
||||
|
||||
---
|
||||
|
||||
@@ -166,10 +204,12 @@
|
||||
|
||||
| Phase | 任务总数 | 已完成 | 进度 |
|
||||
|-------|---------|--------|------|
|
||||
| Phase 1 | 21 | 0 | 0% |
|
||||
| Phase 2 | 20 | 0 | 0% |
|
||||
| Phase 3 | 21 | 0 | 0% |
|
||||
| **总计** | **62** | **0** | **0%** |
|
||||
| Phase 1 | 40 | 34 | 85% |
|
||||
| Phase 2 | 30 | 0 | 0% |
|
||||
| Phase 3 | 22 | 0 | 0% |
|
||||
| **总计** | **92** | **34** | **37%** |
|
||||
|
||||
> **v1.6 更新**:Phase 1 核心流程完成,T 检验端到端测试通过(2026-02-19)
|
||||
|
||||
---
|
||||
|
||||
@@ -183,13 +223,21 @@
|
||||
|
||||
## 每日站会记录
|
||||
|
||||
### 2026-02-xx
|
||||
### 2026-02-19
|
||||
|
||||
**昨日完成:**
|
||||
-
|
||||
**完成项:**
|
||||
- ✅ R 服务 T 检验端到端测试通过
|
||||
- ✅ 修复缺失值导致分组变量识别为 3 组的问题(R 服务自动过滤 NA)
|
||||
- ✅ 修复 DataParserService 类型推断(0/1 数字列识别为分类变量)
|
||||
- ✅ 修复后端 R 服务错误响应处理(返回 422 + user_hint)
|
||||
- ✅ 修复前端代码下载文件名(从 Content-Disposition 提取)
|
||||
- ✅ 修复前端用户会话隔离(组件挂载时重置 store)
|
||||
- ✅ 完成前端模块注册,激活智能统计分析入口
|
||||
|
||||
**今日计划:**
|
||||
-
|
||||
**待解决:**
|
||||
- 配置中台功能待开发
|
||||
- json-repair 和 zod 依赖待安装
|
||||
- DataParserService 隐私保护待实现
|
||||
|
||||
**阻塞问题:**
|
||||
-
|
||||
**下一步:**
|
||||
- 进入 Phase 2 或完善 Phase 1 配置中台
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# SSA-Pro R 服务开发指南
|
||||
|
||||
> **文档版本:** v1.3
|
||||
> **文档版本:** v1.5
|
||||
> **创建日期:** 2026-02-18
|
||||
> **最后更新:** 2026-02-18(纳入 V3.0 终极审查建议)
|
||||
> **最后更新:** 2026-02-18(纳入专家配置体系 + 统一入口函数)
|
||||
> **目标读者:** R 统计工程师
|
||||
|
||||
---
|
||||
@@ -15,31 +15,51 @@ r-statistics-service/
|
||||
├── renv.lock # 📌 包版本锁定文件
|
||||
├── .Rprofile # renv 初始化
|
||||
├── plumber.R # Plumber 入口
|
||||
├── tools/ # 统计工具目录
|
||||
│ ├── ST_T_TEST_IND.R
|
||||
│ ├── ST_T_TEST_PAIRED.R
|
||||
│ ├── ST_ANOVA_ONE.R
|
||||
│ └── ...
|
||||
├── templates/ # 📌 代码模板目录(glue)
|
||||
├── tools/ # 🆕 专家上传的 R 脚本(统一 run_analysis 入口)
|
||||
│ ├── t_test_ind.R # 独立样本 T 检验
|
||||
│ ├── t_test_paired.R # 配对样本 T 检验
|
||||
│ ├── anova_one.R # 单因素方差分析
|
||||
│ ├── wilcoxon.R # Wilcoxon 秩和检验
|
||||
│ └── ... # 📌 约 100 个成熟脚本
|
||||
├── templates/ # 📌 代码交付模板(glue 格式)
|
||||
│ ├── t_test.R.template
|
||||
│ ├── anova.R.template
|
||||
│ └── ...
|
||||
├── utils/
|
||||
│ ├── data_loader.R # 🆕 混合数据协议加载器
|
||||
│ ├── guardrails.R # 护栏函数库
|
||||
│ ├── data_loader.R # 混合数据协议加载器
|
||||
│ ├── guardrails.R # 🆕 护栏函数库(支持 Block/Warn/Switch)
|
||||
│ ├── code_generator.R # 代码生成工具(使用 glue)
|
||||
│ ├── result_formatter.R # 🆕 结果格式化(p_value_fmt)
|
||||
│ ├── result_formatter.R # 结果格式化(p_value_fmt)
|
||||
│ ├── interpretation.R # 🆕 结果解读(基于配置模板)
|
||||
│ └── error_codes.R # 📌 错误码定义
|
||||
├── metadata/ # 工具元数据
|
||||
│ └── tools.yaml # 所有工具定义
|
||||
├── metadata/ # 工具元数据(由配置中台管理)
|
||||
│ └── tools.yaml # 备用配置
|
||||
└── tests/
|
||||
├── test_tools.R # 单元测试
|
||||
└── fixtures/ # 🆕 标准测试数据集
|
||||
└── fixtures/ # 标准测试数据集
|
||||
├── normal_data.csv
|
||||
├── skewed_data.csv
|
||||
└── missing_data.csv
|
||||
```
|
||||
|
||||
### 1.1 🆕 专家 R 脚本规范
|
||||
|
||||
> **核心要求**:所有脚本必须使用统一入口函数 `run_analysis(input)`
|
||||
|
||||
```r
|
||||
# 文件头部注释(必填)
|
||||
#' @tool_code ST_T_TEST_IND
|
||||
#' @name 独立样本 T 检验
|
||||
#' @version 1.0.0
|
||||
#' @description 比较两组独立样本的均值差异
|
||||
#' @author 统计学专家团队
|
||||
|
||||
# 📌 统一入口函数(所有脚本必须实现)
|
||||
run_analysis <- function(input) {
|
||||
# ... 实现逻辑 ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Dockerfile 模板
|
||||
@@ -725,25 +745,46 @@ generate_boxplot <- function(df, group_var, value_var, tmp_files_ref) {
|
||||
# 🆕 大样本优化阈值
|
||||
LARGE_SAMPLE_THRESHOLD <- 5000
|
||||
|
||||
# 正态性检验(🆕 大样本优化)
|
||||
check_normality <- function(values, alpha = 0.05) {
|
||||
# 🆕 护栏 Action 类型
|
||||
ACTION_BLOCK <- "Block" # 阻止执行
|
||||
ACTION_WARN <- "Warn" # 警告但继续
|
||||
ACTION_SWITCH <- "Switch" # 切换到备选方法
|
||||
|
||||
# 🆕 护栏检查结果结构
|
||||
# list(
|
||||
# passed = TRUE/FALSE,
|
||||
# action = "Block" | "Warn" | "Switch",
|
||||
# action_target = "ST_XXX" | NULL,
|
||||
# p_value = 0.05,
|
||||
# reason = "描述"
|
||||
# )
|
||||
|
||||
# 正态性检验(🆕 支持三种 Action)
|
||||
check_normality <- function(values, alpha = 0.05, action = ACTION_SWITCH, action_target = NULL) {
|
||||
n <- length(values)
|
||||
|
||||
# 样本量过小
|
||||
if (n < 3) {
|
||||
return(list(passed = TRUE, reason = "样本量过小,跳过正态性检验", skipped = TRUE))
|
||||
return(list(
|
||||
passed = TRUE,
|
||||
action = NULL,
|
||||
action_target = NULL,
|
||||
reason = "样本量过小,跳过正态性检验",
|
||||
skipped = TRUE
|
||||
))
|
||||
}
|
||||
|
||||
# 🆕 大样本优化:N > 5000 时使用抽样检验
|
||||
if (n > LARGE_SAMPLE_THRESHOLD) {
|
||||
# 抽取 1000 个样本进行检验
|
||||
set.seed(42) # 保证可重复性
|
||||
set.seed(42)
|
||||
sampled_values <- sample(values, 1000)
|
||||
test <- shapiro.test(sampled_values)
|
||||
passed <- test$p.value >= alpha
|
||||
|
||||
return(list(
|
||||
passed = passed,
|
||||
action = if (passed) NULL else action,
|
||||
action_target = if (passed) NULL else action_target,
|
||||
p_value = test$p.value,
|
||||
reason = glue("大样本(N={n})抽样检验,{if (passed) '满足正态性' else '不满足正态性'}"),
|
||||
sampled = TRUE,
|
||||
@@ -757,6 +798,8 @@ check_normality <- function(values, alpha = 0.05) {
|
||||
|
||||
return(list(
|
||||
passed = passed,
|
||||
action = if (passed) NULL else action,
|
||||
action_target = if (passed) NULL else action_target,
|
||||
p_value = test$p.value,
|
||||
reason = if (passed) "满足正态性" else "不满足正态性",
|
||||
sampled = FALSE
|
||||
@@ -764,7 +807,7 @@ check_normality <- function(values, alpha = 0.05) {
|
||||
}
|
||||
|
||||
# 方差齐性检验 (Levene)
|
||||
check_homogeneity <- function(df, group_var, value_var, alpha = 0.05) {
|
||||
check_homogeneity <- function(df, group_var, value_var, alpha = 0.05, action = ACTION_WARN) {
|
||||
library(car)
|
||||
|
||||
formula <- as.formula(paste(value_var, "~", group_var))
|
||||
@@ -774,20 +817,52 @@ check_homogeneity <- function(df, group_var, value_var, alpha = 0.05) {
|
||||
|
||||
return(list(
|
||||
passed = passed,
|
||||
action = if (passed) NULL else action,
|
||||
p_value = p_val,
|
||||
reason = if (passed) "方差齐性满足" else "方差不齐性"
|
||||
))
|
||||
}
|
||||
|
||||
# 样本量检验
|
||||
check_sample_size <- function(n, min_required = 30) {
|
||||
check_sample_size <- function(n, min_required = 30, action = ACTION_BLOCK) {
|
||||
passed <- n >= min_required
|
||||
return(list(
|
||||
passed = passed,
|
||||
action = if (passed) NULL else action,
|
||||
n = n,
|
||||
reason = if (passed) "样本量充足" else paste0("样本量不足, 需要至少 ", min_required)
|
||||
))
|
||||
}
|
||||
|
||||
# 🆕 执行护栏链(按 check_order 顺序执行)
|
||||
run_guardrail_chain <- function(input, guardrail_configs) {
|
||||
for (config in guardrail_configs) {
|
||||
check_func <- get(config$check_code)
|
||||
result <- do.call(check_func, list(
|
||||
input,
|
||||
action = config$action_type,
|
||||
action_target = config$action_target
|
||||
))
|
||||
|
||||
if (!result$passed) {
|
||||
if (result$action == ACTION_BLOCK) {
|
||||
return(list(
|
||||
status = "blocked",
|
||||
reason = result$reason
|
||||
))
|
||||
} else if (result$action == ACTION_SWITCH) {
|
||||
return(list(
|
||||
status = "switch",
|
||||
target_tool = result$action_target,
|
||||
reason = result$reason
|
||||
))
|
||||
}
|
||||
# WARN: 记录警告但继续
|
||||
}
|
||||
}
|
||||
|
||||
return(list(status = "passed"))
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
# SSA-Pro 前端开发指南
|
||||
|
||||
> **文档版本:** v1.3
|
||||
> **文档版本:** v1.5
|
||||
> **创建日期:** 2026-02-18
|
||||
> **最后更新:** 2026-02-18(纳入 V3.0 终极审查建议)
|
||||
> **最后更新:** 2026-02-18(纳入专家配置体系 + 护栏 Action 展示)
|
||||
> **目标读者:** 前端工程师
|
||||
> **原型参考:** `03-UI设计/智能统计分析V2.html`
|
||||
|
||||
@@ -19,7 +19,8 @@ frontend-v2/src/modules/ssa/
|
||||
│ ├── layout/
|
||||
│ │ ├── SSASidebar.tsx # 左侧边栏
|
||||
│ │ ├── SSAHeader.tsx # 顶部标题栏
|
||||
│ │ └── SSAInputArea.tsx # 底部输入区
|
||||
│ │ ├── SSAInputArea.tsx # 底部输入区
|
||||
│ │ └── ModeSwitch.tsx # 🆕 模式切换 Tab
|
||||
│ ├── chat/
|
||||
│ │ ├── MessageList.tsx # 消息流容器
|
||||
│ │ ├── SystemMessage.tsx # 系统消息气泡
|
||||
@@ -31,44 +32,59 @@ frontend-v2/src/modules/ssa/
|
||||
│ │ ├── PlanCard.tsx # 分析计划确认卡片 ⭐
|
||||
│ │ ├── ExecutionTrace.tsx # 执行路径树 ⭐
|
||||
│ │ ├── ExecutionProgress.tsx# 📌 执行进度动画 ⭐
|
||||
│ │ └── ResultCard.tsx # 结果报告卡片 ⭐
|
||||
│ │ ├── ResultCard.tsx # 结果报告卡片 ⭐
|
||||
│ │ └── SAPPreview.tsx # 🆕 SAP 文档预览/下载
|
||||
│ ├── consult/ # 🆕 咨询模式组件
|
||||
│ │ ├── ConsultChat.tsx # 无数据对话界面
|
||||
│ │ └── SAPDownloadButton.tsx# SAP 下载按钮
|
||||
│ └── common/
|
||||
│ ├── APATable.tsx # 三线表组件
|
||||
│ └── PlotViewer.tsx # 图表查看器
|
||||
├── hooks/
|
||||
│ ├── useSSASession.ts # 会话管理 Hook
|
||||
│ └── useSSAExecution.ts # 执行控制 Hook
|
||||
│ ├── useSSAExecution.ts # 执行控制 Hook
|
||||
│ └── useSSAConsult.ts # 🆕 咨询模式 Hook
|
||||
├── store/
|
||||
│ └── ssaStore.ts # Zustand Store
|
||||
│ └── ssaStore.ts # Zustand Store(含 mode 状态)
|
||||
├── api/
|
||||
│ └── ssaApi.ts # API 封装
|
||||
│ └── ssaApi.ts # API 封装(含咨询 API)
|
||||
├── types/
|
||||
│ └── index.ts # 类型定义
|
||||
└── styles/
|
||||
└── ssa.css # 模块样式
|
||||
```
|
||||
|
||||
### 1.1 🆕 双模式设计原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **模式切换** | 顶部 Tab 切换"智能分析"/"统计咨询" |
|
||||
| **无数据友好** | 咨询模式不要求上传数据 |
|
||||
| **SAP 导出** | 咨询完成后可下载 Word/Markdown |
|
||||
|
||||
---
|
||||
|
||||
## 2. 原型图核心元素解析
|
||||
|
||||
根据 `智能统计分析V2.html` 原型,需实现以下核心 UI:
|
||||
|
||||
### 2.1 整体布局
|
||||
### 2.1 整体布局(含模式切换)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ┌───────────┐ ┌─────────────────────────────────────────────┐ │
|
||||
│ │ │ │ Header (会话标题) │ │
|
||||
│ │ Sidebar │ ├─────────────────────────────────────────────┤ │
|
||||
│ │ │ │ │ │
|
||||
│ │ - 导入数据│ │ Chat Flow (消息流) │ │
|
||||
│ │ - 新会话 │ │ │ │
|
||||
│ │ - 历史 │ │ - SystemMessage (欢迎/上传引导) │ │
|
||||
│ │ │ │ 🆕 [智能分析] [统计咨询] ← 模式切换 Tab │ │
|
||||
│ │ Sidebar │ │ Header (会话标题) │ │
|
||||
│ │ │ ├─────────────────────────────────────────────┤ │
|
||||
│ │ - 导入数据│ │ │ │
|
||||
│ │ - 新会话 │ │ Chat Flow (消息流) │ │
|
||||
│ │ - 历史 │ │ │ │
|
||||
│ │ │ │ - SystemMessage (欢迎/上传引导) │ │
|
||||
│ │ │ │ - UserMessage (用户输入) │ │
|
||||
│ │ │ │ - PlanCard (计划确认) │ │
|
||||
│ │ ─────── │ │ - ExecutionTrace (执行路径) │ │
|
||||
│ │ 数据状态 │ │ - ResultCard (结果报告) │ │
|
||||
│ │ (分析模式) │ │ - 🆕 SAPPreview (咨询模式) │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ ├─────────────────────────────────────────────┤ │
|
||||
│ │ │ │ InputArea (输入框 + 发送按钮) │ │
|
||||
@@ -214,9 +230,11 @@ import { CheckCircleFilled, ExclamationCircleFilled,
|
||||
interface TraceStep {
|
||||
id: string;
|
||||
label: string;
|
||||
status: 'success' | 'warning' | 'error' | 'running' | 'pending';
|
||||
status: 'success' | 'warning' | 'error' | 'running' | 'pending' | 'switched'; // 🆕 switched
|
||||
detail?: string;
|
||||
subLabel?: string;
|
||||
actionType?: 'Block' | 'Warn' | 'Switch'; // 🆕 护栏 Action 类型
|
||||
switchTarget?: string; // 🆕 Switch 目标工具
|
||||
}
|
||||
|
||||
interface ExecutionTraceProps {
|
||||
@@ -232,12 +250,32 @@ export const ExecutionTrace: React.FC<ExecutionTraceProps> = ({ steps }) => {
|
||||
return <ExclamationCircleFilled className="text-amber-500" />;
|
||||
case 'error':
|
||||
return <ExclamationCircleFilled className="text-red-500" />;
|
||||
case 'switched': // 🆕 方法切换
|
||||
return <SwapOutlined className="text-blue-500" />;
|
||||
case 'running':
|
||||
return <LoadingOutlined className="text-blue-500" spin />;
|
||||
default:
|
||||
return <div className="w-4 h-4 rounded-full bg-slate-200" />;
|
||||
}
|
||||
};
|
||||
|
||||
// 🆕 获取 Action 类型标签
|
||||
const getActionTag = (step: TraceStep) => {
|
||||
if (!step.actionType) return null;
|
||||
|
||||
const tagStyles = {
|
||||
'Block': 'bg-red-100 text-red-700 border-red-200',
|
||||
'Warn': 'bg-amber-100 text-amber-700 border-amber-200',
|
||||
'Switch': 'bg-blue-100 text-blue-700 border-blue-200'
|
||||
};
|
||||
|
||||
return (
|
||||
<span className={`ml-2 px-1.5 py-0.5 text-xs rounded border ${tagStyles[step.actionType]}`}>
|
||||
{step.actionType}
|
||||
{step.switchTarget && <span className="ml-1">→ {step.switchTarget}</span>}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white border border-slate-200 rounded-xl p-4 shadow-sm">
|
||||
@@ -641,26 +679,39 @@ export const APATable: React.FC<APATableProps> = ({ columns, data }) => {
|
||||
|
||||
---
|
||||
|
||||
## 4. Zustand Store
|
||||
## 4. Zustand Store(含模式切换)
|
||||
|
||||
```typescript
|
||||
// store/ssaStore.ts
|
||||
import { create } from 'zustand';
|
||||
|
||||
// 🆕 模式类型
|
||||
type SSAMode = 'analysis' | 'consult';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
role: 'user' | 'assistant' | 'system';
|
||||
contentType: 'text' | 'plan' | 'result' | 'trace';
|
||||
contentType: 'text' | 'plan' | 'result' | 'trace' | 'sap'; // 🆕 增加 sap 类型
|
||||
content: any;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// 🆕 SAP 文档类型
|
||||
interface SAPDocument {
|
||||
title: string;
|
||||
sections: Array<{ heading: string; content: string }>;
|
||||
recommendedTools: string[];
|
||||
}
|
||||
|
||||
interface SSAState {
|
||||
// 🆕 模式
|
||||
mode: SSAMode;
|
||||
|
||||
// 会话
|
||||
sessionId: string | null;
|
||||
sessionTitle: string;
|
||||
|
||||
// 数据
|
||||
// 数据(分析模式)
|
||||
dataLoaded: boolean;
|
||||
dataSchema: object | null;
|
||||
dataFileName: string;
|
||||
@@ -674,17 +725,25 @@ interface SSAState {
|
||||
isExecuting: boolean;
|
||||
currentPlan: object | null;
|
||||
|
||||
// 🆕 咨询模式状态
|
||||
currentSAP: SAPDocument | null;
|
||||
isGeneratingSAP: boolean;
|
||||
|
||||
// Actions
|
||||
setMode: (mode: SSAMode) => void; // 🆕
|
||||
setSession: (id: string, title?: string) => void;
|
||||
setDataLoaded: (schema: object, fileName: string, rowCount: number) => void;
|
||||
addMessage: (message: Omit<Message, 'id' | 'createdAt'>) => void;
|
||||
setPlanning: (planning: boolean) => void;
|
||||
setExecuting: (executing: boolean) => void;
|
||||
setCurrentPlan: (plan: object | null) => void;
|
||||
setCurrentSAP: (sap: SAPDocument | null) => void; // 🆕
|
||||
setGeneratingSAP: (generating: boolean) => void; // 🆕
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export const useSSAStore = create<SSAState>((set, get) => ({
|
||||
mode: 'analysis', // 🆕 默认分析模式
|
||||
sessionId: null,
|
||||
sessionTitle: '新会话',
|
||||
dataLoaded: false,
|
||||
@@ -695,6 +754,19 @@ export const useSSAStore = create<SSAState>((set, get) => ({
|
||||
isPlanning: false,
|
||||
isExecuting: false,
|
||||
currentPlan: null,
|
||||
currentSAP: null, // 🆕
|
||||
isGeneratingSAP: false, // 🆕
|
||||
|
||||
// 🆕 切换模式
|
||||
setMode: (mode) => set({
|
||||
mode,
|
||||
// 切换模式时重置会话
|
||||
sessionId: null,
|
||||
messages: [],
|
||||
dataLoaded: false,
|
||||
currentPlan: null,
|
||||
currentSAP: null
|
||||
}),
|
||||
|
||||
setSession: (id, title = '新会话') => set({ sessionId: id, sessionTitle: title }),
|
||||
|
||||
@@ -719,8 +791,11 @@ export const useSSAStore = create<SSAState>((set, get) => ({
|
||||
setPlanning: (planning) => set({ isPlanning: planning }),
|
||||
setExecuting: (executing) => set({ isExecuting: executing }),
|
||||
setCurrentPlan: (plan) => set({ currentPlan: plan }),
|
||||
setCurrentSAP: (sap) => set({ currentSAP: sap }), // 🆕
|
||||
setGeneratingSAP: (generating) => set({ isGeneratingSAP: generating }), // 🆕
|
||||
|
||||
reset: () => set({
|
||||
mode: 'analysis',
|
||||
sessionId: null,
|
||||
sessionTitle: '新会话',
|
||||
dataLoaded: false,
|
||||
@@ -730,14 +805,16 @@ export const useSSAStore = create<SSAState>((set, get) => ({
|
||||
messages: [],
|
||||
isPlanning: false,
|
||||
isExecuting: false,
|
||||
currentPlan: null
|
||||
currentPlan: null,
|
||||
currentSAP: null,
|
||||
isGeneratingSAP: false
|
||||
})
|
||||
}));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. API 封装
|
||||
## 5. API 封装(含咨询模式)
|
||||
|
||||
```typescript
|
||||
// api/ssaApi.ts
|
||||
@@ -746,6 +823,8 @@ import { apiClient } from '@/common/api/client';
|
||||
const BASE = '/api/v1/ssa';
|
||||
|
||||
export const ssaApi = {
|
||||
// ==================== 智能分析模式 ====================
|
||||
|
||||
// 会话
|
||||
createSession: () =>
|
||||
apiClient.post<{ id: string }>(`${BASE}/sessions`),
|
||||
@@ -780,6 +859,50 @@ export const ssaApi = {
|
||||
apiClient.get(`${BASE}/sessions/${sessionId}/download-code/${messageId}`, {
|
||||
responseType: 'blob'
|
||||
}),
|
||||
|
||||
// ==================== 🆕 咨询模式 ====================
|
||||
|
||||
// 创建咨询会话(无数据)
|
||||
createConsultSession: () =>
|
||||
apiClient.post<{ id: string }>(`${BASE}/consult`),
|
||||
|
||||
// 咨询对话
|
||||
consultChat: (sessionId: string, message: string) =>
|
||||
apiClient.post<{ response: string }>(`${BASE}/consult/${sessionId}/chat`, { message }),
|
||||
|
||||
// 生成 SAP 文档
|
||||
generateSAP: (sessionId: string) =>
|
||||
apiClient.post<{
|
||||
title: string;
|
||||
sections: Array<{ heading: string; content: string }>;
|
||||
recommendedTools: string[];
|
||||
}>(`${BASE}/consult/${sessionId}/generate-sap`),
|
||||
|
||||
// 下载 SAP(Word/Markdown)
|
||||
downloadSAP: (sessionId: string, format: 'word' | 'markdown' = 'word') =>
|
||||
apiClient.get(`${BASE}/consult/${sessionId}/download-sap`, {
|
||||
params: { format },
|
||||
responseType: 'blob'
|
||||
}),
|
||||
|
||||
// ==================== 🆕 配置中台 ====================
|
||||
|
||||
// 导入配置
|
||||
importConfig: (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return apiClient.post(`${BASE}/config/import`, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
});
|
||||
},
|
||||
|
||||
// 获取工具列表
|
||||
getConfigTools: () =>
|
||||
apiClient.get(`${BASE}/config/tools`),
|
||||
|
||||
// 热加载配置(Admin)
|
||||
reloadConfig: () =>
|
||||
apiClient.post(`${BASE}/config/reload`),
|
||||
};
|
||||
```
|
||||
|
||||
@@ -864,15 +987,301 @@ export const ssaRoutes = [
|
||||
| 组件 | 功能 | 状态 |
|
||||
|------|------|------|
|
||||
| SSASidebar | 导入数据、新建会话、历史列表、数据状态 | ⬜ |
|
||||
| 🆕 **ModeSwitch** | **模式切换 Tab(智能分析/统计咨询)** | ⬜ |
|
||||
| DataUploader | 拖拽/点击上传,进度显示 | ⬜ |
|
||||
| MessageList | 消息流滚动,自动滚底 | ⬜ |
|
||||
| PlanCard | 参数展示、护栏提示、确认/修改按钮 | ⬜ |
|
||||
| 🆕 PlanCard | **增加"仅下载方案"按钮(咨询模式)** | ⬜ |
|
||||
| ExecutionTrace | 步骤树、状态图标、连接线 | ⬜ |
|
||||
| **ExecutionProgress** | **📌 执行中进度动画,缓解等待焦虑** | ⬜ |
|
||||
| ResultCard | 三线表、图表、解读、下载按钮 | ⬜ |
|
||||
| APATable | APA 格式表格样式 | ⬜ |
|
||||
| Zustand Store | 状态管理 | ⬜ |
|
||||
| API 对接 | 所有接口联调,**超时 120s** | ⬜ |
|
||||
| 🆕 **ConsultChat** | **无数据咨询对话界面** | ⬜ |
|
||||
| 🆕 **SAPPreview** | **SAP 文档预览/下载** | ⬜ |
|
||||
| 🆕 **SAPDownloadButton** | **Word/Markdown 下载选择** | ⬜ |
|
||||
| Zustand Store | 状态管理,**含 mode 切换** | ⬜ |
|
||||
| API 对接 | 所有接口联调,**含咨询 API** | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## 9. 🆕 新增组件实现
|
||||
|
||||
### 9.1 ModeSwitch(模式切换 Tab)
|
||||
|
||||
```tsx
|
||||
// components/layout/ModeSwitch.tsx
|
||||
import React from 'react';
|
||||
import { Segmented } from 'antd';
|
||||
import { BarChartOutlined, MessageOutlined } from '@ant-design/icons';
|
||||
import { useSSAStore } from '../../store/ssaStore';
|
||||
|
||||
export const ModeSwitch: React.FC = () => {
|
||||
const { mode, setMode } = useSSAStore();
|
||||
|
||||
return (
|
||||
<Segmented
|
||||
value={mode}
|
||||
onChange={(value) => setMode(value as 'analysis' | 'consult')}
|
||||
options={[
|
||||
{
|
||||
label: (
|
||||
<div className="flex items-center gap-2 px-2">
|
||||
<BarChartOutlined />
|
||||
<span>智能分析</span>
|
||||
</div>
|
||||
),
|
||||
value: 'analysis',
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<div className="flex items-center gap-2 px-2">
|
||||
<MessageOutlined />
|
||||
<span>统计咨询</span>
|
||||
</div>
|
||||
),
|
||||
value: 'consult',
|
||||
},
|
||||
]}
|
||||
className="bg-slate-100"
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 9.2 ConsultChat(无数据咨询界面)
|
||||
|
||||
```tsx
|
||||
// components/consult/ConsultChat.tsx
|
||||
import React, { useState } from 'react';
|
||||
import { Input, Button, Alert } from 'antd';
|
||||
import { SendOutlined, FileWordOutlined } from '@ant-design/icons';
|
||||
import { useSSAStore } from '../../store/ssaStore';
|
||||
import { ssaApi } from '../../api/ssaApi';
|
||||
|
||||
export const ConsultChat: React.FC = () => {
|
||||
const [input, setInput] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const {
|
||||
sessionId,
|
||||
messages,
|
||||
addMessage,
|
||||
setSession,
|
||||
setCurrentSAP,
|
||||
setGeneratingSAP,
|
||||
isGeneratingSAP
|
||||
} = useSSAStore();
|
||||
|
||||
const handleSend = async () => {
|
||||
if (!input.trim()) return;
|
||||
|
||||
setLoading(true);
|
||||
|
||||
// 如果没有会话,先创建
|
||||
let currentSessionId = sessionId;
|
||||
if (!currentSessionId) {
|
||||
const { data } = await ssaApi.createConsultSession();
|
||||
currentSessionId = data.id;
|
||||
setSession(data.id, '统计咨询');
|
||||
}
|
||||
|
||||
// 添加用户消息
|
||||
addMessage({ role: 'user', contentType: 'text', content: { text: input } });
|
||||
setInput('');
|
||||
|
||||
// 发送咨询
|
||||
const { data } = await ssaApi.consultChat(currentSessionId!, input);
|
||||
|
||||
// 添加 AI 回复
|
||||
addMessage({ role: 'assistant', contentType: 'text', content: { text: data.response } });
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const handleGenerateSAP = async () => {
|
||||
if (!sessionId) return;
|
||||
|
||||
setGeneratingSAP(true);
|
||||
const { data } = await ssaApi.generateSAP(sessionId);
|
||||
setCurrentSAP(data);
|
||||
addMessage({ role: 'assistant', contentType: 'sap', content: data });
|
||||
setGeneratingSAP(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
{/* 引导提示 */}
|
||||
<Alert
|
||||
message="统计咨询模式"
|
||||
description="描述您的研究设计和分析需求,无需上传数据。完成咨询后可生成统计分析计划(SAP)文档。"
|
||||
type="info"
|
||||
showIcon
|
||||
className="mx-4 mt-4"
|
||||
/>
|
||||
|
||||
{/* 消息流 */}
|
||||
<div className="flex-1 overflow-auto p-4 space-y-4">
|
||||
{messages.map(msg => (
|
||||
<div
|
||||
key={msg.id}
|
||||
className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
|
||||
>
|
||||
<div className={`
|
||||
max-w-[80%] p-3 rounded-lg
|
||||
${msg.role === 'user'
|
||||
? 'bg-blue-500 text-white'
|
||||
: 'bg-slate-100 text-slate-800'}
|
||||
`}>
|
||||
{msg.contentType === 'sap'
|
||||
? <SAPPreview sap={msg.content} />
|
||||
: msg.content.text
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 输入区 */}
|
||||
<div className="p-4 border-t border-slate-200">
|
||||
<div className="flex gap-2">
|
||||
<Input.TextArea
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="描述您的研究设计和统计分析需求..."
|
||||
autoSize={{ minRows: 2, maxRows: 4 }}
|
||||
onPressEnter={(e) => {
|
||||
if (!e.shiftKey) {
|
||||
e.preventDefault();
|
||||
handleSend();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
onClick={handleSend}
|
||||
loading={loading}
|
||||
>
|
||||
发送
|
||||
</Button>
|
||||
<Button
|
||||
icon={<FileWordOutlined />}
|
||||
onClick={handleGenerateSAP}
|
||||
loading={isGeneratingSAP}
|
||||
disabled={messages.length < 2}
|
||||
>
|
||||
生成 SAP
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 9.3 SAPPreview(SAP 文档预览)
|
||||
|
||||
```tsx
|
||||
// components/cards/SAPPreview.tsx
|
||||
import React from 'react';
|
||||
import { Card, Button, Space, Typography, Divider, Tag } from 'antd';
|
||||
import { DownloadOutlined, FileWordOutlined, FileMarkdownOutlined } from '@ant-design/icons';
|
||||
import { ssaApi } from '../../api/ssaApi';
|
||||
import { useSSAStore } from '../../store/ssaStore';
|
||||
|
||||
const { Title, Paragraph, Text } = Typography;
|
||||
|
||||
interface SAPDocument {
|
||||
title: string;
|
||||
sections: Array<{ heading: string; content: string }>;
|
||||
recommendedTools: string[];
|
||||
}
|
||||
|
||||
interface SAPPreviewProps {
|
||||
sap: SAPDocument;
|
||||
}
|
||||
|
||||
export const SAPPreview: React.FC<SAPPreviewProps> = ({ sap }) => {
|
||||
const { sessionId } = useSSAStore();
|
||||
|
||||
const handleDownload = async (format: 'word' | 'markdown') => {
|
||||
if (!sessionId) return;
|
||||
|
||||
const response = await ssaApi.downloadSAP(sessionId, format);
|
||||
const blob = new Blob([response.data]);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = format === 'word' ? 'SAP.docx' : 'SAP.md';
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="sap-preview"
|
||||
title={
|
||||
<Space>
|
||||
<FileWordOutlined className="text-blue-500" />
|
||||
<span>统计分析计划 (SAP)</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
icon={<FileWordOutlined />}
|
||||
onClick={() => handleDownload('word')}
|
||||
>
|
||||
Word
|
||||
</Button>
|
||||
<Button
|
||||
icon={<FileMarkdownOutlined />}
|
||||
onClick={() => handleDownload('markdown')}
|
||||
>
|
||||
Markdown
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Title level={4}>{sap.title}</Title>
|
||||
|
||||
{sap.sections.map((section, idx) => (
|
||||
<div key={idx} className="mb-4">
|
||||
<Title level={5} className="text-slate-700">{section.heading}</Title>
|
||||
<Paragraph className="text-slate-600">{section.content}</Paragraph>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Divider />
|
||||
|
||||
<div>
|
||||
<Text strong>推荐统计方法:</Text>
|
||||
<div className="mt-2">
|
||||
{sap.recommendedTools.map((tool, idx) => (
|
||||
<Tag key={idx} color="blue">{tool}</Tag>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 9.4 PlanCard 增强(支持仅下载方案)
|
||||
|
||||
```tsx
|
||||
// components/cards/PlanCard.tsx 增加的按钮
|
||||
// 在 "确认并执行" 按钮旁边添加:
|
||||
|
||||
{/* 🆕 仅下载方案(咨询模式下或用户选择不执行) */}
|
||||
<Button
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={onDownloadPlanOnly}
|
||||
>
|
||||
仅下载方案
|
||||
</Button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
318
docs/03-业务模块/SSA-智能统计分析/05-测试文档/SSA端到端测试与架构讨论-2026-02-19.md
Normal file
318
docs/03-业务模块/SSA-智能统计分析/05-测试文档/SSA端到端测试与架构讨论-2026-02-19.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# SSA 端到端测试与架构讨论
|
||||
|
||||
> **日期**: 2026-02-19
|
||||
> **状态**: ✅ 已决策 - 采用方案 B(简化设计,仅支持 OSS)
|
||||
> **参与者**: 开发团队
|
||||
|
||||
---
|
||||
|
||||
## 1. 测试概述
|
||||
|
||||
### 1.1 测试目标
|
||||
|
||||
验证 SSA 智能统计分析模块的完整数据流:
|
||||
|
||||
```
|
||||
前端 → Node.js 后端 → OSS 存储 → R 统计服务 → 返回结果
|
||||
```
|
||||
|
||||
### 1.2 测试环境
|
||||
|
||||
| 组件 | 状态 | 端口 |
|
||||
|------|------|------|
|
||||
| Node.js 后端 | ✅ 运行中 | 3001 |
|
||||
| R Docker 服务 | ✅ 运行中 | 8082 |
|
||||
| PostgreSQL | ✅ 运行中 | 5432 |
|
||||
| OSS (开发环境) | ✅ 可用 | ai-clinical-data-dev |
|
||||
|
||||
### 1.3 测试脚本
|
||||
|
||||
```
|
||||
backend/tests/ssa-e2e-test.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 测试结果
|
||||
|
||||
### 2.1 测试步骤与结果
|
||||
|
||||
| 步骤 | 描述 | 结果 |
|
||||
|------|------|------|
|
||||
| Step 0 | R 服务健康检查 | ✅ 通过 |
|
||||
| Step 1 | 用户登录认证 | ✅ 通过 |
|
||||
| Step 2 | SSA 路由检查 | ✅ 通过(路由已注册) |
|
||||
| Step 3 | 创建分析会话 | ✅ 通过 |
|
||||
| Step 4 | 上传 CSV 文件 | ✅ 通过(存入 OSS) |
|
||||
| Step 5 | 执行 T 检验 | ❌ 失败(修复前)→ ✅ 通过(修复后) |
|
||||
|
||||
### 2.2 发现的问题与修复
|
||||
|
||||
#### 问题 1:SSA 路由未注册
|
||||
|
||||
**现象**: `/api/v1/ssa/*` 返回 404
|
||||
|
||||
**原因**: `backend/src/index.ts` 中未注册 SSA 模块路由
|
||||
|
||||
**修复**: 添加路由注册
|
||||
|
||||
```typescript
|
||||
// backend/src/index.ts
|
||||
import { ssaRoutes } from './modules/ssa/index.js';
|
||||
await fastify.register(ssaRoutes, { prefix: '/api/v1/ssa' });
|
||||
```
|
||||
|
||||
#### 问题 2:数据源选择逻辑错误
|
||||
|
||||
**现象**: 上传 CSV 后执行分析,R 服务报错"列名不存在"
|
||||
|
||||
**原因**: `RClientService.buildDataSource()` 优先读取 `session.dataPayload`(为空),返回空数组,忽略了 `session.dataOssKey`
|
||||
|
||||
**修复**: 调整优先级,先检查 `dataOssKey`
|
||||
|
||||
```typescript
|
||||
// 修复后的逻辑
|
||||
private async buildDataSource(session: any) {
|
||||
// 1. 优先使用 OSS key(已上传的文件)
|
||||
if (session.dataOssKey) {
|
||||
const signedUrl = await storage.getUrl(session.dataOssKey);
|
||||
return { type: 'oss', oss_url: signedUrl };
|
||||
}
|
||||
|
||||
// 2. 其次使用 inline payload
|
||||
if (session.dataPayload) {
|
||||
return { type: 'inline', data: session.dataPayload };
|
||||
}
|
||||
|
||||
// 3. 无数据
|
||||
return { type: 'inline', data: [] };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 架构讨论:数据传输设计
|
||||
|
||||
### 3.1 当前设计
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 原设计:混合数据协议(根据大小选择传输方式) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 数据来源 1: 用户上传文件 → 存入 OSS → dataOssKey │
|
||||
│ 数据来源 2: 前端传 JSON → 存入内存 → dataPayload │
|
||||
│ │
|
||||
│ 执行分析时: │
|
||||
│ - 有 dataOssKey → 生成预签名 URL → R 服务从 OSS 下载 │
|
||||
│ - 有 dataPayload 且 < 2MB → 直接传 inline JSON │
|
||||
│ - 有 dataPayload 且 >= 2MB → 先存 OSS 再传 URL │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 实际使用场景分析
|
||||
|
||||
| 场景 | 是否存在 | 说明 |
|
||||
|------|----------|------|
|
||||
| 用户上传 CSV/Excel 文件 | ✅ **100%** | SSA 核心场景 |
|
||||
| 前端直接传 JSON 数据 | ❌ **0%** | 产品设计不支持手动输入数据 |
|
||||
|
||||
### 3.3 问题:设计与场景不匹配
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 实际数据流(100% 场景) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 用户 → 上传 CSV → Node.js → 存入 OSS → 记录 dataOssKey │
|
||||
│ │
|
||||
│ 执行分析 → 读取 dataOssKey → 生成预签名 URL → R 服务下载 │
|
||||
│ │
|
||||
│ dataPayload 永远为空!"判断大小"逻辑从不执行! │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**结论**: 当前代码中的 `dataPayload` 和"根据大小判断"逻辑是**死代码**,永远不会执行。
|
||||
|
||||
---
|
||||
|
||||
## 4. 待讨论决策
|
||||
|
||||
### 4.1 方案 A:保持现状(保留灵活性)
|
||||
|
||||
**优点**:
|
||||
- 未来可能支持"在线输入数据"功能
|
||||
- 代码改动小
|
||||
|
||||
**缺点**:
|
||||
- 存在永远不执行的代码
|
||||
- 逻辑复杂度高
|
||||
- 新开发者可能困惑
|
||||
|
||||
### 4.2 方案 B:简化设计(推荐)
|
||||
|
||||
```typescript
|
||||
// 简化后的 buildDataSource
|
||||
private async buildDataSource(session: any) {
|
||||
const ossKey = session.dataOssKey;
|
||||
|
||||
if (!ossKey) {
|
||||
throw new Error('请先上传数据文件');
|
||||
}
|
||||
|
||||
const signedUrl = await storage.getUrl(ossKey);
|
||||
return {
|
||||
type: 'oss',
|
||||
oss_url: signedUrl
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 代码简洁
|
||||
- 逻辑清晰
|
||||
- 符合实际使用场景
|
||||
|
||||
**缺点**:
|
||||
- 未来如需支持 inline JSON,需要重新添加
|
||||
|
||||
### 4.3 方案 C:完全移除 inline 支持
|
||||
|
||||
除了简化 `buildDataSource`,还可以:
|
||||
- 移除 `ssaSession.dataPayload` 字段
|
||||
- 移除 R 服务中的 inline JSON 解析逻辑
|
||||
- 只保留 OSS 数据流
|
||||
|
||||
**优点**:
|
||||
- 最简洁
|
||||
- 单一数据流,易于维护
|
||||
|
||||
**缺点**:
|
||||
- 改动较大
|
||||
- 需要修改数据库 schema
|
||||
|
||||
---
|
||||
|
||||
## 5. 相关文件清单
|
||||
|
||||
| 文件 | 作用 |
|
||||
|------|------|
|
||||
| `backend/src/modules/ssa/index.ts` | SSA 模块入口 |
|
||||
| `backend/src/modules/ssa/routes/analysis.routes.ts` | 上传/执行路由 |
|
||||
| `backend/src/modules/ssa/executor/RClientService.ts` | R 服务调用 |
|
||||
| `r-statistics-service/utils/data_loader.R` | R 服务数据加载 |
|
||||
| `backend/tests/ssa-e2e-test.ps1` | 端到端测试脚本 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议结论
|
||||
|
||||
1. **短期**: 使用当前修复后的代码,完成 Week 1-2 开发
|
||||
2. **中期**: 团队讨论后,决定是否采用方案 B 简化设计
|
||||
3. **长期**: 根据产品需求,确定是否需要支持"在线输入数据"功能
|
||||
|
||||
---
|
||||
|
||||
## 7. 附录:测试数据
|
||||
|
||||
### 测试 CSV 文件
|
||||
|
||||
```
|
||||
r-statistics-service/tests/fixtures/sample_t_test.csv
|
||||
```
|
||||
|
||||
```csv
|
||||
group,score
|
||||
A,23
|
||||
A,25
|
||||
A,27
|
||||
A,22
|
||||
A,24
|
||||
A,26
|
||||
A,21
|
||||
A,28
|
||||
B,30
|
||||
B,32
|
||||
B,28
|
||||
B,31
|
||||
B,29
|
||||
B,33
|
||||
B,27
|
||||
B,35
|
||||
```
|
||||
|
||||
### 测试请求参数
|
||||
|
||||
```json
|
||||
{
|
||||
"plan": {
|
||||
"tool_code": "ST_T_TEST_IND",
|
||||
"params": {
|
||||
"group_var": "group",
|
||||
"value_var": "score"
|
||||
},
|
||||
"guardrails": {
|
||||
"check_normality": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 预期结果
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"results": {
|
||||
"method": "Welch Two Sample t-test",
|
||||
"statistic": -4.78,
|
||||
"df": 13.90,
|
||||
"p_value": 0.0003,
|
||||
"p_value_fmt": "< 0.001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 8. 决策结果
|
||||
|
||||
**决策日期**: 2026-02-19
|
||||
|
||||
**采用方案**: B - 简化设计,仅支持 OSS
|
||||
|
||||
**最终代码**:
|
||||
|
||||
```typescript
|
||||
// backend/src/modules/ssa/executor/RClientService.ts
|
||||
private async buildDataSource(session: any): Promise<{ type: string; oss_url: string }> {
|
||||
const ossKey = session.dataOssKey;
|
||||
|
||||
if (!ossKey) {
|
||||
logger.error('[SSA:RClient] No data uploaded', { sessionId: session.id });
|
||||
throw new Error('请先上传数据文件');
|
||||
}
|
||||
|
||||
logger.info('[SSA:RClient] Building OSS data source', { sessionId: session.id, ossKey });
|
||||
const signedUrl = await storage.getUrl(ossKey);
|
||||
|
||||
return {
|
||||
type: 'oss',
|
||||
oss_url: signedUrl
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**变更说明**:
|
||||
- 移除 `dataPayload` 和 inline JSON 支持
|
||||
- 移除"根据大小判断"逻辑
|
||||
- 如果未上传文件,直接抛出用户友好错误
|
||||
- 代码从 30 行简化到 15 行
|
||||
|
||||
---
|
||||
|
||||
*文档结束。*
|
||||
243
docs/03-业务模块/SSA-智能统计分析/06-开发记录/2026-02-19-端到端测试与Bug修复.md
Normal file
243
docs/03-业务模块/SSA-智能统计分析/06-开发记录/2026-02-19-端到端测试与Bug修复.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# SSA-Pro 2026-02-19 开发总结
|
||||
|
||||
> **版本:** v1.0
|
||||
> **日期:** 2026-02-19
|
||||
> **编写:** AI 开发助手
|
||||
> **状态:** ✅ T 检验端到端测试通过
|
||||
|
||||
---
|
||||
|
||||
## 1. 开发目标
|
||||
|
||||
本日核心目标是**完成 T 检验端到端测试**,并修复测试过程中发现的所有问题。
|
||||
|
||||
---
|
||||
|
||||
## 2. 完成工作清单
|
||||
|
||||
### 2.1 前端模块注册与激活
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模块注册 | ✅ 完成 | `moduleRegistry.ts` 中 `placeholder: false` |
|
||||
| 用户会话隔离 | ✅ 修复 | 组件挂载时重置 Zustand store |
|
||||
| 代码下载文件名 | ✅ 修复 | 从 `Content-Disposition` header 提取真实文件名 |
|
||||
|
||||
### 2.2 后端 Bug 修复
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| R 服务错误响应处理 | ✅ 修复 | 检查 `status: error`,返回 422 + `user_hint` |
|
||||
| 变量智能匹配 | ✅ 修复 | 优先使用用户查询中提到的变量 |
|
||||
| 代码下载 API | ✅ 增强 | 动态生成文件名:`{toolName}_{dataName}_{MMDD}_{HHmm}.R` |
|
||||
|
||||
### 2.3 DataParserService 优化
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 类型推断优化 | ✅ 完成 | 0/1 数字列识别为分类变量 |
|
||||
| 规则优先级 | ✅ 完成 | 唯一值 ≤3 或比例 <20% → categorical |
|
||||
|
||||
### 2.4 R 服务 Bug 修复
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 缺失值处理 | ✅ 修复 | 分析前自动过滤 NA/空字符串 |
|
||||
| 数据清洗日志 | ✅ 新增 | 记录移除的缺失值行数 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 关键 Bug 修复详情
|
||||
|
||||
### 3.1 分组变量识别为 3 组问题
|
||||
|
||||
**问题描述:**
|
||||
- 用户数据 `smoke` 列有值 1、2 和缺失值
|
||||
- R 服务将缺失值算作第 3 组
|
||||
- T 检验要求恰好 2 组,返回错误
|
||||
|
||||
**修复方案:**
|
||||
```r
|
||||
# r-statistics-service/tools/t_test_ind.R
|
||||
# 数据清洗:移除分组变量或数值变量中的缺失值
|
||||
df <- df[!is.na(df[[group_var]]) & trimws(as.character(df[[group_var]])) != "", ]
|
||||
df <- df[!is.na(df[[value_var]]), ]
|
||||
```
|
||||
|
||||
**影响:**
|
||||
- R 服务自动过滤缺失值
|
||||
- 日志记录:`数据清洗: 移除 7 行缺失值 (剩余 304 行)`
|
||||
|
||||
### 3.2 类型推断错误:0/1 列识别为 numeric
|
||||
|
||||
**问题描述:**
|
||||
- `smoke` 列是 0/1 或 1/2 数字
|
||||
- DataParserService 将其识别为 `numeric` 而非 `categorical`
|
||||
- 导致变量匹配逻辑找不到分类变量
|
||||
|
||||
**修复方案:**
|
||||
```typescript
|
||||
// backend/src/modules/ssa/services/DataParserService.ts
|
||||
// 规则1:唯一值很少(<=10)且比例很低(<20%)→ 分类变量
|
||||
if (uniqueCount <= 10 && uniqueRatio < 0.2) {
|
||||
return 'categorical';
|
||||
}
|
||||
// 规则2:即使是数字,如果唯一值只有2-3个,也视为分类变量
|
||||
if (uniqueCount <= 3) {
|
||||
return 'categorical';
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 R 服务错误信息未传递给前端
|
||||
|
||||
**问题描述:**
|
||||
- R 服务返回 `status: error` 和 `message`
|
||||
- 后端仍返回 200 OK,前端无法显示错误原因
|
||||
- 用户只看到"执行失败"
|
||||
|
||||
**修复方案:**
|
||||
```typescript
|
||||
// backend/src/modules/ssa/routes/analysis.routes.ts
|
||||
if (result?.status === 'error') {
|
||||
return reply.status(422).send({
|
||||
status: 'error',
|
||||
error: result.message || '分析执行失败',
|
||||
user_hint: result.user_hint || result.message
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// frontend-v2/src/modules/ssa/hooks/useAnalysis.ts
|
||||
const errorData = error.response?.data;
|
||||
const errorMessage = errorData?.user_hint || errorData?.error || '执行出错';
|
||||
setError(errorMessage);
|
||||
```
|
||||
|
||||
### 3.4 下载代码文件名硬编码
|
||||
|
||||
**问题描述:**
|
||||
- 前端硬编码文件名:`analysis_${sessionId}.R`
|
||||
- 后端 `Content-Disposition` header 中的动态文件名被忽略
|
||||
|
||||
**修复方案:**
|
||||
```typescript
|
||||
// frontend-v2/src/modules/ssa/hooks/useAnalysis.ts
|
||||
const downloadCode = useCallback(async (): Promise<DownloadResult> => {
|
||||
const response = await apiClient.get(...);
|
||||
const contentDisposition = response.headers['content-disposition'];
|
||||
let filename = `analysis_${currentSession.id}.R`;
|
||||
if (contentDisposition) {
|
||||
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
|
||||
if (match) {
|
||||
filename = decodeURIComponent(match[1].replace(/['"]/g, ''));
|
||||
}
|
||||
}
|
||||
return { blob: response.data, filename };
|
||||
}, [currentSession]);
|
||||
```
|
||||
|
||||
### 3.5 用户会话隔离问题
|
||||
|
||||
**问题描述:**
|
||||
- 不同用户登录后看到相同的 session 数据
|
||||
- Zustand store 在页面切换时未重置
|
||||
|
||||
**修复方案:**
|
||||
```tsx
|
||||
// frontend-v2/src/modules/ssa/index.tsx
|
||||
useEffect(() => {
|
||||
reset(); // 组件挂载时重置 store
|
||||
}, [reset]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 测试验证结果
|
||||
|
||||
### 4.1 R 服务直接调用测试
|
||||
|
||||
```json
|
||||
// 请求
|
||||
POST http://localhost:8082/api/v1/skills/ST_T_TEST_IND
|
||||
{
|
||||
"data_source": { "type": "oss", "oss_url": "..." },
|
||||
"params": { "group_var": "smoke", "value_var": "age" }
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
"status": "success",
|
||||
"message": "分析完成",
|
||||
"results": {
|
||||
"method": "Welch Two Sample t-test",
|
||||
"statistic": 0.8812,
|
||||
"df": 197.5738,
|
||||
"p_value": 0.3793,
|
||||
...
|
||||
},
|
||||
"plots": ["data:image/png;base64,..."],
|
||||
"trace_log": [
|
||||
"数据清洗: 移除 7 行缺失值 (剩余 304 行)",
|
||||
...
|
||||
],
|
||||
"reproducible_code": "# SSA-Pro 自动生成代码..."
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 端到端测试流程
|
||||
|
||||
| 步骤 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 1. 上传数据 | ✅ 通过 | CSV 文件上传到 OSS |
|
||||
| 2. 数据解析 | ✅ 通过 | Schema 正确识别变量类型 |
|
||||
| 3. 生成计划 | ✅ 通过 | 正确匹配 smoke(分类) + age(数值) |
|
||||
| 4. 执行分析 | ✅ 通过 | R 服务返回完整结果 |
|
||||
| 5. 结果展示 | ✅ 通过 | 统计结果 + 图表 + 代码 |
|
||||
| 6. 代码下载 | ✅ 通过 | 动态文件名生效 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码变更清单
|
||||
|
||||
| 文件 | 变更类型 | 说明 |
|
||||
|------|----------|------|
|
||||
| `r-statistics-service/tools/t_test_ind.R` | 增强 | 缺失值自动过滤 |
|
||||
| `backend/src/modules/ssa/services/DataParserService.ts` | 增强 | 类型推断优化 |
|
||||
| `backend/src/modules/ssa/routes/analysis.routes.ts` | 修复 | R 错误响应处理 + 动态文件名 |
|
||||
| `frontend-v2/src/modules/ssa/hooks/useAnalysis.ts` | 修复 | 错误信息提取 + 文件名获取 |
|
||||
| `frontend-v2/src/modules/ssa/index.tsx` | 修复 | 用户会话隔离 |
|
||||
| `frontend-v2/src/framework/modules/moduleRegistry.ts` | 更新 | 激活 SSA 模块 |
|
||||
|
||||
---
|
||||
|
||||
## 6. MVP 进度更新
|
||||
|
||||
| Phase | 任务数 | 已完成 | 进度 |
|
||||
|-------|--------|--------|------|
|
||||
| Phase 1 | 49 | 38 | 78% |
|
||||
| Phase 2 | 31 | 0 | 0% |
|
||||
| Phase 3 | 26 | 0 | 0% |
|
||||
| **总计** | **106** | **38** | **36%** |
|
||||
|
||||
---
|
||||
|
||||
## 7. 遗留问题与后续工作
|
||||
|
||||
### 7.1 待完成任务(Phase 1)
|
||||
|
||||
| 任务 | 优先级 | 说明 |
|
||||
|------|--------|------|
|
||||
| 配置中台:DecisionTableLoader | 中 | 四维匹配逻辑 |
|
||||
| 配置中台:RCodeLibraryService | 中 | 脚本上传/版本管理 |
|
||||
| DataParserService 隐私保护 | 低 | 稀有值 < 5 隐藏 |
|
||||
| 安装 json-repair + zod | 低 | LLM 输出容错 |
|
||||
|
||||
### 7.2 下一步计划
|
||||
|
||||
1. **进入 Phase 2** - 实现更多统计方法(ANOVA、卡方检验等)
|
||||
2. **或完善 Phase 1** - 配置中台基础功能
|
||||
|
||||
---
|
||||
|
||||
**2026-02-19 开发总结完成。**
|
||||
98
docs/03-业务模块/SSA-智能统计分析/06-开发记录/SSA-Pro R 服务代码深度审查报告.md
Normal file
98
docs/03-业务模块/SSA-智能统计分析/06-开发记录/SSA-Pro R 服务代码深度审查报告.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# **SSA-Pro R 服务代码深度审查报告**
|
||||
|
||||
**审查对象:** SSA-Pro R Service Source Code (v1.0)
|
||||
|
||||
**审查文件:** Dockerfile, plumber.R, data\_loader.R, guardrails.R, etc.
|
||||
|
||||
**审查时间:** 2026-02-18
|
||||
|
||||
**审查结论:** 🟡 **总体优秀,但存在阻断性缺失 (Blocker)**
|
||||
|
||||
## **1\. 🚨 阻断性问题 (Critical Issues)**
|
||||
|
||||
**这些问题会导致服务无法启动或无法下载数据,必须在联调前修复。**
|
||||
|
||||
### **1.1 data\_loader.R 中缺失 OSS 签名函数**
|
||||
|
||||
* **问题描述**:在 data\_loader.R 第 63 行调用了 generate\_oss\_signature(config, "GET", oss\_key),但我翻遍了上传的所有文件,**没有找到这个函数的定义**。
|
||||
* **风险**:代码运行到下载 OSS 步骤时会直接报错 Error: could not find function "generate\_oss\_signature"。
|
||||
* **修复建议**:
|
||||
1. **方案 A (推荐)**:在 utils/ 下新建 oss\_signer.R,实现阿里云 OSS 的 HMAC-SHA1 签名逻辑(需要引入 digest 和 base64enc 包)。
|
||||
2. **方案 B (替代)**:如果不想手写签名,可以使用系统调用 awscli (配置阿里云 endpoint) 或寻找现成的 R 包(如 aliyunr,但需验证维护状态)。
|
||||
|
||||
### **1.2 plumber.R 的动态加载性能隐患**
|
||||
|
||||
* **问题描述**:在 plumber.R 的 POST /api/v1/skills/\<tool\_code\> 接口中,第 38 行使用了 source(tool\_file)。这意味着**每次请求都会重新从磁盘读取并解析 R 脚本**。
|
||||
* **风险**:
|
||||
* **开发环境**:这是好事,支持热重载。
|
||||
* **生产环境**:这是性能杀手。在高并发下,频繁的磁盘 I/O 和语法解析会显著增加延迟。
|
||||
* **修复建议**:
|
||||
* 引入 DEV\_MODE 变量判断。
|
||||
* **生产环境**:在服务启动时(第 13 行左右)预先加载所有 tools/ 下的脚本,或者使用 environment 缓存已加载的函数。
|
||||
* **开发环境**:保持现有的动态 source 逻辑。
|
||||
|
||||
## **2\. 工程与安全隐患 (Engineering & Security Risks)**
|
||||
|
||||
### **2.1 Docker 容器的 Root 权限风险**
|
||||
|
||||
* **问题描述**:Dockerfile 未指定用户,默认使用 root 运行 R 服务。
|
||||
* **风险**:如果 R 代码中存在漏洞(如允许执行系统命令 system()),攻击者将获得容器的 Root 权限,可能逃逸或破坏文件系统。
|
||||
* **修复建议**:在 Dockerfile 末尾添加非特权用户切换:
|
||||
RUN useradd \-m appuser
|
||||
USER appuser
|
||||
|
||||
### **2.2 路径遍历攻击 (Path Traversal)**
|
||||
|
||||
* **问题描述**:plumber.R 第 33 行:
|
||||
tool\_file \<- file.path("tools", paste0(tolower(gsub("ST\_", "", tool\_code)), ".R"))
|
||||
虽然做了 gsub,但如果 tool\_code 包含 ../ 等字符,仍可能尝试访问上层目录。
|
||||
* **修复建议**:增加严格的白名单校验,或者校验 tool\_code 只能包含字母、数字和下划线。
|
||||
if (\!grepl("^\[A-Z0-9\_\]+$", tool\_code)) {
|
||||
return(list(status="error", message="Invalid tool code format"))
|
||||
}
|
||||
|
||||
## **3\. 最佳实践点赞 (Highlights) ✅**
|
||||
|
||||
1. **依赖锁定 (renv.lock)**:使用了 renv 进行包管理,这是 R 工程化的基石,做得非常棒。
|
||||
2. **护栏设计 (guardrails.R)**:
|
||||
* 包含了 LARGE\_SAMPLE\_THRESHOLD (5000) 的抽样逻辑,避免了大样本下 Shapiro 检验过敏的问题,非常专业的统计学处理。
|
||||
* 接口设计清晰 (passed, action, reason)。
|
||||
3. **结果格式化 (result\_formatter.R)**:统一处理了 P 值 \< 0.001 的显示,符合 APA 规范。
|
||||
4. **环境隔离 (docker-compose.yml)**:正确使用了环境变量注入 OSS 配置,且区分了开发/生产环境。
|
||||
|
||||
## **4\. 优化代码清单 (Code Improvement Snippets)**
|
||||
|
||||
### **补全 OSS 签名逻辑 (utils/oss\_signer.R)**
|
||||
|
||||
*这部分逻辑比较复杂,我直接提供一个简版实现供参考:*
|
||||
|
||||
library(digest)
|
||||
library(base64enc)
|
||||
|
||||
generate\_oss\_signature \<- function(config, verb, resource) {
|
||||
date \<- format(Sys.time(), "%a, %d %b %Y %H:%M:%S GMT", tz="GMT")
|
||||
content\_type \<- ""
|
||||
content\_md5 \<- ""
|
||||
|
||||
canonicalized\_resource \<- paste0("/", config$bucket, "/", resource)
|
||||
string\_to\_sign \<- paste(verb, content\_md5, content\_type, date, "", canonicalized\_resource, sep="\\n")
|
||||
|
||||
signature \<- base64encode(hmac(config$access\_key\_secret, string\_to\_sign, algo="sha1", raw=TRUE))
|
||||
auth\_header \<- paste0("OSS ", config$access\_key\_id, ":", signature)
|
||||
|
||||
return(c("Authorization" \= auth\_header, "Date" \= date))
|
||||
}
|
||||
|
||||
*注意:需要在 renv.lock 中补充 digest 包。*
|
||||
|
||||
## **5\. 总结**
|
||||
|
||||
这份代码作为 MVP 已经达到了 **85分** 的水平。
|
||||
|
||||
**接下来的行动指南:**
|
||||
|
||||
1. **必须做**:补全 generate\_oss\_signature 函数(或相关文件)。
|
||||
2. **必须做**:在 renv 中添加 digest 依赖。
|
||||
3. **建议做**:优化 plumber.R 的生产环境加载逻辑。
|
||||
|
||||
请将这份报告发给 R 开发工程师,让他们快速修正,然后就可以开始构建镜像了。
|
||||
260
docs/03-业务模块/SSA-智能统计分析/06-开发记录/Week1-开发总结报告.md
Normal file
260
docs/03-业务模块/SSA-智能统计分析/06-开发记录/Week1-开发总结报告.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# SSA-Pro 模块 Week 1 开发总结报告
|
||||
|
||||
> **版本:** v1.0
|
||||
> **日期:** 2026-02-19
|
||||
> **编写:** AI 开发助手
|
||||
> **状态:** ✅ Week 1 完成
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [开发目标](#1-开发目标)
|
||||
2. [完成工作清单](#2-完成工作清单)
|
||||
3. [关键决策与讨论](#3-关键决策与讨论)
|
||||
4. [技术挑战与解决方案](#4-技术挑战与解决方案)
|
||||
5. [代码审查与规范对齐](#5-代码审查与规范对齐)
|
||||
6. [产出物清单](#6-产出物清单)
|
||||
7. [遗留问题与后续工作](#7-遗留问题与后续工作)
|
||||
|
||||
---
|
||||
|
||||
## 1. 开发目标
|
||||
|
||||
Week 1 的核心目标是**搭建 SSA-Pro 模块的技术骨架**,包括:
|
||||
|
||||
- R 统计服务 Docker 环境
|
||||
- 后端 SSA 模块结构
|
||||
- 前端 SSA 模块结构
|
||||
- 数据库 Schema 设计
|
||||
|
||||
---
|
||||
|
||||
## 2. 完成工作清单
|
||||
|
||||
### 2.1 R 统计服务 (r-statistics-service)
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| Dockerfile 编写 | ✅ 完成 | 基于 `rocker/r-ver:4.3`,包含完整系统依赖 |
|
||||
| plumber.R API 入口 | ✅ 完成 | 健康检查、工具列表、技能执行 |
|
||||
| data_loader.R | ✅ 完成 | 支持 inline 数据和预签名 URL |
|
||||
| guardrails.R | ✅ 完成 | 正态性、方差齐性、样本量检验 |
|
||||
| error_codes.R | ✅ 完成 | 友好错误映射 |
|
||||
| result_formatter.R | ✅ 完成 | APA 格式化 |
|
||||
| t_test_ind.R 示例工具 | ✅ 完成 | 独立样本 T 检验 |
|
||||
| Docker 镜像构建 | ✅ 完成 | `ssa-r-statistics:1.0.1`,1.81GB |
|
||||
|
||||
### 2.2 后端模块 (backend/src/modules/ssa)
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模块目录结构 | ✅ 完成 | 标准模块结构 |
|
||||
| index.ts 入口 | ✅ 完成 | 使用 `authenticate` 中间件 |
|
||||
| session.routes.ts | ✅ 完成 | 会话管理 API |
|
||||
| analysis.routes.ts | ✅ 完成 | 分析执行 API,OSS 存储集成 |
|
||||
| consult.routes.ts | ✅ 完成 | 咨询模式 API,LLM 网关集成 |
|
||||
| config.routes.ts | ✅ 完成 | 配置管理 API |
|
||||
| RClientService.ts | ✅ 完成 | R 服务客户端,预签名 URL 支持 |
|
||||
|
||||
### 2.3 前端模块 (frontend-v2/src/modules/ssa)
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模块目录结构 | ✅ 完成 | 标准模块结构 |
|
||||
| index.tsx 入口 | ✅ 完成 | 主布局组件 |
|
||||
| useAnalysis.ts Hook | ✅ 完成 | 使用 apiClient 认证 |
|
||||
| 组件骨架 | ✅ 完成 | DataUploader, PlanConfirm 等 |
|
||||
|
||||
### 2.4 数据库 Schema
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| Prisma Schema 定义 | ✅ 完成 | 9 个 SSA 相关模型 |
|
||||
| Migration SQL | ✅ 完成 | 手动创建并应用 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 关键决策与讨论
|
||||
|
||||
### 3.1 OSS 访问方案
|
||||
|
||||
**讨论背景:**
|
||||
- 开发团队审查报告建议 R 服务实现 OSS 签名(`oss_signer.R`)
|
||||
- 这需要 R 服务持有 OSS 密钥
|
||||
|
||||
**最终决策:** ❌ 不采用 R 直接签名方案
|
||||
|
||||
**采用方案:** 预签名 URL
|
||||
```
|
||||
Node.js 生成预签名 URL → 传递给 R 服务 → R 直接 GET 下载
|
||||
```
|
||||
|
||||
**理由:**
|
||||
1. 符合平台 OSS 存储规范(密钥集中管控)
|
||||
2. R 服务无需持有敏感密钥
|
||||
3. 简化 R 代码复杂度
|
||||
|
||||
### 3.2 生产环境性能优化
|
||||
|
||||
**问题:** `plumber.R` 每次请求都 `source()` 工具脚本
|
||||
|
||||
**解决方案:**
|
||||
```r
|
||||
# 生产环境:启动时预加载到 TOOL_CACHE
|
||||
if (!DEV_MODE) {
|
||||
preload_tools() # 缓存 run_analysis 函数
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 安全加固
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
|------|----------|
|
||||
| Docker Root 权限 | 添加 `USER appuser` |
|
||||
| 路径遍历攻击 | `tool_code` 正则白名单 `^[A-Z][A-Z0-9_]*$` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 技术挑战与解决方案
|
||||
|
||||
### 4.1 Prisma Migration Drift
|
||||
|
||||
**问题:** `prisma migrate dev` 检测到 drift,要求 `migrate reset`
|
||||
|
||||
**解决方案:**
|
||||
1. 手动创建 SQL 文件
|
||||
2. 直接执行 SQL
|
||||
3. 使用 `prisma migrate resolve --applied` 标记已应用
|
||||
|
||||
### 4.2 Docker 构建依赖问题
|
||||
|
||||
**问题链:**
|
||||
```
|
||||
zlib.h 缺失 → httpuv 编译失败
|
||||
cmake 缺失 → nloptr 编译失败
|
||||
ggplot2 版本冲突 → cowplot 安装失败
|
||||
```
|
||||
|
||||
**解决方案:**
|
||||
1. 添加系统依赖:`zlib1g-dev`, `cmake`, `libnlopt-dev`, `gfortran`
|
||||
2. 放弃 renv,直接 `install.packages()` 让 R 自动解决依赖
|
||||
|
||||
### 4.3 PowerShell 重定向问题
|
||||
|
||||
**问题:** `<` 操作符在 PowerShell 中被保留
|
||||
|
||||
**解决方案:**
|
||||
```powershell
|
||||
Get-Content "file.sql" | docker exec -i postgres psql ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码审查与规范对齐
|
||||
|
||||
Week 1 后期进行了一次重要的**规范对齐审查**,确保新代码遵循平台规范。
|
||||
|
||||
### 5.1 发现的问题
|
||||
|
||||
| 文件 | 问题 | 修复 |
|
||||
|------|------|------|
|
||||
| `useAnalysis.ts` | 使用原生 fetch,无认证 | 改用 `apiClient` |
|
||||
| `ssa/index.ts` | 自定义 authenticate | 使用平台 `authenticate` 中间件 |
|
||||
| `RClientService.ts` | 直接传 OSS key | 使用 `storage.getUrl()` 预签名 |
|
||||
| `ConsultChat.tsx` | 自定义 Chat 组件 | 删除,使用平台 `AIStreamChat` |
|
||||
| 各 routes | 手动获取 userId | 使用 `getUserId(request)` |
|
||||
|
||||
### 5.2 参考规范文档
|
||||
|
||||
- `docs/02-通用能力层/00-通用能力层清单.md`
|
||||
- `docs/04-开发规范/10-模块认证规范.md`
|
||||
- `docs/04-开发规范/11-OSS存储开发规范.md`
|
||||
|
||||
---
|
||||
|
||||
## 6. 产出物清单
|
||||
|
||||
### 6.1 代码文件
|
||||
|
||||
```
|
||||
r-statistics-service/
|
||||
├── Dockerfile # 生产就绪
|
||||
├── docker-compose.yml # 本地开发
|
||||
├── plumber.R # API 入口
|
||||
├── utils/
|
||||
│ ├── data_loader.R # 预签名 URL 方案
|
||||
│ ├── guardrails.R # Block/Warn/Switch
|
||||
│ ├── error_codes.R
|
||||
│ └── result_formatter.R
|
||||
├── tools/
|
||||
│ └── t_test_ind.R # 示例工具
|
||||
└── tests/fixtures/
|
||||
└── normal_data.csv
|
||||
|
||||
backend/src/modules/ssa/
|
||||
├── index.ts
|
||||
├── routes/
|
||||
│ ├── session.routes.ts
|
||||
│ ├── analysis.routes.ts
|
||||
│ ├── consult.routes.ts
|
||||
│ └── config.routes.ts
|
||||
├── executor/
|
||||
│ └── RClientService.ts
|
||||
└── types/
|
||||
|
||||
frontend-v2/src/modules/ssa/
|
||||
├── index.tsx
|
||||
├── components/
|
||||
├── hooks/
|
||||
│ └── useAnalysis.ts
|
||||
└── types/
|
||||
```
|
||||
|
||||
### 6.2 Docker 镜像
|
||||
|
||||
| 镜像名 | 版本 | 大小 | 状态 |
|
||||
|--------|------|------|------|
|
||||
| `ssa-r-statistics` | 1.0.1 | 1.81 GB | ✅ 本地构建成功 |
|
||||
|
||||
### 6.3 数据库 Schema
|
||||
|
||||
- `ssa_schema` 命名空间
|
||||
- 9 个新表:`SsaSession`, `SsaMessage`, `SsaTool`, `SsaExecutionLog` 等
|
||||
|
||||
---
|
||||
|
||||
## 7. 遗留问题与后续工作
|
||||
|
||||
### 7.1 待完成任务
|
||||
|
||||
| 任务 | 优先级 | 说明 |
|
||||
|------|--------|------|
|
||||
| 后端主路由注册 | P0 | 将 SSA 路由加入 `index.ts` |
|
||||
| 前端模块注册 | P0 | 加入 `moduleRegistry.ts` |
|
||||
| T 检验数据格式调试 | P1 | JSON 转 data.frame 格式问题 |
|
||||
| 配置中心 Excel 模板 | P1 | 决策表、参数映射等 |
|
||||
|
||||
### 7.2 Week 2 计划
|
||||
|
||||
1. **完成模块注册** - 后端/前端路由注册
|
||||
2. **端到端测试** - 数据上传 → 计划生成 → 执行
|
||||
3. **配置中心实现** - DecisionTableLoader, RCodeLibraryService
|
||||
4. **Planner 引擎** - LLM 方法推荐逻辑
|
||||
|
||||
---
|
||||
|
||||
## 附录:关键文件变更记录
|
||||
|
||||
| 文件 | 变更类型 | 变更内容 |
|
||||
|------|----------|----------|
|
||||
| `data_loader.R` | 重构 | OSS 签名 → 预签名 URL |
|
||||
| `plumber.R` | 增强 | 生产预加载 + tool_code 校验 |
|
||||
| `Dockerfile` | 增强 | 非特权用户 + 健康检查 |
|
||||
| `RClientService.ts` | 修复 | 使用 storage.getUrl() |
|
||||
| `useAnalysis.ts` | 修复 | 使用 apiClient |
|
||||
| `ssa/index.ts` | 修复 | 使用平台 authenticate |
|
||||
|
||||
---
|
||||
|
||||
**Week 1 开发总结完成。**
|
||||
56
docs/03-业务模块/SSA-智能统计分析/06-开发记录/oss_signer.R
Normal file
56
docs/03-业务模块/SSA-智能统计分析/06-开发记录/oss_signer.R
Normal file
@@ -0,0 +1,56 @@
|
||||
# utils/oss_signer.R
|
||||
# 阿里云 OSS 签名生成器 (R语言实现)
|
||||
# 参考文档: https://help.aliyun.com/document_detail/31951.html
|
||||
|
||||
library(digest)
|
||||
library(base64enc)
|
||||
|
||||
#' 生成 OSS API 签名头
|
||||
#' @param config 包含 access_key_id, access_key_secret, bucket 的列表
|
||||
#' @param verb HTTP 方法 (GET, PUT, etc.)
|
||||
#' @param resource OSS 资源路径 (例如 "/my-bucket/data/file.csv")
|
||||
#' @param content_type 内容类型 (可选)
|
||||
#' @param content_md5 内容 MD5 (可选)
|
||||
#' @return 包含 Authorization 和 Date 的命名向量
|
||||
generate_oss_signature <- function(config, verb, resource, content_type = "", content_md5 = "") {
|
||||
|
||||
# 1. 生成标准时间戳 (GMT 格式)
|
||||
# 例如: "Thu, 18 Feb 2026 08:00:00 GMT"
|
||||
date <- format(Sys.time(), "%a, %d %b %Y %H:%M:%S GMT", tz="GMT")
|
||||
|
||||
# 2. 构造 CanonicalizedResource
|
||||
# 格式: /BucketName/ObjectName
|
||||
canonicalized_resource <- paste0("/", config$bucket, "/", resource)
|
||||
|
||||
# 3. 构造 StringToSign
|
||||
# 格式:
|
||||
# VERB + "\n" +
|
||||
# Content-MD5 + "\n" +
|
||||
# Content-Type + "\n" +
|
||||
# Date + "\n" +
|
||||
# CanonicalizedOSSHeaders +
|
||||
# CanonicalizedResource
|
||||
|
||||
# 注意: 这里简化处理,未包含 CanonicalizedOSSHeaders (x-oss-*)
|
||||
string_to_sign <- paste(
|
||||
verb,
|
||||
content_md5,
|
||||
content_type,
|
||||
date,
|
||||
canonicalized_resource,
|
||||
sep = "\n"
|
||||
)
|
||||
|
||||
# 4. 计算 HMAC-SHA1 签名
|
||||
# 使用 AccessKeySecret 作为密钥
|
||||
signature <- base64encode(hmac(config$access_key_secret, string_to_sign, algo = "sha1", raw = TRUE))
|
||||
|
||||
# 5. 构造 Authorization 头
|
||||
auth_header <- paste0("OSS ", config$access_key_id, ":", signature)
|
||||
|
||||
# 返回需要的 Headers
|
||||
return(c(
|
||||
"Authorization" = auth_header,
|
||||
"Date" = date
|
||||
))
|
||||
}
|
||||
255
docs/06-测试文档/existing_phones.txt
Normal file
255
docs/06-测试文档/existing_phones.txt
Normal file
@@ -0,0 +1,255 @@
|
||||
15810435207
|
||||
18010009162
|
||||
15010181209
|
||||
15611963795
|
||||
18611348738
|
||||
13943635313
|
||||
13581727231
|
||||
13810478176
|
||||
13410168373
|
||||
13811282647
|
||||
17801082043
|
||||
15605519676
|
||||
18919636592
|
||||
18756032620
|
||||
13866173932
|
||||
13522189226
|
||||
18365256560
|
||||
15221056490
|
||||
13803774813
|
||||
13956060845
|
||||
18909696293
|
||||
18601278833
|
||||
13911933105
|
||||
13810366704
|
||||
13675628031
|
||||
17356719361
|
||||
15910681644
|
||||
19909678258
|
||||
13696540086
|
||||
13051291428
|
||||
13681000859
|
||||
13910110950
|
||||
18611103631
|
||||
13683036620
|
||||
15570146357
|
||||
18210079257
|
||||
18920525052
|
||||
18611685198
|
||||
19350528610
|
||||
13611720680
|
||||
15101021070
|
||||
18560082439
|
||||
17801014125
|
||||
15801430103
|
||||
15501120199
|
||||
13683016715
|
||||
15501007199
|
||||
13241516357
|
||||
13466759883
|
||||
13911680467
|
||||
15552835306
|
||||
13049169421
|
||||
谢一泓
|
||||
15010497945
|
||||
13552951189
|
||||
18810957336
|
||||
13717936224
|
||||
13220461848
|
||||
18600017812
|
||||
13611209306
|
||||
13811794835
|
||||
15911086290
|
||||
18612835027
|
||||
13301336613
|
||||
13391567801
|
||||
13912635742
|
||||
15882051125
|
||||
18280063640
|
||||
aaa
|
||||
18611111111
|
||||
18622222222
|
||||
18633333333
|
||||
18644444444
|
||||
13718974561
|
||||
15201593792
|
||||
15501026871
|
||||
17860691820
|
||||
15652526290
|
||||
18800104320
|
||||
15235537621
|
||||
15117925628
|
||||
18954156864
|
||||
18610085697
|
||||
15201278137
|
||||
15201647621
|
||||
13810483563
|
||||
18502894620
|
||||
15822165166
|
||||
18852010317
|
||||
13552405525
|
||||
15010891570
|
||||
13811459968
|
||||
13439020885
|
||||
13811111111
|
||||
13269893936
|
||||
15510992666
|
||||
13520658969
|
||||
13366288066
|
||||
18701021830
|
||||
15210513935
|
||||
13816919105
|
||||
13761189664
|
||||
15175115755
|
||||
15022188250
|
||||
17331514756
|
||||
17625924413
|
||||
13122859786
|
||||
18663667466
|
||||
18801081160
|
||||
18811723822
|
||||
13810384929
|
||||
13001231836
|
||||
16710815063
|
||||
15611908852
|
||||
18522085055
|
||||
13693638871
|
||||
15210325676
|
||||
13611111111
|
||||
13622222222
|
||||
冀召帅
|
||||
18310402093
|
||||
18610164730
|
||||
13810944609
|
||||
13720413071
|
||||
13826610404
|
||||
18219857717
|
||||
15698937284
|
||||
15998659426
|
||||
18710675876
|
||||
17628489151
|
||||
17602871544
|
||||
17877005510
|
||||
15123612362
|
||||
18098875654
|
||||
15029098264
|
||||
18047668006
|
||||
18219029950
|
||||
17387997553
|
||||
13571875487
|
||||
18715854003
|
||||
18970132004
|
||||
18686782201
|
||||
18545662842
|
||||
18734121203
|
||||
13899313719
|
||||
18779835021
|
||||
13751562435
|
||||
15779163306
|
||||
18900913095
|
||||
15129745755
|
||||
13560521592
|
||||
13810002741
|
||||
15032631293
|
||||
15838062093
|
||||
10001000127
|
||||
18610000128
|
||||
13520004917
|
||||
18222376451
|
||||
13752570372
|
||||
13581787350
|
||||
18600589965
|
||||
13901009038
|
||||
18759221287
|
||||
18560080524
|
||||
13611728840
|
||||
15120022447
|
||||
15358136676
|
||||
15920493789
|
||||
18900918397
|
||||
13467609491
|
||||
15924177038
|
||||
18758096745
|
||||
18845764494
|
||||
18340809532
|
||||
18800161511
|
||||
17721871290
|
||||
15951987578
|
||||
13361656372
|
||||
17734891246
|
||||
17637350926
|
||||
18037763215
|
||||
18180230754
|
||||
18600161380
|
||||
18701658727
|
||||
13522421109
|
||||
18621015623
|
||||
17329403301
|
||||
13811401686
|
||||
13818015615
|
||||
13810137047
|
||||
13810947856
|
||||
13581878417
|
||||
18618269437
|
||||
13011825605
|
||||
13522757239
|
||||
13811280948
|
||||
15611908668
|
||||
18511650863
|
||||
15699911299
|
||||
13911598100
|
||||
13810964766
|
||||
13811490288
|
||||
18610966092
|
||||
13681324810
|
||||
17737311521
|
||||
19834513308
|
||||
15188376900
|
||||
15803820068
|
||||
15306419073
|
||||
15237360867
|
||||
15237125268
|
||||
15039063646
|
||||
13001253689
|
||||
13581663887
|
||||
18268383011
|
||||
13161658808
|
||||
15120011793
|
||||
19959113334
|
||||
15810853270
|
||||
15081212977
|
||||
18810793312
|
||||
13811113460
|
||||
13691081209
|
||||
15801391489
|
||||
15611063099
|
||||
15010079214
|
||||
13366972832
|
||||
13911315318
|
||||
13683657545
|
||||
13811502555
|
||||
15210610941
|
||||
13911063662
|
||||
18810834462
|
||||
15601212632
|
||||
13811286188
|
||||
18610381719
|
||||
13699201941
|
||||
13683349097
|
||||
13911857210
|
||||
15101120796
|
||||
13641099415
|
||||
13601060345
|
||||
18811728779
|
||||
15901241029
|
||||
13381177395
|
||||
18910938225
|
||||
13910667213
|
||||
13611218802
|
||||
13910785151
|
||||
18611286922
|
||||
13121909939
|
||||
15010115375
|
||||
18810670329
|
||||
13693160086
|
||||
13810281260
|
||||
230
docs/06-测试文档/北医三院-医点点账号申请.csv
Normal file
230
docs/06-测试文档/北医三院-医点点账号申请.csv
Normal file
@@ -0,0 +1,230 @@
|
||||
手机号,姓名,医院,部门
|
||||
13621369297,刘佳兴,北京大学第三医院,病案科
|
||||
13552371972,张丹,北京大学第三医院,病案科
|
||||
13439604857,刘青青,北京大学第三医院,病案科
|
||||
15910968332,李安临,北京大学第三医院,病案科
|
||||
15901081908,高源,北京大学第三医院,病案科
|
||||
15011401691,李婧楠,北京大学第三医院,病案科
|
||||
13466326635,李杨,北京大学第三医院,病案科
|
||||
13641084052,詹思延,北京大学第三医院,临床流行病学研究中心
|
||||
13651044855,张洁,北京大学第三医院,生物样本库
|
||||
15611963681,穆荣,北京大学第三医院,风湿免疫科
|
||||
18810106285,张现化,北京大学第三医院,药学部
|
||||
18911482830,徐懋,北京大学第三医院,麻醉科
|
||||
13811289616,金姬延,北京大学第三医院,骨科
|
||||
18611302030,张坤,北京大学第三医院,妇科
|
||||
15811123680,邓秀文,北京大学第三医院,肿瘤放疗科
|
||||
15611963578,关里,北京大学第三医院,职业病科
|
||||
15810866570,夏宇曦,北京大学第三医院,医务处
|
||||
13810627171,张迎宏,北京大学第三医院,耳鼻喉
|
||||
15810394568,陈芷谦,北京大学第三医院,老年病内科
|
||||
13810517083,柯嘉,北京大学第三医院,耳鼻喉科
|
||||
13488693118,郝燕婷,北京大学第三医院,老年科
|
||||
18514507016,朱薇,北京大学第三医院,疼痛科
|
||||
13910979132,孙永昌,北京大学第三医院,呼吸内科
|
||||
13521696306,杜俊,北京大学第三医院,医院感染管理处
|
||||
18510967299,方英伦,北京大学第三医院,麻醉科
|
||||
15210502975,雷润宏,北京大学第三医院,放疗科
|
||||
13683363301,林玉晶,北京大学第三医院,老年内科
|
||||
15210907141,刘佳,北京大学第三医院,老年内科
|
||||
13521661293,曲昂,北京大学第三医院,肿瘤放疗科
|
||||
18701567019,李潇潇,北京大学第三医院,药学部
|
||||
13810001444,张晓盈,北京大学第三医院,风湿免疫科
|
||||
15600561969,门鹏,北京大学第三医院,药学部
|
||||
13810388916,杨诗源,北京大学第三医院,超声医学科
|
||||
18839790793,李菲,北京大学第三医院,内分泌科
|
||||
13261875609,宫萍,北京大学第三医院,老年病内科
|
||||
13120336070,么雪婷,北京大学第三医院,药物临床试验机构
|
||||
15201113598,魏枢华,北京大学第三医院,肿瘤放疗科
|
||||
13370137181,李云峰,北京大学第三医院,伤口治疗中心
|
||||
15010341566,王安琪,北京大学第三医院,皮肤科
|
||||
15801376598,王蕊,北京大学第三医院,护理部
|
||||
13522503401,武大伟,北京大学第三医院,耳鼻喉科
|
||||
15652387205,王淑慧,北京大学第三医院,药剂科
|
||||
13321185611,杨丽,北京大学第三医院,药剂科
|
||||
15910965193,王丽嫄,北京大学第三医院,药剂科
|
||||
18810533012,武慧,北京大学第三医院,儿科
|
||||
15611272855,吴捷颖,北京大学第三医院,神经内科
|
||||
13811111694,郭福新,北京大学第三医院,肿瘤放疗科
|
||||
18842627633,刘爽,北京大学第三医院,药学部
|
||||
13041210677,张龙,北京大学第三医院,伤口治疗中心
|
||||
15611908587,苏春燕,北京大学第三医院,肾内科
|
||||
15110158268,胡娴静,北京大学第三医院,护理部
|
||||
18611692313,陈领,北京大学第三医院,伤口治疗中心
|
||||
15010395820,李烜,北京大学第三医院,伤口治疗中心
|
||||
13699176380,王璟,北京大学第三医院,肿瘤化疗与放射病科
|
||||
13141078611,郑伟,北京大学第三医院,神经内科
|
||||
15273111073,许佳琪,北京大学第三医院,普通外科
|
||||
18519650377,张晓静,北京大学第三医院,门诊部
|
||||
15210716367,王艺萌,北京大学第三医院,皮肤科
|
||||
15810292912,胡明奥,北京大学第三医院,骨科
|
||||
18210293651,王晶玭,北京大学第三医院,护理部
|
||||
17812003135,孙文凡,北京大学第三医院,机场住院管理中心
|
||||
13910989410,赵荣生,北京大学第三医院,药学部
|
||||
15010676497,董佳蕙,北京大学第三医院,药学部
|
||||
18811358039,安宇婷,北京大学第三医院,神经外科
|
||||
18310836575,刘泽强,北京大学第三医院,检验科
|
||||
13717959904,周玉洁,北京大学第三医院,普外科
|
||||
13522391517,赵东芳,北京大学第三医院,全科医学科
|
||||
13521115717,郭金竹,北京大学第三医院,皮肤科
|
||||
17837013925,马文静,北京大学第三医院,产科三病房
|
||||
13264046126,荆天意,北京大学第三医院,妇产科
|
||||
15611963829,邓绍晖,北京大学第三医院,泌尿外科
|
||||
13501301199,张艳平,北京大学第三医院,骨科
|
||||
19800308903,王梦瑞,北京大学第三医院,麻醉科
|
||||
15210099011,马莉,北京大学第三医院,急诊科
|
||||
13552930403,强光亮,北京大学第三医院,胸外科
|
||||
13051581652,马善吴,北京大学第三医院,胸外科
|
||||
18511756295,陈凤发,北京大学第三医院,胸外科
|
||||
13651253466,贺未,北京大学第三医院,胸外科
|
||||
13681397086,李桂芬,北京大学第三医院,急诊
|
||||
13810644825,汪宇鹏,北京大学第三医院,心血管内科
|
||||
13811081300,刘文静,北京大学第三医院,感染疾病科
|
||||
13522517275,张玉洁,北京大学第三医院,妇产科
|
||||
17611059621,张晓琦,北京大学第三医院,机场发热急诊
|
||||
18510993486,姜雅楠,北京大学第三医院,儿科
|
||||
13466552713,马媛,北京大学第三医院,心血管内科
|
||||
13520953609,汪宗昱,北京大学第三医院,危重医学科
|
||||
18601309265,闫辉,北京大学第三医院,运动医学
|
||||
15901129743,王晓毅,北京大学第三医院,老年内科
|
||||
18600122874,苗欣,北京大学第三医院,运动医学科
|
||||
17309573451,张辉,北京大学第三医院,感染疾病科
|
||||
15811221023,刘维,北京大学第三医院,药学部
|
||||
18810535187,刘聪颖,北京大学第三医院,心血管内科
|
||||
18810793282,谢鹏昕,北京大学第三医院,心内科
|
||||
15801509989,任佳梦,北京大学第三医院,心内科
|
||||
15026613596,姜熙平,北京大学第三医院,运动医学科
|
||||
15010388257,郑康,北京大学第三医院,急诊科
|
||||
13716250148,谭鲁平,北京大学第三医院,感染疾病科
|
||||
13701366871,焦晨,北京大学第三医院,运动医学
|
||||
17812091912,何华钰,北京大学第三医院,胸外科
|
||||
13811232349,叶剑飞,北京大学第三医院,泌尿外科
|
||||
15611908285,侯小飞,北京大学第三医院,泌尿外科
|
||||
13581517190,宋一萌,北京大学第三医院,泌尿
|
||||
18800198507,张展奕,北京大学第三医院,泌尿外科
|
||||
13810619450,张树栋,北京大学第三医院,泌尿外科
|
||||
13601280387,魏瑗,北京大学第三医院,产科
|
||||
13601375861,王墨培,北京大学第三医院,肿瘤化疗与放射病科
|
||||
13910093201,王欣,北京大学第三医院,眼科
|
||||
13683587263,鲁胜楠,北京大学第三医院,运动医学科
|
||||
15811169856,修萌,北京大学第三医院,肿瘤化疗与放射病科
|
||||
15611908421,王璐,北京大学第三医院,泌尿
|
||||
15810945282,容晓莹,北京大学第三医院,麻醉科
|
||||
13811958963,易福梅,北京大学第三医院,肿瘤化疗与放射病科
|
||||
17778024393,熊振成,北京大学第三医院,胸外科
|
||||
18618451603,宁英泽,北京大学第三医院,胸外科
|
||||
15652930253,林楚童,北京大学第三医院,胸外科
|
||||
19800308315,张秩荻,北京大学第三医院,耳鼻喉科
|
||||
15210197219,严超,北京大学第三医院,耳鼻喉
|
||||
13901193611,杨楠,北京大学第三医院,输血科
|
||||
13520272493,贾博奇,北京大学第三医院,医学工程处
|
||||
15001393084,李倩,北京大学第三医院,肿瘤化疗与放射病科
|
||||
13683207954,皮彦斌,北京大学第三医院,运动医学科
|
||||
13521135624,乔红梅,北京大学第三医院,呼吸科
|
||||
13810944609,王旖旆,北京大学第三医院,医院管理研究所/医务处互联网医院
|
||||
13366621285,乐云逸,北京大学第三医院,内分泌
|
||||
13716382577,杨纨,北京大学第三医院,生殖中心
|
||||
18811199268,解紫钧,北京大学第三医院,眼科
|
||||
13146119710,王凯,北京大学第三医院,呼吸二病房
|
||||
13641391234,张雁林,北京大学第三医院,职业病科
|
||||
13801018940,赵传多,北京大学第三医院,胸外科
|
||||
13810369383,朱明珂,北京大学第三医院,呼吸与危重症医学科
|
||||
15534245986,高旭,北京大学第三医院,感染疾病科
|
||||
18611103019,陈立雪,北京大学第三医院,生殖中心
|
||||
13366448899,庞新亚,北京大学第三医院,胸外科
|
||||
13522535950,汪大伟,北京大学第三医院,人事处
|
||||
18210066530,吴悦,北京大学第三医院,运动医学
|
||||
13466734131,李小涵,北京大学第三医院,机场住院管理中心
|
||||
18627743603,王苏蒙,北京大学第三医院,门诊部
|
||||
18811771533,郭晨霞,北京大学第三医院,呼吸与危重医学科
|
||||
13811854669,刘敬,北京大学第三医院,眼科
|
||||
13616555411,潘佳飞,北京大学第三医院,运动医学科
|
||||
18811097321,赵赞梅,北京大学第三医院,职业病科
|
||||
15001341733,张丛溪,北京大学第三医院,呼吸科
|
||||
13466681757,徐东晓,北京大学第三医院,心内科
|
||||
18612209826,索玲格,北京大学第三医院,眼科
|
||||
18613891959,王蒙,北京大学第三医院,呼吸科
|
||||
13651315864,杨琨,北京大学第三医院,内分泌科
|
||||
13810700702,耿轩,北京大学第三医院,感染疾病科
|
||||
18600640125,申展,北京大学第三医院,眼科
|
||||
13811934661,汪恒,北京大学第三医院,教育处
|
||||
13681384037,张文慧,北京大学第三医院,内分泌科
|
||||
16601101165,王媛媛,北京大学第三医院,妇产科
|
||||
13810970463,何明燕,北京大学第三医院,眼科
|
||||
18518079113,耿春静,北京大学第三医院,麻醉科
|
||||
18810598535,吴天晨,北京大学第三医院,妇产科
|
||||
18210815929,王佳韵,北京大学第三医院,心内科
|
||||
13641088743,徐欣月,北京大学第三医院,心血管内科
|
||||
18511712197,王郝霖霖,北京大学第三医院,心血管内科
|
||||
13910248978,董玥,北京大学第三医院,心内科
|
||||
13683325888,贾珊,北京大学第三医院,医疗美容科
|
||||
13050775099,吴奕璇,北京大学第三医院,生殖中心
|
||||
15001245084,金司爻,北京大学第三医院,药学部
|
||||
13439199415,张莹,北京大学第三医院,疾病预防控制处
|
||||
18710002823,吉喆,北京大学第三医院,肿瘤放疗科
|
||||
18811569934,陈广辉,北京大学第三医院,骨科
|
||||
15501117899,邢珍珍,北京大学第三医院,职业病科
|
||||
15010299379,隋鑫宇,北京大学第三医院,心血管内科
|
||||
18210500535,杨振锟,北京大学第三医院,口腔科
|
||||
13651309071,秦京京,北京大学第三医院,全科
|
||||
13121969380,王松,北京大学第三医院,肾内科
|
||||
18811602096,韩悦,北京大学第三医院,全科医学科
|
||||
13910149228,杨振华,北京大学第三医院,全科医学科
|
||||
13146521125,田金金,北京大学第三医院,体检中心
|
||||
15101597802,王秀会,北京大学第三医院,健康医学科
|
||||
17812168102,宋一帆,北京大学第三医院,全科
|
||||
15117919257,刘珊,北京大学第三医院,健康医学科
|
||||
18701003211,张涛涛,北京大学第三医院,体检中心
|
||||
15652930820,孙晓燕,北京大学第三医院,呼吸
|
||||
19801109952,李彤昕,北京大学第三医院,全科医学科
|
||||
18813037896,李丹,北京大学第三医院,全科医学科
|
||||
18310189257,王晶,北京大学第三医院,心血管内科
|
||||
18610218375,孟亚男,北京大学第三医院,呼吸内科一病房
|
||||
13911533466,张浩琳,北京大学第三医院,中医科
|
||||
13521181273,张星雨,北京大学第三医院,心血管内科
|
||||
13810002686,田勍,北京大学第三医院,内分泌
|
||||
15101021070,魏蕊,北京大学第三医院,内分泌
|
||||
15201303542,姚艳红,北京大学第三医院,肿瘤化疗科
|
||||
13366373225,刘爱华,北京大学第三医院,内分泌科
|
||||
13141213609,马兰,北京大学第三医院,血液科
|
||||
18811771268,汪羚利,北京大学第三医院,血液科
|
||||
13651391951,王闻博,北京大学第三医院,内分泌科
|
||||
13810349928,杨硕,北京大学第三医院,生殖医学科
|
||||
13381281669,闫燕,北京大学第三医院,耳鼻喉
|
||||
13513235782,王悦,北京大学第三医院,内分泌
|
||||
18810887828,张少存,北京大学第三医院,风湿免疫科
|
||||
13126863268,王琛,北京大学第三医院,风湿免疫科
|
||||
13396234497,郭苇,北京大学第三医院,风湿免疫科
|
||||
18600213506,王月麟,北京大学第三医院,眼科
|
||||
18911576658,翟佳羽,北京大学第三医院,风湿免疫科
|
||||
18610121529,王钰,北京大学第三医院,妇科
|
||||
18610121529,王钰,北京大学第三医院,妇科
|
||||
13426248158,周庆涛,北京大学第三医院,呼吸内科
|
||||
15201304342,刘绍清,北京大学第三医院,口腔科
|
||||
13269309414,田小蒙,北京大学第三医院,生殖中心
|
||||
18600017812,赵威,北京大学第三医院,心血管内科、全科医学科
|
||||
13466393220,武睿,北京大学第三医院,病理科
|
||||
13701010401,贺慧颖,北京大学第三医院,病理科
|
||||
15810390491,姚瑶,北京大学第三医院,病理科
|
||||
18801235695,李丹阳,北京大学第三医院,病理科
|
||||
18754278830,季惠惠,北京大学第三医院,病理科
|
||||
13810648499,郑丹枫,北京大学第三医院,病理科
|
||||
13683697009,梅放,北京大学第三医院,病理科
|
||||
13488692897,王惠,北京大学第三医院,病理科
|
||||
15626042244,宋子秀,北京大学第三医院,病理科
|
||||
13651215671,刘从容,北京大学第三医院,病理
|
||||
13269029317,裴斐,北京大学第三医院,病理科
|
||||
18811331969,王玮,北京大学第三医院,病理科
|
||||
15611908149,刘岩,北京大学第三医院,病理科
|
||||
13801211548,杨菁,北京大学第三医院,病理科
|
||||
15210025586,刘士榕,北京大学第三医院,超声医学科
|
||||
13601197736,张雪莹,北京大学第三医院,人事处
|
||||
18610883971,应华,北京大学第三医院,感染疾病科
|
||||
18610883971,应华,北京大学第三医院,感染疾病科
|
||||
18610377492,刘蕊,北京大学第三医院,风湿免疫科
|
||||
18810533283,胡阿锦,北京大学第三医院,病理科
|
||||
13910627163,崔立刚,北京大学第三医院,超声医学科
|
||||
13810920592,高皓宇,北京大学第三医院,医院感染管理处
|
||||
15652249516,白易,北京大学第三医院,医院感染管理处
|
||||
13581530835,王少利,北京大学第三医院,医院感染管理处
|
||||
13681085393,冯香凝,北京大学第三医院,采购管理中心
|
||||
|
36
docs/06-测试文档/第2批.csv
Normal file
36
docs/06-测试文档/第2批.csv
Normal file
@@ -0,0 +1,36 @@
|
||||
手机号,姓名,医院,部门
|
||||
13426376041,彭荣梅,北京大学第三医院,眼科
|
||||
18704316131,蔡熙颖,北京大学第三医院,肿瘤放疗科
|
||||
18132126695,王振宇,北京大学第三医院,肿瘤放疗科
|
||||
19811941420,林坤鸿,北京大学第三医院,儿科
|
||||
18340806465,张勇跃,北京大学第三医院,超声医学科
|
||||
18954565721,王子谦,北京大学第三医院,药剂科
|
||||
18519393450,李坤宇,北京大学第三医院,药剂科
|
||||
13311129801,郑雷刚,北京大学第三医院,
|
||||
18510599667,曲瑞泽,北京大学第三医院,普通外科
|
||||
15662689682,李夏蕾,北京大学第三医院,药剂科
|
||||
13960956506,池苗苗,北京大学第三医院,眼科
|
||||
15611675306,包慧君,北京大学第三医院,
|
||||
18801482074,赵英涵,北京大学第三医院,眼科
|
||||
18212101606,刘德福,北京大学第三医院,
|
||||
19516628985,孙晨哲,北京大学第三医院,
|
||||
18656031676,徐晨,北京大学第三医院,
|
||||
13340057914,陈佳钰,北京大学第三医院,超声医学科
|
||||
15001284388,姚泰康,北京大学第三医院,呼吸与危重症医学科
|
||||
18701180277,宋欣然,北京大学第三医院,
|
||||
18810024263,李熳,北京大学第三医院,消化科
|
||||
13280719719,李睿宁,北京大学第三医院,心血管内科
|
||||
18897919950,范锐,北京大学第三医院,耳鼻喉科
|
||||
15960291363,兰麒锋,北京大学第三医院,
|
||||
18927505128,胡安一,北京大学第三医院,
|
||||
13247015825,范勇兵,北京大学第三医院,心血管内科
|
||||
17596528648,裴康佳,北京大学第三医院,肿瘤放疗科
|
||||
1809314065,王银雪,北京大学第三医院,妇产科
|
||||
17866625865,刘帅,北京大学第三医院,泌尿外科
|
||||
17867180629,武瑞,北京大学第三医院,全科医学科
|
||||
13554870161,丁婧,北京大学第三医院,眼科
|
||||
18518981091,罗仁杰,北京大学第三医院,普通外科
|
||||
15897841227,柏佳丽,北京大学第三医院,妇产科
|
||||
13683324481,汤亚南,北京大学第三医院,儿科
|
||||
13699255070,杨路,北京大学第三医院,超声科
|
||||
18377792128,褚岚和,北京大学第三医院,呼吸科
|
||||
|
215
docs/08-项目管理/旧版本系统/服务器与数据库配置说明.md
Normal file
215
docs/08-项目管理/旧版本系统/服务器与数据库配置说明.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# 旧版本系统 - 服务器与数据库配置说明
|
||||
|
||||
> 最后更新:2026-02-15
|
||||
|
||||
---
|
||||
|
||||
## 1. 服务器信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 服务器地址 | `8.154.22.149` |
|
||||
| 操作系统 | Linux (Ubuntu) |
|
||||
| 数据库类型 | MariaDB |
|
||||
| 数据库端口 | 3306 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库连接信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 连接地址 | `jdbc:mysql://127.0.0.1:3306/xzyx_online?characterEncoding=utf8` |
|
||||
| 数据库名 | `xzyx_online` |
|
||||
| 用户名 | `xzyx_rw` |
|
||||
| 密码 | `SKJfdwalkd` |
|
||||
|
||||
### 命令行连接方式
|
||||
|
||||
```bash
|
||||
# SSH 登录服务器
|
||||
ssh root@8.154.22.149
|
||||
|
||||
# 连接数据库
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 用户表结构 (u_user_info)
|
||||
|
||||
### 核心字段
|
||||
|
||||
| 字段 | 类型 | 说明 | 后台显示名 |
|
||||
|------|------|------|-----------|
|
||||
| `id` | int(11) | 主键,自增 | - |
|
||||
| `phone` | varchar(20) | 手机号(登录账号)**必填** | 账号 |
|
||||
| `nickname` | varchar(40) | 昵称 | 昵称 |
|
||||
| `real_name` | varchar(45) | 真实姓名 | - |
|
||||
| `hospital` | varchar(255) | 固定值 "本地" | - |
|
||||
| `company` | varchar(200) | **实际的机构/医院名称** | 医院 |
|
||||
| `academy` | varchar(200) | **部门** | 部门 |
|
||||
| `user_role` | varchar(20) | 用户角色,默认 "NORMAL" | 用户角色 |
|
||||
| `user_status` | varchar(45) | 用户状态,默认 "NORMAL" | - |
|
||||
| `password` | varchar(45) | 密码(MD5加密) | - |
|
||||
| `hosptial_id` | int(11) | 医院ID,默认 0 | - |
|
||||
| `email_validate_status` | tinyint(4) | 邮箱验证状态,默认 0 | - |
|
||||
| `register_time` | int(11) | 注册时间(Unix时间戳) | - |
|
||||
|
||||
### 字段对应关系
|
||||
|
||||
| 后台显示 | 数据库字段 |
|
||||
|----------|-----------|
|
||||
| 账号 | `phone` |
|
||||
| 昵称 | `nickname` + `real_name` |
|
||||
| 用户角色:普通 | `user_role = 'NORMAL'` |
|
||||
| 医院 | `company`(注意:不是 hospital 字段) |
|
||||
| 部门 | `academy` |
|
||||
|
||||
### 默认密码
|
||||
|
||||
- 明文:`123456`
|
||||
- MD5:`E10ADC3949BA59ABBE56E057F20F883E`
|
||||
|
||||
---
|
||||
|
||||
## 4. 批量导入用户操作指南
|
||||
|
||||
### 步骤1:准备 CSV 文件
|
||||
|
||||
格式要求:
|
||||
|
||||
```csv
|
||||
手机号,姓名,医院,部门
|
||||
13800000001,张三,北京大学第三医院,骨科
|
||||
13800000002,李四,医朵云,医学部
|
||||
```
|
||||
|
||||
### 步骤2:检查重复手机号
|
||||
|
||||
```bash
|
||||
# 导出现有手机号
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -N -e "SELECT phone FROM u_user_info;" > /tmp/existing_phones.txt
|
||||
|
||||
# 查看现有用户数量
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "SELECT COUNT(*) FROM u_user_info;"
|
||||
```
|
||||
|
||||
### 步骤3:生成 SQL 插入语句
|
||||
|
||||
单条插入模板:
|
||||
|
||||
```sql
|
||||
INSERT INTO u_user_info (
|
||||
phone,
|
||||
nickname,
|
||||
real_name,
|
||||
hospital,
|
||||
company,
|
||||
academy,
|
||||
user_role,
|
||||
user_status,
|
||||
password,
|
||||
hosptial_id,
|
||||
email_validate_status,
|
||||
register_time
|
||||
) VALUES (
|
||||
'手机号',
|
||||
'姓名',
|
||||
'姓名',
|
||||
'本地',
|
||||
'机构名称',
|
||||
'部门',
|
||||
'NORMAL',
|
||||
'NORMAL',
|
||||
'E10ADC3949BA59ABBE56E057F20F883E',
|
||||
0,
|
||||
0,
|
||||
UNIX_TIMESTAMP()
|
||||
);
|
||||
```
|
||||
|
||||
批量插入模板(使用 INSERT IGNORE 避免重复报错):
|
||||
|
||||
```sql
|
||||
INSERT IGNORE INTO u_user_info (phone, nickname, real_name, hospital, company, academy, user_role, user_status, password, hosptial_id, email_validate_status, register_time) VALUES
|
||||
('13800000001', '张三', '张三', '本地', '北京大学第三医院', '骨科', 'NORMAL', 'NORMAL', 'E10ADC3949BA59ABBE56E057F20F883E', 0, 0, UNIX_TIMESTAMP()),
|
||||
('13800000002', '李四', '李四', '本地', '医朵云', '医学部', 'NORMAL', 'NORMAL', 'E10ADC3949BA59ABBE56E057F20F883E', 0, 0, UNIX_TIMESTAMP());
|
||||
```
|
||||
|
||||
### 步骤4:上传并执行 SQL
|
||||
|
||||
```bash
|
||||
# 上传 SQL 文件到服务器(或使用 nano 创建)
|
||||
nano /tmp/batch_insert_users.sql
|
||||
|
||||
# 执行 SQL 文件
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online < /tmp/batch_insert_users.sql
|
||||
```
|
||||
|
||||
### 步骤5:验证导入结果
|
||||
|
||||
```bash
|
||||
# 查询指定机构的用户数量
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "SELECT COUNT(*) as '用户数' FROM u_user_info WHERE company = '北京大学第三医院';"
|
||||
|
||||
# 抽查用户数据
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "SELECT id, phone, nickname, company, academy FROM u_user_info WHERE company = '北京大学第三医院' LIMIT 10;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 常用查询命令
|
||||
|
||||
### 查看所有表
|
||||
|
||||
```bash
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "SHOW TABLES;"
|
||||
```
|
||||
|
||||
### 查看表结构
|
||||
|
||||
```bash
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "DESC u_user_info;"
|
||||
```
|
||||
|
||||
### 根据手机号查询用户
|
||||
|
||||
```bash
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "SELECT * FROM u_user_info WHERE phone = '18611348738'\G"
|
||||
```
|
||||
|
||||
### 修改用户信息
|
||||
|
||||
```bash
|
||||
# 修改手机号
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "UPDATE u_user_info SET phone = '新手机号' WHERE phone = '旧手机号';"
|
||||
|
||||
# 重置密码为 123456
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "UPDATE u_user_info SET password = 'E10ADC3949BA59ABBE56E057F20F883E' WHERE phone = '手机号';"
|
||||
```
|
||||
|
||||
### 删除用户
|
||||
|
||||
```bash
|
||||
mysql -u xzyx_rw -p'SKJfdwalkd' -h 127.0.0.1 xzyx_online -e "DELETE FROM u_user_info WHERE phone = '手机号';"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 已导入批次记录
|
||||
|
||||
| 批次 | 日期 | 机构 | 数量 | SQL文件 |
|
||||
|------|------|------|------|---------|
|
||||
| 第1批 | 2026-02-15 | 北京大学第三医院 | 225 | `docs/06-测试文档/batch_insert_users.sql` |
|
||||
| 第2批 | 2026-02-15 | 北京大学第三医院 | 35 | `docs/06-测试文档/batch_insert_users_2.sql` |
|
||||
|
||||
---
|
||||
|
||||
## 7. 注意事项
|
||||
|
||||
1. **手机号唯一性**:手机号是用户的唯一登录凭证,不能重复
|
||||
2. **密码存储**:使用 MD5 加密,默认密码 123456 对应 `E10ADC3949BA59ABBE56E057F20F883E`
|
||||
3. **hospital 字段**:固定填写 "本地",实际医院名称存储在 `company` 字段
|
||||
4. **部门字段**:使用 `academy` 字段存储
|
||||
5. **使用 INSERT IGNORE**:批量导入时使用此语法,遇到重复手机号自动跳过不报错
|
||||
Reference in New Issue
Block a user