# 工具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设计 ? **方案选择**: 完整?0个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(示?)⭐ 重点 - ?覆盖从基础到高级全梯度 **文档位置**: [工具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自我修正机制 ? **方案选择**: 最?次重试(方案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: 上下文传?? **配置**: 传递最?轮对? **实现**: ```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(), // 最?? { role: 'user', content: userMessage } ]; ``` --- ### 决策8: 执行结果展示 ? **配置**: 返回?0行预? **原因**: - 50行足够查看数据变? - 不会过大影响性能 - 符合医疗数据场景(通常几十到几百行? --- ### 决策9: Few-shot示例确认 ? **最?0个示?*: 1. 统一缺失值标? 2. 数值列清洗(检验值符号处理) 3. 分类变量编码(性别?/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. 获取对话历史(最?轮) 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?.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实现?小时)⏰ 09:30-11:30 **任务清单**: - [ ] 创建 `AICodeService.ts` 基础结构 - [ ] 实现 `buildSystemPrompt()` - 10个Few-shot示例集成 - [ ] 实现 `generateCode()` - AI生成代码 - [ ] 实现 `parseAIResponse()` - 解析AI回复 - [ ] 实现 `executeCode()` - 执行Python代码 - [ ] 实现 `generateAndExecute()` - 生成+执行+重试 - [ ] 实现 `getHistory()` - 获取对话历史 - [ ] 实现 `saveMessages()` - 保存消息到数据库 - [ ] 添加完整错误处理和日? **交付?*: - ?`AICodeService.ts` 完整实现(~400行) - ?单元测试通过 --- ### 阶段3: AIController实现?小时)⏰ 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: 路由配置?5分钟)⏰ 13:30-13:45 **任务清单**: - [ ] 更新 `routes/index.ts` - [ ] 注册AI相关路由 - [ ] 测试路由可访问? **交付?*: - ?AI路由注册完成 - ?Swagger文档更新(如有) --- ### 阶段5: 测试验收?.5小时)⏰ 13:45-15:15 #### 5.1 基础测试?0分钟? **测试用例**: 1. [ ] 测试1: 统一缺失值标? 2. [ ] 测试2: 数值列清洗 3. [ ] 测试3: 性别编码 4. [ ] 测试4: 年龄分组 **验收标准**: - AI能正确生成代? - 代码可执? - 结果符合预期 #### 5.2 中级测试?0分钟? **测试用例**: 5. [ ] 测试5: BMI计算 6. [ ] 测试6: 住院天数计算 7. [ ] 测试7: 条件筛? #### 5.3 高级测试?0分钟? **测试用例**: 8. [ ] 测试8: 中位数填? 9. [ ] 测试9: 多重插补MICE ? 10. [ ] 测试10: 智能去重 #### 5.4 特殊测试?0分钟? **测试用例**: 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个示例场?00%可生成正确代?| ⏸️ | | 代码执行 | 生成的代码可成功执行 | ⏸️ | | 自我修正 | 失败后能自动重试(最?次) | ⏸️ | | 对话历史 | 能获取最?轮对?| ⏸️ | | 数据预览 | 执行后返回前50行预?| ⏸️ | ### 技术验? | 指标 | 目标 | 状?| |------|------|------| | 代码质量 | 无TypeScript错误 | ⏸️ | | 云原生规?| 100%符合 | ⏸️ | | 错误处理 | 所有异常都有处?| ⏸️ | | 日志完整?| 关键操作都有日志 | ⏸️ | | 测试覆盖?| ?0% | ⏸️ | ### 性能验收 | 指标 | 目标 | 状?| |------|------|------| | AI生成时间 | <5?| ⏸️ | | 代码执行时间 | <3秒(简单操作) | ⏸️ | | 端到端时?| <10?| ⏸️ | --- ## 📦 交付清单 ### 代码文件?个) 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` - 测试脚本 ### 文档文件?个) 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?.1 - ?实施3次重试机? - ?添加AST静态检查(Python服务? ### 风险2: LLM调用超时 **应对措施**: - ?设置合理的timeout?0秒) - ?前端显示加载状? - ?添加重试机制 ### 风险3: Python执行失败 **应对措施**: - ?AI自我修正(最?次) - ?友好错误提示 - ?建议用户调整需? --- ## 📊 预期成果 **Day 3完成?*: - ?Tool C用户可通过自然语言清洗数据 - ?AI能生?0%场景的正确代? - ?失败场景有自动重试机? - ?完整的对话历史管? **整体进度**: - Day 1: Python微服?? - Day 2: Session管理 ? - Day 3: AI代码生成 ⏸️ - Day 4-5: 前端开? - Day 6: 端到端测? --- ## 📝 更新记录 | 日期 | 版本 | 更新内容 | 更新?| |------|------|---------|--------| | 2025-12-06 | V1.0 | 初始创建,明?大决策和开发计?| AI Assistant | --- **文档状?*: ?已确? **下一?*: 开始执行开发计划(预计5.5-6小时? **准备开始开发!** 🚀