feat(ssa): Complete QPER architecture - Query, Planner, Execute, Reflection layers

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>
This commit is contained in:
2026-02-21 18:15:53 +08:00
parent 428a22adf2
commit 371e1c069c
73 changed files with 9242 additions and 706 deletions

View File

@@ -0,0 +1,174 @@
/**
* 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());