# 工具C Day 3 开发计划 - AI代码生成服务 > **文档版本**: V1.0 > **创建日期**: 2025-12-06 > **开发目标**: AI代码生成 + Python执行 + 自我修正 > **预计工时**: 5.5-6小时 > **依赖**: Day 2已完成(Session管理) --- ## 📋 核心决策总结 ### 决策1: 对话存储方式 ✅ **方案选择**: 创建独立表 `dc_tool_c_ai_history` **理由**: - 未来模块可能独立销售或独立部署 - 符合Schema隔离原则 - Tool C有特殊字段需求(code、executeResult) **数据库Schema**: ```prisma model DcToolCAiHistory { id String @id @default(uuid()) sessionId String // 关联Tool C Session userId String role String // user/assistant/system content String @db.Text // Tool C特有字段 generatedCode String? @db.Text // AI生成的代码 codeExplanation String? @db.Text // 代码解释 executeStatus String? // success/failed/pending executeResult Json? // 执行结果 executeError String? @db.Text // 错误信息 retryCount Int @default(0) model String? // deepseek-v3 createdAt DateTime @default(now()) @@index([sessionId]) @@index([userId]) @@map("dc_tool_c_ai_history") @@schema("dc_schema") } ``` --- ### 决策2: AI代码执行流程 ✅ **方案选择**: 用户确认后执行(方案A) **流程**: ``` 用户输入自然语言 ↓ AI生成代码 + 解释 ↓ 前端展示代码(高亮) ↓ 用户点击"执行"按钮 ← 用户确认 ↓ Python服务执行代码 ↓ 返回结果 + 数据预览(前50行) ``` **理由**: - ✅ 用户可审查代码(安全可控) - ✅ 符合"AI辅助"而非"AI自动"的定位 - ✅ 降低执行错误风险 --- ### 决策3: System Prompt设计 ✅ **方案选择**: 完整版10个Few-shot示例 **示例分布**: | 级别 | 数量 | 示例编号 | 场景 | |------|------|---------|------| | Level 1 | 2个 | 1-2 | 缺失值统一、数值清洗 | | Level 2 | 2个 | 3-4 | 编码、分箱 | | Level 3 | 3个 | 5-7 | BMI、日期、筛选 | | Level 4 | 3个 | 8-10 | 简单填补、**多重插补**、去重 | **核心亮点**: - ✅ 包含缺失值处理(示例8) - ✅ 包含多重插补MICE(示例9)⭐ 重点 - ✅ 覆盖从基础到高级全梯度 **文档位置**: [工具C_AI_Few-shot示例库.md](./工具C_AI_Few-shot示例库.md) --- ### 决策4: 数据状态管理 ✅ **方案选择**: Python内存维护(方案C) **架构**: ``` Session创建 → 数据加载到Python内存 ↓ AI操作1 → 修改内存中的DataFrame ↓ AI操作2 → 继续修改DataFrame(累积) ↓ AI操作N → ... ↓ 用户点击"导出" → 保存到OSS ``` **技术债务**: - 📝 Python重启会丢失状态 - 📝 未来优化:持久化到Redis或OSS - 📝 文档位置: [技术债务清单](../07-技术债务/Tool-C技术债务清单.md) --- ### 决策5: AI自我修正机制 ✅ **方案选择**: 最多3次重试(方案B) **流程**: ```python attempt = 0 while attempt < 3: # 生成代码 code = generate_code(user_message + error_feedback) # 执行代码 result = execute_code(code) if result.success: return result # ✅ 成功 error_feedback = result.error attempt += 1 # ❌ 3次仍失败,返回友好错误 return "执行失败,请调整需求后重试" ``` --- ### 决策6: LLM模型选择 ✅ **优先使用**: DeepSeek-V3 **配置**: ```typescript const llm = LLMFactory.createAdapter('deepseek-v3'); const response = await llm.chat(messages, { temperature: 0.1, // 低温度,确保代码准确性 maxTokens: 2000, // 足够生成代码+解释 topP: 0.9 }); ``` **备选方案**: - Qwen3-72B: 中文理解更好 - GPT-5-Pro: 代码质量最高(成本高) --- ### 决策7: 上下文传递 ✅ **配置**: 传递最近5轮对话 **实现**: ```typescript async getConversationHistory(sessionId: string, limit: number = 5) { return await prisma.dcToolCAiHistory.findMany({ where: { sessionId }, orderBy: { createdAt: 'desc' }, take: limit * 2, // user + assistant 成对 }); } // 构建消息上下文 const messages = [ { role: 'system', content: systemPrompt }, ...history.reverse(), // 最近5轮 { role: 'user', content: userMessage } ]; ``` --- ### 决策8: 执行结果展示 ✅ **配置**: 返回前50行预览 **原因**: - 50行足够查看数据变化 - 不会过大影响性能 - 符合医疗数据场景(通常几十到几百行) --- ### 决策9: Few-shot示例确认 ✅ **最终10个示例**: 1. 统一缺失值标记 2. 数值列清洗(检验值符号处理) 3. 分类变量编码(性别→1/0) 4. 连续变量分箱(年龄分组) 5. BMI计算与分类 6. 日期计算(住院天数) 7. 条件筛选(入组标准) 8. 简单缺失值填补(中位数) 9. **多重插补MICE** ⭐ 核心 10. 智能去重(按日期保留最新) --- ## 🏗️ 技术架构设计 ### 整体架构 ``` ┌─────────────────────────────────────────────────┐ │ Frontend (React) │ │ - 对话界面(Tool C专用) │ │ - 代码展示(高亮) │ │ - 执行按钮 │ │ - 结果预览(AG Grid) │ └──────────────┬──────────────────────────────────┘ │ REST API ┌──────────────▼──────────────────────────────────┐ │ Node.js Backend (Fastify) │ │ ┌─────────────────────────────────────────┐ │ │ │ AICodeService │ │ │ │ - generateCode() │ │ │ │ - executeCode() │ │ │ │ - generateAndExecute() (带重试) │ │ │ │ - getHistory() │ │ │ └──────────┬───────────────┬──────────────┘ │ │ │ │ │ │ ┌───────▼─────┐ ┌────▼──────────┐ │ │ │ LLMFactory │ │ PythonExecutor│ │ │ │ (通用层复用)│ │ Service │ │ │ └─────────────┘ └───────┬───────┘ │ └──────────────────────────────┼─────────────────┘ │ HTTP ┌───────────▼──────────────────┐ │ Python Service (FastAPI) │ │ - /api/dc/validate (AST检查) │ │ - /api/dc/execute (执行代码) │ │ - Session状态管理(内存) │ └──────────────────────────────┘ ``` --- ### 核心服务设计 #### AICodeService (新建,~400行) ```typescript // backend/src/modules/dc/tool-c/services/AICodeService.ts export class AICodeService { // ==================== 核心方法 ==================== /** * 生成Pandas代码 * @param sessionId - Tool C Session ID * @param userMessage - 用户自然语言需求 * @returns { code, explanation, messageId } */ async generateCode( sessionId: string, userMessage: string ): Promise { // 1. 获取Session信息(数据集元数据) const session = await sessionService.getSession(sessionId); // 2. 构建System Prompt(含10个Few-shot) const systemPrompt = this.buildSystemPrompt(session); // 3. 获取对话历史(最近5轮) const history = await this.getHistory(sessionId, 5); // 4. 调用LLM(复用LLMFactory) const llm = LLMFactory.createAdapter('deepseek-v3'); const response = await llm.chat([ { role: 'system', content: systemPrompt }, ...history, { role: 'user', content: userMessage } ], { temperature: 0.1, maxTokens: 2000 }); // 5. 解析AI回复(提取code和explanation) const parsed = this.parseAIResponse(response.content); // 6. 保存到数据库 const messageId = await this.saveMessages( sessionId, userMessage, parsed.code, parsed.explanation ); return { code: parsed.code, explanation: parsed.explanation, messageId }; } /** * 执行Python代码 * @param sessionId - Tool C Session ID * @param code - Python代码 * @param messageId - 关联的消息ID * @returns { success, result, newDataPreview } */ async executeCode( sessionId: string, code: string, messageId: string ): Promise { // 1. 调用Python服务执行 const result = await pythonExecutorService.executeCode(code, { sessionId // Python服务维护Session状态 }); // 2. 更新消息状态 await prisma.dcToolCAiHistory.update({ where: { id: messageId }, data: { executeStatus: result.success ? 'success' : 'failed', executeResult: result.data, executeError: result.error } }); // 3. 如果成功,获取新数据预览(前50行) if (result.success) { const preview = result.data?.slice(0, 50); return { success: true, result: result.data, newDataPreview: preview }; } return { success: false, error: result.error }; } /** * 生成并执行(带自我修正) * @param sessionId - Tool C Session ID * @param userMessage - 用户需求 * @param maxRetries - 最大重试次数(默认3) * @returns { code, explanation, executeResult, retryCount } */ async generateAndExecute( sessionId: string, userMessage: string, maxRetries: number = 3 ): Promise { let attempt = 0; let lastError: string | null = null; let generated: GenerateCodeResult | null = null; while (attempt < maxRetries) { try { // 构建带错误反馈的提示词 const enhancedMessage = attempt === 0 ? userMessage : `${userMessage}\n\n上次执行错误:${lastError}\n请修正代码。`; // 生成代码 generated = await this.generateCode(sessionId, enhancedMessage); // 执行代码 const executeResult = await this.executeCode( sessionId, generated.code, generated.messageId ); if (executeResult.success) { // ✅ 成功 logger.info(`[AICodeService] 执行成功(尝试${attempt + 1}次)`); return { ...generated, executeResult, retryCount: attempt }; } // ❌ 失败,准备重试 lastError = executeResult.error || '未知错误'; attempt++; logger.warn(`[AICodeService] 执行失败(尝试${attempt}/${maxRetries}): ${lastError}`); } catch (error: any) { logger.error(`[AICodeService] 异常: ${error.message}`); lastError = error.message; attempt++; } } // 3次仍失败 throw new Error( `代码执行失败(已重试${maxRetries}次)。最后错误:${lastError}。` + `建议:请调整需求描述或手动修改代码。` ); } /** * 获取对话历史 */ async getHistory(sessionId: string, limit: number = 5): Promise { const records = await prisma.dcToolCAiHistory.findMany({ where: { sessionId }, orderBy: { createdAt: 'desc' }, take: limit * 2 // user + assistant 成对 }); return records.reverse().map(r => ({ role: r.role, content: r.content })); } // ==================== 辅助方法 ==================== /** * 构建System Prompt(含10个Few-shot) */ private buildSystemPrompt(session: SessionData): string { return `你是医疗科研数据清洗专家,负责生成Pandas代码来清洗整理数据。 ## 当前数据集信息 - 文件名: ${session.fileName} - 行数: ${session.totalRows} - 列数: ${session.totalCols} - 列名: ${session.columns.join(', ')} ## 安全规则(强制) 1. 只能操作df变量,不能修改其他变量 2. 禁止导入os、sys、subprocess等危险模块 3. 禁止使用eval、exec、__import__等危险函数 4. 必须进行异常处理 5. 返回格式必须是JSON: {"code": "...", "explanation": "..."} ## Few-shot示例 ### 示例1: 统一缺失值标记 用户: 把所有代表缺失的符号(-、不详、NA、N/A)统一替换为标准空值 代码: \`\`\`python df = df.replace(['-', '不详', 'NA', 'N/A', '\\\\', '未查'], np.nan) \`\`\` 说明: 将多种缺失值表示统一为NaN,便于后续统计分析 ### 示例2: 数值列清洗 用户: 把肌酐列里的非数字符号去掉,<0.1按0.05处理,转为数值类型 代码: \`\`\`python df['creatinine'] = df['creatinine'].astype(str).str.replace('>', '').str.replace('<', '') df.loc[df['creatinine'] == '0.1', 'creatinine'] = '0.05' df['creatinine'] = pd.to_numeric(df['creatinine'], errors='coerce') \`\`\` 说明: 检验科数据常含符号,需清理后才能计算 [... 示例3-8 ...] ### 示例9: 多重插补(MICE)⭐ 重点 用户: 使用多重插补法对BMI、年龄、肌酐列的缺失值进行填补 代码: \`\`\`python from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer # 选择需要插补的数值列 cols = ['BMI', 'age', 'creatinine'] # 多重插补 imputer = IterativeImputer(max_iter=10, random_state=0) df[cols] = imputer.fit_transform(df[cols]) \`\`\` 说明: 利用变量间相关性预测缺失值,保持数据分布特征,适用于MAR(随机缺失) ### 示例10: 智能去重 用户: 按患者ID去重,保留检查日期最新的记录 代码: \`\`\`python df['check_date'] = pd.to_datetime(df['check_date']) df = df.sort_values('check_date').drop_duplicates(subset=['patient_id'], keep='last') \`\`\` 说明: 先按日期排序,再去重保留最后一条(最新) ## 用户当前请求 请根据以上示例和当前数据集信息,生成代码并解释。 `; } /** * 解析AI回复(提取code和explanation) */ private parseAIResponse(content: string): { code: string; explanation: string } { try { // 方法1:尝试解析JSON const json = JSON.parse(content); if (json.code && json.explanation) { return { code: json.code, explanation: json.explanation }; } } catch { // 方法2:正则提取代码块 const codeMatch = content.match(/```python\n([\s\S]+?)\n```/); const code = codeMatch ? codeMatch[1] : ''; // 提取解释(代码块之外的文本) const explanation = content.replace(/```python[\s\S]+?```/g, '').trim(); if (code) { return { code, explanation }; } } throw new Error('AI回复格式错误,无法提取代码'); } /** * 保存消息到数据库 */ private async saveMessages( sessionId: string, userMessage: string, code: string, explanation: string ): Promise { // 保存用户消息 await prisma.dcToolCAiHistory.create({ data: { sessionId, userId: 'test-user', // TODO: 从JWT获取 role: 'user', content: userMessage } }); // 保存AI回复 const assistantMessage = await prisma.dcToolCAiHistory.create({ data: { sessionId, userId: 'test-user', role: 'assistant', content: explanation, generatedCode: code, codeExplanation: explanation, executeStatus: 'pending', model: 'deepseek-v3' } }); return assistantMessage.id; } } // 导出单例 export const aiCodeService = new AICodeService(); ``` --- #### AIController (新建,~200行) ```typescript // backend/src/modules/dc/tool-c/controllers/AIController.ts export class AIController { /** * POST /api/v1/dc/tool-c/ai/generate * 生成代码(不执行) */ async generateCode(request: FastifyRequest, reply: FastifyReply) { try { const { sessionId, message } = request.body as any; // 参数验证 if (!sessionId || !message) { return reply.code(400).send({ success: false, error: '缺少必要参数:sessionId、message' }); } // 生成代码 const result = await aiCodeService.generateCode(sessionId, message); return reply.code(200).send({ success: true, data: result }); } catch (error: any) { logger.error(`[AIController] generateCode失败: ${error.message}`); return reply.code(500).send({ success: false, error: error.message }); } } /** * POST /api/v1/dc/tool-c/ai/execute * 执行代码 */ async executeCode(request: FastifyRequest, reply: FastifyReply) { try { const { sessionId, code, messageId } = request.body as any; const result = await aiCodeService.executeCode(sessionId, code, messageId); return reply.code(200).send({ success: true, data: result }); } catch (error: any) { logger.error(`[AIController] executeCode失败: ${error.message}`); return reply.code(500).send({ success: false, error: error.message }); } } /** * POST /api/v1/dc/tool-c/ai/process * 生成并执行(一步到位,带重试) */ async process(request: FastifyRequest, reply: FastifyReply) { try { const { sessionId, message, maxRetries = 3 } = request.body as any; const result = await aiCodeService.generateAndExecute( sessionId, message, maxRetries ); return reply.code(200).send({ success: true, data: result }); } catch (error: any) { logger.error(`[AIController] process失败: ${error.message}`); return reply.code(500).send({ success: false, error: error.message }); } } /** * GET /api/v1/dc/tool-c/ai/history/:sessionId * 获取对话历史 */ async getHistory( request: FastifyRequest<{ Params: { sessionId: string } }>, reply: FastifyReply ) { try { const { sessionId } = request.params; const history = await aiCodeService.getHistory(sessionId, 10); return reply.code(200).send({ success: true, data: { history } }); } catch (error: any) { logger.error(`[AIController] getHistory失败: ${error.message}`); return reply.code(500).send({ success: false, error: error.message }); } } } export const aiController = new AIController(); ``` --- ## 📅 开发计划 ### 阶段1: 数据库设计(30分钟)⏰ 09:00-09:30 **任务清单**: - [ ] 更新 `backend/prisma/schema.prisma`(添加DcToolCAiHistory模型) - [ ] 创建数据库迁移脚本 `create-tool-c-ai-history-table.mjs` - [ ] 执行迁移(创建表) - [ ] 验证表结构 - [ ] 生成Prisma Client (`npx prisma generate`) **交付物**: - ✅ `dc_schema.dc_tool_c_ai_history` 表创建成功 - ✅ Prisma Client更新完成 --- ### 阶段2: AICodeService实现(2小时)⏰ 09:30-11:30 **任务清单**: - [ ] 创建 `AICodeService.ts` 基础结构 - [ ] 实现 `buildSystemPrompt()` - 10个Few-shot示例集成 - [ ] 实现 `generateCode()` - AI生成代码 - [ ] 实现 `parseAIResponse()` - 解析AI回复 - [ ] 实现 `executeCode()` - 执行Python代码 - [ ] 实现 `generateAndExecute()` - 生成+执行+重试 - [ ] 实现 `getHistory()` - 获取对话历史 - [ ] 实现 `saveMessages()` - 保存消息到数据库 - [ ] 添加完整错误处理和日志 **交付物**: - ✅ `AICodeService.ts` 完整实现(~400行) - ✅ 单元测试通过 --- ### 阶段3: AIController实现(1小时)⏰ 11:30-12:30 **任务清单**: - [ ] 创建 `AIController.ts` - [ ] 实现 `POST /ai/generate` - 生成代码 - [ ] 实现 `POST /ai/execute` - 执行代码 - [ ] 实现 `POST /ai/process` - 一步到位 - [ ] 实现 `GET /ai/history/:sessionId` - 对话历史 - [ ] 添加参数验证 - [ ] 添加错误处理 **交付物**: - ✅ `AIController.ts` 完整实现(~200行) - ✅ 4个API端点就绪 --- ### 午休 ⏰ 12:30-13:30 --- ### 阶段4: 路由配置(15分钟)⏰ 13:30-13:45 **任务清单**: - [ ] 更新 `routes/index.ts` - [ ] 注册AI相关路由 - [ ] 测试路由可访问性 **交付物**: - ✅ AI路由注册完成 - ✅ Swagger文档更新(如有) --- ### 阶段5: 测试验收(1.5小时)⏰ 13:45-15:15 #### 5.1 基础测试(30分钟) **测试用例**: 1. [ ] 测试1: 统一缺失值标记 2. [ ] 测试2: 数值列清洗 3. [ ] 测试3: 性别编码 4. [ ] 测试4: 年龄分组 **验收标准**: - AI能正确生成代码 - 代码可执行 - 结果符合预期 #### 5.2 中级测试(30分钟) **测试用例**: 5. [ ] 测试5: BMI计算 6. [ ] 测试6: 住院天数计算 7. [ ] 测试7: 条件筛选 #### 5.3 高级测试(30分钟) **测试用例**: 8. [ ] 测试8: 中位数填补 9. [ ] 测试9: 多重插补MICE ⭐ 10. [ ] 测试10: 智能去重 #### 5.4 特殊测试(30分钟) **测试用例**: 11. [ ] 自我修正测试(故意错误,验证重试机制) 12. [ ] 边界测试(列不存在、全部缺失等) 13. [ ] 并发测试(多用户同时使用) 14. [ ] 端到端测试(上传→AI处理→结果验证) **交付物**: - ✅ 测试脚本 `test-tool-c-day3.mjs` - ✅ 测试报告(通过率≥90%) --- ### 阶段6: 文档与优化(30分钟)⏰ 15:15-15:45 **任务清单**: - [ ] 创建技术债务清单 `Tool-C技术债务清单.md` - [ ] 更新模块状态文档 `00-工具C当前状态与开发指南.md` - [ ] 创建Day 3开发完成总结 - [ ] 提交Git并推送 **交付物**: - ✅ 技术债务文档 - ✅ Day 3开发记录 - ✅ Git提交成功 --- ## 🎯 验收标准 ### 功能验收 | 功能 | 验收标准 | 状态 | |------|---------|------| | AI代码生成 | 10个示例场景100%可生成正确代码 | ⏸️ | | 代码执行 | 生成的代码可成功执行 | ⏸️ | | 自我修正 | 失败后能自动重试(最多3次) | ⏸️ | | 对话历史 | 能获取最近5轮对话 | ⏸️ | | 数据预览 | 执行后返回前50行预览 | ⏸️ | ### 技术验收 | 指标 | 目标 | 状态 | |------|------|------| | 代码质量 | 无TypeScript错误 | ⏸️ | | 云原生规范 | 100%符合 | ⏸️ | | 错误处理 | 所有异常都有处理 | ⏸️ | | 日志完整性 | 关键操作都有日志 | ⏸️ | | 测试覆盖率 | ≥80% | ⏸️ | ### 性能验收 | 指标 | 目标 | 状态 | |------|------|------| | AI生成时间 | <5秒 | ⏸️ | | 代码执行时间 | <3秒(简单操作) | ⏸️ | | 端到端时间 | <10秒 | ⏸️ | --- ## 📦 交付清单 ### 代码文件(6个) 1. ✅ `backend/prisma/schema.prisma` - 新增DcToolCAiHistory模型 2. ✅ `backend/scripts/create-tool-c-ai-history-table.mjs` - 建表脚本 3. ✅ `backend/src/modules/dc/tool-c/services/AICodeService.ts` - 400行 4. ✅ `backend/src/modules/dc/tool-c/controllers/AIController.ts` - 200行 5. ✅ `backend/src/modules/dc/tool-c/routes/index.ts` - 更新 6. ✅ `backend/test-tool-c-day3.mjs` - 测试脚本 ### 文档文件(4个) 1. ✅ `工具C_AI_Few-shot示例库.md` - 10个示例详解 2. ✅ `工具C_Day3开发计划.md` - 本文档 3. ✅ `Tool-C技术债务清单.md` - 待优化项 4. ✅ `2025-12-06_工具C_Day3开发完成总结.md` - 总结报告 --- ## 🔗 相关文档 - [工具C_AI_Few-shot示例库.md](./工具C_AI_Few-shot示例库.md) - [工具C_MVP开发计划_V1.0.md](./工具C_MVP开发计划_V1.0.md) - [通用对话服务抽取计划.md](../../../08-项目管理/05-技术债务/通用对话服务抽取计划.md) - [云原生开发规范.md](../../../04-开发规范/08-云原生开发规范.md) --- ## 🔄 风险管理 ### 风险1: AI生成代码质量不稳定 **应对措施**: - ✅ 使用10个Few-shot示例提升质量 - ✅ 降低temperature至0.1 - ✅ 实施3次重试机制 - ✅ 添加AST静态检查(Python服务) ### 风险2: LLM调用超时 **应对措施**: - ✅ 设置合理的timeout(10秒) - ✅ 前端显示加载状态 - ✅ 添加重试机制 ### 风险3: Python执行失败 **应对措施**: - ✅ AI自我修正(最多3次) - ✅ 友好错误提示 - ✅ 建议用户调整需求 --- ## 📊 预期成果 **Day 3完成后**: - ✅ Tool C用户可通过自然语言清洗数据 - ✅ AI能生成90%场景的正确代码 - ✅ 失败场景有自动重试机制 - ✅ 完整的对话历史管理 **整体进度**: - Day 1: Python微服务 ✅ - Day 2: Session管理 ✅ - Day 3: AI代码生成 ⏸️ - Day 4-5: 前端开发 - Day 6: 端到端测试 --- ## 📝 更新记录 | 日期 | 版本 | 更新内容 | 更新人 | |------|------|---------|--------| | 2025-12-06 | V1.0 | 初始创建,明确9大决策和开发计划 | AI Assistant | --- **文档状态**: ✅ 已确认 **下一步**: 开始执行开发计划(预计5.5-6小时) **准备开始开发!** 🚀