Major Changes: - Database: Install pg_bigm/pgvector plugins, create test database - Python service: v1.0 -> v1.1, add pymupdf4llm/openpyxl/pypandoc - Node.js backend: v1.3 -> v1.7, fix pino-pretty and ES Module imports - Frontend: v1.2 -> v1.3, skip TypeScript check for deployment - Code recovery: Restore empty files from local backup Technical Fixes: - Fix pino-pretty error in production (conditional loading) - Fix ES Module import paths (add .js extensions) - Fix OSSAdapter TypeScript errors - Update Prisma Schema (63 models, 16 schemas) - Update environment variables (DATABASE_URL, EXTRACTION_SERVICE_URL, OSS) - Remove deprecated variables (REDIS_URL, DIFY_API_URL, DIFY_API_KEY) Documentation: - Create 0126 deployment folder with 8 documents - Update database development standards v2.0 - Update SAE deployment status records Deployment Status: - PostgreSQL: ai_clinical_research_test with plugins - Python: v1.1 @ 172.17.173.84:8000 - Backend: v1.7 @ 172.17.173.89:3001 - Frontend: v1.3 @ 172.17.173.90:80 Tested: All services running successfully on SAE
564 lines
14 KiB
TypeScript
564 lines
14 KiB
TypeScript
/**
|
||
* Protocol Agent 初始配置数据种子
|
||
*
|
||
* 运行方式: npx tsx prisma/seeds/protocol-agent-seed.ts
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
async function main() {
|
||
console.log('🌱 Seeding Protocol Agent configuration...');
|
||
|
||
// 1. 创建Agent定义
|
||
const agentDefinition = await prisma.agentDefinition.upsert({
|
||
where: { code: 'protocol_agent' },
|
||
update: {},
|
||
create: {
|
||
code: 'protocol_agent',
|
||
name: '研究方案制定助手',
|
||
description: '帮助研究者系统地制定临床研究方案,覆盖科学问题、PICO、研究设计、样本量和观察指标5个核心阶段',
|
||
version: '1.0.0',
|
||
config: {
|
||
defaultModel: 'deepseek-v3',
|
||
maxTurns: 100,
|
||
timeout: 60000,
|
||
enableTrace: true,
|
||
enableReflexion: true,
|
||
},
|
||
isActive: true,
|
||
},
|
||
});
|
||
|
||
console.log('✅ Created Agent Definition:', agentDefinition.code);
|
||
|
||
// 2. 创建5个阶段
|
||
const stages = [
|
||
{
|
||
stageCode: 'scientific_question',
|
||
stageName: '科学问题梳理',
|
||
sortOrder: 1,
|
||
isInitial: true,
|
||
isFinal: false,
|
||
nextStages: ['pico'],
|
||
config: {
|
||
requiredFields: ['content'],
|
||
minContentLength: 10,
|
||
},
|
||
},
|
||
{
|
||
stageCode: 'pico',
|
||
stageName: 'PICO要素',
|
||
sortOrder: 2,
|
||
isInitial: false,
|
||
isFinal: false,
|
||
nextStages: ['study_design'],
|
||
config: {
|
||
requiredFields: ['P', 'I', 'C', 'O'],
|
||
},
|
||
},
|
||
{
|
||
stageCode: 'study_design',
|
||
stageName: '研究设计',
|
||
sortOrder: 3,
|
||
isInitial: false,
|
||
isFinal: false,
|
||
nextStages: ['sample_size'],
|
||
config: {
|
||
requiredFields: ['type'],
|
||
},
|
||
},
|
||
{
|
||
stageCode: 'sample_size',
|
||
stageName: '样本量计算',
|
||
sortOrder: 4,
|
||
isInitial: false,
|
||
isFinal: false,
|
||
nextStages: ['endpoints'],
|
||
config: {
|
||
requiredFields: ['total'],
|
||
},
|
||
},
|
||
{
|
||
stageCode: 'endpoints',
|
||
stageName: '观察指标',
|
||
sortOrder: 5,
|
||
isInitial: false,
|
||
isFinal: true,
|
||
nextStages: [],
|
||
config: {
|
||
requiredFields: ['primary'],
|
||
},
|
||
},
|
||
];
|
||
|
||
for (const stage of stages) {
|
||
await prisma.agentStage.upsert({
|
||
where: {
|
||
agentId_stageCode: {
|
||
agentId: agentDefinition.id,
|
||
stageCode: stage.stageCode,
|
||
},
|
||
},
|
||
update: stage,
|
||
create: {
|
||
agentId: agentDefinition.id,
|
||
...stage,
|
||
},
|
||
});
|
||
console.log(` ✅ Stage: ${stage.stageName}`);
|
||
}
|
||
|
||
// 3. 创建Prompt模板
|
||
const prompts = [
|
||
// 系统Prompt
|
||
{
|
||
promptType: 'system',
|
||
promptCode: 'protocol_system',
|
||
content: `你是一位经验丰富的临床研究方法学专家,正在帮助研究者制定研究方案。
|
||
|
||
你的职责:
|
||
1. 系统引导用户完成研究方案的5个核心要素:科学问题、PICO、研究设计、样本量、观察指标
|
||
2. 提供专业、准确的方法学建议
|
||
3. 确保研究设计的科学性和可行性
|
||
4. 使用通俗易懂的语言,同时保持学术严谨性
|
||
|
||
当前阶段: {{context.currentStage}}
|
||
已完成阶段: {{context.completedStages}}
|
||
|
||
请根据用户的输入,提供专业指导。`,
|
||
variables: ['context'],
|
||
},
|
||
// 科学问题阶段Prompt
|
||
{
|
||
promptType: 'stage',
|
||
promptCode: 'stage_scientific_question',
|
||
stageCode: 'scientific_question',
|
||
content: `【科学问题梳理阶段】
|
||
|
||
你正在帮助用户梳理研究的科学问题。一个好的科学问题应该:
|
||
- 明确、具体、可操作
|
||
- 有实际的临床或学术意义
|
||
- 可通过研究方法验证
|
||
|
||
{{#if context.scientificQuestion}}
|
||
用户当前的科学问题草稿:
|
||
{{context.scientificQuestion.content}}
|
||
{{/if}}
|
||
|
||
请引导用户:
|
||
1. 描述研究背景和动机
|
||
2. 明确想要解决的核心问题
|
||
3. 阐述研究的潜在意义
|
||
|
||
当用户表达清晰后,帮助整理成规范的科学问题陈述,并提供"同步到方案"按钮。`,
|
||
variables: ['context'],
|
||
},
|
||
// PICO阶段Prompt
|
||
{
|
||
promptType: 'stage',
|
||
promptCode: 'stage_pico',
|
||
stageCode: 'pico',
|
||
content: `【PICO要素梳理阶段】
|
||
|
||
PICO是临床研究问题结构化的核心框架:
|
||
- P (Population): 研究人群
|
||
- I (Intervention): 干预措施
|
||
- C (Comparison): 对照措施
|
||
- O (Outcome): 结局指标
|
||
|
||
{{#if context.pico}}
|
||
当前PICO:
|
||
- P: {{context.pico.P.value}}
|
||
- I: {{context.pico.I.value}}
|
||
- C: {{context.pico.C.value}}
|
||
- O: {{context.pico.O.value}}
|
||
{{/if}}
|
||
|
||
请引导用户逐一明确四个要素,确保:
|
||
1. P: 纳入标准、排除标准清晰
|
||
2. I: 干预措施具体可操作
|
||
3. C: 对照组设置合理
|
||
4. O: 结局指标可测量、有临床意义
|
||
|
||
当四要素都明确后,提供"同步到方案"按钮。`,
|
||
variables: ['context'],
|
||
},
|
||
// 研究设计阶段Prompt
|
||
{
|
||
promptType: 'stage',
|
||
promptCode: 'stage_study_design',
|
||
stageCode: 'study_design',
|
||
content: `【研究设计阶段】
|
||
|
||
根据科学问题和PICO,需要确定合适的研究设计:
|
||
|
||
科学问题:{{context.scientificQuestion.content}}
|
||
PICO:
|
||
- P: {{context.pico.P.value}}
|
||
- I: {{context.pico.I.value}}
|
||
|
||
常见研究类型:
|
||
- 随机对照试验(RCT):最高证据等级,适合验证干预效果
|
||
- 队列研究:适合观察性研究,探索风险因素
|
||
- 病例对照研究:适合罕见疾病研究
|
||
- 横断面研究:描述性研究
|
||
|
||
请引导用户确定:
|
||
1. 研究类型
|
||
2. 盲法设计(如适用)
|
||
3. 随机化方法(如适用)
|
||
4. 研究周期
|
||
5. 是否多中心
|
||
|
||
设计确定后,提供"同步到方案"按钮。`,
|
||
variables: ['context'],
|
||
},
|
||
// 样本量阶段Prompt
|
||
{
|
||
promptType: 'stage',
|
||
promptCode: 'stage_sample_size',
|
||
stageCode: 'sample_size',
|
||
content: `【样本量计算阶段】
|
||
|
||
样本量计算需要考虑:
|
||
- α (显著性水平): 通常0.05
|
||
- β (统计效力): 通常0.8-0.9
|
||
- 预期效应量
|
||
- 预计脱落率
|
||
|
||
研究设计:{{context.studyDesign.type}}
|
||
主要结局:{{context.pico.O.value}}
|
||
|
||
请引导用户:
|
||
1. 确定检验类型(优效、非劣效、等效)
|
||
2. 估计预期效应量(基于文献或预试验)
|
||
3. 设定显著性水平和统计效力
|
||
4. 考虑脱落率调整
|
||
|
||
可以使用样本量计算工具辅助计算。
|
||
|
||
样本量确定后,提供"同步到方案"按钮。`,
|
||
variables: ['context'],
|
||
},
|
||
// 观察指标阶段Prompt
|
||
{
|
||
promptType: 'stage',
|
||
promptCode: 'stage_endpoints',
|
||
stageCode: 'endpoints',
|
||
content: `【观察指标设计阶段】
|
||
|
||
观察指标是评价研究结果的关键:
|
||
|
||
研究类型:{{context.studyDesign.type}}
|
||
PICO-O:{{context.pico.O.value}}
|
||
|
||
需要明确的指标类型:
|
||
1. **主要结局指标(Primary Endpoint)**:
|
||
- 与科学问题直接相关
|
||
- 用于样本量计算
|
||
- 每个研究通常只有1-2个
|
||
|
||
2. **次要结局指标(Secondary Endpoints)**:
|
||
- 支持主要结局的补充指标
|
||
- 可以有多个
|
||
|
||
3. **安全性指标(Safety Endpoints)**:
|
||
- 不良事件、实验室检查等
|
||
|
||
4. **探索性指标(Exploratory)**:
|
||
- 为未来研究提供线索
|
||
|
||
请引导用户定义每个指标的:
|
||
- 名称
|
||
- 操作定义
|
||
- 测量方法
|
||
- 评价时点
|
||
|
||
所有指标确定后,提供"同步到方案"按钮。
|
||
|
||
🎉 完成观察指标后,您可以点击"一键生成研究方案"生成完整方案文档!`,
|
||
variables: ['context'],
|
||
},
|
||
// 数据提取Prompt
|
||
{
|
||
promptType: 'extraction',
|
||
promptCode: 'extraction_scientific_question',
|
||
stageCode: 'scientific_question',
|
||
content: `请从以下对话中提取科学问题信息:
|
||
|
||
用户消息:{{userMessage}}
|
||
|
||
请以JSON格式输出:
|
||
{
|
||
"content": "完整的科学问题陈述",
|
||
"background": "研究背景",
|
||
"significance": "研究意义",
|
||
"readyToSync": true/false
|
||
}
|
||
|
||
如果信息不完整,readyToSync设为false。`,
|
||
variables: ['userMessage'],
|
||
},
|
||
{
|
||
promptType: 'extraction',
|
||
promptCode: 'extraction_pico',
|
||
stageCode: 'pico',
|
||
content: `请从以下对话中提取PICO要素:
|
||
|
||
用户消息:{{userMessage}}
|
||
当前PICO:{{currentPico}}
|
||
|
||
请以JSON格式输出:
|
||
{
|
||
"P": { "value": "研究人群", "details": "详细描述" },
|
||
"I": { "value": "干预措施", "details": "详细描述" },
|
||
"C": { "value": "对照措施", "details": "详细描述" },
|
||
"O": { "value": "结局指标", "details": "详细描述" },
|
||
"readyToSync": true/false
|
||
}
|
||
|
||
只更新用户提到的字段,保留其他字段不变。
|
||
如果PICO四要素都已完整,readyToSync设为true。`,
|
||
variables: ['userMessage', 'currentPico'],
|
||
},
|
||
// 研究方案生成Prompt
|
||
{
|
||
promptType: 'generation',
|
||
promptCode: 'generate_protocol',
|
||
content: `你是一位资深的临床研究方法学专家,请基于以下核心要素生成一份完整、规范的临床研究方案。
|
||
|
||
## 核心要素
|
||
|
||
### 科学问题
|
||
{{scientificQuestion.content}}
|
||
{{#if scientificQuestion.background}}背景:{{scientificQuestion.background}}{{/if}}
|
||
|
||
### PICO要素
|
||
- **研究人群(P)**: {{pico.P.value}}
|
||
{{pico.P.details}}
|
||
- **干预措施(I)**: {{pico.I.value}}
|
||
{{pico.I.details}}
|
||
- **对照措施(C)**: {{pico.C.value}}
|
||
{{pico.C.details}}
|
||
- **结局指标(O)**: {{pico.O.value}}
|
||
{{pico.O.details}}
|
||
|
||
### 研究设计
|
||
- 研究类型: {{studyDesign.type}}
|
||
- 盲法设计: {{studyDesign.blinding}}
|
||
- 随机化方法: {{studyDesign.randomization}}
|
||
- 研究周期: {{studyDesign.duration}}
|
||
{{#if studyDesign.multiCenter}}- 多中心: 是,{{studyDesign.centerCount}}个中心{{/if}}
|
||
|
||
### 样本量
|
||
- 总样本量: {{sampleSize.total}}
|
||
- 每组样本量: {{sampleSize.perGroup}}
|
||
- 计算依据: {{sampleSize.justification}}
|
||
|
||
### 观察指标
|
||
**主要结局指标:**
|
||
{{#each endpoints.primary}}
|
||
- {{name}}: {{definition}} ({{method}}, {{timePoint}})
|
||
{{/each}}
|
||
|
||
**次要结局指标:**
|
||
{{#each endpoints.secondary}}
|
||
- {{name}}: {{definition}}
|
||
{{/each}}
|
||
|
||
**安全性指标:**
|
||
{{#each endpoints.safety}}
|
||
- {{name}}: {{definition}}
|
||
{{/each}}
|
||
|
||
---
|
||
|
||
## 生成要求
|
||
|
||
请生成包含以下章节的完整研究方案:
|
||
|
||
1. **研究背景与立题依据**
|
||
- 疾病/问题背景
|
||
- 国内外研究现状
|
||
- 研究的必要性和意义
|
||
|
||
2. **研究目的**
|
||
- 主要目的
|
||
- 次要目的
|
||
|
||
3. **研究方法**
|
||
- 研究类型与设计
|
||
- 研究对象
|
||
- 干预措施
|
||
- 对照设置
|
||
- 随机化与盲法
|
||
|
||
4. **受试者选择**
|
||
- 入选标准
|
||
- 排除标准
|
||
- 退出/剔除标准
|
||
|
||
5. **观察指标与评价标准**
|
||
- 主要疗效指标
|
||
- 次要疗效指标
|
||
- 安全性指标
|
||
- 评价时点
|
||
|
||
6. **统计分析计划**
|
||
- 样本量估算
|
||
- 分析数据集定义
|
||
- 统计方法
|
||
|
||
7. **质量控制**
|
||
- 数据管理
|
||
- 质量保证措施
|
||
|
||
8. **伦理考虑**
|
||
- 伦理审查
|
||
- 知情同意
|
||
- 受试者保护
|
||
|
||
9. **研究进度安排**
|
||
- 时间节点
|
||
- 里程碑
|
||
|
||
请使用专业、规范的学术语言,确保内容完整、逻辑清晰、符合临床研究规范。`,
|
||
variables: ['scientificQuestion', 'pico', 'studyDesign', 'sampleSize', 'endpoints'],
|
||
},
|
||
];
|
||
|
||
// 获取阶段ID映射
|
||
const stageIdMap = new Map<string, string>();
|
||
const savedStages = await prisma.agentStage.findMany({
|
||
where: { agentId: agentDefinition.id },
|
||
});
|
||
for (const stage of savedStages) {
|
||
stageIdMap.set(stage.stageCode, stage.id);
|
||
}
|
||
|
||
// 创建Prompts
|
||
for (const prompt of prompts) {
|
||
const stageId = prompt.stageCode ? stageIdMap.get(prompt.stageCode) : null;
|
||
|
||
await prisma.agentPrompt.upsert({
|
||
where: {
|
||
agentId_promptCode_version: {
|
||
agentId: agentDefinition.id,
|
||
promptCode: prompt.promptCode,
|
||
version: 1,
|
||
},
|
||
},
|
||
update: {
|
||
content: prompt.content,
|
||
variables: prompt.variables,
|
||
},
|
||
create: {
|
||
agentId: agentDefinition.id,
|
||
stageId: stageId,
|
||
promptType: prompt.promptType,
|
||
promptCode: prompt.promptCode,
|
||
content: prompt.content,
|
||
variables: prompt.variables,
|
||
version: 1,
|
||
isActive: true,
|
||
},
|
||
});
|
||
console.log(` ✅ Prompt: ${prompt.promptCode}`);
|
||
}
|
||
|
||
// 4. 创建Reflexion规则
|
||
const reflexionRules = [
|
||
{
|
||
ruleCode: 'scientific_question_completeness',
|
||
ruleName: '科学问题完整性检查',
|
||
triggerStage: 'scientific_question',
|
||
triggerTiming: 'on_sync',
|
||
ruleType: 'rule_based',
|
||
conditions: {
|
||
content: { required: true, minLength: 10 },
|
||
},
|
||
severity: 'warning',
|
||
failureAction: 'warn',
|
||
sortOrder: 1,
|
||
},
|
||
{
|
||
ruleCode: 'pico_completeness',
|
||
ruleName: 'PICO要素完整性检查',
|
||
triggerStage: 'pico',
|
||
triggerTiming: 'on_sync',
|
||
ruleType: 'rule_based',
|
||
conditions: {
|
||
P: 'required',
|
||
I: 'required',
|
||
C: 'required',
|
||
O: 'required',
|
||
},
|
||
severity: 'error',
|
||
failureAction: 'warn',
|
||
sortOrder: 2,
|
||
},
|
||
{
|
||
ruleCode: 'sample_size_validity',
|
||
ruleName: '样本量有效性检查',
|
||
triggerStage: 'sample_size',
|
||
triggerTiming: 'on_sync',
|
||
ruleType: 'rule_based',
|
||
conditions: {
|
||
total: { required: true, min: 1 },
|
||
},
|
||
severity: 'error',
|
||
failureAction: 'warn',
|
||
sortOrder: 3,
|
||
},
|
||
{
|
||
ruleCode: 'endpoints_primary_required',
|
||
ruleName: '主要终点指标必填',
|
||
triggerStage: 'endpoints',
|
||
triggerTiming: 'on_sync',
|
||
ruleType: 'rule_based',
|
||
conditions: {
|
||
primary: { notEmpty: true },
|
||
},
|
||
severity: 'error',
|
||
failureAction: 'warn',
|
||
sortOrder: 4,
|
||
},
|
||
];
|
||
|
||
for (const rule of reflexionRules) {
|
||
await prisma.reflexionRule.upsert({
|
||
where: {
|
||
agentId_ruleCode: {
|
||
agentId: agentDefinition.id,
|
||
ruleCode: rule.ruleCode,
|
||
},
|
||
},
|
||
update: rule,
|
||
create: {
|
||
agentId: agentDefinition.id,
|
||
...rule,
|
||
isActive: true,
|
||
},
|
||
});
|
||
console.log(` ✅ Rule: ${rule.ruleName}`);
|
||
}
|
||
|
||
console.log('\n🎉 Protocol Agent configuration seeded successfully!');
|
||
}
|
||
|
||
main()
|
||
.catch((e) => {
|
||
console.error('❌ Seed failed:', e);
|
||
process.exit(1);
|
||
})
|
||
.finally(async () => {
|
||
await prisma.$disconnect();
|
||
});
|
||
|
||
|
||
|
||
|
||
|