Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/02-技术设计/数据库设计文档-DC模块(完整版).md
HaHafeng 8a17369138 feat(dc): Complete Tool B MVP with full API integration and bug fixes
Phase 5: Export Feature
- Add Excel export API endpoint (GET /tasks/:id/export)
- Fix Content-Disposition header encoding for Chinese filenames
- Fix export field order to match template definition
- Export finalResult or resultA as fallback

API Integration Fixes (Phase 1-5):
- Fix API response parsing (return result.data consistently)
- Fix field name mismatch (fileKey -> sourceFileKey)
- Fix Excel parsing bug (range:99 -> slice(0,100))
- Add file upload with Excel parsing (columns, totalRows)
- Add detailed error logging for debugging

LLM Integration Fixes:
- Fix LLM call method: LLMFactory.createLLM -> getAdapter
- Fix adapter interface: generateText -> chat([messages])
- Fix response fields: text -> content, tokensUsed -> usage.totalTokens
- Fix model names: qwen-max -> qwen3-72b

React Infinite Loop Fixes:
- Step2: Remove updateState from useEffect deps
- Step3: Add useRef to prevent Strict Mode double execution
- Step3: Clear interval on API failure (max 3 retries)
- Step4: Add useRef to prevent infinite data loading
- Add cleanup functions to all useEffect hooks

Frontend Enhancements:
- Add comprehensive error handling with user-friendly messages
- Remove debug console.logs (production ready)
- Fix TypeScript type definitions (TaskProgress, ExtractionItem)
- Improve Step4Verify data transformation logic

Backend Enhancements:
- Add detailed logging at each step for debugging
- Add parameter validation in controllers
- Improve error messages with stack traces (dev mode)
- Add export field ordering by template definition

Documentation Updates:
- Update module status: Tool B MVP completed
- Create MVP completion summary (06-开发记录)
- Create technical debt document (07-技术债务)
- Update API documentation with test status
- Update database documentation with verified status
- Update system overview with DC module status
- Document 4 known issues (Excel preprocessing, progress display, etc.)

Testing Results:
- File upload: 9 rows parsed successfully
- Health check: Column validation working
- Dual model extraction: DeepSeek-V3 + Qwen-Max both working
- Processing time: ~49s for 9 records (~5s per record)
- Token usage: ~10k tokens total (~1.1k per record)
- Conflict detection: 1 clean, 8 conflicts (88.9% conflict rate)
- Excel export: Working with proper encoding

Files Changed:
Backend (~500 lines):
- ExtractionController.ts: Add upload endpoint, improve logging
- DualModelExtractionService.ts: Fix LLM call methods, add detailed logs
- HealthCheckService.ts: Fix Excel range parsing
- routes/index.ts: Add upload route

Frontend (~200 lines):
- toolB.ts: Fix API response parsing, add error handling
- Step1Upload.tsx: Integrate upload and health check APIs
- Step2Schema.tsx: Fix infinite loop, load templates from API
- Step3Processing.tsx: Fix infinite loop, integrate progress polling
- Step4Verify.tsx: Fix infinite loop, transform backend data correctly
- Step5Result.tsx: Integrate export API
- index.tsx: Add file metadata to state

Scripts:
- check-task-progress.mjs: Database inspection utility

Docs (~8 files):
- 00-模块当前状态与开发指南.md: Update to v2.0
- API设计文档.md: Mark all endpoints as tested
- 数据库设计文档.md: Update verification status
- DC模块Tool-B开发计划.md: Add MVP completion notice
- DC模块Tool-B开发任务清单.md: Update progress to 100%
- Tool-B-MVP完成总结.md: New completion summary
- Tool-B技术债务清单.md: New technical debt document
- 00-系统当前状态与开发指南.md: Update DC module status

Status: Tool B MVP complete and production ready
2025-12-03 15:07:39 +08:00

14 KiB
Raw Blame History

数据库设计文档 - 工具B病历结构化机器人

模块: DC数据清洗整理 - 工具B
版本: V2.0 (MVP)
Schema: dc_schema
更新日期: 2025-12-03
状态: MVP完成已验证可用真实数据测试通过


📋 目录


一、概述

1.1 设计目标

工具B的数据库设计旨在支持

  • 双大模型交叉验证的文本结构化
  • 大规模异步任务处理1000+条记录)
  • 冲突检测与人工裁决
  • 预设模板管理与复用
  • 健康检查缓存优化

1.2 表关系总览

dc_schema ✅ 已创建并运行中
├── dc_health_checks          [健康检查缓存] ✅ 运行正常
├── dc_templates              [预设模板] ✅ 3个预设模板可用
├── dc_extraction_tasks       [提取任务] ✅ 已完成多个任务
│   └── dc_extraction_items   [提取记录] (1:N) ✅ 双模型结果正常保存

MVP完成状态2025-12-03

  • 所有表正常工作,已处理多个真实任务
  • 3个预设模板肺癌病理报告、糖尿病入院记录、高血压门诊病历
  • 真实测试9条病理数据提取成功100%成功率
  • 双模型结果resultA、resultB、finalResult字段正常保存
  • Token统计totalTokens字段正常累加
  • 冲突检测conflictFields数组正常工作
  • 验证脚本:backend/scripts/check-task-progress.mjs

1.3 技术栈

  • 数据库: PostgreSQL 15
  • ORM: Prisma 6
  • Schema隔离: dc_schema(独立命名空间)
  • JSON字段: 使用JSONB类型高性能查询

二、Schema设计原则

2.1 Schema隔离

-- 所有表使用dc_schema命名空间
CREATE TABLE "dc_schema"."dc_health_checks" (...);
CREATE TABLE "dc_schema"."dc_extraction_tasks" (...);

优势

  • 与其他模块完全隔离platform_schema、asl_schema等
  • 数据安全,避免误操作
  • 便于模块化管理和迁移

2.2 命名规范

规则 说明 示例
表名前缀 dc_ dc_extraction_tasks
字段命名 snake_case user_id, source_file_key
时间戳 统一后缀 created_at, started_at
外键 实体名_id task_id, user_id

2.3 JSONB字段使用场景

字段 类型 原因
target_fields JSONB 灵活的字段配置
result_a/result_b JSONB 动态提取结果
final_result JSONB 最终裁决结果

三、数据表设计

3.1 dc_health_checks健康检查缓存表

用途: 缓存健康检查结果,避免重复计算

CREATE TABLE "dc_schema"."dc_health_checks" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "user_id" TEXT NOT NULL,
    "file_name" TEXT NOT NULL,
    "column_name" TEXT NOT NULL,
    
    -- 统计指标
    "empty_rate" DOUBLE PRECISION NOT NULL,
    "avg_length" DOUBLE PRECISION NOT NULL,
    "total_rows" INTEGER NOT NULL,
    "estimated_tokens" INTEGER NOT NULL,
    
    -- 检查结果
    "status" TEXT NOT NULL,  -- 'good' | 'bad'
    "message" TEXT NOT NULL,
    
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);

字段说明

字段 类型 说明 示例
id TEXT UUID主键 uuid()
user_id TEXT 用户ID user-123
file_name TEXT 文件名 患者数据.xlsx
column_name TEXT 检查的列名 病历文本
empty_rate DOUBLE 空值率 (0-1) 0.15 (15%)
avg_length DOUBLE 平均文本长度 256.8
total_rows INT 总行数 500
estimated_tokens INT 预估Token数 150000
status TEXT 健康状态 good / bad
message TEXT 提示信息 健康度良好

索引

CREATE INDEX "dc_health_checks_user_id_file_name_idx" 
ON "dc_schema"."dc_health_checks"("user_id", "file_name");

业务规则

  • 空值率 > 80% → status = 'bad'
  • 平均长度 < 10 → status = 'bad'
  • 缓存有效期24小时应用层实现

3.2 dc_templates预设模板表

用途: 存储疾病类型的预设提取模板

CREATE TABLE "dc_schema"."dc_templates" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "disease_type" TEXT NOT NULL,    -- 'lung_cancer', 'diabetes', 'hypertension'
    "report_type" TEXT NOT NULL,     -- 'pathology', 'admission', 'outpatient'
    "display_name" TEXT NOT NULL,    -- '肺癌病理报告'
    "fields" JSONB NOT NULL,         -- [{name, desc, width}]
    "prompt_template" TEXT NOT NULL,
    
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMP(3) NOT NULL,
    
    CONSTRAINT "dc_templates_disease_type_report_type_key" 
        UNIQUE ("disease_type", "report_type")
);

字段说明

字段 类型 说明 示例
disease_type TEXT 疾病类型 lung_cancer
report_type TEXT 报告类型 pathology
display_name TEXT 显示名称 肺癌病理报告
fields JSONB 提取字段配置 见下方示例
prompt_template TEXT Prompt模板 请从以下病理报告中提取...

fields字段结构

[
  {
    "name": "病理类型",
    "desc": "如:浸润性腺癌、鳞状细胞癌",
    "width": "w-40"
  },
  {
    "name": "分化程度",
    "desc": "高/中/低分化",
    "width": "w-32"
  }
]

唯一约束

UNIQUE ("disease_type", "report_type")

同一疾病+报告类型组合只能有一个模板


3.3 dc_extraction_tasks提取任务表

用途: 管理批量提取任务,追踪进度和成本

CREATE TABLE "dc_schema"."dc_extraction_tasks" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "user_id" TEXT NOT NULL,
    "project_name" TEXT NOT NULL,
    "source_file_key" TEXT NOT NULL,  -- Storage中的路径
    "text_column" TEXT NOT NULL,
    
    -- 模板配置
    "disease_type" TEXT NOT NULL,
    "report_type" TEXT NOT NULL,
    "target_fields" JSONB NOT NULL,
    
    -- 双模型配置
    "model_a" TEXT NOT NULL DEFAULT 'deepseek-v3',
    "model_b" TEXT NOT NULL DEFAULT 'qwen3-72b',
    
    -- 任务状态
    "status" TEXT NOT NULL DEFAULT 'pending',
    "total_count" INTEGER NOT NULL DEFAULT 0,
    "processed_count" INTEGER NOT NULL DEFAULT 0,
    "clean_count" INTEGER NOT NULL DEFAULT 0,
    "conflict_count" INTEGER NOT NULL DEFAULT 0,
    "failed_count" INTEGER NOT NULL DEFAULT 0,
    
    -- 成本统计
    "total_tokens" INTEGER NOT NULL DEFAULT 0,
    "total_cost" DOUBLE PRECISION NOT NULL DEFAULT 0,
    
    -- 错误信息
    "error" TEXT,
    
    -- 时间戳
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "started_at" TIMESTAMP(3),
    "completed_at" TIMESTAMP(3)
);

字段说明

字段 类型 说明 示例
source_file_key TEXT Storage路径 uploads/user123/data.xlsx
text_column TEXT 文本列名 病历文本
target_fields JSONB 提取字段 [{name, desc}]
status TEXT 任务状态 pending/processing/completed/failed
total_count INT 总记录数 500
processed_count INT 已处理数 250
clean_count INT 一致数 200
conflict_count INT 冲突数 45
failed_count INT 失败数 5
total_tokens INT 总Token数 150000
total_cost DOUBLE 总成本($) 0.27

状态流转

pending → processing → completed
                     → failed

索引

CREATE INDEX "dc_extraction_tasks_user_id_status_idx" 
ON "dc_schema"."dc_extraction_tasks"("user_id", "status");

3.4 dc_extraction_items提取记录表

用途: 存储每条记录的双模型提取结果和冲突状态

CREATE TABLE "dc_schema"."dc_extraction_items" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "task_id" TEXT NOT NULL,
    
    -- 原始数据
    "row_index" INTEGER NOT NULL,
    "original_text" TEXT NOT NULL,
    
    -- 双模型结果
    "result_a" JSONB,
    "result_b" JSONB,
    
    -- 冲突检测
    "status" TEXT NOT NULL DEFAULT 'pending',
    "conflict_fields" TEXT[] DEFAULT ARRAY[]::TEXT[],
    
    -- 最终结果
    "final_result" JSONB,
    
    -- Token统计
    "tokens_a" INTEGER NOT NULL DEFAULT 0,
    "tokens_b" INTEGER NOT NULL DEFAULT 0,
    
    -- 错误信息
    "error" TEXT,
    
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "resolved_at" TIMESTAMP(3),
    
    CONSTRAINT "dc_extraction_items_task_id_fkey" 
        FOREIGN KEY ("task_id") 
        REFERENCES "dc_schema"."dc_extraction_tasks"("id") 
        ON DELETE CASCADE
);

字段说明

字段 类型 说明 示例
row_index INT Excel行号 5
original_text TEXT 原始病历文本 患者45岁...
result_a JSONB DeepSeek结果 {"肿瘤大小": "3cm"}
result_b JSONB Qwen结果 {"肿瘤大小": "3.0cm"}
status TEXT 处理状态 clean/conflict/resolved/failed
conflict_fields TEXT[] 冲突字段列表 ["肿瘤大小"]
final_result JSONB 最终裁决结果 {"肿瘤大小": "3cm"}

result_a/result_b结构示例

{
  "病理类型": "浸润性腺癌",
  "分化程度": "中分化",
  "肿瘤大小": "3cm",
  "淋巴结转移": "无"
}

状态说明

  • pending: 等待处理
  • clean: 双模型结果一致
  • conflict: 存在冲突,需人工裁决
  • resolved: 冲突已解决
  • failed: 提取失败

索引

CREATE INDEX "dc_extraction_items_task_id_status_idx" 
ON "dc_schema"."dc_extraction_items"("task_id", "status");

外键约束

  • ON DELETE CASCADE: 删除任务时自动删除所有记录

四、索引设计

4.1 索引列表

表名 索引字段 类型 用途
dc_health_checks (user_id, file_name) 复合 查询用户的历史检查
dc_templates (disease_type, report_type) 唯一 防止重复模板
dc_extraction_tasks (user_id, status) 复合 查询用户的任务列表
dc_extraction_items (task_id, status) 复合 查询任务的记录列表

4.2 性能考虑

查询优化

-- 高效查询:利用索引
SELECT * FROM dc_extraction_tasks 
WHERE user_id = 'user123' AND status = 'processing';

-- 高效查询:利用索引
SELECT * FROM dc_extraction_items 
WHERE task_id = 'task456' AND status = 'conflict';

避免全表扫描

  • 始终在WHERE子句中包含索引字段
  • 使用status字段过滤可以显著减少扫描行数

五、外键约束

5.1 级联删除

ALTER TABLE "dc_schema"."dc_extraction_items" 
ADD CONSTRAINT "dc_extraction_items_task_id_fkey" 
FOREIGN KEY ("task_id") 
REFERENCES "dc_schema"."dc_extraction_tasks"("id") 
ON DELETE CASCADE;

行为

  • 删除任务 → 自动删除所有关联的提取记录
  • 保证数据一致性

5.2 无外键的表

  • dc_health_checks: 独立表,无外键
  • dc_templates: 独立表,无外键
  • dc_extraction_tasks: 无外键user_id仅为标识不强制关联

原因

  • 减少跨Schema依赖
  • 提高模块独立性
  • 简化迁移和回滚

六、数据生命周期

6.1 数据保留策略

表名 保留时间 清理策略
dc_health_checks 7天 定期清理旧记录
dc_templates 永久 手动管理
dc_extraction_tasks 90天 归档后删除
dc_extraction_items 90天 随任务删除

6.2 归档策略

大任务归档 (> 1000条记录)

  1. 任务完成后导出结果到CSV/Excel
  2. 上传到Storage永久保存
  3. 删除数据库记录(释放空间)

6.3 清理脚本(示例)

// 清理7天前的健康检查记录
await prisma.dCHealthCheck.deleteMany({
  where: {
    createdAt: {
      lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
    }
  }
});

// 归档90天前的已完成任务
const oldTasks = await prisma.dCExtractionTask.findMany({
  where: {
    status: 'completed',
    completedAt: {
      lt: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000)
    }
  },
  include: { items: true }
});

// 导出后删除
for (const task of oldTasks) {
  await exportTaskToStorage(task);
  await prisma.dCExtractionTask.delete({ where: { id: task.id } });
}

七、数据安全

7.1 PII保护

敏感字段

  • original_text: 可能包含患者姓名、身份证号
  • result_a/result_b/final_result: 可能包含结构化的敏感信息

保护措施

  • 发送LLM前自动脱敏PIIMaskUtil
  • 数据库加密PostgreSQL SSL
  • 定期清理历史数据

7.2 用户隔离

机制

  • 所有表包含user_id字段
  • 应用层强制过滤:WHERE user_id = currentUserId
  • 永不跨用户查询

八、附录

8.1 完整Schema DDL

完整的Schema创建脚本位于

backend/prisma/migrations/20251127_add_dc_tool_b_tables/migration.sql

8.2 Prisma模型定义

完整的Prisma模型定义位于

backend/prisma/schema.prisma

搜索 dc_schema 查看所有模型。

8.3 变更历史

版本 日期 变更内容
V1.0 2025-11-27 初始版本4个表

文档结束