/** * Protocol Agent 独立 Seed 脚本 * * 只初始化 Protocol Agent 相关的配置数据,不影响其他模块 * * 运行方式: * npx ts-node prisma/seed-protocol-agent.ts * 或者: * npx tsx prisma/seed-protocol-agent.ts */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); async function seedProtocolAgent() { console.log('🌱 开始初始化 Protocol Agent 配置...\n'); try { // ============================================ // 1. 创建 Agent 定义 // ============================================ console.log('📌 创建 Agent 定义...'); const protocolAgent = await prisma.agentDefinition.upsert({ where: { code: 'protocol_agent' }, update: { name: '全流程研究方案制定', description: '引导用户完成5个核心阶段(科学问题、PICO、研究设计、样本量、观察指标),最终一键生成研究方案', version: '1.0.0', config: { defaultModel: 'deepseek-v3', maxTurns: 100, timeout: 120000, enableTrace: true, enableReflexion: true, }, isActive: true, }, create: { code: 'protocol_agent', name: '全流程研究方案制定', description: '引导用户完成5个核心阶段(科学问题、PICO、研究设计、样本量、观察指标),最终一键生成研究方案', version: '1.0.0', config: { defaultModel: 'deepseek-v3', maxTurns: 100, timeout: 120000, enableTrace: true, enableReflexion: true, }, isActive: true, }, }); console.log(` ✅ Agent 定义创建成功: ${protocolAgent.name} (ID: ${protocolAgent.id})`); // ============================================ // 2. 创建 5 个阶段 // ============================================ console.log('📌 创建 5 个阶段配置...'); const stages = [ { stageCode: 'scientific_question', stageName: '科学问题梳理', sortOrder: 1, isInitial: true, isFinal: false, nextStages: ['pico'] }, { stageCode: 'pico', stageName: 'PICO要素', sortOrder: 2, isInitial: false, isFinal: false, nextStages: ['study_design'] }, { stageCode: 'study_design', stageName: '研究设计', sortOrder: 3, isInitial: false, isFinal: false, nextStages: ['sample_size'] }, { stageCode: 'sample_size', stageName: '样本量计算', sortOrder: 4, isInitial: false, isFinal: false, nextStages: ['endpoints'] }, { stageCode: 'endpoints', stageName: '观察指标', sortOrder: 5, isInitial: false, isFinal: true, nextStages: [] }, ]; const stageMap = new Map(); for (const stage of stages) { const created = await prisma.agentStage.upsert({ where: { agentId_stageCode: { agentId: protocolAgent.id, stageCode: stage.stageCode } }, update: { stageName: stage.stageName, sortOrder: stage.sortOrder, isInitial: stage.isInitial, isFinal: stage.isFinal, nextStages: stage.nextStages, }, create: { agentId: protocolAgent.id, stageCode: stage.stageCode, stageName: stage.stageName, sortOrder: stage.sortOrder, isInitial: stage.isInitial, isFinal: stage.isFinal, nextStages: stage.nextStages, }, }); stageMap.set(stage.stageCode, created.id); console.log(` ✅ 阶段 ${stage.sortOrder}: ${stage.stageName}`); } // ============================================ // 3. 创建系统 Prompt // ============================================ console.log('📌 创建系统 Prompt...'); const systemPromptContent = `你是一位资深的临床研究方法学专家,正在帮助医生设计临床研究方案。 ## 你的角色 - 你是一位友好、专业的研究方案设计顾问 - 你会引导用户一步步完成研究方案的核心要素 - 你善于提问,帮助用户理清思路 ## 当前工作流程 你将引导用户完成5个核心阶段: 1. 科学问题梳理 - 明确研究要解决的核心问题 2. PICO要素 - 确定研究人群(P)、干预(I)、对照(C)和结局(O) 3. 研究设计 - 选择合适的研究类型和方法 4. 样本量计算 - 估算所需的样本量 5. 观察指标 - 定义基线、暴露、结局指标和混杂因素 ## 输出要求 1. 回复要简洁、专业、有针对性 2. 每次只关注当前阶段的问题 3. 当用户提供了足够信息后,整理成结构化内容 4. 整理完成后,在回复末尾输出提取的数据(用于同步到方案) ## 数据提取格式 当你认为当前阶段的信息已经收集完整,请在回复末尾添加: { "字段1": "值1", "字段2": "值2" } 注意:只有在信息收集完整时才输出 extracted_data 标签。`; await prisma.agentPrompt.upsert({ where: { agentId_promptCode_version: { agentId: protocolAgent.id, promptCode: 'system', version: 1 } }, update: { content: systemPromptContent, isActive: true, }, create: { agentId: protocolAgent.id, promptType: 'system', promptCode: 'system', content: systemPromptContent, variables: ['context', 'intent'], version: 1, isActive: true, }, }); console.log(` ✅ 系统 Prompt 创建成功`); // ============================================ // 4. 创建各阶段 Prompt // ============================================ console.log('📌 创建各阶段 Prompt...'); const stagePrompts = [ { stageCode: 'scientific_question', content: `## 当前阶段:科学问题梳理 ### 目标 帮助用户明确研究要解决的核心科学问题。 ### 引导方向 1. 了解用户的研究背景和动机 2. 明确研究的核心问题是什么 3. 确认问题的科学价值和临床意义 ### 提问示例 - "您想研究什么问题?" - "这个研究的临床背景是什么?" - "您希望通过这个研究解决什么问题?" ### 数据提取 当信息完整时,提取以下字段: - content: 科学问题的完整描述 - background: 研究背景 - significance: 研究意义`, }, { stageCode: 'pico', content: `## 当前阶段:PICO要素 ### 目标 帮助用户确定PICO四要素。 ### PICO定义 - P (Population): 研究人群 - 谁是研究对象? - I (Intervention): 干预措施 - 研究什么干预/暴露? - C (Comparison): 对照 - 与什么比较? - O (Outcome): 结局 - 关注什么结果? ### 引导方向 1. 逐一确认每个要素 2. 确保定义清晰、可操作 ### 数据提取 当信息完整时,提取以下字段: - population: 研究人群描述 - intervention: 干预措施描述 - comparison: 对照描述 - outcome: 结局指标描述`, }, { stageCode: 'study_design', content: `## 当前阶段:研究设计 ### 目标 帮助用户选择合适的研究设计类型。 ### 常见研究类型 - 随机对照试验 (RCT) - 队列研究 (Cohort) - 病例对照研究 (Case-Control) - 横断面研究 (Cross-sectional) - 前后对照研究 (Before-After) ### 引导方向 1. 根据研究问题推荐合适的设计类型 2. 讨论设计的优缺点 3. 确定关键设计要素(如盲法、随机化方法等) ### 数据提取 当信息完整时,提取以下字段: - studyType: 研究类型 - design: 设计要素列表 - features: 特殊设计特征`, }, { stageCode: 'sample_size', content: `## 当前阶段:样本量计算 ### 目标 帮助用户估算所需的样本量。 ### 关键参数 - α (显著性水平): 通常0.05 - β (检验效能): 通常0.80或0.90 - 效应量: 预期的效果大小 - 脱落率: 预计的失访比例 ### 引导方向 1. 了解主要结局指标的类型 2. 讨论预期的效应量 3. 考虑脱落率 ### 数据提取 当信息完整时,提取以下字段: - sampleSize: 计算的样本量 - alpha: 显著性水平 - power: 检验效能 - effectSize: 效应量 - dropoutRate: 脱落率`, }, { stageCode: 'endpoints', content: `## 当前阶段:观察指标 ### 目标 帮助用户定义完整的观察指标体系。 ### 指标分类 1. 基线指标 - 人口学特征、病史、实验室检查 2. 暴露/干预指标 - 干预措施的具体内容 3. 结局指标 - 主要结局、次要结局、安全性指标 4. 混杂因素 - 需要控制的混杂变量 ### 引导方向 1. 逐类确认各项指标 2. 确保指标定义清晰、可测量 3. 确定测量时点 ### 数据提取 当信息完整时,提取以下字段: - baseline: 基线指标列表 - exposure: 暴露/干预指标 - outcomes: 结局指标(primary, secondary, safety) - confounders: 混杂因素列表`, }, ]; for (const prompt of stagePrompts) { const stageId = stageMap.get(prompt.stageCode); await prisma.agentPrompt.upsert({ where: { agentId_promptCode_version: { agentId: protocolAgent.id, promptCode: `stage_${prompt.stageCode}`, version: 1 } }, update: { stageId: stageId, content: prompt.content, isActive: true, }, create: { agentId: protocolAgent.id, stageId: stageId, promptType: 'stage', promptCode: `stage_${prompt.stageCode}`, content: prompt.content, variables: ['context'], version: 1, isActive: true, }, }); console.log(` ✅ 阶段 Prompt: ${prompt.stageCode}`); } // ============================================ // 完成 // ============================================ console.log('\n🎉 Protocol Agent 配置初始化完成!\n'); console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ Protocol Agent 配置摘要 ║'); console.log('╠════════════════════════════════════════════════════════════╣'); console.log(`║ Agent ID: ${protocolAgent.id} ║`); console.log('║ Agent Code: protocol_agent ║'); console.log('║ 阶段数量: 5 ║'); console.log('║ Prompt 数量: 6 (1 系统 + 5 阶段) ║'); console.log('╠════════════════════════════════════════════════════════════╣'); console.log('║ 阶段流程: ║'); console.log('║ 1. 科学问题梳理 → 2. PICO要素 → 3. 研究设计 ║'); console.log('║ → 4. 样本量计算 → 5. 观察指标 → 一键生成 ║'); console.log('╚════════════════════════════════════════════════════════════╝'); } catch (error) { console.error('❌ Protocol Agent 初始化失败:', error); throw error; } } // 执行 seedProtocolAgent() .then(async () => { await prisma.$disconnect(); }) .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });