Files
AIclinicalresearch/backend/scripts/seed-ssa-pico-prompt.ts
HaHafeng 3446909ff7 feat(ssa): Complete Phase I-IV intelligent dialogue and tool system development
Phase I - Session Blackboard + READ Layer:
- SessionBlackboardService with Postgres-Only cache
- DataProfileService for data overview generation
- PicoInferenceService for LLM-driven PICO extraction
- Frontend DataContextCard and VariableDictionaryPanel
- E2E tests: 31/31 passed

Phase II - Conversation Layer LLM + Intent Router:
- ConversationService with SSE streaming
- IntentRouterService (rule-first + LLM fallback, 6 intents)
- SystemPromptService with 6-segment dynamic assembly
- TokenTruncationService for context management
- ChatHandlerService as unified chat entry
- Frontend SSAChatPane and useSSAChat hook
- E2E tests: 38/38 passed

Phase III - Method Consultation + AskUser Standardization:
- ToolRegistryService with Repository Pattern
- MethodConsultService with DecisionTable + LLM enhancement
- AskUserService with global interrupt handling
- Frontend AskUserCard component
- E2E tests: 13/13 passed

Phase IV - Dialogue-Driven Analysis + QPER Integration:
- ToolOrchestratorService (plan/execute/report)
- analysis_plan SSE event for WorkflowPlan transmission
- Dual-channel confirmation (ask_user card + workspace button)
- PICO as optional hint for LLM parsing
- E2E tests: 25/25 passed

R Statistics Service:
- 5 new R tools: anova_one, baseline_table, fisher, linear_reg, wilcoxon
- Enhanced guardrails and block helpers
- Comprehensive test suite (run_all_tools_test.js)

Documentation:
- Updated system status document (v5.9)
- Updated SSA module status and development plan (v1.8)

Total E2E: 107/107 passed (Phase I: 31, Phase II: 38, Phase III: 13, Phase IV: 25)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 18:53:39 +08:00

148 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* SSA PICO Inference Prompt Seed 脚本 (Phase I)
*
* 将 SSA_PICO_INFERENCE prompt 写入 capability_schema.prompt_templates
* 运行: npx tsx scripts/seed-ssa-pico-prompt.ts
*/
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const SSA_PICO_INFERENCE_PROMPT = `你是一个临床研究设计分析引擎。你的任务是根据数据概览信息,推断该数据集可能的 PICO 结构。
## 输入信息
### 数据概览
{{dataOverviewSummary}}
### 变量列表
{{variableList}}
## 你的任务
请根据数据概览推断出 PICO 结构,以 JSON 格式输出(不要输出任何其他内容,只输出 JSON
\`\`\`json
{
"population": "研究人群描述(必须基于数据特征推断,如 '311 例行口腔智齿拔除术的患者'",
"intervention": "干预措施(如果是观察性研究,输出 null",
"comparison": "对照组(如果无对照或无干预,输出 null",
"outcome": "结局指标描述(可列出多个结局变量)",
"confidence": "high | medium | low",
"reasoning": "你的推理过程1-2 句话"
}
\`\`\`
## 关键规则
1. **并非所有数据都是随机对照试验RCT。** 如果数据是观察性研究(横断面调查、回顾性队列、病例对照等),在 intervention 和 comparison 字段输出 null绝不要强行捏造干预措施。
2. **变量名必须精确引用**数据概览中列出的真实变量名。
3. population 应包含样本量(如"311 例")和研究对象特征。
4. outcome 应列出最可能作为结局变量的变量名。
5. 如果数据中存在明显的分组变量(如 treatment/control、手术方式等则推断为 intervention。
## Confidence 评分准则
- **high**: 数据中有明确的分组变量和结局变量PICO 结构清晰。
- **medium**: 能推断出大致的研究目的,但部分要素不确定。
- **low**: 数据缺乏明显的研究设计特征PICO 结构高度不确定。
## Few-Shot 示例
### 示例 1有明确干预的 RCT
数据概览: 200 行, 变量: patient_id, group (2 水平: Drug/Placebo), age, gender, SBP_before, SBP_after, adverse_event
输出:
\`\`\`json
{"population":"200 例参与药物临床试验的患者","intervention":"药物治疗 (group=Drug)","comparison":"安慰剂 (group=Placebo)","outcome":"治疗后收缩压 (SBP_after)、不良事件 (adverse_event)","confidence":"high","reasoning":"group 变量有 Drug/Placebo 两水平,典型 RCT 设计SBP_after 和 adverse_event 是可能的结局变量"}
\`\`\`
### 示例 2观察性研究无干预
数据概览: 500 行, 变量: id, age, sex, bmi, smoking, exercise, blood_pressure, cholesterol, diabetes
输出:
\`\`\`json
{"population":"500 例社区居民健康调查样本","intervention":null,"comparison":null,"outcome":"血压 (blood_pressure)、胆固醇 (cholesterol)、糖尿病 (diabetes)","confidence":"medium","reasoning":"数据无明显分组/干预变量,为典型的横断面调查问卷,多个健康指标可作为结局变量"}
\`\`\`
### 示例 3手术方式比较
数据概览: 311 行, 变量: sex, smoke, age, bmi, mouth_open, toot_morph, operation (3 水平), time, Yqol
输出:
\`\`\`json
{"population":"311 例行口腔智齿拔除术的患者","intervention":"不同手术方式 (operation)","comparison":null,"outcome":"手术时间 (time)、术后生活质量 (Yqol)","confidence":"medium","reasoning":"operation 变量有 3 个水平可能代表不同手术方式time 和 Yqol 是可能的结局变量。但 operation 是否为干预需用户确认"}
\`\`\`
请只输出 JSON不要输出其他内容。`;
async function main() {
console.log('🚀 开始写入 SSA PICO Inference Prompt...\n');
const existing = await prisma.prompt_templates.findUnique({
where: { code: 'SSA_PICO_INFERENCE' }
});
if (existing) {
console.log('⚠️ SSA_PICO_INFERENCE 已存在 (id=%d),创建新版本...', existing.id);
const latestVersion = await prisma.prompt_versions.findFirst({
where: { template_id: existing.id },
orderBy: { version: 'desc' }
});
const newVersion = (latestVersion?.version ?? 0) + 1;
await prisma.prompt_versions.updateMany({
where: { template_id: existing.id, status: 'ACTIVE' },
data: { status: 'ARCHIVED' }
});
await prisma.prompt_versions.create({
data: {
template_id: existing.id,
version: newVersion,
content: SSA_PICO_INFERENCE_PROMPT,
model_config: { model: 'deepseek-v3', temperature: 0.3, maxTokens: 1024 },
status: 'ACTIVE',
changelog: `Phase I v${newVersion}: PICO 推断 Prompt含观察性研究 null 处理 — H3`,
created_by: 'system-seed',
}
});
console.log(' ✅ 新版本 v%d 已创建并设为 ACTIVE', newVersion);
} else {
console.log('📝 创建 SSA_PICO_INFERENCE 模板...');
const template = await prisma.prompt_templates.create({
data: {
code: 'SSA_PICO_INFERENCE',
name: 'SSA PICO 推断 Prompt',
module: 'SSA',
description: 'Phase I — 根据数据概览推断 PICO 结构(支持观察性研究 null 输出)',
variables: ['dataOverviewSummary', 'variableList'],
}
});
await prisma.prompt_versions.create({
data: {
template_id: template.id,
version: 1,
content: SSA_PICO_INFERENCE_PROMPT,
model_config: { model: 'deepseek-v3', temperature: 0.3, maxTokens: 1024 },
status: 'ACTIVE',
changelog: 'Phase I v1.0: PICO 推断初始版本3 组 Few-Shot含 H3 观察性研究处理)',
created_by: 'system-seed',
}
});
console.log(' ✅ 模板 id=%d + 版本 v1 已创建', template.id);
}
console.log('\n✅ SSA PICO Inference Prompt 写入完成!');
}
main()
.catch(e => {
console.error('❌ 写入失败:', e);
process.exit(1);
})
.finally(() => prisma.$disconnect());