diff --git a/DC模块代码恢复指南.md b/DC模块代码恢复指南.md
index 007f7496..566bce66 100644
--- a/DC模块代码恢复指南.md
+++ b/DC模块代码恢复指南.md
@@ -222,3 +222,4 @@
+
diff --git a/backend/recover-code-from-cursor-db.js b/backend/recover-code-from-cursor-db.js
index aa106518..829e2085 100644
--- a/backend/recover-code-from-cursor-db.js
+++ b/backend/recover-code-from-cursor-db.js
@@ -179,3 +179,4 @@ function extractCodeBlocks(obj, blocks = []) {
+
diff --git a/backend/scripts/check-dc-tables.mjs b/backend/scripts/check-dc-tables.mjs
index a197dd41..5b2af70a 100644
--- a/backend/scripts/check-dc-tables.mjs
+++ b/backend/scripts/check-dc-tables.mjs
@@ -198,3 +198,4 @@ async function checkDCTables() {
checkDCTables();
+
diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts
index 5c571dde..f16232d8 100644
--- a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts
+++ b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts
@@ -302,3 +302,4 @@ runTests().catch((error) => {
+
diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts
index 3d568284..026cbdaa 100644
--- a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts
+++ b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts
@@ -243,3 +243,4 @@ runTest()
+
diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http
index 1ff705e6..ff1b6d79 100644
--- a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http
+++ b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http
@@ -281,3 +281,4 @@ Content-Type: application/json
+
diff --git a/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts b/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts
index 5f0ce885..da779300 100644
--- a/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts
+++ b/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts
@@ -360,3 +360,4 @@ export class ExcelExporter {
+
diff --git a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts
index 5eb7e21f..55c65304 100644
--- a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts
+++ b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts
@@ -217,3 +217,4 @@ export const conflictDetectionService = new ConflictDetectionService();
+
diff --git a/backend/src/modules/dc/tool-b/services/TemplateService.ts b/backend/src/modules/dc/tool-b/services/TemplateService.ts
index ac2065a2..8fdf2103 100644
--- a/backend/src/modules/dc/tool-b/services/TemplateService.ts
+++ b/backend/src/modules/dc/tool-b/services/TemplateService.ts
@@ -245,3 +245,4 @@ export const templateService = new TemplateService();
+
diff --git a/backend/sync-dc-database.ps1 b/backend/sync-dc-database.ps1
index af38a3d2..5bb6dfb5 100644
--- a/backend/sync-dc-database.ps1
+++ b/backend/sync-dc-database.ps1
@@ -25,3 +25,4 @@ Write-Host "✅ 完成!" -ForegroundColor Green
+
diff --git a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md
index f996157f..fe031562 100644
--- a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md
+++ b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md
@@ -1242,3 +1242,4 @@ interface FulltextScreeningResult {
+
diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md
index 322436cb..1f88a2ff 100644
--- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md
+++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md
@@ -356,3 +356,4 @@ GET /api/v1/asl/fulltext-screening/tasks/:taskId/export
+
diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md
index 26278967..15b7734f 100644
--- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md
+++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md
@@ -299,3 +299,4 @@ Linter错误:0个
+
diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md
index 5621af70..3fef2af8 100644
--- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md
+++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md
@@ -458,3 +458,4 @@ Failed to open file '\\tmp\\extraction_service\\temp_10000_test.pdf'
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD_工具C_科研数据编辑器_V6.md b/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD_工具C_科研数据编辑器_V6.md
new file mode 100644
index 00000000..1d5aa3aa
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD_工具C_科研数据编辑器_V6.md
@@ -0,0 +1,114 @@
+# **PRD:Tool C \- 科研数据编辑器 (The Research Editor)**
+
+| 文档版本 | V6.0 (AI Code Interpreter 增强版) |
+| :---- | :---- |
+| **产品形态** | Web 端双核编辑器 (GUI 可视化操作 \+ LUI 自然语言交互) |
+| **核心价值** | 将“Excel 的易用性”与“Python 的强大能力”结合。医生既可以通过鼠标点击完成微操,也可以通过自然语言指挥 AI 编写代码完成复杂的清洗任务(如长宽转换、多重插补)。 |
+| **技术底座** | Node.js BFF \+ Python Server-side Sandbox \+ DeepSeek-V3 |
+
+## **一、 产品核心理念 (Core Philosophy)**
+
+### **1.1 双核驱动 (Dual-Core Interaction)**
+
+* **左脑 (GUI):** 提供类似 Excel 的网格和工具栏,适合“直觉式、原子化”的操作(如手动修改一个值、排序、筛选)。
+* **右脑 (AI Copilot):** 提供对话式代码解释器,适合“逻辑性、批量化”的操作(如“把年龄按60岁分箱”、“删除所有空行”、“计算生存时间”)。
+
+### **1.2 可控黑盒 (Controllable Blackbox)**
+
+AI 不直接修改数据,而是**生成 Python 代码**。系统在执行前展示\*\*“预操作卡片”\*\*,由用户确认执行,确保科研数据的严谨性。
+
+## **二、 核心业务流程 (User Flow)**
+
+数据导入 \-\> 双模式清洗 (点击工具栏 OR 对话 AI) \-\> 代码/操作执行 \-\> 实时预览更新 \-\> 版本快照 \-\> 导出结果
+
+## **三、 功能模块详解 (Functional Requirements)**
+
+### **1\. 界面布局 (The Workspace)**
+
+* **P0:** **分栏布局 (Split View):**
+ * **左侧 (70%):** 超级网格 (The Grid),展示数据预览。
+ * **右侧 (30%):** 智能侧边栏 (Smart Sidebar),包含 **\[统计概览\]** 和 **\[AI 助手\]** 两个 Tab。
+* **P0:** **全局状态指示:**
+ * 当 AI 正在思考或后端正在计算时,左侧网格显示 **“AI 处理中...”** 遮罩,并锁定编辑,防止双写冲突。
+
+### **2\. 顶部扁平工具栏 (Flat Toolbar) —— GUI 核心**
+
+*保留高频、标准化的操作入口,作为 AI 的补充。*
+
+* **P0: 变量加工:**
+ * **生成新变量:** 弹窗公式构建器。
+ * **计算时间差:** 内置医学常数 (年=365.25天)。
+ * **生成哑变量:** 回归分析专用。
+ * **横纵表转换 (Pivot):** \* *交互升级:* 点击后不再只是纯前端计算,而是调用后端 Python 逻辑,支持处理更复杂的转换。
+* **P0: 质量治理:**
+ * **查找重复值:** 按 ID 或全字段查重。
+ * **多重插补 (MICE):** 全局入口,调用后端 sklearn 或 fancyimpute 库。
+* **P0: 样本筛选:** 构建入排标准。
+
+### **3\. AI Copilot 智能助手 (The Brain) —— V6 核心升级**
+
+*位于右侧侧边栏的 \[AI 助手\] Tab。*
+
+#### **3.1 自然语言指令解析**
+
+* **P0:** **意图识别:** 支持模糊指令,如“洗一下数据”、“把男变成1”。
+* **P0:** **上下文感知:** AI 能够读取当前的列名 (Metadata) 和前 5 行数据示例,理解数据含义。
+
+#### **3.2 代码解释器模式 (Code Interpreter)**
+
+* **P0:** **代码生成:** AI 针对用户需求,生成可执行的 **Python (Pandas)** 代码块。
+* **P0:** **预操作卡片 (Action Card):**
+ * AI 不直接执行代码。
+ * 界面展示一个卡片:操作类型: 数据分箱 | 目标列: 年龄 | 代码预览。
+ * 按钮:**\[运行代码\]** | **\[取消\]**。
+* **P0:** **执行反馈:**
+ * 执行成功:显示 ✅,左侧表格自动刷新。
+ * 执行失败:AI 自动分析 Error Log,尝试自我修正代码并建议重试。
+
+#### **3.3 典型 AI 场景支持**
+
+* **高级清洗:** “把所有列的异常值(\>3倍标准差)替换为缺失值”。
+* **复杂提取:** “从‘诊断’列中提取出由‘/’分隔的第二部分,生成新列”。
+* **批量处理:** “删除所有缺失率超过 50% 的列”。
+
+### **4\. 智能统计面板 (Insight Panel)**
+
+*位于右侧侧边栏的 \[统计概览\] Tab。*
+
+* **P0:** **列联动:** 点击左侧网格某一列,右侧自动显示该列的分布图(直方图/频次图)。
+* **P0:** **快捷操作:** 图表下方直接提供“填补”、“分箱”、“映射”等快捷按钮。
+
+### **5\. 导出与流转 (Export)**
+
+* **P0:** **结果导出:** 支持 Excel (.xlsx) 和 SPSS (.sav) 格式。
+* **P0:** **操作审计:** 导出的文件中,附带一份 **"清洗日志 (Cleaning Log)"**,记录了所有的 AI 代码和手动操作步骤(用于科研溯源)。
+
+## **四、 数据与性能策略 (Data Strategy)**
+
+### **4.1 性能准入 (Guardrails)**
+
+* **文件大小限制:** 单个文件 **\< 20MB**。
+* **行数限制:** 建议 **\< 50,000 行** 以保证前端渲染流畅度。
+ * *策略:* 后端 Python 可以处理百万行,但前端 AG Grid 仅加载前 100-1000 行作为预览(Preview Mode),导出时才生成全量文件。
+
+### **4.2 安全与隐私**
+
+* **P0:** **沙箱隔离:** AI 生成的 Python 代码必须在服务端的安全沙箱(Docker/SAE)中运行,禁止访问外网和系统文件。
+* **P0:** **数据脱敏:** 确保输入编辑器的数据已在前置环节(工具 B)完成了 PII 脱敏。
+
+## **五、 埋点与统计**
+
+* **AI 采纳率:** 展示 Action Card 后,用户点击“运行”的比例。
+* **代码报错率:** AI 生成的代码在后端执行失败的比例。
+* **常用指令 Top 10:** 统计医生最常对 AI 说的话。
+
+## **六、 附录:AI 指令集示例 (Few-Shot Examples)**
+
+| 用户指令 | AI 动作 (Action) | 生成代码逻辑 (Python Pandas) |
+| :---- | :---- | :---- |
+| "把性别转为数字" | Recode | df\['sex'\] \= df\['sex'\].map({'男':1, '女':0}) |
+| "年龄按60分两组" | Binning | df\['age\_group'\] \= pd.cut(df\['age'\], bins=\[0,60,150\], labels=\['0','1'\]) |
+| "删除没有ID的行" | Filter | df \= df.dropna(subset=\['patient\_id'\]) |
+| "计算BMI" | Formula | df\['bmi'\] \= df\['weight'\] / (df\['height'\]/100)\*\*2 |
+| "把每个人的一行变成多行" | Pivot/Melt | df \= df.melt(id\_vars=\['id'\], ...) |
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD:Tool C - 科研数据编辑器 (MVP V1.1).md b/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD:Tool C - 科研数据编辑器 (MVP V1.1).md
new file mode 100644
index 00000000..9d2e960b
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD:Tool C - 科研数据编辑器 (MVP V1.1).md
@@ -0,0 +1,107 @@
+# **PRD:Tool C \- 科研数据编辑器 (MVP V1.1)**
+
+| 文档版本 | V1.1 (工程细化版) |
+| :---- | :---- |
+| **产品形态** | **Web 端数据编辑器 (AG Grid \+ AI Chat)** |
+| **核心策略** | **"AI-First" \+ "Server-side State"**。依靠 AI 生成 Python 代码完成清洗;以服务端 DataFrame 为单一数据源,前端负责渲染和轻量编辑。 |
+| **技术底座** | React \+ AG Grid \+ Node.js BFF \+ Python Sandbox (FastAPI) \+ DeepSeek-V3 |
+| **变更记录** | V1.1: 增加数据同步机制、撤销回滚策略、会话生命周期定义。 |
+
+## **一、 MVP 核心目标 (Objectives)**
+
+1. **验证闭环:** 跑通 “自然语言 \-\> Python 代码 \-\> 后端执行 \-\> 前端刷新” 的完整链路。
+2. **数据一致性:** 确保手动编辑与 AI 操作不冲突,状态可追溯。
+3. **可用性:** 解决中文乱码、会话超时等实际工程问题。
+
+## **二、 详细功能需求 (Functional Requirements)**
+
+### **1\. 界面框架与会话 (Shell & Session)**
+
+* **P0: 左右分栏布局:** 左侧 AG Grid (70%),右侧 AI Chat (30%)。
+* **P0: 会话初始化 (Session Init):**
+ * 用户上传文件 \-\> 后端开启 Python 进程/容器 \-\> 加载 df \-\> 返回 sessionId。
+ * **编码检测:** 后端必须尝试 utf-8 和 gbk 解码,防止中文乱码。
+* **P1: 心跳与保活 (Keep-alive):**
+ * 前端每 30s 发送心跳。
+ * **超时策略:** 若超过 30min 无操作,后端释放内存。用户再次操作时,提示“会话已过期,请重新加载文件”。
+
+### **2\. 超级网格 (The Grid) \- *前端交互***
+
+* **P0: 数据展示 (View):**
+ * 通过 API 分页拉取数据(预览模式,仅取前 100-500 行)。
+ * **列类型推断:** 前端根据后端返回的 dtypes 渲染列头图标(数值/文本/日期)。
+* **P0: 手动编辑 (Manual Edit):**
+ * 支持双击修改单元格。
+ * **关键逻辑(脏数据标记):** 用户修改后,单元格右标红,数据暂存在前端 dirtyRows 队列中。
+* **P0: 状态锁 (UI Locking):**
+ * 当 AI 正在执行时,Grid 变为 **只读 (Read-only)**,显示 Loading 遮罩。
+
+### **3\. AI Copilot 智能助手 (The Brain) \- *后端驱动***
+
+#### **3.1 交互流程 (Chat Loop)**
+
+1. **用户输入:** “把年龄大于60的设为老年组”。
+2. **前置同步 (Auto-Sync):** **(V1.1 新增)**
+ * **判定:** 前端检查是否有未保存的手动修改 (dirtyRows).
+ * **动作:** 如果有,先静默发送 PATCH /api/data 将手动修改同步给后端 df。确保 AI 基于最新数据操作。
+3. **代码生成:** 后端调用 DeepSeek,生成 Pandas 代码。
+4. **预操作确认 (Action Card):**
+ * 展示:代码预览 \+ 摘要。
+ * 按钮:\[运行\] | \[取消\]。
+
+#### **3.2 执行与回滚 (Execute & Rollback) \- (V1.1 核心)**
+
+* **P0: 自动快照 (Auto-Checkpoint):**
+ * 在执行 exec(code) 之前,后端必须先对当前 df 进行内存快照(或序列化备份)。
+ * 记录操作日志:ActionID: 101, Type: AI\_CODE, Code: "..."。
+* **P0: 执行反馈:**
+ * 成功:返回新的预览数据 \-\> 刷新 Grid \-\> 添加一条“操作成功”消息。
+ * 失败:捕获 Python Traceback \-\> 让 AI 尝试自我修复 (Self-Correction) 一次 \-\> 若仍失败,向用户展示错误原因。
+* **P0: 撤销操作 (Undo):**
+ * 聊天框每条成功记录下显示 \[撤销\] 按钮。
+ * 逻辑:调用后端 rollback(action\_id) \-\> 恢复到该操作前的快照 \-\> 刷新 Grid。
+
+### **4\. 快捷指令 (Prompt Chips)**
+
+* **P0:** 顶部工具栏按钮(生成变量、长宽转换等),点击仅作为“快捷短语”填入输入框,不触发独立 UI 逻辑,保持架构统一。
+
+### **5\. 导出 (Export)**
+
+* **P0:** 导出 Excel。
+ * 逻辑:后端直接将当前的 df (包含所有 AI 修改和手动修改) 写入 Excel 流并返回。
+
+## **三、 异常处理规范 (Error Handling)**
+
+| 异常场景 | 前端表现 | 后端处理 |
+| :---- | :---- | :---- |
+| **中文乱码** | 提示“编码格式识别失败,请手动选择” | 尝试 chardet 检测,失败则报错 |
+| **AI 代码报错** | Chat 气泡变红,显示“AI 正在尝试修复...” | 捕获 stderr,将错误反喂给 AI 重试 (Max 1次) |
+| **会话过期** | 全屏遮罩“会话已过期” | 清理 Redis/内存,返回 401/404 |
+| **手动修改冲突** | 提示“正在同步数据...” | 优先处理手动 Patch,再执行 AI 任务 |
+
+## **四、 开发与测试重点 (QA Focus)**
+
+1. **一致性测试:**
+ * 先手动改一个值,再让 AI 删一行,确认那个值还在不在(或者是否正确被删)。
+ * 先让 AI 改一列,再撤销,确认是否完全恢复。
+2. **边界测试:**
+ * 上传空文件。
+ * 上传全中文列名的文件。
+ * 让 AI 计算一个不存在的列。
+3. **性能测试:**
+ * 连续快速发送 5 条指令,确保后端是**串行队列**处理,而不是并发搞乱数据。
+
+## **五、 附录:数据同步 API 定义 (简版)**
+
+* POST /api/sync: 前端 \-\> 后端。发送手动修改的 Diff。
+ * Payload: \[{ rowId: "P001", col: "age", value: 66 }\]
+* POST /api/run: 前端 \-\> 后端。发送 AI 代码执行请求。
+ * Payload: { code: "df\['new'\] \= 1", snapshot: true }
+* POST /api/undo: 前端 \-\> 后端。
+ * Payload: { step: \-1 }
+
+\#\#\# 给开发团队的一句话总结
+
+\*\*“V1.1 的核心在于‘状态管理’。请务必保证后端 Python 内存里的 \`DataFrame\` 是唯一的‘真理来源 (Source of Truth)’。前端的所有操作(无论是手改还是 AI 改),本质上都是在向这个真理层发送指令和同步状态。”\*\*
+
+现在,您可以拿着这份文档,很有底气地去和开发团队开工了。它已经堵上了最容易翻车的几个漏洞。
diff --git a/docs/03-业务模块/DC-数据清洗整理/02-技术设计/技术设计文档:工具 C - 科研数据编辑器 (V7 云端沙箱抗风险版).md b/docs/03-业务模块/DC-数据清洗整理/02-技术设计/技术设计文档:工具 C - 科研数据编辑器 (V7 云端沙箱抗风险版).md
new file mode 100644
index 00000000..2cf27679
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/02-技术设计/技术设计文档:工具 C - 科研数据编辑器 (V7 云端沙箱抗风险版).md
@@ -0,0 +1,164 @@
+# **技术设计文档:工具 C \- 科研数据编辑器 (V7 云端沙箱抗风险版)**
+
+| 文档类型 | Technical Design Document (TDD) |
+| :---- | :---- |
+| **对应原型** | **工具C\_科研数据编辑器\_原型设计\_V6\_修复版.html** |
+| **版本** | **V7.1** (完整收录架构决策 ADR 与红队风险对策) |
+| **状态** | Final Standard |
+| **核心目标** | 构建一个高可靠的云端 Python 数据清洗平台。在保障“数据不出域”的前提下,通过 Apache Arrow 和样式分离技术,解决服务端执行带来的延迟与格式丢失问题。 |
+
+## **1\. 总体架构设计 (System Architecture)**
+
+鉴于文件大小限制 (\<20MB) 和脱敏前提,采用 “Node.js BFF \+ Python Microservice” 架构。
+V7 核心升级: 引入 Apache Arrow 作为前后端数据交换标准,替代低效的 Excel 文件反复读写,将单次交互延迟从 8s 降低至 0.5s。
+
+### **1.1 架构拓扑图 (V7 优化版)**
+
+graph TD
+ subgraph Client\_Layer \[用户端\]
+ ReactApp\[React 19 \+ AG Grid\]
+ ArrowClient\[Apache Arrow JS\]
+ end
+
+ subgraph Aliyun\_SAE \[阿里云 Serverless 应用引擎\]
+ BFF\[Node.js Web 服务 (Fastify)\]
+ PythonService\[Python 计算微服务 (FastAPI)\]
+ end
+
+ subgraph Cache\_Layer \[高速缓存层\]
+ Redis\_Session\[Redis (存 DataFrame Arrow 序列化)\]
+ end
+
+ subgraph AI\_PaaS \[AI 能力层\]
+ Dify\[Dify 编排引擎\]
+ DeepSeek\[DeepSeek-V3 模型\]
+ end
+
+ subgraph Cloud\_Infra \[持久化层\]
+ OSS\[对象存储 (存 Excel 底板)\]
+ RDS\[RDS PostgreSQL (存元数据)\]
+ end
+
+ %% 交互流
+ User\[用户\] \--\>|1. 上传| BFF
+ BFF \--\>|2. 存原始Excel| OSS
+ BFF \--\>|3. 预热 Session| PythonService
+ PythonService \--\>|4. 加载并转为 Arrow| Redis\_Session
+
+ User \--\>|5. AI 指令| Dify
+ Dify \--\>|6. Python 代码| BFF
+ BFF \--\>|7. 发送代码| PythonService
+
+ PythonService \--\>|8. 读取 Arrow (内存)| Redis\_Session
+ PythonService \--\>|9. Pandas 执行| PythonService
+ PythonService \--\>|10. 写回 Arrow| Redis\_Session
+
+ PythonService \--\>|11. 返回 Preview 数据 (JSON/Arrow)| ReactApp
+
+ User \--\>|12. 导出/保存| BFF
+ BFF \--\>|13. 触发合并| PythonService
+ PythonService \--\>|14. 读OSS底板 \+ 填入数据| OSS
+
+## **2\. 关键架构决策记录 (ADR)**
+
+本节记录了为何从“前端 Pyodide”转向“后端沙箱”的决策过程,供团队参考。
+
+### **决策点:前端运行 (WASM) vs 后端运行 (Server-side)**
+
+| 维度 | 方案 A:前端 Pyodide (WASM) | 方案 B:后端 Python (本方案) | 决策结论 |
+| :---- | :---- | :---- | :---- |
+| **启动延迟** | **极慢 (15s+)**。需下载 \~20MB 引擎包,用户体验极差。 | **秒开**。环境在服务器预热,即开即用。 | **后端胜** |
+| **交互延迟** | **极快 (\< 0.1s)**。本地内存操作,无网络开销。 | **中等 (0.5s)**。通过 Apache Arrow 优化后可接受。 | 前端胜 |
+| **稳定性** | **高风险**。浏览器 Tab 内存有限,易 OOM 崩溃。 | **高稳定**。服务器内存充足,容器隔离,崩溃不影响前端。 | **后端胜** |
+| **库支持** | **有限**。不支持部分 C 扩展库 (如复杂统计库)。 | **无限**。标准 Linux 环境,生态完整。 | **后端胜** |
+| **开发难度** | **极高**。需处理 JS-Python 通信、内存管理。 | **低**。标准 Web API 开发。 | **后端胜** |
+
+**结论:** 鉴于“数据已脱敏”且“文件较小”,**后端执行方案** 在稳定性、兼容性和开发成本上全面胜出。
+
+## **3\. 技术选型与融合 (Tech Stack Fusion)**
+
+### **3.1 核心组件更新**
+
+| 领域 | 选型 | V7 新增理由 |
+| :---- | :---- | :---- |
+| **数据交换** | **Apache Arrow** | **关键升级**。用于 Python 和 Node.js/前端之间的高性能数据传输,避免 JSON 序列化开销,**解决 IO 延迟核心**。 |
+| **Excel 处理** | **openpyxl** | 替代纯 Pandas。用于在导出时**保留原始 Excel 样式**(如颜色、边框),**解决格式丢失核心**。 |
+| **会话缓存** | **Redis** | 用于暂存用户的 DataFrame (序列化为 Parquet/Arrow),避免每次操作都去 OSS 读文件。 |
+| **计算服务** | **FastAPI \+ Celery** | 引入 Celery 处理异步任务,防止长计算阻塞 HTTP 线程。 |
+
+## **4\. 逆向风险评估与对策 (Red Teaming Analysis)**
+
+本节详细记录了“红队测试”中发现的潜在致命风险及其工程化解决方案。
+
+### **风险一:交互延迟的“体感崩塌”**
+
+* **逆向拷问:** 每次 AI 操作都走 OSS 下载 \-\> Pandas 读取 \-\> 计算 \-\> 上传,单次耗时可能超过 8秒,用户无法忍受。
+* **V7 解决方案:** **Session 驻留模式 (Memory-Resident)**
+ 1. **初始化:** 用户上传 Excel 后,后端将其加载为 DataFrame,并序列化为 **Arrow** 格式存入 Redis (TTL 30min)。
+ 2. **增量交互:** 前端发送指令,Python 从 Redis 读取 Arrow 数据(毫秒级),执行 Pandas 计算,将结果写回 Redis。
+ 3. **轻量反馈:** 计算完成后,只返回 **前 100 行预览数据** 给前端 AG Grid 渲染。
+ 4. **效果:** 耗时缩短至 **0.5s \- 1s**。
+
+### **风险二:Excel 格式丢失 (The Format Loss)**
+
+* **逆向拷问:** Pandas 的 to\_excel 会重置所有单元格样式,医生标注的颜色和批注会丢失。
+* **V7 解决方案:** **底板分离策略 (Template Separation)**
+ 1. **上传时:** 将原始 Excel 标记为 **"Style Template" (样式底板)**,永久保存在 OSS。
+ 2. **计算时:** 只在内存/Redis 中处理纯数据 (Values),不关心样式。
+ 3. **导出时:** 使用 openpyxl 加载“样式底板”,将内存中的新数据**填入**到底板的对应坐标中,保留未修改区域的背景色和批注。
+
+### **风险三:状态同步的“双写冲突”**
+
+* **逆向拷问:** 用户手动修改了第 5 行,同时 AI 删除了第 5 行,导致数据状态不一致。
+* **V7 解决方案:** **UI 互斥锁 (UI Locking)**
+ * 当 AI 正在生成代码或后端正在计算时,AG Grid 强制进入 **readOnly** 模式,并在界面显示 "AI 正在处理..." 遮罩,**物理层面上禁止并发操作**。
+
+### **风险四:安全沙箱逃逸**
+
+* **逆向拷问:** AI 生成了 import os; os.system('rm \-rf /')。
+* **V7 解决方案:** **AST 静态分析 \+ 容器隔离**
+ * **预检:** 在执行 exec() 前,使用 Python ast 模块扫描代码树,检测到 import os 等关键词直接抛出异常。
+ * **资源限额:** 使用 Python resource 模块限制单次执行的 CPU 时间 (10s) 和 内存 (1GB)。
+
+## **5\. 数据库设计 (元数据层)**
+
+新增 TaskAudit 表用于记录每一次 AI 操作的上下文,便于回滚和审计。
+
+model TaskAudit {
+ id String @id @default(uuid())
+ datasetId String
+ version Int // 操作后的版本号
+
+ actionType String // "AI\_CODE" or "MANUAL\_EDIT"
+ prompt String? // 用户的自然语言指令
+ code String? // AI 生成的 Python 代码
+
+ executionTime Int // 执行耗时 (ms)
+ status String // SUCCESS / FAILED
+
+ createdAt DateTime @default(now())
+}
+
+## **6\. API 接口定义 (V7 优化)**
+
+* POST /api/session/init: 上传文件,初始化 Redis Session,返回 sessionId。
+* POST /api/session/execute:
+ * **Input:** { sessionId, code, version }
+ * **Output:** { previewData: ArrowBase64, newVersion: int, logs: string }
+ * **说明:** 仅返回预览数据,不生成 Excel 文件。
+* POST /api/session/save:
+ * **Input:** { sessionId }
+ * **Output:** { downloadUrl }
+ * **说明:** 触发 openpyxl 合并逻辑,生成最终 Excel 并上传 OSS。
+
+## **7\. 开发分工建议**
+
+* **Python 组 (重中之重):**
+ * 实现 Arrow \<-\> Pandas 的序列化逻辑。
+ * 封装 openpyxl 的样式回填逻辑。
+ * 搭建 FastAPI \+ Redis 环境。
+* **Node.js 组:**
+ * 负责 Dify 转发和鉴权。
+* **前端组:**
+ * 集成 apache-arrow JS 库,解析后端返回的二进制流并在 AG Grid 展示。
+ * 实现“AI 处理中”的全屏锁定交互。
\ No newline at end of file
diff --git a/docs/03-业务模块/DC-数据清洗整理/03-UI设计/工具C_原型设计V6 .html b/docs/03-业务模块/DC-数据清洗整理/03-UI设计/工具C_原型设计V6 .html
new file mode 100644
index 00000000..b559d742
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/03-UI设计/工具C_原型设计V6 .html
@@ -0,0 +1,479 @@
+
+
+
+
+
+ 工具C - 科研数据编辑器 V6 (修复版)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发_TODO清单.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发_TODO清单.md
new file mode 100644
index 00000000..6c8c8fe7
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发_TODO清单.md
@@ -0,0 +1,620 @@
+# 工具C MVP开发 - To-do List
+
+> **文档版本**:v1.0
+> **创建日期**:2025-12-06
+> **预计工期**:3周(15个工作日)
+> **参考文档**:[工具C_MVP开发计划_V1.0.md](./工具C_MVP开发计划_V1.0.md)
+
+---
+
+## 📊 整体进度概览
+
+| 阶段 | 任务数 | 已完成 | 进行中 | 待开始 | 完成率 |
+|------|-------|-------|-------|-------|--------|
+| **Week 1: 基础架构** | 12 | 0 | 0 | 12 | 0% |
+| **Week 2: 核心功能** | 10 | 0 | 0 | 10 | 0% |
+| **Week 3: 测试优化** | 8 | 0 | 0 | 8 | 0% |
+| **总计** | **30** | **0** | **0** | **30** | **0%** |
+
+---
+
+## 🎯 核心里程碑(必须完成)
+
+- [ ] **M1**:Python代码执行环境搭建完成(Day 1)
+- [ ] **M2**:AI生成代码能力验证通过(Day 7)
+- [ ] **M3**:基础场景成功率 > 90%(Day 12)
+- [ ] **M4**:总体成功率 > 80%(Day 15)
+
+---
+
+## 📅 Week 1:基础架构搭建(Day 1-5)
+
+### Day 1:Python服务扩展 + 环境验证 ⭐
+
+#### Python微服务扩展
+- [ ] **P0** 创建 `extraction_service/services/dc_executor.py`
+ - [ ] 实现 `validate_code(code)` - AST静态检查
+ - [ ] 实现 `execute_pandas_code(data, code)` - 代码执行
+ - [ ] 添加危险模块黑名单(os、sys、subprocess等)
+ - [ ] 添加超时保护(30秒)
+ - [ ] 添加异常捕获和错误消息
+
+- [ ] **P0** 扩展 `extraction_service/main.py`
+ - [ ] 添加 `POST /api/dc/execute` 端点
+ - [ ] 添加 `POST /api/dc/validate` 端点
+ - [ ] 添加请求日志记录
+ - [ ] 添加错误处理中间件
+
+- [ ] **P0** 测试Python服务
+ - [ ] 启动服务:`cd extraction_service && venv\Scripts\activate && uvicorn main:app --reload`
+ - [ ] 测试健康检查:`GET http://localhost:8000/api/health`
+ - [ ] 测试代码验证:发送简单Pandas代码
+ - [ ] 测试代码执行:发送真实数据+代码
+ - [ ] 验证AST拦截:发送危险代码(如 `import os`)
+
+#### Node.js后端集成
+- [ ] **P0** 创建后端文件夹结构
+ ```
+ backend/src/modules/dc/tool-c/
+ ├── services/
+ │ ├── SessionService.ts # Session管理
+ │ ├── AICodeService.ts # AI代码生成
+ │ ├── PythonExecutorService.ts # Python执行(新增)
+ │ └── DataProcessService.ts # 数据处理
+ ├── controllers/
+ │ └── ToolCController.ts # HTTP控制器
+ ├── routes/
+ │ └── index.ts # 路由定义
+ └── utils/
+ └── codeValidator.ts # 前置验证
+ ```
+
+- [ ] **P0** 实现 `PythonExecutorService.ts`
+ - [ ] 实现 `executeCode(data, code)` 方法
+ - [ ] 实现 `validateCode(code)` 方法
+ - [ ] 添加超时控制(30秒)
+ - [ ] 添加日志记录(复用 `@/common/logging`)
+ - [ ] 添加错误处理和重试机制
+
+- [ ] **P1** 环境变量配置
+ - [ ] 添加 `EXTRACTION_SERVICE_URL=http://localhost:8000` 到 `.env`
+ - [ ] 验证环境变量加载
+
+#### 验收标准
+- [ ] Python服务能成功执行简单Pandas代码(如 `df['age'] > 60`)
+- [ ] AST检查能拦截危险代码(如 `import os`)
+- [ ] Node.js能成功调用Python服务并获取结果
+- [ ] 所有日志正常输出到控制台
+
+---
+
+### Day 2:数据库 + Session管理
+
+#### 数据库Schema设计
+- [ ] **P0** 创建Prisma Schema(`prisma/schema.prisma`)
+ ```prisma
+ // @@schema("dc")
+ model DcToolCSession {
+ id String @id @default(uuid())
+ userId String
+ fileName String
+ fileKey String // OSS存储key
+ totalRows Int
+ totalCols Int
+ columns Json // 列名数组
+ encoding String? // 编码格式
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ @@index([userId])
+ @@map("dc_tool_c_sessions")
+ }
+ ```
+
+- [ ] **P0** 执行数据库迁移
+ ```bash
+ npx prisma db push
+ npx prisma generate
+ ```
+
+- [ ] **P1** 验证表创建成功
+ ```sql
+ SELECT * FROM dc.dc_tool_c_sessions LIMIT 1;
+ ```
+
+#### SessionService实现
+- [ ] **P0** 实现 `SessionService.ts`
+ - [ ] `createSession(userId, fileName, fileBuffer)` - 创建会话
+ - [ ] 上传Excel到OSS(复用 `storage.uploadBuffer`)
+ - [ ] 解析Excel到JSON(使用xlsx库)
+ - [ ] 保存元数据到数据库(prisma)
+ - [ ] `getSession(sessionId)` - 获取会话
+ - [ ] 从数据库读取元数据
+ - [ ] 从OSS下载数据(如需要)
+ - [ ] `deleteSession(sessionId)` - 删除会话
+ - [ ] 删除OSS文件
+ - [ ] 删除数据库记录
+
+- [ ] **P1** 添加Excel解析逻辑
+ - [ ] 使用 `xlsx` 库读取Excel
+ - [ ] 转换为JSON格式(数组对象)
+ - [ ] 检测编码(中文支持)
+ - [ ] 提取列名和数据类型
+
+#### 验收标准
+- [ ] 能成功上传10MB以内的Excel文件
+- [ ] 数据正确保存到OSS(零落盘)
+- [ ] Session元数据正确存储到数据库
+- [ ] 能通过sessionId检索到完整数据
+
+---
+
+### Day 3:AI代码生成服务
+
+#### AICodeService实现
+- [ ] **P0** 实现 `AICodeService.ts`
+ - [ ] 集成LLMFactory(复用 `@/common/llm`)
+ - [ ] 实现 `generateCode(prompt, dataContext)` 方法
+ - [ ] 构建System Prompt(包含10个Few-shot示例)
+ - [ ] 注入数据上下文(行数、列名、样本数据)
+ - [ ] 调用LLM生成代码
+ - [ ] 提取纯代码(去除Markdown格式)
+ - [ ] 实现 `fixCode(originalCode, errorMsg, dataContext)` 方法
+ - [ ] AI自我修复逻辑
+ - [ ] 最多重试1次
+
+- [ ] **P0** System Prompt设计
+ - [ ] 基础场景示例(5个)
+ - [ ] 中等场景示例(3个)
+ - [ ] 高级场景示例(2个)
+ - [ ] 安全规范说明
+ - [ ] 输出格式要求
+
+- [ ] **P1** 代码提取逻辑
+ - [ ] 识别 ` ```python ... ``` ` 格式
+ - [ ] 识别纯代码格式
+ - [ ] 去除注释和说明
+
+#### 验收标准
+- [ ] AI能生成正确的Pandas代码(基础场景)
+- [ ] 生成的代码符合安全规范(无危险导入)
+- [ ] 能正确处理中文列名
+- [ ] 代码提取准确率 > 95%
+
+---
+
+### Day 4:前端基础框架
+
+#### 前端文件夹结构
+- [ ] **P0** 创建前端目录
+ ```
+ frontend-v2/src/modules/dc/pages/tool-c/
+ ├── index.tsx # 主页面入口
+ ├── components/
+ │ ├── DataTable.tsx # AG Grid数据表格
+ │ ├── AICopilot.tsx # AI对话侧边栏
+ │ ├── FileUploader.tsx # 文件上传
+ │ ├── Toolbar.tsx # 顶部工具栏
+ │ └── ChatMessage.tsx # 对话消息组件
+ ├── hooks/
+ │ ├── useSession.ts # Session管理
+ │ └── useAIChat.ts # AI对话
+ ├── types.ts # TypeScript类型定义
+ └── api.ts # API封装
+ ```
+
+- [ ] **P0** 安装依赖
+ ```bash
+ cd frontend-v2
+ npm install ag-grid-react ag-grid-community xlsx
+ ```
+
+#### 主页面布局
+- [ ] **P0** 实现 `index.tsx`(主布局)
+ - [ ] 左侧:数据表格区域(70%宽度)
+ - [ ] 右侧:AI Copilot侧边栏(30%宽度)
+ - [ ] 顶部:扁平工具栏(文件上传、导出、撤销)
+ - [ ] 状态管理:useState/useReducer
+
+- [ ] **P1** 实现 `FileUploader.tsx`
+ - [ ] 拖拽上传支持
+ - [ ] 文件类型验证(仅Excel)
+ - [ ] 文件大小限制(10MB)
+ - [ ] 上传进度显示
+
+#### 验收标准
+- [ ] 页面布局正确(左表格右AI)
+- [ ] 能成功上传Excel文件
+- [ ] 上传后能看到加载状态
+- [ ] 响应式布局(最小宽度1280px)
+
+---
+
+### Day 5:数据表格实现(AG Grid)
+
+#### DataTable组件
+- [ ] **P0** 实现 `DataTable.tsx`
+ - [ ] 集成AG Grid
+ - [ ] 动态列定义(根据Excel自动生成)
+ - [ ] 单元格编辑功能
+ - [ ] 脏数据标记(黄色高亮)
+ - [ ] 分页支持(每页100行)
+
+- [ ] **P1** 配置AG Grid主题
+ - [ ] 使用 `ag-theme-alpine`
+ - [ ] 自定义样式(Ant Design风格)
+ - [ ] 列宽自适应
+
+- [ ] **P1** 表格功能
+ - [ ] 列排序
+ - [ ] 列筛选
+ - [ ] 行选择(多选)
+ - [ ] 导出CSV(AG Grid内置)
+
+#### 验收标准
+- [ ] 能正确显示Excel数据(100行+)
+- [ ] 列宽自适应且可手动调整
+- [ ] 单元格编辑后有黄色标记
+- [ ] 表格性能流畅(1000行不卡顿)
+
+---
+
+## 📅 Week 2:核心功能实现(Day 6-10)
+
+### Day 6:AI对话UI
+
+#### AICopilot组件
+- [ ] **P0** 实现 `AICopilot.tsx`
+ - [ ] 对话消息列表(滚动)
+ - [ ] 输入框(多行,支持Enter发送)
+ - [ ] 发送按钮
+ - [ ] 加载状态(AI思考中...)
+
+- [ ] **P0** 实现 `ChatMessage.tsx`
+ - [ ] 用户消息(右对齐,蓝色)
+ - [ ] AI消息(左对齐,灰色)
+ - [ ] 代码块高亮(使用 `react-syntax-highlighter`)
+ - [ ] 时间戳显示
+
+- [ ] **P1** 消息历史管理
+ - [ ] 保存到localStorage
+ - [ ] 最多保存50条
+ - [ ] 清空历史按钮
+
+#### 验收标准
+- [ ] 对话界面美观(参考原型设计)
+- [ ] 消息发送/接收流畅
+- [ ] 代码块正确高亮
+- [ ] 滚动到最新消息
+
+---
+
+### Day 7:AI生成代码集成 ⭐
+
+#### API集成
+- [ ] **P0** 实现 `api.ts`
+ - [ ] `uploadFile(file)` - 上传Excel
+ - [ ] `sendMessage(sessionId, message)` - 发送AI消息
+ - [ ] `executeCode(sessionId, code)` - 执行代码
+ - [ ] `getSessionData(sessionId)` - 获取数据
+
+- [ ] **P0** 后端API实现(`ToolCController.ts`)
+ - [ ] `POST /api/v1/dc/tool-c/upload` - 文件上传
+ - [ ] `POST /api/v1/dc/tool-c/chat` - AI对话
+ - [ ] `POST /api/v1/dc/tool-c/execute` - 执行代码
+ - [ ] `GET /api/v1/dc/tool-c/sessions/:id` - 获取会话
+
+#### 业务逻辑实现
+- [ ] **P0** 实现完整流程
+ 1. [ ] 用户发送消息 → AICodeService生成代码
+ 2. [ ] 前端展示生成的代码(Markdown格式)
+ 3. [ ] 用户点击"执行"按钮 → 调用Python服务
+ 4. [ ] 执行成功 → 刷新表格数据
+ 5. [ ] 执行失败 → AI自我修复 → 重试
+
+- [ ] **P1** 错误处理
+ - [ ] AST检查失败 → 提示用户
+ - [ ] 执行超时(30秒) → 提示用户
+ - [ ] AI生成失败 → 重试机制
+
+#### 验收标准
+- [ ] **基础场景测试(5个)成功率 > 90%**
+ - [ ] "把年龄大于60的标记为老年组"
+ - [ ] "删除所有患者ID为空的行"
+ - [ ] "把性别转为数字,男1女0"
+ - [ ] "计算BMI = 体重 / (身高/100)^2"
+ - [ ] "删除缺失率超过50%的列"
+
+---
+
+### Day 8:UI锁定机制
+
+#### 互斥锁实现
+- [ ] **P0** 前端状态管理
+ - [ ] 添加 `isAIProcessing` 状态
+ - [ ] AI对话中 → 锁定表格编辑
+ - [ ] 显示友好提示:"AI正在处理,请稍候..."
+
+- [ ] **P0** 表格锁定逻辑
+ - [ ] `isAIProcessing=true` → AG Grid设置为只读
+ - [ ] 禁用工具栏按钮(导出除外)
+ - [ ] 显示半透明蒙层
+
+- [ ] **P1** 视觉反馈
+ - [ ] 表格半透明(opacity: 0.6)
+ - [ ] 显示加载动画
+ - [ ] 顶部显示进度条
+
+#### 验收标准
+- [ ] AI处理时,表格无法编辑
+- [ ] 锁定状态有明显的视觉反馈
+- [ ] AI完成后,表格自动解锁
+- [ ] 用户体验流畅(无卡顿)
+
+---
+
+### Day 9:自动检查点(Checkpoint)
+
+#### 数据快照管理
+- [ ] **P0** 实现检查点逻辑
+ - [ ] 每次AI执行成功 → 自动保存快照
+ - [ ] 最多保存10个检查点
+ - [ ] 快照数据存储到OSS(压缩JSON)
+
+- [ ] **P0** 回滚功能
+ - [ ] 工具栏添加"撤销"按钮
+ - [ ] 点击撤销 → 恢复到上一个检查点
+ - [ ] 最多支持10次撤销
+
+- [ ] **P1** 检查点列表UI
+ - [ ] 侧边栏显示检查点列表
+ - [ ] 每个检查点显示:时间、操作描述
+ - [ ] 点击检查点 → 恢复到该状态
+
+#### 验收标准
+- [ ] 每次AI操作后自动保存检查点
+- [ ] 撤销功能正常工作
+- [ ] 快照数据正确存储到OSS
+- [ ] 10个检查点后,自动删除最旧的
+
+---
+
+### Day 10:Excel导出
+
+#### 导出功能实现
+- [ ] **P0** 后端导出API
+ - [ ] `POST /api/v1/dc/tool-c/export/:sessionId`
+ - [ ] 使用 `openpyxl`(Python)或 `xlsx`(Node.js)
+ - [ ] 保留原始Excel格式(可选,MVP可跳过)
+
+- [ ] **P0** 前端导出按钮
+ - [ ] 工具栏添加"导出"按钮
+ - [ ] 点击 → 下载Excel文件
+ - [ ] 文件名:`原文件名_cleaned_YYYYMMDD.xlsx`
+
+- [ ] **P1** 导出选项(可选)
+ - [ ] 仅导出修改的行
+ - [ ] 保留样式(复杂,可延后)
+
+#### 验收标准
+- [ ] 能成功导出Excel文件
+- [ ] 导出的数据与表格一致
+- [ ] 文件名正确
+- [ ] 下载速度快(< 3秒)
+
+---
+
+## 📅 Week 3:测试优化(Day 11-15)
+
+### Day 11:中等场景测试 🟡
+
+#### 测试用例执行
+- [ ] **P0** 准备测试数据
+ - [ ] 创建测试Excel文件(包含多个列)
+ - [ ] 包含真实医疗数据示例
+
+- [ ] **P0** 中等场景测试(5个)
+ 1. [ ] "把诊断日期和出院日期计算天数差,如果出院日期早于诊断日期则标记为异常"
+ 2. [ ] "根据白细胞、中性粒细胞、淋巴细胞三个指标,计算NLR,并按2.5分为高低两组"
+ 3. [ ] "从病理报告列中提取TNM分期,生成新列"
+ 4. [ ] "把血压列的'120/80'格式拆分成收缩压和舒张压,并判断是否高血压"
+ 5. [ ] "删除重复的患者ID,保留最新的一条记录(根据就诊日期)"
+
+#### 优化AI Prompt
+- [ ] **P1** 根据失败案例优化Prompt
+ - [ ] 增加错误处理示例
+ - [ ] 强化中文列名处理
+ - [ ] 增加边界情况说明
+
+#### 验收标准
+- [ ] **中等场景成功率 > 80%(4/5成功)**
+
+---
+
+### Day 12:高级场景测试 🔴
+
+#### 高级场景测试(5个)
+- [ ] **P0** 复杂场景测试
+ 1. [ ] "对于每个患者,找出第一次化疗日期和最后一次化疗日期,计算化疗持续时间"
+ 2. [ ] "生成生存状态和生存时间"(复杂条件逻辑)
+ 3. [ ] "根据ALT、AST、ALP、TBIL判断肝功能分级"
+ 4. [ ] "按患者ID分组,计算每次随访相比上次的肿瘤大小变化率"
+ 5. [ ] "根据入院时间,计算季节变量,统计不同季节的发病人数"
+
+#### Prompt深度优化
+- [ ] **P1** 针对失败场景优化
+ - [ ] 增加分组聚合示例
+ - [ ] 增加时间序列示例
+ - [ ] 增加医学规则示例
+
+#### 验收标准
+- [ ] **高级场景成功率 > 60%(3/5成功)**
+- [ ] **总体成功率 > 80%(12/15成功)**
+
+---
+
+### Day 13:性能优化
+
+#### 性能测试
+- [ ] **P1** 测试性能指标
+ - [ ] 文件上传速度(10MB文件 < 5秒)
+ - [ ] AI代码生成速度(< 10秒)
+ - [ ] Python执行速度(< 5秒)
+ - [ ] 表格刷新速度(< 2秒)
+ - [ ] 端到端流程(< 20秒)
+
+#### 优化措施
+- [ ] **P1** 前端优化
+ - [ ] AG Grid虚拟滚动
+ - [ ] React.memo优化渲染
+ - [ ] 防抖输入(debounce 300ms)
+
+- [ ] **P1** 后端优化
+ - [ ] 数据压缩(OSS上传前)
+ - [ ] 缓存会话数据(Redis可选)
+ - [ ] 并发控制(限制同时执行数)
+
+#### 验收标准
+- [ ] 端到端操作 < 20秒
+- [ ] 1000行数据表格不卡顿
+- [ ] 无内存泄漏
+
+---
+
+### Day 14:集成测试
+
+#### 端到端测试
+- [ ] **P0** 完整流程测试(10次)
+ 1. [ ] 上传Excel文件
+ 2. [ ] 查看数据表格
+ 3. [ ] 发送AI指令
+ 4. [ ] 执行生成的代码
+ 5. [ ] 验证表格刷新
+ 6. [ ] 测试撤销功能
+ 7. [ ] 导出Excel文件
+ 8. [ ] 验证导出数据正确
+
+- [ ] **P1** 异常场景测试
+ - [ ] 上传损坏的Excel文件
+ - [ ] 发送空消息
+ - [ ] 执行危险代码(应被拦截)
+ - [ ] 网络断开恢复
+
+#### Bug修复
+- [ ] **P1** 修复测试中发现的问题
+ - [ ] 记录所有bug到GitHub Issues
+ - [ ] 按优先级修复(P0 > P1 > P2)
+
+#### 验收标准
+- [ ] 端到端流程100%通过
+- [ ] 无P0级别bug
+- [ ] P1级别bug < 3个
+
+---
+
+### Day 15:MVP验收 🎉
+
+#### 最终验收测试
+- [ ] **P0** 15个场景全覆盖测试
+ - [ ] 基础场景:5/5 ✅
+ - [ ] 中等场景:4/5 ✅
+ - [ ] 高级场景:3/5 ✅
+ - [ ] **总体成功率 > 80%**
+
+- [ ] **P0** 非功能性验收
+ - [ ] 性能:端到端 < 20秒 ✅
+ - [ ] 安全:AST拦截危险代码 ✅
+ - [ ] 稳定:10次测试无崩溃 ✅
+ - [ ] 易用:用户能独立完成任务 ✅
+
+#### 文档完善
+- [ ] **P1** 更新文档
+ - [ ] 用户使用手册
+ - [ ] API接口文档
+ - [ ] 部署指南
+ - [ ] 已知问题清单
+
+#### 验收决策
+- [ ] ✅ **通过**:总体成功率 > 80%,进入下一阶段
+- [ ] ❌ **失败**:总体成功率 < 60%,需要Pivot到模板库模式
+
+---
+
+## 🔥 每日站会检查清单
+
+### 每天工作开始前
+- [ ] 查看昨日遗留问题
+- [ ] 确认今日任务清单
+- [ ] 检查环境是否正常(Python服务、数据库、前端dev server)
+
+### 每天工作结束前
+- [ ] 更新To-do List进度
+- [ ] 提交代码到Git(✅ 重要!防止丢失)
+- [ ] 记录遇到的问题和解决方案
+- [ ] 规划明日任务
+
+---
+
+## ⚠️ 风险提示
+
+### 技术风险
+1. **AI生成质量不稳定**
+ - 缓解:多轮测试,优化Prompt
+ - 备选:失败后人工编写模板
+
+2. **Python执行安全问题**
+ - 缓解:AST静态检查 + 超时控制
+ - 备选:Docker沙箱隔离(Phase 2)
+
+3. **性能不达标**
+ - 缓解:分步优化,设定性能基准
+ - 备选:降低数据量要求(10MB → 5MB)
+
+### 进度风险
+1. **AI生成成功率 < 60%**
+ - 应对:紧急会议,决定是否Pivot
+
+2. **前端开发延期**
+ - 应对:简化UI,聚焦核心功能
+
+---
+
+## 📊 成功标准(最终验收)
+
+| 指标 | 目标 | 当前 | 状态 |
+|------|------|------|------|
+| **基础场景成功率** | > 90% | 0% | 🔴 |
+| **中等场景成功率** | > 80% | 0% | 🔴 |
+| **高级场景成功率** | > 60% | 0% | 🔴 |
+| **总体成功率** | > 80% | 0% | 🔴 |
+| **端到端性能** | < 20秒 | 0秒 | 🔴 |
+| **代码安全性** | 100%拦截 | 0% | 🔴 |
+
+---
+
+## 🎯 下一步行动(启动开发)
+
+### 立即开始(Day 1)
+1. **扩展Python服务**(2小时)
+ ```bash
+ cd AIclinicalresearch/extraction_service
+ # 创建dc_executor.py
+ # 扩展main.py添加2个端点
+ # 测试服务
+ ```
+
+2. **创建后端文件夹**(1小时)
+ ```bash
+ cd AIclinicalresearch/backend/src/modules/dc
+ mkdir -p tool-c/services tool-c/controllers tool-c/routes tool-c/utils
+ ```
+
+3. **实现PythonExecutorService**(2小时)
+ - 编写代码
+ - 单元测试
+ - 集成测试
+
+---
+
+**准备好了吗?让我们开始Day 1的开发!** 🚀
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发计划_V1.0.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发计划_V1.0.md
new file mode 100644
index 00000000..bd63e2f5
--- /dev/null
+++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_MVP开发计划_V1.0.md
@@ -0,0 +1,2061 @@
+# 工具C - 科研数据编辑器 MVP开发计划
+
+> **文档版本:** V1.0 (务实快速验证版)
+> **创建日期:** 2025-12-06
+> **计划周期:** 3周(15个工作日)
+> **核心策略:** 用最小成本验证核心假设,快速失败优于完美计划
+> **状态:** 待启动
+
+---
+
+## ⚠️ 开发前必读:严格遵守现有架构与规范
+
+### 🔴 不要重复造轮子!复用平台能力
+
+**本项目已有完整的3层架构体系和平台基础设施,所有代码必须复用现有能力:**
+
+#### 平台基础层(✅ 已完成,直接使用)
+
+| 服务 | 导入方式 | 用途 | 文档 |
+|------|---------|------|------|
+| **存储服务** | `import { storage } from '@/common/storage'` | 文件上传下载 | ✅ 必须使用 |
+| **日志系统** | `import { logger } from '@/common/logging'` | 标准化日志 | ✅ 必须使用 |
+| **缓存服务** | `import { cache } from '@/common/cache'` | 分布式缓存 | ✅ 必须使用 |
+| **异步任务** | `import { jobQueue } from '@/common/jobs'` | 长时间任务 | ✅ 必须使用 |
+| **数据库** | `import { prisma } from '@/config/database'` | 数据库操作 | ✅ 必须使用 |
+| **LLM能力** | `import { LLMFactory } from '@/common/llm'` | LLM调用 | ✅ 必须使用 |
+
+#### 云原生开发规范(✅ 强制执行)
+
+**详细文档**:`docs/04-开发规范/08-云原生开发规范.md`
+
+**核心要求:**
+- ✅ **文件存储**:使用`storage.upload()`,不要用`fs.writeFile()`
+- ✅ **Session管理**:存数据库,不要用`Map`
+- ✅ **日志输出**:使用`logger.info()`,不要用`console.log()`
+- ✅ **数据库连接**:使用全局`prisma`实例,不要`new PrismaClient()`
+- ✅ **LLM调用**:使用`LLMFactory.getLLM()`,不要自己集成
+- ❌ **禁止本地文件存储**:Excel直接从内存解析
+- ❌ **禁止内存缓存Map**:用数据库或cache服务
+- ❌ **禁止硬编码配置**:使用环境变量
+
+#### 代码文件夹结构(✅ 参考tool-b)
+
+**后端**:
+```
+backend/src/modules/dc/tool-c/ ← 已存在
+├── services/ ← 业务逻辑
+├── controllers/ ← HTTP控制器
+├── routes/ ← 路由定义
+└── utils/ ← 工具函数
+```
+
+**前端**:
+```
+frontend-v2/src/modules/dc/pages/tool-c/ ← 已存在
+```
+
+#### 常见错误示例(❌ 严禁)
+
+```typescript
+// ❌ 错误1:自己实现Session管理
+const sessions = new Map(); // 违反规范!
+
+// ❌ 错误2:本地文件存储
+fs.writeFileSync('./uploads/file.xlsx', buffer); // 违反规范!
+
+// ❌ 错误3:不用logger
+console.log('User uploaded file'); // 违反规范!
+
+// ❌ 错误4:新建Prisma实例
+const prisma = new PrismaClient(); // 违反规范!
+
+// ❌ 错误5:自己集成LLM
+import Anthropic from '@anthropic-ai/sdk'; // 违反规范!
+```
+
+**正确示例(✅ 必须)**:参考本文档Day 1-5的代码示例
+
+---
+
+## 📋 目录
+
+- [开发前必读](#开发前必读严格遵守现有架构与规范)
+- [一、MVP核心目标](#一mvp核心目标)
+- [二、技术架构方案(务实版)](#二技术架构方案务实版)
+- [三、功能优先级矩阵](#三功能优先级矩阵)
+- [四、3周详细开发计划](#四3周详细开发计划)
+- [五、风险应对策略](#五风险应对策略)
+- [六、验收标准](#六验收标准)
+- [七、快速失败机制](#七快速失败机制)
+
+---
+
+## 一、MVP核心目标
+
+### 1.1 核心假设验证
+
+**我们需要验证的3个核心假设:**
+
+| 假设 | 验证方式 | 成功标准 | 失败后果 |
+|------|---------|---------|---------|
+| **H1: AI能生成高质量Pandas代码并成功执行** | 15个真实场景测试 | 总体成功率 > 80% | MVP失败,改用代码模板库 |
+| **H2: Python代码执行环境稳定可靠** | 复杂场景测试 | 高级场景成功率 > 60% | 简化为批处理模式 |
+| **H3: 左表格+右AI的交互模式好用** | 用户体验测试 | 用户能独立完成任务 | 重新设计UI交互 |
+| **H4: 性能可接受(含Python执行)** | 性能测试 | 端到端 < 20秒 | 优化Python执行或改批处理 |
+
+**⚠️ 核心价值主张:**
+- ✅ **AI生成代码 + 真实执行 + 表格刷新**是工具C的差异化价值
+- ✅ 如果只生成代码不执行,用户还不如直接用ChatGPT
+- ✅ Python执行环境是MVP的**技术核心**,不是可选项
+
+### 1.2 MVP功能范围
+
+**✅ MVP必须有的(P0):**
+1. 文件上传(10MB限制)
+2. 表格展示(AG Grid,100行预览)
+3. AI对话界面(右侧侧边栏)
+4. AI代码生成(DeepSeek-V3)
+5. 代码执行(Python沙箱)
+6. UI锁定机制(AI处理时表格只读)
+7. AST安全检查
+8. 表格自动刷新
+9. 导出Excel
+
+**❌ MVP明确不做的:**
+- 手动编辑单元格(专注AI能力)
+- 撤销/回滚(节省内存)
+- Apache Arrow(先用JSON)
+- Redis会话(用进程内存)
+- 样式保留(直接覆盖)
+- 操作审计日志
+- 协同编辑
+
+### 1.3 MVP交付物
+
+**最终演示场景:**
+```
+用户上传 "lung_cancer_patients.xlsx" (5000行 × 20列)
+ ↓
+左侧显示数据表格,右侧AI助手准备就绪
+ ↓
+用户对AI说:"把年龄大于60的患者标记为老年组"
+ ↓
+AI生成代码 → 展示预操作卡片 → 用户确认 → 执行成功
+ ↓
+表格自动刷新,新增"age_group"列
+ ↓
+用户继续说:"删除所有缺失患者ID的行"
+ ↓
+AI执行 → 表格刷新,显示删除了23行
+ ↓
+用户点击"导出",下载处理后的Excel
+```
+
+**成功标准:**
+- ✅ 整个流程 < 2分钟完成
+- ✅ AI代码一次性执行成功
+- ✅ 用户无需看文档就能操作
+
+---
+
+## 二、技术架构方案(务实版)
+
+### 2.1 总体架构(简化版)- ⚠️ 重要:复用平台能力
+
+```
+┌─────────────────────────────────────────────────────────┐
+│ 前端 (React) │
+│ frontend-v2/src/modules/dc/pages/tool-c/ │
+│ ┌──────────────────────┐ ┌────────────────────────┐ │
+│ │ AG Grid (70%) │ │ AI Chat Sidebar (30%) │ │
+│ │ • 展示100行数据 │ │ • 自然语言输入 │ │
+│ │ • 只读模式切换 │ │ • 预操作卡片 │ │
+│ │ • 锁定遮罩 │ │ • 消息历史 │ │
+│ └──────────────────────┘ └────────────────────────┘ │
+└─────────────────────────────────────────────────────────┘
+ ↕ REST API (JSON)
+┌─────────────────────────────────────────────────────────┐
+│ Node.js后端 (backend/src/modules/dc/tool-c/) │
+│ • 文件上传(复用storage服务)✅ │
+│ • 会话管理(存数据库,不用内存Map)✅ │
+│ • LLM集成(复用LLMFactory)✅ │
+│ • 日志记录(复用logger)✅ │
+│ • 异步任务(复用jobQueue)✅ │
+└─────────────────────────────────────────────────────────┘
+ ↕ HTTP(如需Python执行)
+┌─────────────────────────────────────────────────────────┐
+│ Python微服务(可选,扩展文档处理引擎) │
+│ • DataFrame管理(存数据库,不用内存) │
+│ • exec()代码执行 │
+│ • AST静态安全检查 │
+│ • JSON序列化返回 │
+└─────────────────────────────────────────────────────────┘
+```
+
+**⚠️ 云原生架构强制要求:**
+- ✅ **复用storage服务**:`import { storage } from '@/common/storage'`
+- ✅ **复用logger服务**:`import { logger } from '@/common/logging'`
+- ✅ **复用cache服务**:`import { cache } from '@/common/cache'`
+- ✅ **复用LLMFactory**:`import { LLMFactory } from '@/common/llm'`
+- ✅ **复用prisma实例**:`import { prisma } from '@/config/database'`
+- ✅ **Session存数据库**:不用内存Map(违反规范)
+- ❌ **禁止本地文件存储**:Excel直接从内存解析
+- ❌ **禁止新建Prisma实例**:使用全局实例
+
+**关键决策:**
+- ✅ **不用Apache Arrow**:JSON够快(100行 ≈ 20KB)
+- ✅ **Session存数据库**:符合云原生规范,支持多实例
+- ✅ **不做撤销**:节省开发时间,用户重新上传即可
+- ✅ **不保留样式**:直接生成新Excel
+
+### 2.2 技术栈选型(✅ 复用现有技术栈)
+
+#### 前端(frontend-v2)
+```json
+{
+ "framework": "React 19 + TypeScript 5 (已有)",
+ "table": "AG Grid Community (免费版)",
+ "ui": "Ant Design 5 (已有)",
+ "state": "React Query v5 (已有)",
+ "http": "axios (已有)",
+ "routing": "React Router DOM v6 (已有)"
+}
+```
+
+#### Node.js后端(backend)
+```json
+{
+ "framework": "Fastify v4 (已有)",
+ "llm": "✅ 复用 LLMFactory (平台通用能力层)",
+ "storage": "✅ 复用 storage服务 (平台基础层)",
+ "logging": "✅ 复用 logger服务 (平台基础层)",
+ "cache": "✅ 复用 cache服务 (平台基础层)",
+ "database": "✅ 复用 prisma全局实例 (平台基础层)",
+ "session": "✅ PostgreSQL (dc_tool_c_sessions表)",
+ "excel": "xlsx 库(内存解析)",
+ "validation": "Joi"
+}
+```
+
+#### Python微服务(⚠️ 核心功能,扩展现有服务)⭐⭐⭐⭐⭐
+**决策**:✅ **系统已有Python微服务(FastAPI),需扩展代码执行功能**
+
+**📦 现有Python服务(已完成):**
+- ✅ **extraction_service**:FastAPI + PyMuPDF + Pandas + openpyxl
+- ✅ **端口**:8000(已运行)
+- ✅ **功能**:PDF/Docx/Txt文档提取、语言检测
+- ✅ **集成**:Node.js通过ExtractionClient调用
+- ✅ **依赖**:Pandas、openpyxl、chardet、langdetect(已安装)
+
+**🔧 工具C需要的新功能:**
+| 功能 | 现有服务 | 需求 | 方案 |
+|------|---------|------|------|
+| **Pandas代码执行** | ❌ 不支持 | ✅ 核心 | **新增API端点** `/api/dc/execute` |
+| **Excel上传** | ❌ 不支持 | ✅ 需要 | 复用MultiPart上传 |
+| **DataFrame管理** | ❌ 不支持 | ✅ 会话 | 新增Session管理 |
+| **AST代码检查** | ❌ 不支持 | ✅ 必须 | 新增AST模块 |
+| **Excel导出** | ❌ 不支持 | ✅ 需要 | 使用openpyxl(已安装) |
+
+**⚠️ 不需要重复开发:**
+- ❌ 不需要新建Python项目
+- ❌ 不需要重新安装Pandas/openpyxl(已安装)
+- ❌ 不需要重新配置FastAPI(已运行)
+- ❌ 不需要重新写Node.js调用逻辑(ExtractionClient已存在)
+
+**✅ MVP扩展方案:**
+```python
+# extraction_service/services/dc_executor.py(新增)
+import pandas as pd
+import ast
+from typing import Dict, Any
+
+def validate_code(code: str) -> Dict[str, Any]:
+ """AST静态检查(安全验证)"""
+ try:
+ tree = ast.parse(code)
+ # 禁止import os、sys、subprocess等
+ for node in ast.walk(tree):
+ if isinstance(node, ast.Import):
+ for alias in node.names:
+ if alias.name in ['os', 'sys', 'subprocess', 'socket']:
+ return {'valid': False, 'error': f'禁止导入{alias.name}'}
+ return {'valid': True}
+ except Exception as e:
+ return {'valid': False, 'error': str(e)}
+
+def execute_pandas_code(data: list, code: str) -> Dict[str, Any]:
+ """执行Pandas代码(⭐核心功能)"""
+ try:
+ # 1. 安全检查
+ validation = validate_code(code)
+ if not validation['valid']:
+ return {'success': False, 'error': validation['error']}
+
+ # 2. 加载数据
+ df = pd.DataFrame(data)
+
+ # 3. 执行代码(注入df和pd)
+ exec(code, {'df': df, 'pd': pd})
+
+ # 4. 返回结果(前100行)
+ return {
+ 'success': True,
+ 'data': df.head(100).to_dict('records'),
+ 'totalRows': len(df),
+ 'totalCols': len(df.columns),
+ 'columns': df.columns.tolist()
+ }
+ except Exception as e:
+ return {'success': False, 'error': str(e)}
+```
+
+```python
+# extraction_service/main.py(扩展)
+from services.dc_executor import execute_pandas_code, validate_code
+
+@app.post("/api/dc/execute")
+async def execute_code(
+ data: List[Dict],
+ code: str
+):
+ """工具C:执行Pandas代码"""
+ result = execute_pandas_code(data, code)
+ return JSONResponse(result)
+
+@app.post("/api/dc/validate")
+async def validate_code_endpoint(code: str):
+ """工具C:AST代码检查"""
+ result = validate_code(code)
+ return JSONResponse(result)
+```
+
+**✅ Node.js调用(复用ExtractionClient模式):**
+```typescript
+// backend/src/modules/dc/tool-c/services/PythonExecutorService.ts
+import axios from 'axios';
+
+const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
+
+export class PythonExecutorService {
+ async executeCode(data: any[], code: string) {
+ const response = await axios.post(`${EXTRACTION_SERVICE_URL}/api/dc/execute`, {
+ data,
+ code
+ });
+ return response.data;
+ }
+}
+```
+
+### 2.3 数据流设计
+
+**会话生命周期:**
+```python
+# 1. 用户上传文件
+POST /api/tool-c/session/init
+{
+ file: File,
+ userId: string
+}
+
+# Node.js: 转发到Python
+# Python:
+# - 读取Excel → DataFrame
+# - 存入内存:sessions[sessionId] = df
+# - 返回:sessionId + 数据概览
+
+# 2. 用户发送AI指令
+POST /api/tool-c/ai/execute
+{
+ sessionId: string,
+ prompt: string
+}
+
+# Node.js:
+# - 构建System Prompt(包含数据上下文)
+# - 调用LLM生成代码
+# - 转发代码到Python
+
+# Python:
+# - AST检查
+# - exec(code)修改df
+# - 返回前100行JSON
+
+# 3. 用户导出
+GET /api/tool-c/session/export/{sessionId}
+
+# Python:
+# - df.to_excel(buffer)
+# - 返回二进制流
+```
+
+---
+
+## 三、功能优先级矩阵
+
+### 3.1 P0级:必须开发(核心闭环)⭐⭐⭐⭐⭐
+
+| ID | 功能 | 描述 | 验证目标 | 工时 | 负责人 |
+|----|------|------|---------|------|--------|
+| **P0-001** | 文件上传 | 前端Upload组件 + 10MB限制 | 能否解析Excel | 0.5天 | 前端 |
+| **P0-002** | Session初始化 | 后端接收文件,Python加载DataFrame | 中文列名、GBK编码 | 1天 | 后端 |
+| **P0-003** | 表格展示 | AG Grid展示100行数据 | 列类型识别、空值高亮 | 1天 | 前端 |
+| **P0-004** | AI对话UI | 右侧侧边栏,消息列表 | 聊天交互流畅 | 0.5天 | 前端 |
+| **P0-005** | System Prompt构建 | 包含数据上下文的Prompt | AI能理解数据结构 | 1天 | 后端 |
+| **P0-006** | AI代码生成 | 调用DeepSeek-V3生成Pandas代码 | **成功率>80%** | 2天 | 后端 |
+| **P0-007** | AST安全检查 | 拦截危险代码 | `import os`被拦截 | 1天 | Python |
+| **P0-008** | 代码执行 | exec()在沙箱中运行代码 | 修改DataFrame成功 | 1天 | Python |
+| **P0-009** | 预操作卡片 | 展示代码,用户确认后执行 | 用户能看懂代码意图 | 0.5天 | 前端 |
+| **P0-010** | 表格刷新 | 执行后自动拉取新数据 | 前端实时更新 | 0.5天 | 前端 |
+| **P0-011** | UI锁定机制 | AI处理时表格变灰+遮罩 | 物理禁止并发操作 | 0.5天 | 前端 |
+| **P0-012** | 导出Excel | 下载处理后的文件 | 文件完整性 | 1天 | Python |
+
+**P0小计:11.5天**
+
+### 3.2 P1级:必须验证,可简化实现 ⭐⭐⭐⭐
+
+| ID | 功能 | MVP简化方案 | 完整版 | 工时 |
+|----|------|------------|--------|------|
+| **P1-001** | 会话管理 | 进程内存Map(单实例) | Redis分布式 | 0.5天 |
+| **P1-002** | 心跳保活 | 固定10分钟过期,不续期 | 前端心跳续期 | 0.5天 |
+| **P1-003** | 编码检测 | chardet自动检测+友好报错 | 自动转换 | 1天 |
+| **P1-004** | AI自我修复 | 失败后重试1次 | 多次重试+学习 | 1天 |
+| **P1-005** | 快捷模板 | 3个常用模板(年龄分组等) | 10+模板库 | 0.5天 |
+
+**P1小计:3.5天**
+
+### 3.3 P2级:延后或不做 ⭐⭐
+
+| 功能 | 延后原因 | 何时做 |
+|------|---------|--------|
+| 手动编辑单元格 | MVP专注AI | P2阶段 |
+| 撤销/回滚 | 节省内存 | P2阶段 |
+| Apache Arrow | JSON够用 | 性能不达标时 |
+| Redis分布式 | 单实例够用 | 横向扩展时 |
+| 样式保留 | 复杂度高 | P3阶段 |
+| 操作审计 | 非核心 | P3阶段 |
+| 多Sheet支持 | 简化逻辑 | P3阶段 |
+
+---
+
+## 四、3周详细开发计划
+
+### Week 1:基础架构搭建(5天)
+
+#### Day 1:环境搭建 + 代码结构(⚠️ 参考tool-b结构 + Python环境)
+
+**任务清单:**
+- [ ] 创建项目目录结构(**参考tool-b**)
+ ```
+ backend/src/modules/dc/tool-c/ ← 主目录
+ ├── services/ ← 业务逻辑层
+ │ ├── SessionService.ts ← Session管理(存数据库)
+ │ ├── AICodeService.ts ← AI代码生成
+ │ ├── PythonExecutorService.ts ← ⭐ Python代码执行(核心)
+ │ └── DataProcessService.ts ← 数据处理逻辑
+ ├── controllers/ ← 控制器层
+ │ └── ToolCController.ts ← HTTP请求处理
+ ├── routes/ ← 路由层
+ │ └── index.ts ← 路由定义
+ └── utils/ ← 工具函数
+ ├── codeValidator.ts ← AST代码检查
+ └── pythonScripts/ ← ⭐ Python执行脚本
+ └── executor.py ← Pandas代码执行器
+
+ frontend-v2/src/modules/dc/pages/tool-c/ ← 前端(已存在)
+ ```
+
+- [ ] **⭐ 扩展现有Python服务(核心功能)**
+ ```bash
+ # 系统已有Python微服务(extraction_service),只需扩展功能
+ cd extraction_service
+
+ # 1. 创建DC执行器模块
+ cat > services/dc_executor.py << 'EOF'
+ import pandas as pd
+ import ast
+ from typing import Dict, Any, List
+
+ def validate_code(code: str) -> Dict[str, Any]:
+ """AST静态检查(安全验证)"""
+ try:
+ tree = ast.parse(code)
+ # 禁止危险导入
+ forbidden_modules = ['os', 'sys', 'subprocess', 'socket', 'shutil', 'requests']
+ for node in ast.walk(tree):
+ if isinstance(node, ast.Import):
+ for alias in node.names:
+ if alias.name in forbidden_modules:
+ return {'valid': False, 'error': f'禁止导入{alias.name}模块'}
+ elif isinstance(node, ast.ImportFrom):
+ if node.module in forbidden_modules:
+ return {'valid': False, 'error': f'禁止导入{node.module}模块'}
+ return {'valid': True}
+ except Exception as e:
+ return {'valid': False, 'error': f'代码语法错误: {str(e)}'}
+
+ def execute_pandas_code(data: List[Dict], code: str) -> Dict[str, Any]:
+ """执行Pandas代码(⭐核心功能)"""
+ try:
+ # 1. 安全检查
+ validation = validate_code(code)
+ if not validation['valid']:
+ return {'success': False, 'error': validation['error']}
+
+ # 2. 加载数据到DataFrame
+ df = pd.DataFrame(data)
+
+ # 3. 执行代码(注入df和pd,隔离环境)
+ local_env = {'df': df, 'pd': pd}
+ exec(code, {'__builtins__': {}}, local_env)
+
+ # 4. 获取执行后的df
+ df_result = local_env.get('df', df)
+
+ # 5. 返回结果(前100行,避免数据量过大)
+ return {
+ 'success': True,
+ 'data': df_result.head(100).to_dict('records'),
+ 'totalRows': len(df_result),
+ 'totalCols': len(df_result.columns),
+ 'columns': df_result.columns.tolist()
+ }
+ except Exception as e:
+ return {
+ 'success': False,
+ 'error': f'代码执行失败: {str(e)}'
+ }
+ EOF
+
+ # 2. 扩展main.py,添加DC端点
+ # 在main.py末尾添加:
+ cat >> main.py << 'EOF'
+
+ # ==================== DC工具C端点 ====================
+ from services.dc_executor import execute_pandas_code, validate_code
+ from pydantic import BaseModel
+
+ class ExecuteRequest(BaseModel):
+ data: List[Dict]
+ code: str
+
+ class ValidateRequest(BaseModel):
+ code: str
+
+ @app.post("/api/dc/execute")
+ async def dc_execute_code(request: ExecuteRequest):
+ """工具C:执行Pandas代码"""
+ logger.info(f"DC Execute: code length={len(request.code)}, data rows={len(request.data)}")
+ result = execute_pandas_code(request.data, request.code)
+ return JSONResponse(result)
+
+ @app.post("/api/dc/validate")
+ async def dc_validate_code(request: ValidateRequest):
+ """工具C:AST代码检查"""
+ logger.info(f"DC Validate: code length={len(request.code)}")
+ result = validate_code(request.code)
+ return JSONResponse(result)
+ EOF
+ ```
+
+- [ ] **Node.js调用Python服务(PythonExecutorService)**
+ ```typescript
+ // backend/src/modules/dc/tool-c/services/PythonExecutorService.ts
+ import axios from 'axios';
+ import { logger } from '@/common/logging';
+
+ const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
+
+ export interface ExecuteResult {
+ success: boolean;
+ data?: any[];
+ totalRows?: number;
+ totalCols?: number;
+ columns?: string[];
+ error?: string;
+ }
+
+ export class PythonExecutorService {
+ private baseUrl: string;
+
+ constructor() {
+ this.baseUrl = EXTRACTION_SERVICE_URL;
+ }
+
+ /**
+ * 执行Pandas代码(⭐ 核心功能)
+ * 复用现有Python微服务,添加新端点
+ */
+ async executeCode(data: any[], code: string): Promise {
+ try {
+ logger.info('Calling Python executor', {
+ dataRows: data.length,
+ codeLength: code.length
+ });
+
+ const response = await axios.post(
+ `${this.baseUrl}/api/dc/execute`,
+ { data, code },
+ { timeout: 30000 } // 30秒超时
+ );
+
+ logger.info('Python execution success', {
+ totalRows: response.data.totalRows
+ });
+
+ return response.data;
+ } catch (error) {
+ logger.error('Python execution failed', { error });
+
+ if (axios.isAxiosError(error) && error.response) {
+ throw new Error(error.response.data.error || 'Python execution failed');
+ }
+
+ throw new Error('无法连接到Python执行服务');
+ }
+ }
+
+ /**
+ * AST代码检查(执行前验证)
+ */
+ async validateCode(code: string): Promise<{ valid: boolean; error?: string }> {
+ try {
+ const response = await axios.post(
+ `${this.baseUrl}/api/dc/validate`,
+ { code },
+ { timeout: 5000 }
+ );
+
+ return response.data;
+ } catch (error) {
+ logger.error('Code validation failed', { error });
+ throw new Error('代码验证失败');
+ }
+ }
+ }
+
+ export const pythonExecutorService = new PythonExecutorService();
+ ```
+
+- [ ] **强制检查**:确保复用平台服务
+ ```typescript
+ // backend/src/modules/dc/tool-c/services/SessionService.ts
+
+ // ✅ 必须导入这些平台服务
+ import { storage } from '@/common/storage';
+ import { logger } from '@/common/logging';
+ import { cache } from '@/common/cache';
+ import { prisma } from '@/config/database';
+
+ // ❌ 禁止自己实现
+ // const sessions = new Map() ← 违反规范!
+ ```
+
+- [ ] 数据库Schema设计(dc_schema)
+ ```prisma
+ // prisma/schema.prisma(添加到dc_schema)
+ model DcToolCSession {
+ id String @id @default(uuid())
+ userId String
+ sessionId String @unique
+ fileName String
+ dataSnapshot Json // 存储100行预览数据
+ totalRows Int
+ totalCols Int
+ columns Json // 列信息
+ expiresAt DateTime // 10分钟过期
+ createdAt DateTime @default(now())
+
+ @@schema("dc_schema")
+ @@map("dc_tool_c_sessions")
+ }
+ ```
+
+**验收标准:**
+- ✅ 文件夹结构与tool-b一致
+- ✅ 导入了所有必须的平台服务
+- ✅ 没有内存Map、没有本地文件存储
+
+**负责人:** 后端开发
+
+---
+
+#### Day 2:Session管理 + 数据加载(⚠️ 存数据库,不用内存)
+
+**任务清单:**
+- [ ] 实现SessionService(**存数据库,符合云原生规范**)
+ ```typescript
+ // backend/src/modules/dc/tool-c/services/SessionService.ts
+ import { storage } from '@/common/storage';
+ import { logger } from '@/common/logging';
+ import { prisma } from '@/config/database';
+ import * as xlsx from 'xlsx';
+ import chardet from 'chardet';
+
+ export class SessionService {
+ /**
+ * 创建Session(✅ 存数据库,不用内存Map)
+ */
+ async createSession(userId: string, fileBuffer: Buffer, fileName: string): Promise {
+ // 1. 检测编码
+ const detected = chardet.detect(fileBuffer);
+ if (detected.encoding.toLowerCase() !== 'utf-8') {
+ throw new Error(`文件编码为${detected.encoding},请转换为UTF-8`);
+ }
+
+ // 2. 内存解析Excel(✅ 云原生:不落盘)
+ const workbook = xlsx.read(fileBuffer, { type: 'buffer' });
+ const sheet = workbook.Sheets[workbook.SheetNames[0]];
+ const data = xlsx.utils.sheet_to_json(sheet);
+
+ // 3. 提取列信息
+ const columns = Object.keys(data[0] || {}).map(col => ({
+ name: col,
+ type: typeof data[0][col]
+ }));
+
+ // 4. Session存数据库(✅ 符合云原生规范)
+ const sessionId = `session_${Date.now()}_${Math.random().toString(36)}`;
+ await prisma.dcToolCSession.create({
+ data: {
+ sessionId,
+ userId,
+ fileName,
+ dataSnapshot: data.slice(0, 100), // 只存前100行预览
+ totalRows: data.length,
+ totalCols: columns.length,
+ columns,
+ expiresAt: new Date(Date.now() + 10 * 60 * 1000) // 10分钟过期
+ }
+ });
+
+ // 5. 完整数据上传到OSS(✅ 云原生:持久化存储)
+ const dataKey = `dc/tool-c/${sessionId}/full-data.json`;
+ await storage.uploadBuffer(dataKey, Buffer.from(JSON.stringify(data)));
+
+ logger.info('Session created', { sessionId, totalRows: data.length });
+
+ return sessionId;
+ }
+
+ /**
+ * 获取Session(从数据库读取)
+ */
+ async getSession(sessionId: string) {
+ const session = await prisma.dcToolCSession.findUnique({
+ where: { sessionId }
+ });
+
+ if (!session || new Date() > session.expiresAt) {
+ throw new Error('Session已过期');
+ }
+
+ return session;
+ }
+ }
+ ```
+
+**测试用例:**
+- [ ] 上传UTF-8编码的Excel,正常解析
+- [ ] 上传GBK编码的Excel,被拦截并提示
+- [ ] 上传中文列名的Excel,无乱码
+- [ ] Session存入数据库,可查询
+- [ ] 10分钟后Session自动过期
+
+**验收标准:**
+- ✅ Session存储在数据库(不是内存Map)
+- ✅ 完整数据存储在OSS
+- ✅ 符合云原生开发规范
+
+**负责人:** Node.js后端
+
+---
+
+#### Day 3:Node.js BFF + 文件上传
+
+**任务清单:**
+- [ ] 创建Fastify路由
+ ```typescript
+ // backend/src/modules/dc/tool-c/routes/index.ts
+ import { FastifyInstance } from 'fastify';
+
+ export async function registerToolCRoutes(fastify: FastifyInstance) {
+ // 文件上传
+ fastify.post('/api/v1/dc/tool-c/session/init', async (req, reply) => {
+ const file = await req.file();
+
+ // 1. 文件大小检查
+ if (file.file.bytesRead > 10 * 1024 * 1024) {
+ return reply.code(413).send({
+ success: false,
+ error: '文件过大,请压缩后重试(限10MB)'
+ });
+ }
+
+ // 2. 转发到Python服务
+ const formData = new FormData();
+ formData.append('file', file.file, file.filename);
+
+ const response = await axios.post('http://localhost:8001/api/python/init', formData);
+
+ return {
+ success: true,
+ sessionId: response.data.sessionId,
+ data: response.data
+ };
+ });
+ }
+ ```
+- [ ] 集成到主应用
+ ```typescript
+ // backend/src/modules/dc/index.ts
+ import { registerToolCRoutes } from './tool-c/routes';
+
+ export async function registerDCRoutes(fastify: FastifyInstance) {
+ await registerToolBRoutes(fastify);
+ await registerToolCRoutes(fastify); // 新增
+ }
+ ```
+
+**测试用例:**
+- [ ] 上传9MB文件,成功
+- [ ] 上传11MB文件,被拦截
+- [ ] 并发上传2个文件,sessionId不冲突
+
+**验收标准:**
+- ✅ Node.js能正确转发文件到Python
+- ✅ 文件大小限制生效
+
+**负责人:** Node.js后端
+
+---
+
+#### Day 4:前端框架搭建
+
+**任务清单:**
+- [ ] 创建Tool C页面
+ ```typescript
+ // frontend-v2/src/modules/dc/pages/tool-c/index.tsx
+ import { AgGridReact } from 'ag-grid-react';
+ import { Upload, Spin } from 'antd';
+
+ export default function ToolCEditor() {
+ const [sessionId, setSessionId] = useState();
+ const [data, setData] = useState([]);
+ const [columns, setColumns] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleUpload = async (file: File) => {
+ setIsLoading(true);
+ const formData = new FormData();
+ formData.append('file', file);
+
+ const response = await api.post('/api/v1/dc/tool-c/session/init', formData);
+
+ setSessionId(response.data.sessionId);
+ setData(response.data.data.preview);
+ setColumns(response.data.data.columns);
+ setIsLoading(false);
+ };
+
+ return (
+
+ {/* 左侧:表格区域 */}
+
+ {!sessionId ? (
+
+
+
+ ) : (
+
({
+ field: col.name,
+ headerName: col.name
+ }))}
+ />
+ )}
+
+
+ {/* 右侧:AI侧边栏(占位) */}
+
+
AI助手
+
+
+ );
+ }
+ ```
+- [ ] 集成AG Grid
+ ```bash
+ cd frontend-v2
+ npm install ag-grid-react ag-grid-community
+ ```
+- [ ] 路由配置
+ ```typescript
+ // frontend-v2/src/modules/dc/routes.tsx
+ {
+ path: 'tool-c',
+ element:
+ }
+ ```
+
+**测试用例:**
+- [ ] 上传文件,表格正确显示
+- [ ] 中文列名显示正常
+- [ ] 空值单元格有视觉提示
+
+**验收标准:**
+- ✅ 用户能看到左右分栏界面
+- ✅ 表格能展示100行数据
+
+**负责人:** 前端开发
+
+---
+
+#### Day 5:System Prompt构建
+
+**任务清单:**
+- [ ] 创建Prompt模板
+ ```typescript
+ // backend/src/modules/dc/tool-c/prompts/system-prompt.ts
+ export function buildSystemPrompt(dataContext: DataContext): string {
+ return `# AI医疗数据清洗助手 - 系统角色
+
+## 当前数据结构
+- 总行数:${dataContext.totalRows} 行
+- 总列数:${dataContext.totalCols} 列
+- 列名:${dataContext.columns.map(c => c.name).join(', ')}
+
+### 前5行数据示例
+${JSON.stringify(dataContext.headData, null, 2)}
+
+## 严格规则
+1. 只能使用pandas操作(已预导入为pd)
+2. 变量名必须是df(不要用其他名字)
+3. 就地修改:df['new'] = ... 或 df.drop(...)
+4. 不要print()、display()等输出
+5. 禁止import os、sys、requests等
+
+## Few-shot示例(分层难度:基础→中等→高级)
+
+### 🟢 基础场景(单步骤操作)
+#### 场景1:年龄分组
+用户:"把年龄大于60的标记为老年组"
+代码:
+df['age_group'] = df['age'].apply(lambda x: '老年组' if pd.notna(x) and x > 60 else '非老年组')
+
+#### 场景2:删除缺失
+用户:"删除没有患者ID的行"
+代码:
+df.dropna(subset=['patient_id'], inplace=True)
+
+#### 场景3:性别编码
+用户:"把性别转为数字"
+代码:
+df['gender_code'] = df['gender'].map({'男': 1, '女': 0})
+
+### 🟡 中等场景(多步骤或跨列逻辑)
+#### 场景4:计算NLR并分组
+用户:"计算中性粒细胞淋巴细胞比值NLR,并按2.5分为高低两组"
+代码:
+df['NLR'] = df.apply(lambda row: row['neutrophil'] / row['lymphocyte'] if pd.notna(row['neutrophil']) and pd.notna(row['lymphocyte']) and row['lymphocyte'] > 0 else None, axis=1)
+df['NLR_group'] = df['NLR'].apply(lambda x: 'High' if pd.notna(x) and x > 2.5 else 'Low')
+
+#### 场景5:字符串拆分(血压)
+用户:"把血压列的'120/80'格式拆分成收缩压和舒张压,并判断是否高血压"
+代码:
+df[['systolic_bp', 'diastolic_bp']] = df['blood_pressure'].str.split('/', expand=True)
+df['systolic_bp'] = pd.to_numeric(df['systolic_bp'], errors='coerce')
+df['diastolic_bp'] = pd.to_numeric(df['diastolic_bp'], errors='coerce')
+df['is_hypertension'] = ((df['systolic_bp'] > 140) | (df['diastolic_bp'] > 90)).astype(int)
+
+#### 场景6:时间差计算(逻辑验证)
+用户:"计算住院天数,如果出院日期早于入院日期则标记为异常"
+代码:
+df['admission_date'] = pd.to_datetime(df['admission_date'], errors='coerce')
+df['discharge_date'] = pd.to_datetime(df['discharge_date'], errors='coerce')
+df['hospital_days'] = (df['discharge_date'] - df['admission_date']).dt.days
+df['date_error'] = df['hospital_days'] < 0
+df.loc[df['date_error'], 'hospital_days'] = None
+
+### 🔴 高级场景(分组聚合、时间序列、医学规则)
+#### 场景7:生存时间计算(复杂条件逻辑)
+用户:"生成生存状态和生存时间,如果死亡日期存在则状态为1,时间为死亡日期减诊断日期,否则状态为0,时间为随访截止日期减诊断日期"
+代码:
+df['diagnosis_date'] = pd.to_datetime(df['diagnosis_date'], errors='coerce')
+df['death_date'] = pd.to_datetime(df['death_date'], errors='coerce')
+df['followup_end_date'] = pd.to_datetime(df['followup_end_date'], errors='coerce')
+df['vital_status'] = df['death_date'].notna().astype(int)
+df['survival_days'] = df.apply(lambda row: (row['death_date'] - row['diagnosis_date']).days if pd.notna(row['death_date']) else (row['followup_end_date'] - row['diagnosis_date']).days, axis=1)
+df['survival_months'] = (df['survival_days'] / 30.44).round(1)
+
+#### 场景8:分组聚合(首末记录)
+用户:"对每个患者找出第一次化疗日期和最后一次化疗日期,计算持续时间"
+代码:
+df['chemo_date'] = pd.to_datetime(df['chemo_date'], errors='coerce')
+patient_chemo = df.groupby('patient_id')['chemo_date'].agg(['min', 'max']).reset_index()
+patient_chemo.columns = ['patient_id', 'first_chemo', 'last_chemo']
+patient_chemo['chemo_duration_days'] = (patient_chemo['last_chemo'] - patient_chemo['first_chemo']).dt.days
+df = df.merge(patient_chemo[['patient_id', 'first_chemo', 'last_chemo', 'chemo_duration_days']], on='patient_id', how='left')
+
+#### 场景9:时间序列变化率
+用户:"按患者ID分组,计算每次随访相比上次的肿瘤大小变化率"
+代码:
+df = df.sort_values(['patient_id', 'followup_date'])
+df['prev_tumor_size'] = df.groupby('patient_id')['tumor_size'].shift(1)
+df['tumor_change_rate'] = ((df['tumor_size'] - df['prev_tumor_size']) / df['prev_tumor_size'] * 100).round(2)
+df['tumor_change_rate'] = df['tumor_change_rate'].fillna(0)
+
+#### 场景10:医学规则引擎(肝功能分级)
+用户:"根据ALT、AST、ALP、TBIL判断肝功能分级"
+代码:
+def classify_liver_function(row):
+ abnormal_count = 0
+ if pd.notna(row.get('ALT')) and row['ALT'] > 40: abnormal_count += 1
+ if pd.notna(row.get('AST')) and row['AST'] > 40: abnormal_count += 1
+ if pd.notna(row.get('ALP')) and row['ALP'] > 125: abnormal_count += 1
+ if pd.notna(row.get('TBIL')) and row['TBIL'] > 20: abnormal_count += 1
+ if abnormal_count == 0: return '正常'
+ elif abnormal_count == 1: return '轻度异常'
+ elif abnormal_count == 2: return '中度异常'
+ else: return '重度异常'
+df['liver_function_grade'] = df.apply(classify_liver_function, axis=1)
+
+现在,请准备好接收用户的指令。记住:代码要安全、可靠、易懂,能处理从基础到高级的复杂医疗场景。
+`;
+ }
+ ```
+- [ ] 集成LLMFactory(✅ 复用平台通用能力层)
+ ```typescript
+ // backend/src/modules/dc/tool-c/services/AICodeService.ts
+ import { LLMFactory } from '@/common/llm'; // ✅ 复用平台LLM能力
+ import { logger } from '@/common/logging'; // ✅ 复用日志
+
+ export class AICodeService {
+ /**
+ * 生成Pandas代码(✅ 复用LLMFactory)
+ */
+ async generateCode(prompt: string, dataContext: DataContext): Promise {
+ logger.info('Generating Pandas code', { prompt, dataContext });
+
+ // ✅ 复用平台LLM服务
+ const llm = LLMFactory.getLLM('deepseek-v3');
+
+ const systemPrompt = buildSystemPrompt(dataContext);
+
+ const response = await llm.chat([
+ { role: 'system', content: systemPrompt },
+ { role: 'user', content: prompt }
+ ]);
+
+ // 提取纯代码(去除Markdown格式)
+ const code = this.extractCode(response.content);
+
+ logger.info('Code generated successfully', { codeLength: code.length });
+
+ return code;
+ }
+
+ /**
+ * AI自我修复(失败后重试1次)
+ */
+ async fixCode(originalCode: string, errorMsg: string, dataContext: DataContext): Promise {
+ logger.warn('Code execution failed, attempting self-repair', { errorMsg });
+
+ const llm = LLMFactory.getLLM('deepseek-v3');
+
+ const fixPrompt = `以下代码执行失败,请修复:
+
+错误信息:
+${errorMsg}
+
+原始代码:
+${originalCode}
+
+数据结构:
+${JSON.stringify(dataContext)}
+
+请生成修复后的代码(不要有Markdown格式):`;
+
+ const response = await llm.chat([{ role: 'user', content: fixPrompt }]);
+
+ return this.extractCode(response.content);
+ }
+
+ private extractCode(text: string): string {
+ // 去除```python```或```标记
+ const match = text.match(/```(?:python)?\n([\s\S]*?)\n```/);
+ return match ? match[1] : text;
+ }
+ }
+ ```
+
+**测试用例:**
+- [ ] 输入"年龄分组",生成正确代码
+- [ ] 输入"删除空行",生成正确代码
+- [ ] 检查代码中是否包含危险语句
+
+**验收标准:**
+- ✅ AI能生成可执行的Pandas代码
+- ✅ 代码符合规范(无print、无import)
+
+**负责人:** Node.js后端
+
+---
+
+### Week 2:核心功能开发(5天)
+
+#### Day 6-7:AI代码生成 + AST检查
+
+**Day 6任务:**
+- [ ] 实现AST静态检查
+ ```python
+ # python-service/code_validator.py
+ import ast
+
+ DANGEROUS_IMPORTS = {'os', 'sys', 'subprocess', 'requests', 'urllib'}
+ DANGEROUS_BUILTINS = {'eval', 'exec', 'compile', 'open', '__import__'}
+
+ def validate_code_safety(code: str) -> Tuple[bool, str]:
+ try:
+ tree = ast.parse(code)
+
+ for node in ast.walk(tree):
+ # 检查import
+ if isinstance(node, ast.Import):
+ for alias in node.names:
+ if alias.name in DANGEROUS_IMPORTS:
+ return False, f"禁止导入:{alias.name}"
+
+ # 检查函数调用
+ if isinstance(node, ast.Call):
+ if isinstance(node.func, ast.Name):
+ if node.func.id in DANGEROUS_BUILTINS:
+ return False, f"禁止使用:{node.func.id}"
+
+ return True, "验证通过"
+ except SyntaxError as e:
+ return False, f"语法错误:{str(e)}"
+ ```
+
+**Day 7任务:**
+- [ ] 实现AI代码生成API
+ ```typescript
+ // Node.js
+ fastify.post('/api/v1/dc/tool-c/ai/generate', async (req, reply) => {
+ const { sessionId, prompt } = req.body;
+
+ // 1. 获取数据上下文
+ const context = await pythonService.getDataContext(sessionId);
+
+ // 2. 调用AI生成代码
+ const code = await aiService.generateCode(prompt, context);
+
+ return {
+ success: true,
+ code,
+ summary: `将执行以下操作:${extractSummary(code)}`
+ };
+ });
+ ```
+
+**测试场景(15个真实医疗数据清洗场景):**
+
+**🟢 基础场景(5个)- 单步骤操作:**
+1. [ ] "把年龄大于60的标记为老年组" - 简单条件判断
+2. [ ] "删除所有患者ID为空的行" - 数据完整性清洗
+3. [ ] "把性别转为数字,男1女0" - 分类变量编码
+4. [ ] "计算BMI = 体重 / (身高/100)^2" - 简单公式计算
+5. [ ] "删除缺失率超过50%的列" - 列级数据质量控制
+
+**🟡 中等场景(5个)- 多步骤或跨列逻辑:**
+6. [ ] "把诊断日期和出院日期计算天数差,如果出院日期早于诊断日期则标记为异常" - 逻辑验证
+7. [ ] "根据白细胞、中性粒细胞、淋巴细胞三个指标,计算NLR(中性粒细胞/淋巴细胞),并按2.5分为高低两组" - 多步骤计算
+8. [ ] "从病理报告列中提取TNM分期,生成新列,如果没有提取到则标记为'未分期'" - 文本提取(可用正则)
+9. [ ] "把血压列中的'120/80'格式拆分成收缩压和舒张压两列,并判断是否高血压(收缩压>140 or 舒张压>90)" - 字符串处理+逻辑判断
+10. [ ] "删除重复的患者ID,保留最新的一条记录(根据就诊日期)" - 去重+排序
+
+**🔴 高级场景(5个)- 复杂分组、时间序列、医学规则:**
+11. [ ] "对于每个患者,找出第一次化疗日期和最后一次化疗日期,计算化疗持续时间" - 分组聚合
+12. [ ] "生成生存状态变量:如果死亡日期存在则为1,否则为0;生成生存时间:如果死亡则为(死亡日期-诊断日期),否则为(随访截止日期-诊断日期)" - 复杂条件逻辑
+13. [ ] "根据多个实验室指标(ALT、AST、ALP、TBIL)判断肝功能分级(正常、轻度异常、中度异常、重度异常)" - 医学规则引擎
+14. [ ] "按患者ID分组,对每个患者的多次随访记录,计算相邻两次之间的指标变化率(如肿瘤大小变化率)" - 时间序列分析
+15. [ ] "根据入院时间,计算患者的季节变量(春夏秋冬),然后统计不同季节的发病人数" - 时间特征提取+统计分析
+
+**验收标准(分层要求):**
+- ✅ **基础场景成功率 > 90%**(5/5或4/5成功)
+- ✅ **中等场景成功率 > 80%**(4/5成功)
+- ✅ **高级场景成功率 > 60%**(3/5成功)
+- ✅ **总体成功率 > 80%**(12/15场景成功)
+- ✅ AST能拦截`import os`等危险代码
+- ❌ 如果总体成功率 < 60%(9/15失败),**MVP失败,需要Pivot到模板库模式**
+
+**负责人:** Node.js后端 + Python开发
+
+---
+
+#### Day 8:代码执行 + 表格刷新
+
+**任务清单:**
+- [ ] 实现代码执行API
+ ```python
+ # Python
+ @app.post("/api/python/execute")
+ async def execute_code(request: ExecuteRequest):
+ # 1. 获取Session
+ df = session_manager.get(request.sessionId)
+
+ # 2. AST检查
+ is_safe, error_msg = validate_code_safety(request.code)
+ if not is_safe:
+ return {"success": False, "error": error_msg}
+
+ # 3. 执行代码
+ try:
+ exec(request.code, {'df': df, 'pd': pd, 'np': np})
+
+ # 4. 返回预览数据
+ preview = df.head(100).to_dict('records')
+
+ return {
+ "success": True,
+ "preview": preview,
+ "stats": {
+ "totalRows": len(df),
+ "totalCols": len(df.columns)
+ }
+ }
+ except Exception as e:
+ return {
+ "success": False,
+ "error": str(e),
+ "traceback": traceback.format_exc()
+ }
+ ```
+- [ ] 前端执行流程
+ ```typescript
+ async function executeAICode(code: string) {
+ // 1. 展示预操作卡片
+ const confirmed = await showActionCard(code);
+ if (!confirmed) return;
+
+ // 2. 锁定表格
+ setIsLocked(true);
+
+ try {
+ // 3. 执行代码
+ const response = await api.post('/api/v1/dc/tool-c/ai/execute', {
+ sessionId,
+ code
+ });
+
+ if (response.data.success) {
+ // 4. 刷新表格
+ setData(response.data.preview);
+ message.success('执行成功!');
+ } else {
+ message.error(`执行失败:${response.data.error}`);
+ }
+ } finally {
+ // 5. 解锁表格
+ setIsLocked(false);
+ }
+ }
+ ```
+
+**测试用例:**
+- [ ] 执行成功,表格正确刷新
+- [ ] 执行失败,显示错误信息
+- [ ] 执行期间,表格处于锁定状态
+
+**验收标准:**
+- ✅ 代码能正确修改DataFrame
+- ✅ 前端能实时看到变化
+
+**负责人:** Python开发 + 前端
+
+---
+
+#### Day 9:UI锁定 + 预操作卡片
+
+**任务清单:**
+- [ ] 实现AI对话UI
+ ```typescript
+ function AIChatPanel({ sessionId }: Props) {
+ const [messages, setMessages] = useState([]);
+ const [input, setInput] = useState('');
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const handleSend = async () => {
+ if (!input.trim()) return;
+
+ // 1. 添加用户消息
+ setMessages(prev => [...prev, {
+ role: 'user',
+ content: input
+ }]);
+
+ setIsProcessing(true);
+
+ // 2. 调用AI生成代码
+ const response = await api.post('/api/v1/dc/tool-c/ai/generate', {
+ sessionId,
+ prompt: input
+ });
+
+ // 3. 添加AI消息(包含代码)
+ setMessages(prev => [...prev, {
+ role: 'assistant',
+ content: response.data.summary,
+ code: response.data.code
+ }]);
+
+ setIsProcessing(false);
+ setInput('');
+ };
+
+ return (
+
+ {/* 消息列表 */}
+
+ {messages.map((msg, idx) => (
+
+ ))}
+
+
+ {/* 输入框 */}
+
+ setInput(e.target.value)}
+ placeholder="输入指令,例如:把年龄大于60的标记为老年组"
+ disabled={isProcessing}
+ />
+
+
+
+ );
+ }
+ ```
+- [ ] 实现预操作卡片
+ ```typescript
+ function ActionCard({ code, onConfirm, onCancel }: Props) {
+ return (
+
+
+ AI生成的代码 - 请确认后执行
+
+
+ {code}
+
+
+
+
+
+
+ );
+ }
+ ```
+- [ ] 实现UI锁定
+ ```typescript
+
+
+ {isLocked && (
+
+
+
+ )}
+ ```
+
+**验收标准:**
+- ✅ 用户能发送消息
+- ✅ AI返回代码时展示预操作卡片
+- ✅ 执行期间表格锁定
+
+**负责人:** 前端
+
+---
+
+#### Day 10:导出 + 端到端测试
+
+**任务清单:**
+- [ ] 实现导出API
+ ```python
+ @app.get("/api/python/export/{session_id}")
+ async def export_excel(session_id: str):
+ df = session_manager.get(session_id)
+
+ # 生成Excel
+ output = io.BytesIO()
+ df.to_excel(output, index=False, engine='openpyxl')
+ output.seek(0)
+
+ return StreamingResponse(
+ output,
+ media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ headers={
+ 'Content-Disposition': f'attachment; filename=cleaned_data_{session_id}.xlsx'
+ }
+ )
+ ```
+- [ ] 前端导出按钮
+ ```typescript
+ const handleExport = async () => {
+ const response = await api.get(`/api/v1/dc/tool-c/session/export/${sessionId}`, {
+ responseType: 'blob'
+ });
+
+ const url = window.URL.createObjectURL(response.data);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'cleaned_data.xlsx';
+ a.click();
+ };
+ ```
+- [ ] **端到端测试(完整流程)**
+ ```
+ 1. 上传 test_data.xlsx (5000行 × 20列)
+ 2. AI指令:"把年龄大于60的标记为老年组"
+ 3. 确认 → 执行 → 表格刷新(验证新增列)
+ 4. AI指令:"删除患者ID为空的行"
+ 5. 确认 → 执行 → 表格刷新(验证行数减少)
+ 6. 点击"导出" → 下载文件
+ 7. 打开下载的文件,验证数据正确
+ ```
+
+**验收标准:**
+- ✅ 整个流程 < 2分钟
+- ✅ 导出的Excel数据正确
+- ✅ AI代码执行成功
+
+**负责人:** 全员
+
+---
+
+### Week 3:优化与测试(5天)
+
+#### Day 11-12:错误处理 + AI自我修复
+
+**任务清单:**
+- [ ] 实现AI自我修复
+ ```typescript
+ async function executeWithRetry(code: string): Promise {
+ // 第一次执行
+ let result = await pythonService.execute(sessionId, code);
+
+ if (!result.success) {
+ // 失败,让AI修复
+ const fixedCode = await aiService.fixCode(code, result.error);
+
+ // 重试1次
+ result = await pythonService.execute(sessionId, fixedCode);
+
+ if (!result.success) {
+ // 彻底失败
+ return {
+ success: false,
+ error: '代码执行失败,请尝试更详细地描述您的需求',
+ originalError: result.error
+ };
+ }
+ }
+
+ return result;
+ }
+ ```
+- [ ] 优化错误提示
+ ```typescript
+ function showErrorDetail(error: string) {
+ const errorMap = {
+ "KeyError: 'age'": "列名'age'不存在,请检查列名是否正确",
+ "ValueError": "数据类型不匹配,请检查数据格式",
+ "MemoryError": "数据量过大,请减少数据行数"
+ };
+
+ const friendlyMsg = errorMap[error] || error;
+
+ Modal.error({
+ title: '执行失败',
+ content: friendlyMsg
+ });
+ }
+ ```
+
+**测试场景(边界情况):**
+- [ ] 列名不存在:`df['nonexistent']`
+- [ ] 语法错误:`df[df['age'] > 60 and df['age'] < 80]`
+- [ ] 数据类型错误:`df['age'] + '字符串'`
+- [ ] 内存溢出:处理超大数据
+
+**验收标准:**
+- ✅ 常见错误能自我修复
+- ✅ 无法修复时有友好提示
+
+**负责人:** Node.js后端
+
+---
+
+#### Day 13:快捷模板 + 编码检测
+
+**任务清单:**
+- [ ] 实现快捷模板
+ ```typescript
+ const QUICK_TEMPLATES = {
+ '年龄分组': {
+ label: '年龄分组(60岁分界)',
+ code: `df['age_group'] = pd.cut(df['age'], bins=[0,60,150], labels=['非老年','老年'])`
+ },
+ '删除空行': {
+ label: '删除空行',
+ code: `df.dropna(how='all', inplace=True)`
+ },
+ '性别编码': {
+ label: '性别编码(男1女0)',
+ code: `df['gender_code'] = df['gender'].map({'男':1, '女':0})`
+ }
+ };
+
+ function QuickActions() {
+ return (
+
+
快捷操作
+ {Object.entries(QUICK_TEMPLATES).map(([key, template]) => (
+
+ ))}
+
+ );
+ }
+ ```
+- [ ] 实现编码检测
+ ```python
+ import chardet
+
+ def detect_encoding(file_bytes: bytes) -> str:
+ result = chardet.detect(file_bytes)
+ encoding = result['encoding']
+ confidence = result['confidence']
+
+ if confidence < 0.8:
+ raise ValueError(f"无法确定文件编码(置信度{confidence:.0%})")
+
+ return encoding
+
+ @app.post("/api/python/init")
+ async def init_session(file: UploadFile):
+ content = await file.read()
+
+ # 检测编码
+ encoding = detect_encoding(content)
+
+ if encoding.lower() not in ['utf-8', 'utf-8-sig']:
+ return {
+ "success": False,
+ "error": f"文件编码为{encoding},请转换为UTF-8后重新上传",
+ "suggestion": "在Excel中另存为CSV UTF-8格式"
+ }
+
+ # 正常加载
+ # ...
+ ```
+
+**验收标准:**
+- ✅ 快捷模板一键执行
+- ✅ GBK文件被友好拦截
+
+**负责人:** 前端 + Python开发
+
+---
+
+#### Day 14:性能测试 + 压力测试
+
+**测试场景:**
+- [ ] **性能测试**
+ ```
+ 测试数据:5000行 × 20列(约5MB)
+
+ 场景1:上传文件
+ - 目标:< 5秒
+ - 实测:____秒
+
+ 场景2:AI生成代码
+ - 目标:< 5秒
+ - 实测:____秒
+
+ 场景3:代码执行+刷新
+ - 目标:< 3秒
+ - 实测:____秒
+
+ 场景4:导出Excel
+ - 目标:< 3秒
+ - 实测:____秒
+
+ 总计:< 16秒
+ ```
+- [ ] **压力测试**
+ ```
+ 场景1:并发用户
+ - 5个用户同时上传文件
+ - 验证:Session隔离,互不影响
+
+ 场景2:大数据量
+ - 上传50000行 × 50列(约10MB)
+ - 验证:不崩溃,响应时间可接受
+
+ 场景3:连续操作
+ - 连续执行10次AI指令
+ - 验证:内存不泄漏
+ ```
+
+**性能优化(如果不达标):**
+- [ ] 前端:AG Grid虚拟滚动配置
+- [ ] 后端:DataFrame操作改为惰性计算
+- [ ] Python:使用Polars替代Pandas(如果需要)
+
+**验收标准:**
+- ✅ 单次操作 < 16秒
+- ✅ 5个并发用户正常工作
+- ✅ 无内存泄漏
+
+**负责人:** 全员
+
+---
+
+#### Day 15:文档 + 演示准备
+
+**任务清单:**
+- [ ] 编写用户文档
+ ```markdown
+ # 工具C使用指南
+
+ ## 快速开始
+ 1. 点击"上传文件",选择Excel(限10MB)
+ 2. 等待3-5秒,表格加载完成
+ 3. 在右侧AI助手输入指令,例如:"把年龄大于60的标记为老年组"
+ 4. 点击"运行代码"确认
+ 5. 查看表格自动刷新
+ 6. 完成所有操作后,点击"导出"下载结果
+
+ ## 常见问题
+ Q: 文件上传失败,提示文件过大?
+ A: 请将Excel文件压缩到10MB以内,或删除不需要的列。
+
+ Q: 列名显示乱码?
+ A: 请在Excel中另存为"CSV UTF-8"格式后重新上传。
+ ```
+- [ ] 准备演示数据
+ ```
+ 创建 demo_data.xlsx:
+ - 100行患者数据
+ - 包含:patient_id, name, age, gender, admission_date, bmi
+ - 故意制造一些问题:空值、异常值、需要清洗的数据
+ ```
+- [ ] 准备演示脚本
+ ```
+ 演示流程(5分钟):
+ 1. 上传demo_data.xlsx
+ 2. AI指令:"把年龄大于60的标记为老年组"
+ 3. AI指令:"删除患者ID为空的行"
+ 4. AI指令:"把性别转为数字,男1女0"
+ 5. 导出结果
+ 6. 展示导出的Excel文件
+ ```
+
+**验收标准:**
+- ✅ 文档清晰易懂
+- ✅ 演示流畅无卡顿
+- ✅ 演示数据能体现核心功能
+
+**负责人:** 全员
+
+---
+
+## 五、风险应对策略
+
+### 5.1 风险清单与应对
+
+| 风险 | 概率 | 影响 | 应对策略 | 降级方案 |
+|------|------|------|---------|---------|
+| **AI代码质量低(成功率<60%)** | 中 | 致命 | 1. 优化Prompt工程
2. 增加Few-shot示例
3. 实现自我修复 | **Pivot:改用代码模板库** |
+| **Apache Arrow集成困难** | 高 | 高 | 1. MVP不用Arrow
2. 直接用JSON | **已降级:MVP用JSON** |
+| **Redis内存成本高** | 中 | 中 | 1. MVP用进程内存
2. 激进的Session过期 | **已降级:用Map缓存** |
+| **Python内存泄漏** | 中 | 高 | 1. 不做历史快照
2. 定期重启进程 | **SAE自动重启** |
+| **中文Excel乱码** | 高 | 中 | 1. chardet自动检测
2. 友好报错提示 | **文档说明转UTF-8** |
+| **SAE冷启动慢** | 高 | 中 | 1. 最小实例数=1
2. 异步初始化 | **Loading优化** |
+| **前端AG Grid性能差** | 低 | 中 | 1. 只展示100行
2. 虚拟滚动 | **已优化** |
+
+### 5.2 快速失败触发器
+
+**立即停止开发的条件:**
+
+1. **Day 7结束,AI代码成功率 < 60%**
+ - 决策:放弃AI Code Interpreter路线
+ - Pivot:改为"代码模板库 + 参数化配置"
+
+2. **Day 10结束,端到端时间 > 30秒**
+ - 决策:性能无法接受
+ - Pivot:改为批处理模式(上传 → 后台处理 → 下载)
+
+3. **Day 14结束,3个用户测试,都无法独立完成任务**
+ - 决策:交互设计失败
+ - Pivot:重新设计UI,增加新手引导
+
+---
+
+## 六、验收标准
+
+### 6.1 功能验收清单
+
+| 编号 | 验收项 | 验收标准 | 验收方式 |
+|------|--------|---------|---------|
+| **F-001** | 文件上传 | 能上传10MB以内的Excel | 手动测试 |
+| **F-002** | 编码检测 | GBK文件被友好拦截 | 手动测试 |
+| **F-003** | 表格展示 | 100行数据正确显示,中文无乱码 | 手动测试 |
+| **F-004** | AI对话 | 能发送消息,接收回复 | 手动测试 |
+| **F-005** | 代码生成 | **10个场景,8个成功(80%)** | 自动化测试 |
+| **F-006** | AST检查 | 拦截`import os`等危险代码 | 单元测试 |
+| **F-007** | 代码执行 | 能正确修改DataFrame | 集成测试 |
+| **F-008** | 表格刷新 | 执行后自动更新 | 手动测试 |
+| **F-009** | UI锁定 | AI处理时表格只读+遮罩 | 手动测试 |
+| **F-010** | 导出Excel | 下载的文件数据正确 | 手动测试 |
+
+### 6.2 性能验收标准
+
+| 指标 | 目标值 | 验收方式 |
+|------|--------|---------|
+| 文件上传到表格显示 | < 5秒 | 性能测试 |
+| AI生成代码 | < 5秒 | 性能测试 |
+| 代码执行+刷新 | < 3秒 | 性能测试 |
+| 导出Excel | < 3秒 | 性能测试 |
+| **端到端总时间** | **< 16秒** | 性能测试 |
+| 并发用户数 | ≥ 5人 | 压力测试 |
+| 内存占用 | < 2GB(5用户) | 压力测试 |
+
+### 6.3 安全验收标准
+
+| 指标 | 验收标准 | 验收方式 |
+|------|---------|---------|
+| 代码沙箱 | 拦截所有危险代码 | 渗透测试 |
+| Session隔离 | 用户A看不到用户B数据 | 并发测试 |
+| Session过期 | 10分钟后自动清理 | 时间测试 |
+
+---
+
+## 七、快速失败机制
+
+### 7.1 关键检查点
+
+```
+Checkpoint 1 (Day 5结束):
+├─ System Prompt能否让AI理解数据?
+├─ AI能生成Pandas代码吗?
+└─ 决策:继续 or 调整Prompt策略
+
+Checkpoint 2 (Day 7结束):
+├─ AI代码成功率 ≥ 80%?
+├─ 如果 < 60%:立即停止,改用模板库
+└─ 如果 60-80%:继续优化Prompt
+
+Checkpoint 3 (Day 10结束):
+├─ 端到端流程能跑通?
+├─ 性能 < 16秒?
+└─ 决策:继续 or 性能优化
+
+Checkpoint 4 (Day 14结束):
+├─ 用户测试通过?
+├─ 无重大Bug?
+└─ 决策:发布 or 修复Bug
+```
+
+### 7.2 Pivot决策树
+
+```
+如果 AI代码成功率 < 60%:
+ ├─ Pivot 1:改用"代码模板库 + 参数化配置"
+ │ └─ 用户选择模板 → 填写参数 → 生成代码
+ │
+ ├─ Pivot 2:AI变成"辅助建议"角色
+ │ └─ 用户手动写代码,AI提供建议
+ │
+ └─ Pivot 3:简化为"批处理模式"
+ └─ 上传 → 选择预设操作 → 后台处理 → 下载
+
+如果 性能无法接受(> 30秒):
+ ├─ 方案1:引入Apache Arrow
+ ├─ 方案2:使用Polars替代Pandas
+ └─ 方案3:改为批处理+异步通知
+
+如果 用户无法独立完成任务:
+ ├─ 方案1:增加交互式新手引导
+ ├─ 方案2:提供示例数据集
+ └─ 方案3:简化UI,减少选项
+```
+
+---
+
+## 八、附录
+
+### 8.1 测试数据准备
+
+**创建标准测试数据集:**
+```python
+# create_test_data.py
+import pandas as pd
+import numpy as np
+
+# 生成5000行测试数据
+data = {
+ 'patient_id': [f'P{i:04d}' for i in range(1, 5001)],
+ 'name': [f'患者{i}' for i in range(1, 5001)],
+ 'age': np.random.randint(18, 90, 5000),
+ 'gender': np.random.choice(['男', '女'], 5000),
+ 'admission_date': pd.date_range('2023-01-01', periods=5000, freq='H'),
+ 'weight': np.random.uniform(45, 95, 5000).round(1),
+ 'height': np.random.uniform(150, 190, 5000).round(0),
+ 'diagnosis': np.random.choice(['肺癌', '糖尿病', '高血压'], 5000)
+}
+
+df = pd.DataFrame(data)
+
+# 故意制造问题
+df.loc[np.random.choice(5000, 100, replace=False), 'age'] = None # 100个缺失
+df.loc[np.random.choice(5000, 10, replace=False), 'age'] = 150 # 10个异常值
+df.loc[np.random.choice(5000, 50, replace=False), 'patient_id'] = None # 50个空ID
+
+df.to_excel('test_data.xlsx', index=False)
+```
+
+### 8.2 10个典型场景测试用例
+
+```python
+# test_ai_scenarios.py
+test_cases = [
+ {
+ "id": "TC-001",
+ "prompt": "把年龄大于60的患者标记为老年组",
+ "expected_code": "df['age_group'] = df['age'].apply(lambda x: '老年组' if pd.notna(x) and x > 60 else '非老年组')",
+ "verify": lambda df: 'age_group' in df.columns
+ },
+ {
+ "id": "TC-002",
+ "prompt": "删除所有患者ID为空的行",
+ "expected_code": "df.dropna(subset=['patient_id'], inplace=True)",
+ "verify": lambda df: df['patient_id'].isnull().sum() == 0
+ },
+ # ... 其余8个场景
+]
+```
+
+### 8.3 环境配置清单
+
+**Node.js依赖:**
+```json
+{
+ "dependencies": {
+ "fastify": "^4.0.0",
+ "axios": "^1.6.0",
+ "joi": "^17.11.0",
+ "@fastify/multipart": "^8.0.0"
+ }
+}
+```
+
+**Python依赖:**
+```txt
+fastapi==0.115.0
+uvicorn==0.30.0
+pandas==2.2.0
+openpyxl==3.1.0
+chardet==5.2.0
+python-multipart==0.0.9
+```
+
+---
+
+## 九、项目管理
+
+### 9.1 团队配置
+
+| 角色 | 人数 | 职责 |
+|------|------|------|
+| 前端开发 | 1人 | React + AG Grid + UI |
+| Node.js后端 | 1人 | BFF + LLM集成 + Prompt工程 |
+| Python开发 | 1人 | FastAPI + DataFrame + AST检查 |
+| **总计** | **3人** | **3周(15天)** |
+
+### 9.2 沟通机制
+
+- **每日站会**:15分钟,同步进度和问题
+- **关键检查点**:Day 5、7、10、14
+- **问题升级**:阻塞问题1小时内升级
+- **文档更新**:每日更新开发记录
+
+### 9.3 代码管理
+
+**分支策略:**
+```
+main (稳定版)
+ └── develop (开发版)
+ ├── feature/tool-c-frontend
+ ├── feature/tool-c-backend
+ └── feature/tool-c-python
+```
+
+**提交规范:**
+```
+feat: 新增AI代码生成功能
+fix: 修复表格刷新Bug
+test: 增加AST检查测试用例
+docs: 更新开发文档
+```
+
+---
+
+## 十、总结
+
+### 核心成功要素
+1. ✅ **AI代码质量**:成功率 > 80%(核心假设)
+2. ✅ **性能可接受**:端到端 < 16秒
+3. ✅ **交互简单**:用户无需文档就能用
+
+### 风险控制
+1. ✅ **快速失败**:7天验证AI能力,不行立即Pivot
+2. ✅ **务实技术**:JSON不用Arrow,内存不用Redis
+3. ✅ **降级方案**:准备好模板库、批处理等Plan B
+
+### 时间节点
+- **Week 1**:基础架构(5天)
+- **Week 2**:核心功能(5天)
+- **Week 3**:优化测试(5天)
+- **总计**:15个工作日
+
+---
+
+## 📝 文档修订记录
+
+### V1.3(2025-12-06)- 发现现有Python服务 ⭐ 重大发现
+
+**修正内容**:检查系统发现已有Python微服务,不需要重复开发:
+
+#### 修正1:复用现有Python服务,不重复造轮 ⭐⭐⭐⭐⭐
+- **重大发现**:系统已有 `extraction_service/`(FastAPI + Pandas + openpyxl)
+- **现有功能**:
+ - ✅ PDF/Docx/Txt文档提取(PyMuPDF + Mammoth)
+ - ✅ Pandas、openpyxl、chardet、langdetect已安装
+ - ✅ FastAPI框架已运行(端口8000)
+ - ✅ Node.js已有ExtractionClient集成
+- **新增方案**:
+ - ✅ 扩展现有服务,添加 `/api/dc/execute` 端点
+ - ✅ 新增 `dc_executor.py` 模块(AST检查 + 代码执行)
+ - ✅ 复用ExtractionClient模式调用
+- **避免重复**:
+ - ❌ 不需要新建Python项目
+ - ❌ 不需要重新安装依赖
+ - ❌ 不需要重新写HTTP调用逻辑
+
+---
+
+### V1.2(2025-12-06)- Python执行环境 + 复杂场景 ⚠️ 核心功能
+
+**修正内容**:根据用户反馈,明确Python代码执行是核心功能:
+
+#### 修正1:Python执行是核心,不是可选 ⭐⭐⭐⭐⭐
+- **原错误**:说"MVP阶段可能不需要Python微服务"
+- **已修正**:**Python代码执行是工具C的核心价值,必须实现**
+- **新增内容**:
+ - Day 1增加Python环境搭建
+ - 新增PythonExecutorService(Node.js ↔ Python通信)
+ - 新增executor.py(Pandas代码执行器)
+ - 技术方案:Node.js child_process调用Python脚本
+
+#### 修正2:测试场景从简单到复杂 ✅
+- **原问题**:10个测试场景过于简单
+- **已修正**:15个真实医疗数据清洗场景
+ - 🟢 基础场景5个:单步骤操作
+ - 🟡 中等场景5个:多步骤、跨列逻辑
+ - 🔴 高级场景5个:分组聚合、时间序列、医学规则
+- **新增场景**:
+ - 复杂条件逻辑(生存时间计算)
+ - 医学规则引擎(肝功能分级)
+ - 时间序列分析(指标变化率)
+ - 文本提取(TNM分期)
+ - 字符串处理(血压拆分)
+
+#### 修正3:验收标准分层 ✅
+- **原标准**:总体成功率 > 80%
+- **新标准**:
+ - 基础场景成功率 > 90%
+ - 中等场景成功率 > 80%
+ - 高级场景成功率 > 60%
+ - 总体成功率 > 80%(12/15场景)
+
+#### 修正4:核心假设验证 ✅
+- **新增H2**:Python代码执行环境稳定可靠
+- **修改H1**:从"生成代码"改为"生成代码并成功执行"
+- **强调**:AI生成代码 + 真实执行 + 表格刷新是差异化价值
+
+---
+
+### V1.1(2025-12-06)- 架构合规性修正 ⚠️ 重要
+
+**修正内容**:根据用户严肃提醒,修正以下违反规范的问题:
+
+#### 修正1:强制复用平台能力 ✅
+- **原错误**:建议自己实现Session管理、存储、日志
+- **已修正**:强制使用`storage`, `logger`, `cache`, `prisma`, `LLMFactory`
+- **影响章节**:所有Day 1-15的代码示例
+
+#### 修正2:Session存储方式 ✅
+- **原错误**:建议用`Map`内存缓存
+- **已修正**:Session存数据库(`dc_tool_c_sessions`表)
+- **原因**:违反云原生规范第2条(禁止内存缓存)
+
+#### 修正3:文件夹结构 ✅
+- **原错误**:建议创建`python-service/`、`node-service/`子文件夹
+- **已修正**:遵循tool-b结构(`services/`, `controllers/`, `routes/`)
+- **参考**:`backend/src/modules/dc/tool-b/`
+
+#### 修正4:技术栈说明 ✅
+- **原错误**:未强调复用现有能力
+- **已修正**:明确标注"已有"、"复用平台能力"
+- **新增**:云原生开发规范检查清单
+
+#### 修正5:代码示例 ✅
+- **原错误**:Day 1-5的代码示例未体现平台服务
+- **已修正**:所有代码示例都使用`import { storage } from '@/common/storage'`等
+- **新增**:常见错误示例(❌ 严禁)
+
+#### 新增章节 ✅
+- **开发前必读**:强调不要重复造轮子
+- **云原生规范强制要求**:列出6条核心规范
+- **常见错误示例**:展示5个严禁的错误写法
+
+---
+
+**文档状态:** ✅ 已完成(V1.1 架构合规性修正版)
+**下一步:** 团队Review → 严格按规范开发
+**负责人:** 项目经理
+**创建日期:** 2025-12-06
+**修订日期:** 2025-12-06(架构合规性修正)
+
+**⚠️ 重要提醒**:
+1. 开发前必须阅读:`docs/04-开发规范/08-云原生开发规范.md`
+2. 参考现有实现:`backend/src/modules/dc/tool-b/`
+3. 禁止违反规范:内存缓存、本地文件存储、重复实现平台能力
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md
index 5a5f38ad..8335f21d 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md
@@ -295,3 +295,4 @@ Changes:
**版本**: V1.0
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md
index ac9442ec..def027a8 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md
@@ -385,3 +385,4 @@ Docs: docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md
index 080899bb..03d6cced 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md
@@ -360,3 +360,4 @@ const mockAssets: Asset[] = [
**文档版本**: V1.0
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md
index 70b8a9be..1f37201b 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md
@@ -344,3 +344,4 @@ frontend-v2/src/modules/dc/
**UI质量**: ⭐⭐⭐⭐⭐
**状态**: ✅ 已完成,待测试
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md
index b506fb9b..e2579462 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md
@@ -304,3 +304,4 @@
**文档版本**: V1.0
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md
index 6f613a2c..5983637b 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md
@@ -258,3 +258,4 @@ ConflictDetectionService // 冲突检测(字段级对比)
**文档创建时间:** 2025-12-03
**维护者:** DC模块开发团队
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md
index 350e9247..6f3e7b0e 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md
@@ -307,3 +307,4 @@
**UI质量**: ⭐⭐⭐⭐⭐
**用户体验**: ⭐⭐⭐⭐⭐
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md
index 5041a550..f236ea65 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md
@@ -270,3 +270,4 @@
**测试状态**: ✅ 待用户验证
**代码质量**: ⭐⭐⭐⭐⭐
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md
index 5fca2c2a..6a405c6c 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md
@@ -334,3 +334,4 @@
**测试完成后,请更新此文档并标记所有测试点的完成状态!**
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md
index e3769019..bb5bea30 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md
@@ -422,3 +422,4 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发
*本报告将持续更新,随着测试进展补充更多测试结果*
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md
index e796282a..716acced 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md
@@ -268,3 +268,4 @@
**更新人**: AI Assistant
**下次更新**: 测试完成后
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md
index dce50cec..42082ee7 100644
--- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md
+++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md
@@ -199,3 +199,4 @@ $ node scripts/check-dc-tables.mjs
**下次验证**: 不需要(除非重建数据库)
+
diff --git a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md
index 96647022..2c4f24b0 100644
--- a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md
+++ b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md
@@ -432,3 +432,4 @@ ${fields.map((f, i) => `${i + 1}. ${f.name}:${f.desc}`).join('\n')}
**文档维护:** 每次处理技术债务时更新此文档
+
diff --git a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx
index ed254c6c..ce5f4f69 100644
--- a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx
+++ b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx
@@ -511,3 +511,4 @@ export default FulltextDetailDrawer;
+
diff --git a/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts b/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts
index be8855f3..b4a96dc8 100644
--- a/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts
+++ b/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts
@@ -110,3 +110,4 @@ export function useFulltextResults({
+
diff --git a/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts b/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts
index fe6e8cc6..ddda6250 100644
--- a/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts
+++ b/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts
@@ -73,3 +73,4 @@ export function useFulltextTask({
+
diff --git a/frontend-v2/src/modules/asl/pages/FulltextResults.tsx b/frontend-v2/src/modules/asl/pages/FulltextResults.tsx
index d1d2975b..851d6c7a 100644
--- a/frontend-v2/src/modules/asl/pages/FulltextResults.tsx
+++ b/frontend-v2/src/modules/asl/pages/FulltextResults.tsx
@@ -464,3 +464,4 @@ export default FulltextResults;
+
diff --git a/frontend-v2/src/modules/dc/hooks/useAssets.ts b/frontend-v2/src/modules/dc/hooks/useAssets.ts
index bacce2e4..a733d643 100644
--- a/frontend-v2/src/modules/dc/hooks/useAssets.ts
+++ b/frontend-v2/src/modules/dc/hooks/useAssets.ts
@@ -104,3 +104,4 @@ export const useAssets = (activeTab: AssetTabType) => {
};
+
diff --git a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts
index 7d01a294..49211dd7 100644
--- a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts
+++ b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts
@@ -94,3 +94,4 @@ export const useRecentTasks = () => {
};
+
diff --git a/frontend-v2/src/modules/dc/types/portal.ts b/frontend-v2/src/modules/dc/types/portal.ts
index 21169196..5b3dd0cd 100644
--- a/frontend-v2/src/modules/dc/types/portal.ts
+++ b/frontend-v2/src/modules/dc/types/portal.ts
@@ -52,3 +52,4 @@ export interface Asset {
export type AssetTabType = 'all' | 'processed' | 'raw';
+
diff --git a/recover_dc_code.py b/recover_dc_code.py
index d10a9468..1429bb58 100644
--- a/recover_dc_code.py
+++ b/recover_dc_code.py
@@ -216,3 +216,4 @@ if __name__ == "__main__":
+
diff --git a/run_recovery.ps1 b/run_recovery.ps1
index 67065829..7075eedb 100644
--- a/run_recovery.ps1
+++ b/run_recovery.ps1
@@ -40,3 +40,4 @@ Write-Host "====================================================================
+