Implement the full QPER intelligent analysis pipeline: - Phase E+: Block-based standardization for all 7 R tools, DynamicReport renderer, Word export enhancement - Phase Q: LLM intent parsing with dynamic Zod validation against real column names, ClarificationCard component, DataProfile is_id_like tagging - Phase P: ConfigLoader with Zod schema validation and hot-reload API, DecisionTableService (4-dimension matching), FlowTemplateService with EPV protection, PlannedTrace audit output - Phase R: ReflectionService with statistical slot injection, sensitivity analysis conflict rules, ConclusionReport with section reveal animation, conclusion caching API, graceful R error classification End-to-end test: 40/40 passed across two complete analysis scenarios. Co-authored-by: Cursor <cursoragent@cursor.com>
175 lines
6.3 KiB
TypeScript
175 lines
6.3 KiB
TypeScript
/**
|
||
* SSA Reflection Prompt Seed 脚本
|
||
*
|
||
* 将 SSA_REFLECTION prompt 写入 capability_schema.prompt_templates
|
||
* 运行: npx tsx scripts/seed-ssa-reflection-prompt.ts
|
||
*
|
||
* Phase R — 论文级结论生成 Prompt
|
||
* 特性:
|
||
* - 统计量槽位注入(反幻觉)
|
||
* - 敏感性分析冲突处理准则
|
||
* - 6 要素结构化 JSON 输出
|
||
* - 基于 decision_trace 的方法学说明
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
const SSA_REFLECTION_PROMPT = `你是一位高级生物统计师,请基于以下分析结果生成论文级结论。
|
||
|
||
## 分析背景
|
||
|
||
分析目标:{{goal}}
|
||
分析标题:{{title}}
|
||
采用方法:{{methodology}}
|
||
样本信息:{{sampleInfo}}
|
||
|
||
## 方法选择的决策轨迹
|
||
|
||
请据此撰写方法学说明,不得臆造选择理由:
|
||
|
||
匹配规则:{{decision_trace.matched_rule}}
|
||
主要工具:{{decision_trace.primary_tool}}
|
||
{{#if decision_trace.fallback_tool}}备选工具:{{decision_trace.fallback_tool}}(触发条件:{{decision_trace.switch_condition}}){{/if}}
|
||
决策推理:{{decision_trace.reasoning}}
|
||
{{#if decision_trace.epv_warning}}⚠️ EPV 警告:{{decision_trace.epv_warning}}{{/if}}
|
||
|
||
## 各步骤统计结果
|
||
|
||
⚠️ 以下数值由系统自动注入,你必须原样引用,不得修改、四舍五入或重新表述任何数字。
|
||
|
||
{{#each findings}}
|
||
### 步骤 {{step_number}}:{{tool_name}}({{tool_code}})
|
||
- 使用方法:{{method}}
|
||
{{#if statistic}}- 统计量({{statistic_name}}):{{statistic}}{{/if}}
|
||
{{#if p_value}}- P 值:{{p_value}}{{/if}}
|
||
{{#if effect_size}}- 效应量({{effect_size_name}}):{{effect_size}}{{/if}}
|
||
{{#if ci_lower}}- 95% 置信区间:{{ci_lower}} ~ {{ci_upper}}{{/if}}
|
||
- 显著性:{{#if is_significant}}显著(P < 0.05){{else}}不显著(P ≥ 0.05){{/if}}
|
||
{{#if group_stats}}
|
||
- 各组统计:
|
||
{{#each group_stats}} · {{group}} 组:n={{n}}{{#if mean}}, 均值={{mean}}, SD={{sd}}{{/if}}{{#if median}}, 中位数={{median}}{{/if}}
|
||
{{/each}}
|
||
{{/if}}
|
||
|
||
{{/each}}
|
||
|
||
## 冲突处理准则(强制执行)
|
||
|
||
当主分析与敏感性分析的显著性结论不一致时:
|
||
1. 在 limitations 数组中必须包含:"敏感性分析未得到一致结论,结果的稳健性(Robustness)较弱,需谨慎解释临床意义"
|
||
2. 在 key_findings 中以主分析结果为基准报告,但需加注"(注:敏感性分析未验证此结论)"
|
||
3. 严禁选择性报告、强行拼凑显著性
|
||
4. 当所有分析方向一致时,在 key_findings 中可强调"敏感性分析进一步验证了结论的稳健性"
|
||
|
||
## 输出要求
|
||
|
||
请输出一个严格的 JSON 对象(不要输出任何其他内容,只输出 JSON),包含以下字段:
|
||
|
||
\`\`\`json
|
||
{
|
||
"executive_summary": "200-500字的综合摘要,涵盖研究目的、主要发现和临床意义。使用论文'结果'章节的行文风格,可直接复制到论文中。引用统计量时必须与上方数值完全一致。",
|
||
"key_findings": [
|
||
"发现1:具体描述,含统计量和P值(必须与上方数值一致)",
|
||
"发现2:..."
|
||
],
|
||
"statistical_summary": {
|
||
"total_tests": 3,
|
||
"significant_results": 2,
|
||
"methods_used": ["独立样本T检验", "Mann-Whitney U检验"]
|
||
},
|
||
"methodology": "方法学说明段落:基于上方决策轨迹撰写,解释为什么选择此方法、是否发生降级、数据满足了哪些假设。使用论文'方法'章节的行文风格。",
|
||
"limitations": [
|
||
"局限性1",
|
||
"局限性2"
|
||
],
|
||
"recommendations": [
|
||
"建议1:基于分析结果的后续研究建议",
|
||
"建议2:..."
|
||
]
|
||
}
|
||
\`\`\`
|
||
|
||
## 关键规则
|
||
|
||
1. **所有数值必须与上方统计结果完全一致**,不得修改、四舍五入、近似或重新表述
|
||
2. executive_summary 必须是完整的论文段落,不是要点列表
|
||
3. key_findings 每条必须包含具体的统计量和 P 值
|
||
4. methodology 必须基于决策轨迹撰写,说明方法选择的理由
|
||
5. limitations 至少包含 1 条,如果数据有局限则如实报告
|
||
6. 请只输出 JSON,不要输出其他内容`;
|
||
|
||
async function main() {
|
||
console.log('🚀 开始写入 SSA Reflection Prompt...\n');
|
||
|
||
const existing = await prisma.prompt_templates.findUnique({
|
||
where: { code: 'SSA_REFLECTION' }
|
||
});
|
||
|
||
if (existing) {
|
||
console.log('⚠️ SSA_REFLECTION 已存在 (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_REFLECTION_PROMPT,
|
||
model_config: { model: 'deepseek-v3', temperature: 0.3, maxTokens: 4096 },
|
||
status: 'ACTIVE',
|
||
changelog: `Phase R v1.0: 6要素结构化JSON + 槽位注入 + 冲突处理准则`,
|
||
created_by: 'system-seed',
|
||
}
|
||
});
|
||
|
||
console.log(' ✅ 新版本 v%d 已创建并设为 ACTIVE', newVersion);
|
||
} else {
|
||
console.log('📝 创建 SSA_REFLECTION 模板...');
|
||
|
||
const template = await prisma.prompt_templates.create({
|
||
data: {
|
||
code: 'SSA_REFLECTION',
|
||
name: 'SSA 论文级结论生成 Prompt',
|
||
module: 'SSA',
|
||
description: 'Phase R — 将 StepResult[] 转化为论文级结论(6要素结构化JSON,含槽位注入反幻觉 + 敏感性冲突准则)',
|
||
variables: ['goal', 'title', 'methodology', 'sampleInfo', 'decision_trace', 'findings'],
|
||
}
|
||
});
|
||
|
||
await prisma.prompt_versions.create({
|
||
data: {
|
||
template_id: template.id,
|
||
version: 1,
|
||
content: SSA_REFLECTION_PROMPT,
|
||
model_config: { model: 'deepseek-v3', temperature: 0.3, maxTokens: 4096 },
|
||
status: 'ACTIVE',
|
||
changelog: 'Phase R v1.0: 初始版本,6要素JSON + 槽位注入 + 冲突处理准则',
|
||
created_by: 'system-seed',
|
||
}
|
||
});
|
||
|
||
console.log(' ✅ 模板 id=%d + 版本 v1 已创建', template.id);
|
||
}
|
||
|
||
console.log('\n✅ SSA Reflection Prompt 写入完成!');
|
||
}
|
||
|
||
main()
|
||
.catch(e => {
|
||
console.error('❌ 写入失败:', e);
|
||
process.exit(1);
|
||
})
|
||
.finally(() => prisma.$disconnect());
|