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>
82 KiB
SSA-Pro Q-P-E-R 架构开发计划 — 智能化主线
文档版本: v7.1
创建日期: 2026-02-20
最后更新: 2026-02-21(v7.1 — 新增核心原则"领域知识可配置化" + Phase P 配置化基础设施:Zod 校验 / 热更新 API / 领域文件拆分)
架构模式: Query → Planner → Execute → Reflection
目标: 让不懂统计的医生完成专业级的统计分析
本文档定位: 替代旧 MVP 开发计划总览,成为 SSA 开发的主线指南
1. 架构总览
1.1 Q-P-E-R 四层架构
用户:"我有 200 个患者数据,想看看新药有没有效"
│
▼
┌─────────────────────────────────────────────────────────┐
│ Q · Query Layer (理解层) │
│ "用户到底想要什么?数据长什么样?" │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ IntentParser │→ │ DataProfiler │→ │ Clarifier │ │
│ │ LLM 意图 │ │ 数据诊断 │ │ 追问澄清 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 输出:ParsedQuery { goal, y, x, design, dataProfile } │
└──────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ P · Planner Layer (规划层) │
│ "该用什么方法?按什么顺序?" │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │DecisionTable │→ │FlowTemplate │→ │ SAP Builder │ │
│ │ 四维匹配 │ │ 流程模板 │ │ 计划生成 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 输出:AnalysisPlan { steps[], methodology, rationale } │
└──────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ E · Execute Layer (执行层) ✅ 已完成 │
│ "调用 R 引擎,跑出数字" │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Orchestrator│→ │ R Client │→ │ SSE Stream │ │
│ │ 步骤编排 │ │ 调用 R 引擎 │ │ 实时进度 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 输出:StepResult[] { stats, tables, plots, code } │
└──────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ R · Reflection Layer (审视层) │
│ "结果说明了什么?可以发论文吗?" │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Integrator │→ │ LLM Critic │→ │ReportBuilder │ │
│ │ 结果整合 │ │ 论文级结论 │ │ 报告生成 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 输出:Report { conclusion, methodology, limitations } │
└─────────────────────────────────────────────────────────┘
1.2 与现有代码的映射
| Q-P-E-R 层 | 现有代码 | 现状 | 目标 |
|---|---|---|---|
| Q · Query | WorkflowPlannerService.parseUserIntent() |
正则匹配,无 LLM | LLM 四维提取 + 追问 |
| Q · Query | DataProfileService + DataParserService |
基础统计 | 增加诊断项 + 传递给 P 层 |
| P · Planner | WorkflowPlannerService.generateSteps() |
硬编码 if/else | 决策表 + 流程模板 |
| E · Execute | WorkflowExecutorService + RClientService |
✅ 完成 | 保持不变 |
| E · Execute | 7 个 R 工具 + SSE + 前端展示 | ✅ 完成 | Block-based 标准化输出 |
| R · Reflection | ConclusionGeneratorService |
规则拼接,无 LLM | LLM 论文级结论 |
1.3 核心原则
-
Execute 层不动 — 这是花了最多时间搭建的基础,完整保留
-
前后加层 — 在 Execute 前面加更好的 Q+P,后面加 R
-
LLM 只在 Q 和 R 层使用 — P 层用确定性的决策表,E 层用确定性的 R 引擎
-
渐进式替换 — 每层完成后立即可用,不需要全部完成才能看到效果
-
复用平台通用能力层,禁止重复造轮 —
- LLM 调用 必须 通过
common/llm/LLMFactory+common/streaming/StreamingService - Prompt 管理 必须 使用
common/prompt/PromptService(数据库版本化capability_schema.prompt_templates),禁止在代码中硬编码 Prompt 字符串 - 缓存使用
common/cache/CacheService(Postgres-Only),日志使用common/logging/ - 参考
docs/04-开发规范/08-云原生开发规范.md和docs/02-通用能力层/00-通用能力层清单.md
- LLM 调用 必须 通过
-
⭐ 领域知识可配置化 — QPER 四层的所有"领域知识"由统计学方法学团队配置,不写死在代码中 —
IT 团队负责搭建引擎和管道,统计学方法学团队负责往管道里填充内容。"可配置"是贯穿所有 Phase 的架构约束。
约束:一切业务逻辑靠读 JSON/数据库驱动,绝不写死在 TypeScript 的 if-else 和常量对象中。
QPER 层 方法学团队可配置的内容 配置载体 Q 层 Intent Prompt(Few-Shot 示例、Confidence Rubric、Goal 类型枚举) PromptService数据库(✅ 已实现)P 层 决策表规则、流程模板、Switch Condition、EPV 阈值 JSON 文件 → Repository 接口(Phase P) E 层 R 工具注册表(100 个工具的参数定义、前置条件、护栏规则) JSON 文件 tools_registry.json(Phase P 创建)R 层 结论模板、方法学说明模板、统计量阈值定义 JSON 文件 narrative_templates.json(Phase R 创建)配置化三道防线(Phase P 落地):
- Zod Schema 严格校验 — 方法学团队编辑 JSON 时的拼写错误、结构错误在加载时立即拦截,不传播到运行时
- 热更新 API — 方法学团队修改 JSON 后无需 IT 团队重启服务,调用
POST /reload-config即可生效(校验失败则保留旧配置) - 领域文件物理拆分 — 按职责拆为独立 JSON 文件,避免版本冲突,每个文件有明确的所有者
backend/src/modules/ssa/config/ ├── tools_registry.json # E 层:100 个工具的注册定义(方法学团队维护) ├── decision_tables.json # P 层:四维匹配规则 + 降级触发条件(方法学团队维护) ├── flow_templates.json # P 层:标准步骤流组合(方法学团队维护) └── narrative_templates.json # R 层:结论生成和理由说明的文案模板(Phase R 创建)
1.4 架构红线(不可为清单)
来源: 四份外部调研报告 + 架构审查共识。以下三条为强制约束,任何 Phase 均不可违反。
| # | 红线 | 理由 |
|---|---|---|
| 🚫 1 | 禁止引入 LangGraph / AutoGen 等编排框架 | QPER 是线性流水线 + 重试,Node.js 原生 while + try-catch 足够编排,框架只增加复杂度和调试成本 |
| 🚫 2 | 禁止 LLM 生成并执行 R 代码 | 只允许 LLM 修改参数 JSON 重新请求固定 R 脚本(r-statistics-service/tools/),杜绝远程代码执行风险。R 工具是参数化封装的固定脚本,不是 LLM 的画布 |
| 🚫 3 | 禁止多智能体辩论(Multi-Agent Debate) | 统计学有硬性定理(正态性 P<0.05 就是不满足),用决策表规则判定即可,不需要两个 LLM 互相消耗 Token |
2. 当前系统资产盘点
2.1 可直接复用(不改动)
| 资产 | 文件 | 状态 |
|---|---|---|
| R 统计引擎 | r-statistics-service/ (7 个工具) |
✅ |
| R 调用客户端 | RClientService.ts |
✅ |
| 工作流执行器 | WorkflowExecutorService.ts |
✅ |
| SSE 实时通信 | workflow.routes.ts |
✅ |
| 数据上传 + OSS | 会话管理 + 文件上传路由 | ✅ |
| 前端 V11 UI | SSAWorkspace 全套组件 | ✅ |
| 前端执行日志 | terminal-box + TraceLogItem | ✅ |
| 前端结果展示 | 统计量/表格/图表渲染 | ✅ |
| R 代码导出 | SSACodeModal (多步骤聚合) | ✅ |
| Word 报告导出 | useAnalysis.exportWorkflowReport | ✅ |
| Python 数据质量 | DataProfileService + extraction_service | ✅ |
2.2 需要拆分重构
| 现有代码 | 拆分为 | 层级 |
|---|---|---|
WorkflowPlannerService.parseUserIntent() |
QueryService.parseIntent() |
Q |
WorkflowPlannerService.generateSteps() |
PlannerService.plan() |
P |
AVAILABLE_TOOLS 硬编码对象 |
DecisionTable 配置文件 |
P |
ConclusionGeneratorService(已有,规则拼接) |
ReflectionService(LLM 升级) |
R |
迁移策略:
WorkflowPlannerService不立即删除,而是在内部委托给新的 QueryService / PlannerService,保留旧入口作为兼容层,待 Q+P 层稳定后再移除。
2.3 需要新建
| 新建服务 | 层级 | 核心能力 |
|---|---|---|
QueryService |
Q | LLM 意图解析 + 追问(通过平台 LLMFactory + PromptService) |
DataDiagnosticService |
Q | 异常值/正态性/平衡性检测(扩展现有 DataProfileService) |
DecisionTableService |
P | 四维匹配 |
FlowTemplateService |
P | 流程模板管理 |
DynamicReport.tsx |
E(前端) | Block-based 动态渲染 |
注意:
ReflectionService不是新建,而是对已有ConclusionGeneratorService的 LLM 升级重构(见 2.2)。
2.4 已有数据库资产(Prisma schema ssa_schema)
| 模型 | 状态 | 说明 |
|---|---|---|
SsaSession / SsaMessage / SsaFileUpload |
✅ 使用中 | 会话管理 + 消息 + 文件上传 |
SsaDecisionTable |
✅ 已建模 | 决策表记录,DecisionTableService 应优先使用此表 |
SsaRCodeLibrary |
✅ 已建模 | R 代码库记录 |
SsaAnalysisResult |
✅ 已建模 | 分析结果记录(含 report_blocks 字段) |
Phase P 的决策表配置应评估是否直接使用
SsaDecisionTable数据库表,而非仅用静态 JSON 文件。
3. 开发计划(5 个 Phase)
Phase E+ : Execute 层标准化 — Block-based(2.5 天)
为什么先做这个: 后续每新增一个 R 工具,前端都需要写自定义渲染代码。Block-based 协议让这个成本归零,是所有后续开发的前提。
目标:R 输出 report_blocks[] → Node.js 透传 → 前端 DynamicReport 渲染
| # | 任务 | 层级 | 工时 | 产出 |
|---|---|---|---|---|
| 1 | R 端辅助函数库 block_helpers.R |
R | 1h | make_table_block(), make_kv_block(), make_image_block() |
| 2 | 改造 t_test_ind.R 输出 report_blocks |
R | 1h | 第一个 Block-based 工具 |
| 3 | 改造其余 6 个 R 工具 | R | 6h | 全部输出 report_blocks |
| 4 | 后端透传 report_blocks 全链路 |
后端 | 1.5h | WorkflowExecutorService → SSE 事件 → 前端 store;需验证 SsaAnalysisResult 表 report_blocks 字段持久化 |
| 5 | 前端 DynamicReport.tsx 组件 |
前端 | 2h | 4 个 Block 渲染子组件 |
| 6 | 前端 exportBlocksToWord.ts |
前端 | 2h | Block 数组 → Word 文档 |
| 7 | SSAWorkspacePane 集成 + fallback |
前端 | 1h | 优先读 report_blocks,旧逻辑兜底 |
| 8 | 旧渲染代码保留为 fallback | 前端 | 1h | DescriptiveResultView 等组件(2026-02-20 新建)暂保留,当 report_blocks 为空时自动降级使用;待 Block-based 全面验证后再清理 |
验收标准: 所有 7 个 R 工具的结果通过 DynamicReport 统一渲染,Word 导出正常。
Phase Q : Query 层建设 — LLM 意图理解(4 天)
为什么第二做: 这是用户体验提升最大的单一改进。从"用户必须知道 T 检验"变为"用户说'有没有效'就够了"。
目标:用户自然语言 → LLM 提取四维信息 → 不确定时追问
3.1 后端任务
| # | 任务 | 工时 | 说明 |
|---|---|---|---|
| 1 | 通过 PromptService 注册 Intent Prompt |
5h | 编写 Prompt + seed 脚本写入 capability_schema.prompt_templates;输出:{ goal, outcome_var, predictor_vars, design, confidence }。必须包含 3-5 组 Few-Shot 示例(覆盖"哪个组更好"→差异比较、"血压和体重有关吗"→关联分析等典型口语表达),显著提升首次解析准确率。Confidence Rubric 客观化:Prompt 中必须内嵌打分准则(0.9+ = 用户原话明确了 Y 和至少一个 X;0.7-0.8 = 指出了 Y 但 X 需推断;< 0.7 = 只说了"帮我分析"需追问),防止 LLM 自评虚高 |
| 2 | 新建 QueryService.ts |
8h | 通过 LLMFactory.create() 调用 LLM + json-repair + Zod 校验 + 低置信度追问逻辑 + 正则兜底(保留现有 parseUserIntent 逻辑作为 fallback)。Zod 动态防幻觉:用 createIntentSchema(validColumns) 动态生成 Schema,通过 .refine() 校验 LLM 输出的 outcome_var/predictor_vars 是否存在于真实列名中,捏造列名立即触发重试或 fallback。Confidence 二次验证:若 LLM 打分 ≥0.9 但 outcome_var 或 predictor_vars 为空,强制降级到 0.5 |
| 3 | 增强 DataProfileService |
4h | 增加异常值检测(IQR)、分组平衡性、样本量评估;注意:DataParserService 的 0/1 分类规则已在 2026-02-19 优化完成,不重复。非分析变量自动标记:Python 端对高基数字符串列(uniqueValues/totalRows > 0.95)、日期列、列名匹配 _id/_no/编号/序号 模式的列打 is_id_like: true 标签;Q→P 上下文裁剪时物理剔除这些列,让 LLM 看不到 patient_id 等非分析列 |
| 4 | 定义 ParsedQuery 接口 |
1h | Q 层输出 → P 层输入的标准契约,放 types/query.types.ts |
| 5 | 新建追问 API | 2h | POST /api/v1/ssa/sessions/:id/clarify,在现有 analysis.routes.ts 中扩展 |
| 6 | 安装 json-repair + zod 依赖 |
0.5h | Phase 1 遗留任务,此处一并完成 |
| 7 | Q→P 上下文裁剪(Context Pruning) | 1h | Q 层识别出 Y/X 变量后,只提取这几列的 DataProfile 子集传给 P 层(Hot Context);其余列的详情留在数据库按需拉取(Cold Context)。防止 100 列 CSV 的 50KB DataProfile JSON 导致 Planner 的 Token 爆炸和"注意力涣散" |
| 8 | DataProfile 会话级缓存 | 0.5h | 用户上传文件后 DataProfiler 只执行一次,结果通过 CacheService 缓存(key: ssa:profile:{sessionId}:{fileHash})。同一会话+同一文件的后续 Q 层循环(如追问后重新解析)直接读缓存,实现毫秒级响应,避免重复调用 Python 解析 20MB CSV |
QueryService 核心逻辑:
// 伪代码 — 使用平台通用能力层
class QueryService {
constructor(
private promptService: PromptService, // 平台通用能力:Prompt 管理
private llmFactory: LLMFactory, // 平台通用能力:LLM 网关
) {}
async parseQuery(userText: string, dataProfile: DataProfile): Promise<ParsedQuery> {
// 1. 从数据库加载 Prompt 模板(支持版本化 + A/B 测试)
const promptTemplate = await this.promptService.getPrompt('ssa_intent_parse', 'latest');
const prompt = this.promptService.render(promptTemplate, { userText, variables: dataProfile.variables });
// 2. 通过 LLMFactory 调用 LLM(自动选模型 + 统一错误处理)
const llm = this.llmFactory.create({ model: 'deepseek-v3', temperature: 0.1 });
const llmResult = await llm.chat(prompt);
// 3. Zod 校验结构(json-repair 容错)
const parsed = IntentSchema.parse(jsonRepair(llmResult));
// 4. 低置信度 → 生成追问
if (parsed.confidence < 0.7) {
return { needsClarification: true, questions: this.generateQuestions(parsed) };
}
// 5. 融合数据诊断结果
const diagnosis = await this.diagnoseData(dataProfile, parsed);
// 6. 上下文裁剪(Context Pruning)— 只保留 Y/X 变量的 DataProfile 子集
// Planner 不需要看 100 列的完整统计特征,只需相关变量的 Hot Context
const prunedProfile = this.pruneForPlanner(dataProfile, parsed);
return { ...parsed, dataDiagnosis: diagnosis, prunedProfile, needsClarification: false };
}
// 上下文裁剪:从全量 DataProfile 中提取 Planner 需要的最小子集
private pruneForPlanner(fullProfile: DataProfile, parsed: ParsedQuery): PrunedProfile {
const relevantVars = [parsed.outcome_var, ...parsed.predictor_vars];
return {
schema: fullProfile.variables.map(v => ({ name: v.name, type: v.type })), // 全部列的类型(轻量)
details: fullProfile.variables.filter(v => relevantVars.includes(v.name)), // 只有 Y/X 的详细统计
sampleSize: fullProfile.sampleSize,
missingRateSummary: fullProfile.overallMissingRate,
};
}
// Fallback:LLM 调用失败时降级到现有正则匹配(WorkflowPlannerService.parseUserIntent)
private async fallbackToRegex(userText: string, variables: Variable[]): Promise<ParsedQuery> { ... }
}
3.2 前端任务
| # | 任务 | 工时 | 说明 |
|---|---|---|---|
| 6 | 追问卡片组件 ClarificationCard.tsx |
3h | 必须是封闭式数据驱动选择题,禁止开放式提问。后端基于 DataProfile 变量列表预生成 2-3 个具有统计学意义的分析假设,前端渲染为可点击的快捷 Tag(如:"检测到 [Drug] 和 [BP],您是想:👉[比较差异] 👉[相关分析]")。错误示范:"请问您想分析哪两列?" |
| 7 | SSAChatPane 集成追问流程 |
2h | 收到 needsClarification 时展示卡片;用户点击选项后自动填充 ParsedQuery 缺失字段,重新提交 |
| 8 | 数据诊断增强展示 | 2h | DataProfileCard 增加异常值/平衡性信息 |
3.3 Prompt 设计要点
存储方式: 以下 Prompt 通过 seed 脚本写入
capability_schema.prompt_templates表,template_key = 'ssa_intent_parse'。运行时通过PromptService.getPrompt()加载,禁止硬编码在 TypeScript 中。
你是一位临床研究统计顾问。请从用户的描述中提取以下信息:
1. goal: 分析目的
- "difference": 比较差异("有没有效"、"是否不同"、"比较")
- "association": 关联分析("相关"、"影响因素"、"关系")
- "prediction": 预测建模("预测"、"风险"、"预后")
- "description": 描述统计("描述"、"特征"、"分布")
- "cohort_study": 队列研究全套分析("出一套完整报告"、"基线+单因素+多因素"、"Table 1-3"、"队列研究")
2. outcome_var: 结局变量(Y),从变量列表中识别
3. predictor_vars: 自变量/分组变量(X),从变量列表中识别
4. design: 实验设计
- "independent": 独立样本(不同的人比较)
- "paired": 配对设计(同一患者前后比较)
5. confidence: 0.0-1.0,你对以上解析的确信程度
**重要规则:**
- 请自动忽略明显的非分析变量(如 patient_id、姓名、病历号、病床号、录入日期等标识/管理类字段),不要将它们选为 outcome_var 或 predictor_vars。
- 如果变量列表中附有用户标注的中文含义(variable_description),优先参考含义而非列名进行角色判断。
可用变量列表:{{variables}}
用户查询:{{query}}
验收标准:
- "分析 sex 与 Yqol 的相关性" →
{ goal: "association", outcome: "Yqol", predictors: ["sex"], confidence: 0.9 } - "有没有效" →
{ goal: "difference", confidence: 0.3, needsClarification: true, questions: [...] }- 追问必须是选择题:
"检测到数据包含 [Drug](分类) 和 [BP](连续),您是想:A. 比较用药组 vs 对照组的 BP 差异 B. 分析 Drug 与 BP 的相关性" - 禁止开放式提问如
"请问您想比较哪个指标?"
- 追问必须是选择题:
prunedProfile只包含 Y/X 变量的详细统计(非 100 列全量),schema 字段包含全部列名+类型- 探路测试(Tracer Bullet): 后端需提供
test_query_pipeline.ts脚本,用 mock DataProfile 验证 Q 层输出结构正确,无需前端和 R 服务
Phase P : Planner 层重构 — 决策表 + 流程模板(4 天)
为什么第三做: 让系统从"单方法执行"跃迁到"完整分析流程"。用户会看到一个包含 4-6 个步骤的专业分析计划。
目标:ParsedQuery → 决策表匹配 → 流程模板填充 → 完整 SAP
3.4 决策表设计
核心思想:一张表解决"该用什么方法"的问题。
v7.0 增强: ① 新增
Switch Condition列 — 描述 Primary/Fallback 互换的触发条件,让方法切换从硬编码变为配置化;② 参数检验优先原则 — Primary 始终设为参数检验(统计效力更高),非参数方法作为 Fallback(安全网),最终裁决权交给 R 引擎的数据分布检验。
| Goal | Y_Type | X_Type | Design | Primary Tool | Fallback Tool | Switch Condition |
|---|---|---|---|---|---|---|
| difference | continuous | categorical_2 | independent | ST_T_TEST_IND | ST_MANN_WHITNEY | normality_fail: Shapiro-Wilk P<0.05 |
| difference | continuous | categorical_2 | paired | ST_T_TEST_PAIRED | — | — |
| difference | continuous | categorical_multi | independent | ST_ANOVA_ONE | ST_KRUSKAL | normality_fail: Shapiro-Wilk P<0.05 |
| difference | categorical | categorical | independent | ST_CHI_SQUARE | ST_FISHER | expected_freq_low: 期望频数<5 |
| association | continuous | continuous | — | ST_CORRELATION | — | — |
| association | categorical | any | — | ST_CHI_SQUARE | ST_FISHER | expected_freq_low: 期望频数<5 |
| prediction | categorical_binary | any | — | ST_LOGISTIC | — | — |
| prediction | continuous | any | — | ST_LINEAR_REG | — | — |
| description | any | any | — | ST_DESCRIPTIVE | — | — |
| cohort_study | categorical_binary | categorical | independent | ST_BASELINE_TABLE | — | — |
cohort_study场景说明: 当 Q 层识别到用户意图为"队列研究全套分析"(触发词:"出一套完整报告"、"基线比较+单因素+多因素"、"Table 1-3"等)时,不走单工具匹配,而是直接选用cohort_study_standard流程模板。Q 层ParsedQuery.goal需扩展支持'cohort_study'值。
3.4.1 决策表存储策略 — Repository 模式
v7.0 新增架构决策: 决策表初期使用 JSON 文件(内容稳定、不需 A/B 测试),但通过 Repository 接口解耦,后期可无缝切换到数据库。
// Repository 接口 — 核心业务逻辑只依赖此接口
interface IDecisionTableRepo {
getRules(): Promise<DecisionRule[]>;
}
// Phase P 实现:JSON 文件
class JsonDecisionTableRepo implements IDecisionTableRepo {
async getRules() { return decisionTableJson as DecisionRule[]; }
}
// 预留 Phase Deploy 实现:数据库(SsaDecisionTable 模型已建好)
class PgDecisionTableRepo implements IDecisionTableRepo {
async getRules() { return await prisma.ssaDecisionTable.findMany(); }
}
3.4.2 Expected vs Actual 双层审计日志
v7.0 新增架构决策: P 层规划时不做正态性预检(正态性检验只在 R 引擎中执行),而是生成"策略日志 (Planned Trace)"。E 层执行后生成"事实日志 (Actual Trace)"。R 层合并两者生成方法学说明。
P 层(策略)──→ PlannedTrace: { primary: "T-Test", fallback: "Wilcoxon", switchCondition: "Shapiro P<0.05" }
↓
前端 SAP 卡片: "将执行 T 检验。🛡️护栏:若正态性不满足,将自动降级为 Wilcoxon。"
↓
E 层(事实)──→ R trace_log: { check: "normality", result: "fail", action: "switched to Wilcoxon" }
↓
R 层(合并)──→ 结合 PlannedTrace + trace_log 生成论文级方法学说明
PlannedTrace 类型定义:
interface PlannedTrace {
matchedRule: string; // "Goal=difference, Y=continuous, X=categorical_2, Design=independent"
primaryTool: string; // "ST_T_TEST_IND"
fallbackTool: string | null; // "ST_MANN_WHITNEY"
switchCondition: string | null; // "normality_fail: Shapiro-Wilk P<0.05"
templateUsed: string; // "standard_analysis"
reasoning: string; // 人类可读的方法选择理由
}
原则: P 层只描述"如果…则…"的策略,绝不在 Node.js 中做正态性预检。R 引擎已有完整的分布检验 + 自动降级逻辑,它的
trace_log天然就是 Actual Trace。
3.5 流程模板设计
核心思想:每种分析目的对应一个标准流程。
v7.0 优化: 将
two_group_comparison和association_analysis合并为standard_analysis(结构相同,区别仅在决策表填充的工具不同)。最终为 4 个通用模板 + 1 个队列研究专用模板。
const FLOW_TEMPLATES = {
// 通用三步模板 — 适用于 comparison / correlation / association
"standard_analysis": {
name: "标准分析流程",
steps: [
{ order: 1, role: "descriptive", tool: "ST_DESCRIPTIVE" },
{ order: 2, role: "primary_test", tool: "{{matched_tool}}" },
{ order: 3, role: "sensitivity", tool: "{{fallback_tool}}", condition: "fallback_exists" },
]
},
// 配对设计专用
"paired_analysis": {
name: "配对设计分析",
steps: [
{ order: 1, role: "descriptive", tool: "ST_DESCRIPTIVE" },
{ order: 2, role: "primary_test", tool: "{{matched_tool}}" },
]
},
// 回归建模
"regression_analysis": {
name: "回归建模",
steps: [
{ order: 1, role: "descriptive", tool: "ST_DESCRIPTIVE" },
{ order: 2, role: "primary_test", tool: "{{matched_tool}}" },
]
},
// 纯描述统计
"descriptive_only": {
name: "描述性统计",
steps: [
{ order: 1, role: "descriptive", tool: "ST_DESCRIPTIVE" },
]
},
// v6.0 新增:队列研究全套分析(覆盖经典 Table 1 → Table 2 → Table 3)
"cohort_study_standard": {
name: "经典队列研究全套分析",
steps: [
{ order: 1, role: "baseline_table", tool: "ST_BASELINE_TABLE",
name: "表1: 组间基线特征比较",
params_mapping: { group_var: "{{exposure_var}}", analyze_vars: "{{all_covariates}}" }
},
{ order: 2, role: "univariate_screen", tool: "ST_BASELINE_TABLE",
name: "表2: 结局指标单因素分析",
params_mapping: { group_var: "{{outcome_var}}", analyze_vars: "{{all_covariates}}" }
},
{ order: 3, role: "multivariate_reg", tool: "ST_LOGISTIC_BINARY",
name: "表3: 多因素 Logistic 回归",
params_mapping: { outcome_var: "{{outcome_var}}", predictors: "{{epv_capped_predictors}}" }
},
]
}
};
3.5.1 队列研究 Table 3 — "全量推入 + EPV 防护 + 免责声明"策略
v7.0 新增架构决策: Phase Q+ 的变量选择面板尚未上线前,Table 3 的自变量列表采用全量推入策略,辅以 EPV 上限防护。
EPV(Events Per Variable)防护逻辑:
可纳入变量数 = floor( min(outcome=0的数量, outcome=1的数量) / 10 )
- 如果 Q 层给出 20 个 predictor,但 EPV 只允许 5 个 → P 层自动截断到前 5 个
- 截断优先级:按 DataProfile 中与 outcome 的关联强度排序(分类变量用卡方统计量,连续变量用 T/Mann-Whitney 统计量)
- 前端 SAP 卡片标注红色 Tag:
[AI 自动探索模式] - 免责文案:"当前多因素回归模型纳入了 AI 自动选择的变量(受样本量限制已自动筛选),在后续版本中您将可以手动调整变量。"
Phase Q+ 上线后:
{{epv_capped_predictors}}替换为{{user_confirmed_predictors}},EPV 防护仍保留作为兜底。
3.6 后端任务
v7.1 调整: 新增任务 0(配置化基础设施)和任务 1(工具注册表),原有任务顺延。所有领域知识从代码常量迁移到 JSON 文件,通过 Repository + Zod 校验加载。
| # | 任务 | 工时 | 说明 |
|---|---|---|---|
| 0 | 配置化基础设施:ConfigLoader + Zod Schema + 热更新 API | 2h | ① 通用 ConfigLoader 基类(读 JSON + Zod 校验 + 内存缓存);② POST /api/v1/system/reload-config(管理员权限,校验失败保留旧配置,返回 400 + 错误详情);③ 四个领域 JSON 文件的 Zod Schema 定义 |
| 1 | 创建工具注册表 tools_registry.json |
2h | 将 AVAILABLE_TOOLS 硬编码常量迁移为 JSON 文件。每个工具定义包含:code, name, category, description, inputParams(含 Zod 类型), outputType, prerequisite, fallback。通过 ToolRegistryService + Repository 加载 |
| 2 | 创建决策表配置 decision_tables.json |
2h | 四维匹配规则的 JSON 版本,含 switchCondition 字段 |
| 3 | 新建 DecisionTableService.ts |
4h | 通过 IDecisionTableRepo 接口加载(Phase P: JSON 实现),四维匹配逻辑 |
| 4 | 创建流程模板配置 flow_templates.json |
2h | 4+1 个标准模板 |
| 5 | 新建 FlowTemplateService.ts |
4h | 模板选择 + 参数填充(含 EPV 截断逻辑) |
| 6 | 重构 PlannerService.ts |
4h | 接收 ParsedQuery → 调用决策表 → 选模板 → 生成 SAP + PlannedTrace |
| 7 | 前端 SAP 确认卡片增强 | 3h | 显示每步方法、选择理由、护栏说明、[AI 自动探索模式] 标签 |
| 8 | 联调测试 | 3h | Q → P → E 全链路 + Tracer Bullet 脚本 |
配置化校验流程:
方法学团队修改 JSON → 调用 POST /reload-config → Zod 校验 ├── 通过 → 刷新内存缓存 → 返回 200 ✅ 新规则生效 └── 失败 → 保留旧配置 → 返回 400 + 详细错误信息 ❌ 服务不受影响
PlannerService 核心逻辑(v7.0 更新):
// 伪代码 — 体现 Repository 模式 + Expected/Actual 双层日志
class PlannerService {
constructor(
private decisionTableRepo: IDecisionTableRepo, // Repository 模式:JSON 或 DB
private flowTemplateService: FlowTemplateService
) {}
async plan(query: ParsedQuery, profile?: DataProfile): Promise<AnalysisPlan> {
// 1. 决策表匹配 → 主方法 + 备选方法(通过 Repository 加载规则)
const rules = await this.decisionTableRepo.getRules();
const match = this.matchRule(rules, query.goal, query.outcome_type, query.predictor_types, query.design);
// 2. 选择流程模板
const template = this.flowTemplateService.select(query.goal, query.design, match);
// 3. 填充参数(含 EPV 防护)
const steps = this.flowTemplateService.fill(template, {
matched_tool: match.primaryTool,
fallback_tool: match.fallbackTool,
outcome_var: query.outcome_var,
predictor_vars: query.predictor_vars,
grouping_var: query.grouping_var,
profile,
});
// 4. 生成 PlannedTrace(策略日志 — P 层只描述"如果…则…")
const plannedTrace: PlannedTrace = {
matchedRule: `Goal=${query.goal}, Y=${query.outcome_type}, X=${query.predictor_types[0]}, Design=${query.design}`,
primaryTool: match.primaryTool,
fallbackTool: match.fallbackTool,
switchCondition: match.switchCondition, // "normality_fail: Shapiro-Wilk P<0.05"
templateUsed: template.id,
reasoning: this.explainMethodChoice(match, query),
};
// 注意:Actual Trace 由 E 层的 R trace_log 提供,P 层不做正态性预检
// 5. 生成 SAP
return { steps, plannedTrace, methodology: plannedTrace.reasoning };
}
}
验收标准(v7.0 更新):
- 输入
{ goal: "comparison", outcome_type: "continuous", predictor_types: ["binary"], design: "independent" } - 输出 3 步流程:描述统计 → T 检验(Primary) → Mann-Whitney(Sensitivity,条件展示)
plannedTrace包含switchCondition: "normality_fail"+reasoning人类可读理由- 前端 SAP 卡片每步显示选择理由;有 fallback 的步骤显示护栏说明("若正态性不满足,将自动降级为…")
- P 层不做正态性预检,方法切换由 R 引擎在执行时根据数据分布自行决定
- 队列研究场景:输入
{ goal: "cohort_study" }→ 输出 Table 1/2/3 三步流程,Table 3 自变量经 EPV 截断 +[AI 自动探索模式]标签 - 探路测试(Tracer Bullet): 后端需提供
test_planner_pipeline.ts脚本,用 mock ParsedQuery 验证 P 层输出结构正确(不依赖前端和 R 服务)。Q→P 串联测试也必须通过
Phase R : Reflection 层建设 — LLM 论文级结论(3 天)
为什么第四做: 这是让输出从"P=0.015"变成"可以直接用于论文"的关键。
目标:StepResult[] → LLM 综合解读 → 论文级结论 + 方法学说明
3.7 后端任务
| # | 任务 | 工时 | 说明 |
|---|---|---|---|
| 1 | 通过 PromptService 注册 Reflection Prompt |
3h | seed 脚本写入 capability_schema.prompt_templates,template_key = 'ssa_reflection';输出:6 要素结论。统计量通过槽位注入,禁止 LLM 生成数值。含敏感性分析冲突处理准则(3.10 节) |
| 2 | 重构 ConclusionGeneratorService → ReflectionService |
6h | 通过 LLMFactory 调用 LLM + Zod 强校验 LLM 输出结构(3.11 节) + 结果整合。接收 decision_trace 生成方法学说明。LLM 输出完整收集后校验,不做字符级流式推送(3.12 节) |
| 3 | E 层运行时崩溃优雅处理(重试机制推迟至 Phase Deploy) | 1h | 错误分类映射表(NA 值/列名缺失/R Fatal Error → 友好用户提示),不做跨层 Self-healing。完整重试机制(MAX_RETRIES=2 + 参数级修复 + 方法级降级)推迟至 Phase Deploy(见 3.8 节详述) |
| 4 | 结论缓存(CacheService)+ API |
2h | GET /sessions/:id/conclusion,使用平台 CacheService 缓存结论避免重复 LLM 调用 |
| 5 | 前端论文结论展示 | 4h | Markdown 渲染 + 一键复制 + 折叠/展开;采用"完整 JSON + 逐 section 渐入动画"方案(3.12 节),不做字符级流式推送 |
| 6 | Word 报告增强 | 3h | 纳入 LLM 结论(替代当前的简单 summary) |
| 7 | 联调测试 | 3h | Q → P → E → R 完整链路 |
重要:
ReflectionService是对现有ConclusionGeneratorService的升级重构,不是从零新建。保留ConclusionGeneratorService作为 fallback 入口,LLM 调用失败或 Zod 校验失败时降级到规则拼接。
3.8 E 层运行时错误处理策略
来源: 《QPER架构审查与工程避坑指南》暗礁 2 + 架构委员会裁决。
关键区分: "统计降级"(如正态性不满足自动切非参数)由 R 脚本内部 if-else 处理,不是运行时错误。"运行时崩溃"(如 NA 值导致 R Fatal Error、列名隐形空格、数据结构异常)才需要 Node.js 层处理。
Phase R 当前实施(优雅错误分类):
现有 WorkflowExecutorService 已具备步骤级 try-catch + step_error SSE 推送能力。Phase R 在此基础上增加错误分类映射表,将 R 引擎的原始错误转化为用户友好提示:
| 错误模式(R 报错关键词) | 用户友好提示 | 错误码 |
|---|---|---|
NA、missing values、incomplete cases |
"数据中存在缺失值,请检查数据清洗后重试" | E_MISSING_DATA |
column not found、undefined columns、not found |
"运算引擎未找到指定变量列,请检查数据源列名是否正确" | E_COLUMN_NOT_FOUND |
system is computationally singular、collinear |
"数据存在严重共线性,建议排除冗余变量后重试" | E_COLLINEARITY |
not enough observations、sample size |
"样本量不足以执行该统计方法,建议增加样本或选用非参数方法" | E_INSUFFICIENT_SAMPLE |
contrasts can be applied only to factors with 2 or more levels |
"分组变量的水平数不足,请检查数据分组" | E_FACTOR_LEVELS |
| 其他未匹配的 R 错误 | "运算引擎遇到异常,请检查数据结构后重试" | E_UNKNOWN |
Phase Deploy 推迟实施(完整重试短路机制):
以下机制推迟到 Phase Deploy 阶段实施,Phase R 不做跨层 Self-healing。
强制规则: MAX_RETRIES = 2,超过后直接中断。
| 错误类型 | 典型报错关键词 | 处理策略 |
|---|---|---|
| 不可重试(Hard Abort) | system is computationally singular、not enough observations、contrasts can be applied only to factors with 2 or more levels |
直接中断,跳过重试,生成诊断报告给用户 |
| 可重试 — 参数级修复 | column not found、invalid factor level、missing values |
LLM 分析错误日志 → 修改参数 JSON → 重新请求同一 R 脚本(禁止生成新 R 代码) |
| 可重试 — 方法级降级 | sample size too small for parametric test |
回调 Planner 切换 Fallback Tool(如 T 检验 → Mann-Whitney) |
3.9 统计量"槽位注入"反幻觉机制
来源: 《医疗AI统计助手架构研究》议题 3 — LLM 被剥夺生成数值 Token 的权限。
核心规则: 结论中的所有统计量(P 值、效应量、置信区间等)必须来自 R 引擎的实际输出,通过模板槽位渲染,禁止 LLM 在自由文本中"编写"任何数值。
// Reflection Prompt 中的槽位引用示例
各步骤结果(以下数值为系统自动注入,你不得修改或重新表述这些数字):
步骤 1:独立样本 T 检验
- 统计量:t = {{steps[1].statistic}}
- P 值:{{steps[1].p_value}}
- 效应量 Cohen's d:{{steps[1].effect_size}}
- 95% 置信区间:{{steps[1].ci_lower}} ~ {{steps[1].ci_upper}}
请基于上述精确数值生成论文结论,结论中引用数值时必须与上方完全一致。
实现方式: ReflectionService.extractKeyFindings() 将 R 返回的 JSON 中的数值提取为 {{slot}} 变量,在 Prompt 渲染时注入。LLM 只负责生成叙述性文字框架。
ReflectionService 核心逻辑:
// 伪代码 — 使用平台通用能力层(v8.0 更新:Zod 校验 + 完整 JSON 推送)
import { z } from 'zod';
import { jsonrepair } from 'jsonrepair';
// Zod Schema — 强校验 LLM 输出结构(见 3.11 节)
const ConclusionReportSchema = z.object({
executive_summary: z.string().min(10),
key_findings: z.array(z.string()).min(1),
statistical_summary: z.object({
total_tests: z.number(),
significant_results: z.number(),
methods_used: z.array(z.string()),
}),
methodology: z.string().min(10),
limitations: z.array(z.string()).min(1),
recommendations: z.array(z.string()).optional(),
});
class ReflectionService {
constructor(
private promptService: PromptService, // 平台通用能力:Prompt 管理
private llmFactory: LLMFactory, // 平台通用能力:LLM 网关
private cacheService: CacheService, // 平台通用能力:缓存
private conclusionGenerator: ConclusionGeneratorService, // Fallback:旧规则拼接
) {}
async reflect(plan: AnalysisPlan, results: StepResult[], sseEmitter?: SSEEmitter): Promise<ConclusionReport> {
// 0. 缓存命中检查
const cacheKey = `ssa:conclusion:${plan.workflow_id}`;
const cached = await this.cacheService.get(cacheKey);
if (cached) return cached;
// 1. 发送 QPER 状态:正在生成结论
sseEmitter?.emit({ type: 'qper_status', status: 'reflecting', message: '正在生成论文级结论...' });
// 2. 整合所有步骤的关键指标(提取为槽位变量,用于反幻觉注入)
const keyFindings = this.extractKeyFindings(results);
// 3. 从数据库加载 Prompt 模板
const promptTemplate = await this.promptService.getPrompt('ssa_reflection', 'latest');
const prompt = this.promptService.render(promptTemplate, {
goal: plan.goal,
methodology: plan.methodology,
decision_trace: plan.decision_trace,
findings: keyFindings,
sampleSize: plan.sampleInfo
});
// 4. 调用 LLM(完整收集,不做字符级流式推送)
const llm = this.llmFactory.create({ model: 'deepseek-v3', temperature: 0.3 });
try {
const rawOutput = await llm.chat(prompt);
// 5. jsonrepair + Zod 强校验(见 3.11 节)
const repaired = jsonrepair(rawOutput);
const parsed = JSON.parse(repaired);
const conclusion = ConclusionReportSchema.parse(parsed);
// 6. 缓存 + 通过 SSE 推送完整结构化结论(见 3.12 节)
const report: ConclusionReport = {
workflow_id: plan.workflow_id,
...conclusion,
step_summaries: this.buildStepSummaries(results),
generated_at: new Date().toISOString(),
};
await this.cacheService.set(cacheKey, report, { ttl: 3600 });
sseEmitter?.emit({ type: 'reflection_complete', conclusion: report });
return report;
} catch (error) {
// LLM 失败或 Zod 校验失败 → 降级到规则拼接
logger.warn('[SSA:Reflection] LLM/Zod failed, falling back to rule-based', { error });
const fallback = this.conclusionGenerator.generateConclusion(results, plan.goal);
const report = this.adaptLegacyToNew(plan.workflow_id, fallback);
sseEmitter?.emit({ type: 'reflection_complete', conclusion: report });
return report;
}
}
}
Reflection Prompt 设计要点:
存储方式: 以下 Prompt 通过 seed 脚本写入
capability_schema.prompt_templates表,template_key = 'ssa_reflection'。运行时通过PromptService.getPrompt()加载。
你是一位高级生物统计师,请基于以下分析结果生成论文级结论。
分析目标:{{goal}}
采用方法:{{methodology}}
方法选择的决策轨迹(请据此撰写方法学说明,不得臆造选择理由):
{{decision_trace.matched_rule}}
{{#each decision_trace.diagnosis_adjustments}}
- 调整:{{this}}
{{/each}}
各步骤结果(⚠️ 以下数值由系统自动注入,你必须原样引用,不得修改、四舍五入或重新表述任何数字):
{{#each findings}}
步骤 {{step_number}}:{{tool_name}}
- 统计量:{{statistic}}
- P 值:{{p_value}}
- 效应量:{{effect_size}}
- 置信区间:{{ci_lower}} ~ {{ci_upper}}
{{/each}}
请生成包含以下要素的结论:
1. 样本描述(纳入/排除)
2. 主要结果(含统计量和 P 值 — 必须与上方数值完全一致)
3. 效应量解读(临床意义)
4. 敏感性分析结论(如有)
5. 方法学说明(基于上方决策轨迹撰写,解释为什么选择此方法)
6. 局限性声明
要求:使用论文"结果"章节的行文风格,可直接复制到论文中。
验收标准:
- 输入 T 检验结果
{ t=2.45, p=0.015, d=0.52 } - 输出包含 6 个要素的论文级结论
- Word 导出包含 LLM 结论(非简单数字罗列)
3.10 敏感性分析结论冲突 Prompt 策略
来源: 架构委员会建议 1 — 当主分析与敏感性分析显著性不一致时,LLM 容易陷入逻辑混乱或强行拼凑显著性。
业务痛点: 在"描述→主分析→敏感性分析"的标准流程中,如果 T 检验(主)P=0.04(显著)但 Wilcoxon 检验(辅)P=0.06(不显著),LLM 可能选择性忽略不一致的结果。在临床研究中,这属于必须报告的结果稳健性问题。
实施方式: 在 ssa_reflection Prompt 模板中硬编码冲突处理准则:
## 冲突处理准则(强制执行)
当主分析与敏感性分析的显著性结论不一致时:
1. 在【局限性声明】中必须指出:"敏感性分析未得到一致结论,结果的稳健性(Robustness)较弱,需谨慎解释临床意义"
2. 在【主要发现】中以主分析结果为基准报告,但需加注"敏感性分析未验证此结论"
3. 严禁选择性报告、强行拼凑显著性
4. 当所有分析方向一致时,在【主要发现】中强调"敏感性分析进一步验证了结论的稳健性"
效果: LLM 遇到矛盾数据时有明确的处理规程,既保证了学术诚信,又为临床研究者提供了稳健性判断依据。实现成本极低(仅在 Prompt 中增加 4 行准则)。
3.11 Zod Schema 强校验 LLM 输出
来源: 架构委员会建议 2 — LLM 偶尔漏掉 JSON Key 或将数组写成字符串,导致前端渲染崩溃。
与 Phase Q 的模式一致性: Phase Q 中已成功实践
jsonrepair+ Zod 动态校验(createDynamicIntentSchema)。Phase R 延续同一防御范式。
实施方式: ReflectionService 中对 LLM 输出进行三层防御:
Layer 1: jsonrepair — 修复 LLM 输出的 JSON 格式错误(漏逗号、多余尾逗号等)
Layer 2: JSON.parse — 解析为 JS 对象
Layer 3: Zod Schema — 强校验结构完整性(字段是否齐全、类型是否正确、数组最小长度等)
Zod Schema 定义(与前端 ConclusionReport 接口对齐):
const ConclusionReportSchema = z.object({
executive_summary: z.string().min(10), // 不允许空摘要
key_findings: z.array(z.string()).min(1), // 至少 1 条发现
statistical_summary: z.object({
total_tests: z.number(),
significant_results: z.number(),
methods_used: z.array(z.string()),
}),
methodology: z.string().min(10), // 不允许空方法学说明
limitations: z.array(z.string()).min(1), // 至少 1 条局限性
recommendations: z.array(z.string()).optional(), // 建议为可选
});
降级触发: Zod 校验失败时,立即切回旧的 ConclusionGeneratorService(规则拼接),确保前端始终收到有效的结论结构。日志记录 Zod 错误详情,用于后续 Prompt 迭代优化。
3.12 Reflection 输出交付策略(完整 JSON + 逐 Section 渐入)
来源: 架构委员会建议 3 — 逐字推送 JSON 字符串会导致前端频繁抛出
SyntaxError。核心决策: Phase R 的 Reflection 输出不做字符级流式推送,采用"后端完整收集 + Zod 校验 + 一次性推送 + 前端逐 section 渐入动画"方案。
不采用字符级流式推送的理由:
- Zod 校验需要完整 JSON — 无法对不完整的 JSON 片段执行结构校验
- 结构化数据需求 — Word 导出、数据库存储、API 返回都需要完整的
ConclusionReportJSON - 等待时间可接受 — LLM 生成结论通常 3-8 秒,期间通过
qper_statusSSE 事件展示"正在生成论文级结论...",用户已看到所有数字结果(E 层report_blocks),不会焦虑 - 避免 Markdown↔JSON 双向转换的脆弱性 — 如果 LLM 输出纯 Markdown 再解析为 JSON,逆向解析极易出错
完整的交付流程:
后端流程:
1. 发送 SSE: { type: 'qper_status', status: 'reflecting', message: '正在生成论文级结论...' }
2. LLM 完整生成结构化 JSON(非流式)
3. jsonrepair → JSON.parse → Zod 校验
4. 校验通过 → SSE: { type: 'reflection_complete', conclusion: ConclusionReport }
5. 校验失败 → ConclusionGeneratorService fallback → SSE: { type: 'reflection_complete', ... }
前端渲染(逐 section 渐入动画):
1. 收到 qper_status(reflecting) → 显示加载动画 "📝 正在生成论文级结论..."
2. 收到 reflection_complete → 开始渐入动画:
- 0ms: executive_summary 淡入
- 300ms: key_findings 逐条滑入
- 600ms: methodology 淡入
- 900ms: limitations 淡入
- 1200ms: recommendations 淡入(如有)
3. 动画完成 → 显示"一键复制"和"导出 Word"按钮
SSE 事件类型调整(见 5.5 节): 原 reflection_stream(chunk-based)改为 reflection_complete(一次性完整推送)。
Phase Deploy : 工具补齐 + 部署上线(4 天)
为什么最后做: 智能化架构搭好后,补齐剩余工具和部署上线。
| # | 任务 | 工时 | 说明 |
|---|---|---|---|
| 1 | R 工具补齐:ANOVA | 3h | ST_ANOVA_ONE + Block-based 输出 |
| 2 | R 工具补齐:Fisher | 2h | ST_FISHER + Block-based 输出 |
| 3 | R 工具补齐:Wilcoxon | 2h | ST_WILCOXON + Block-based 输出 |
| 4 | R 工具补齐:线性回归 | 3h | ST_LINEAR_REG + Block-based 输出 |
| 5 | 复合工具 ST_BASELINE_TABLE(R 端) |
4h | 基于 gtsummary::tbl_summary(by=group_var) %>% add_p() 封装;输入:group_var + analyze_vars[];自动判断连续/分类、正态/非正态、选择 T 检验/Mann-Whitney/卡方/Fisher;R Docker 镜像需新增 gtsummary+gt+broom 依赖 |
| 6 | gtsummary → report_blocks 转换层 |
4h | gtsummary::as_tibble() 提取结构化表格 → 转换为 table block(需处理合并行:分类变量名+各水平值;列头:分组名称);输出需同时包含渲染用 blocks 和结构化 significant_vars[](P<0.05 的变量列表,供后续步骤消费) |
| 7 | 前端三线表渲染增强 | 4h | DynamicReport.tsx 的 table block 增强:支持 rowspan(分类变量合并行)、分组列头(group1 vs group2 vs P 值)、P<0.05 加粗/标星、横向滚动(20+ 变量场景) |
| 8 | 决策表补齐所有工具映射 | 2h | 11 工具全部纳入(含 ST_BASELINE_TABLE) |
| 9 | 流程模板补齐 | 2h | 覆盖所有 Goal 类型 + cohort_study_standard 模板(见下方) |
| 10 | R Docker 镜像推送 ACR | 1h | 新工具 + gtsummary 依赖包含在内 |
| 11 | SAE 部署 + 联调 | 4h | R 服务 + 后端 + 前端 |
| 12 | 端到端测试(12 场景) | 8h | 原 10 场景 + 队列研究全套流程(表1→表2→表3)×2 数据集 |
Phase Q+ : 人机协同增强 — 变量字典 + 变量选择面板(2.5 天)
为什么独立分期: Phase Q 核心目标是证明 LLM 能从自然语言中提取 [Goal, Y, X, Design]。将重度前端交互(表格编辑、穿梭框、状态回传)与核心 AI 逻辑耦合,会导致单点阻塞。Phase Q+ 在 Q-P-E-R 主线闭环跑通后再启动,此时:① 已有 AI 基线准确率数据,可量化人机协同的提升价值;② 后端接口已稳定,前端可安全叠加。
核心哲学:AI 负责统计专业知识,医生负责临床领域知识。
定位:Phase Q 的增强层,非阻塞主线交付
前置依赖:Phase Q 验收通过(LLM 意图解析基线可用)
触发时机:Q-P-E-R 主线闭环跑通后
3.10 增强点一:变量数据字典(Data Dictionary)
解决什么问题: 临床数据列名极不规范(grp、Tx、SBP),DataProfile 只有统计特征没有语义信息。LLM 靠猜列名含义,猜错即全链路错误。
交互模式:"AI 先猜,用户微调"
- 文件上传 + DataProfiler 完成后,后端静默调用 LLM(基于列名 + 前 5 行数据 + 数据类型)猜测每个变量的中文含义
- 前端推送变量字典编辑面板,用户确认或修改
- 经用户确认的字典成为黄金上下文(Golden Context),后续 Q/P/R 全链路可消费
| # | 任务 | 层级 | 工时 | 说明 |
|---|---|---|---|---|
| 1 | VariableDictService.ts — LLM 变量含义猜测 |
后端 | 3h | 通过 PromptService + LLMFactory 调用 LLM,输入列名+前5行+类型,输出 { name, guessed_meaning, guessed_role }[];Zod 校验 |
| 2 | Prisma schema 扩展 | 后端 | 1h | SsaFileUpload 新增 variable_dictionary: Json? 字段(或新建 SsaVariableDictionary 表),存储用户确认后的字典 |
| 3 | 变量字典 API | 后端 | 1h | GET /api/v1/ssa/sessions/:id/variable-dict(获取 AI 猜测结果)+ PUT(保存用户修改) |
| 4 | VariableDictEditor.tsx 前端组件 |
前端 | 3h | 表格形式:`变量名 |
| 5 | QueryService 集成字典 |
后端 | 1h | parseQuery 方法接受可选 variableDict 参数,有字典时将 variable_description 注入 Prompt 的 {{variables}} 中 |
验收标准:
- 上传含
grp(1,2)列的 CSV → AI 猜测"分组变量" → 用户标注"1=新药, 2=安慰剂" → 后续 Q 层正确识别grp为分组变量 - 用户跳过字典编辑(直接点"确认")→ 系统正常运行(AI 猜测结果作为默认值)
3.11 增强点二:变量选择确认面板(Variable Selection)
解决什么问题: LLM 从 100 列中猜 Y/X 变量,可能选错或遗漏关键协变量。医生最清楚哪些是核心指标、哪些必须作为调整变量纳入。
交互模式:AI 推荐 + 医生确认/调整
- Q 层 LLM 解析完意图后,在进入 P 层之前推送变量选择确认面板
- AI 预选的 Y/X 变量已标记,医生可增删、可添加协变量(Confounders)
- 医生确认后的变量集合替代 AI 原始选择,传入 P 层
| # | 任务 | 层级 | 工时 | 说明 |
|---|---|---|---|---|
| 6 | QueryService 输出扩展 |
后端 | 1h | ParsedQuery 增加 suggested_confounders: string[](AI 建议的协变量)+ all_candidate_vars 列表供前端渲染 |
| 7 | VariableSelectionPanel.tsx 前端组件 |
前端 | 4h | 穿梭框/卡片交互:左侧"可用变量"(全部),右侧"已选变量"分三区(Y/X/协变量);AI 预选项高亮标记;支持拖拽或点击增删 |
| 8 | 确认 API + Context Pruning 衔接 | 后端 | 1h | POST /api/v1/ssa/sessions/:id/confirm-variables;用户确认的变量集合覆盖 AI 原始选择,pruneForPlanner 以医生确认集合为基准裁剪 |
| 9 | SSE 事件 + 状态回传 | 后端 | 1h | DICT_EDITING / VARIABLE_CONFIRMING 状态推送 + 前端状态管理集成 |
| 10 | SSAChatPane 集成两个面板 |
前端 | 2h | 接收 SSE 事件渲染字典编辑器/变量选择面板,用户操作后回传并恢复流程 |
验收标准:
- AI 推荐 Y=BP, X=Drug → 医生增加协变量 Age, Sex → P 层收到完整的
[Y=BP, X=Drug, Confounders=[Age, Sex]] - 医生不修改直接确认 → 使用 AI 原始选择(零额外成本)
3.12 Phase Q+ 默认放行策略
重要: Phase Q+ 未上线前,系统自动跳过
DICT_EDITING和VARIABLE_CONFIRMING状态,直接使用 AI 自动解析结果。后端接口契约保持不变。
// Phase Q+ 开关(feature flag)
const PHASE_Q_PLUS_ENABLED = false; // Phase Q+ 上线后改为 true 或从配置读取
// 状态机跳过逻辑
if (currentStatus === 'profiling_done') {
nextStatus = PHASE_Q_PLUS_ENABLED ? 'dict_editing' : 'pending_intent';
}
if (currentStatus === 'intent_parsed') {
nextStatus = PHASE_Q_PLUS_ENABLED ? 'variable_confirming' : 'planning';
}
Phase Q+ 工时汇总:
| 类型 | 任务 | 工时 |
|---|---|---|
| 后端 | VariableDictService + Schema + API + QueryService集成 + 确认API + SSE | 8h |
| 前端 | VariableDictEditor + VariableSelectionPanel + SSAChatPane集成 | 9h |
| 测试 | 两个面板的端到端验证 | 3h |
| 合计 | 20h(2.5天) |
4. 代码目录结构(渐进式,不做大规模重组)
策略: 所有新文件放入现有的
services/和config/目录,而非创建query/planner/reflection/子目录。原因:现有 SSA 模块已有大量文件互相引用,子目录化会导致全量 import 路径变更、风险过高、产出为零。用 文件命名前缀 区分 QPER 层级即可。
backend/src/modules/ssa/
├── services/ ← 所有服务统一放此目录
│ ├── QueryService.ts # Q 层:LLM 意图解析 + 追问逻辑(新建)
│ ├── VariableDictService.ts # Q+ 层:LLM 变量含义猜测 + 字典管理(Phase Q+ 新建)
│ ├── DataDiagnosticService.ts # Q 层:数据深度诊断(新建,扩展 DataProfileService)
│ ├── PlannerService.ts # P 层:核心规划逻辑(新建,接收 ParsedQuery)
│ ├── DecisionTableService.ts # P 层:决策表加载 + 四维匹配(新建)
│ ├── FlowTemplateService.ts # P 层:流程模板管理(新建)
│ ├── ReflectionService.ts # R 层:LLM 结论生成(重构自 ConclusionGeneratorService)
│ ├── WorkflowExecutorService.ts # E 层:步骤编排 + SSE(✅ 保持不变)
│ ├── RClientService.ts # E 层:R 引擎调用(✅ 保持不变)
│ ├── WorkflowPlannerService.ts # 兼容层:旧入口,内部委托 QueryService + PlannerService
│ ├── ConclusionGeneratorService.ts # 兼容层:旧入口,内部委托 ReflectionService
│ ├── DataProfileService.ts # 共享:Python 数据质量(✅ 保留)
│ └── DataParserService.ts # 共享:文件解析(✅ 保留)
│
├── config/ ← 决策表 + 流程模板配置
│ ├── decision_table.json # P 层配置
│ └── flow_templates.json # P 层配置
│
├── types/ ← 新增 QPER 接口定义
│ ├── query.types.ts # ParsedQuery 接口
│ ├── planner.types.ts # AnalysisPlan / AnalysisStep 接口
│ └── reflection.types.ts # Conclusion 接口
│
├── routes/ # API 路由(扩展,不重建)
│ ├── analysis.routes.ts # ✅ 保留
│ ├── workflow.routes.ts # ✅ 保留
│ └── config.routes.ts # ✅ 保留(已有决策表/代码库 CRUD)
└── ...
Prompt 不放在本地文件中,而是通过平台
PromptService存入capability_schema.prompt_templates数据库表,支持版本管理和 A/B 测试。开发阶段使用 seed 脚本初始化。
5. 数据流协议
5.1 Q → P 接口契约
interface ParsedQuery {
// 用户意图
goal: 'difference' | 'association' | 'prediction' | 'description';
confidence: number; // 0.0 - 1.0
// 变量角色
outcome_var: string; // 结局变量 (Y)
outcome_type: 'continuous' | 'categorical' | 'binary';
predictor_vars: string[]; // 自变量 (X)
predictor_types: string[]; // 各自变量类型
// 实验设计
design: 'independent' | 'paired';
// 数据诊断(Q 层产出)
dataDiagnosis: {
sampleSize: number;
missingRate: Record<string, number>;
outlierCount: Record<string, number>;
normalityTests?: Record<string, { pValue: number; isNormal: boolean }>;
groupBalance?: { groups: string[]; counts: number[] };
};
// 追问状态
needsClarification: boolean;
clarificationQuestions?: string[];
}
5.2 P → E 接口契约
兼容策略: 新
AnalysisPlan接口必须兼容现有WorkflowPlan(WorkflowExecutorService已在使用),避免 Execute 层改动。AnalysisStep扩展自现有WorkflowStep,新增字段为可选。
// 现有接口(WorkflowExecutorService 已使用,不可破坏)
interface WorkflowStep {
step_number: number;
tool_code: string;
tool_name: string;
description: string;
params: Record<string, unknown>;
}
// 新增接口(扩展,向后兼容)
interface AnalysisStep extends WorkflowStep {
role?: 'descriptive' | 'primary_test' | 'sensitivity' | 'effect_size'; // 可选,新增
}
interface AnalysisPlan {
workflow_id: string;
title: string;
methodology: string; // "因 Y 为连续变量且两组独立,采用独立样本 T 检验"
rationale: string; // "数据满足正态分布假设(Shapiro P=0.15)"
steps: AnalysisStep[]; // 兼容 WorkflowStep[]
// 元信息(新增,P 层产出)
primary_tool: string;
fallback_tool?: string;
flow_template_used: string;
// 决策审计日志(P 层产出 → R 层消费,用于生成方法学说明)
decision_trace: {
matched_rule: string; // "Y=continuous, X=categorical_2, Design=independent → ST_T_TEST_IND"
diagnosis_adjustments: string[]; // ["Shapiro-Wilk P=0.03 < 0.05 → 切换非参数 Mann-Whitney"]
triggered_at: string; // ISO timestamp
};
}
// 兼容转换函数(PlannerService 内部使用)
function toWorkflowPlan(plan: AnalysisPlan): WorkflowPlan {
return {
workflow_id: plan.workflow_id,
steps: plan.steps, // AnalysisStep extends WorkflowStep,直接兼容
// ...
};
}
5.3 E → R 接口契约
interface ExecutionResult {
steps: StepResult[]; // 各步骤结果(已有)
report_blocks: ReportBlock[]; // Block-based 输出(Phase E+ 新增)
total_duration_ms: number;
}
5.4 会话状态机(防面条代码)
来源: 《QPER V3.0 架构审查与工程护航报告》隐患 2 — QPER 流程存在 Clarifier(等用户回复)和 Reflection(错误重试)两处中断/恢复逻辑,用嵌套 if-else + while 会迅速劣化为面条代码。
enum ExecutionStatus {
PENDING_UPLOAD = 'pending_upload', // 等待数据上传
PROFILING = 'profiling', // 数据诊断中(Python Tool C)
DICT_EDITING = 'dict_editing', // 🆕 Phase Q+:变量字典编辑中 — ⏸️ 中断,等待用户确认
PENDING_INTENT = 'pending_intent', // 等待意图解析
CLARIFYING = 'clarifying', // 追问中 — ⏸️ 中断,等待用户回复
VARIABLE_CONFIRMING = 'variable_confirming', // 🆕 Phase Q+:变量选择确认中 — ⏸️ 中断,等待用户确认
PLANNING = 'planning', // 规划中
PLAN_CONFIRMING = 'plan_confirming', // 等待用户确认 SAP — ⏸️ 中断
EXECUTING = 'executing', // R 引擎执行中
REFLECTING = 'reflecting', // 结论生成中
RETRYING = 'retrying', // 错误修复后重试中(MAX_RETRIES=2)
COMPLETED = 'completed', // 完成
FAILED = 'failed', // 失败(不可恢复)
}
状态持久化: ExecutionStatus 存入 SsaSession 表。当状态为 DICT_EDITING、CLARIFYING、VARIABLE_CONFIRMING 或 PLAN_CONFIRMING 时,后端立即中断执行并向前端发送交互面板,等待下一次 HTTP 请求(用户操作/确认)后从该状态恢复继续。
状态流转图:
PENDING_UPLOAD → PROFILING → [DICT_EDITING]* → PENDING_INTENT → CLARIFYING (可选,循环)
↓
[VARIABLE_CONFIRMING]*
↓
PLANNING → PLAN_CONFIRMING (可选)
↓
EXECUTING → REFLECTING → COMPLETED
↑ ↓
└── RETRYING (MAX 2次)
↓ (超限)
FAILED
* [方括号] 表示 Phase Q+ 新增状态,Phase Q+ 未上线时自动跳过(feature flag 控制)
5.5 QPER 级 SSE 事件类型(全链路状态推送)
来源: 《QPER V3.0 架构审查与工程护航报告》隐患 3 — R 层重试过程可能耗时 15-20 秒,用户只看到转圈会认为系统死了。"展示 AI 工作过程"是信任建立的关键。
当前 SSE 只覆盖 E 层步骤进度。扩展为 QPER 全链路状态推送:
// SSE 事件类型扩展(v8.0 更新:reflection_stream → reflection_complete)
type SSAEvent =
| { type: 'qper_status'; status: ExecutionStatus; message: string } // 状态跃迁
| { type: 'step_progress'; step: number; total: number; ... } // E 层步骤进度(已有)
| { type: 'clarification'; questions: ClarificationOption[] } // 追问卡片
| { type: 'plan_ready'; plan: AnalysisPlan } // SAP 确认
| { type: 'reflection_complete'; conclusion: ConclusionReport } // R 层完整结论(一次性推送,非字符流)
| { type: 'error'; code: string; message: string } // 错误
// 前端渲染效果示例:
// [Query] 🧠 正在理解您的分析意图...
// [Query] ✅ 识别到:差异比较 | Y=血压 | X=用药组
// [Planner] 📋 正在规划分析方案...
// [Planner] ✅ 已生成 3 步分析计划(描述统计 → T检验 → Mann-Whitney)
// [Executor] 🔄 步骤 1/3:描述统计...
// [Executor] ✅ 步骤 1/3 完成 [0.8s]
// [Executor] ❌ 步骤 2/3 失败:变量存在完全共线性
// [Executor] ⚠️ 运算引擎遇到异常:数据存在严重共线性(E_COLLINEARITY)
// [Executor] 🔄 步骤 3/3:Mann-Whitney...
// [Executor] ✅ 步骤 3/3 完成 [0.6s]
// [Reflection] 📝 正在生成论文级结论...(qper_status: reflecting)
// [Reflection] ✅ 结论生成完成(reflection_complete → 前端逐 section 渐入动画)
6. 工时与里程碑
| Phase | 名称 | 工时 | 日历天 | 里程碑 | 变更说明 |
|---|---|---|---|---|---|
| E+ | Block-based 标准化 | 15.5h | 2.5天 | R 输出标准化,前端动态渲染 | 后端透传需含 report_blocks 全链路验证 |
| Q | Query 层(LLM 意图) | 33h | 5天 | 用户说"有没有效"即可分析 | v4.0 +1.5h:DataProfile 会话级缓存(0.5h) + Intent Prompt Few-Shot(1h);v3.0 +1h:Context Pruning |
| P | Planner 层(决策表+模板) | 23h | 4天 | 完整分析流程(非单方法) | v3.0 +1h:decision_trace 决策审计日志输出 |
| R | Reflection 层(LLM 结论) | 22h | 3天 | 论文级结论,可直接用于论文 | v3.0 +2h:统计量槽位注入反幻觉;v8.0 -1h:完整重试推迟至 Deploy,Phase R 仅做错误分类映射(1h);+0h:敏感性冲突 Prompt + Zod 校验 + 完整 JSON 交付(融入现有任务工时) |
| Deploy | 工具补齐 + 部署 | 37h | 5.5天 | 11 工具上线(含复合工具),生产环境可用 | v6.0 +12h:ST_BASELINE_TABLE(4h) + gtsummary→blocks 转换(4h) + 前端三线表增强(4h);端到端测试 +2h |
| 主线合计 | 130.5h | ~20天 | Q-P-E-R 主线闭环 | v6.0 Deploy +12h;v4.0 +1.5h;v3.0 +4h;v8.0 -1h | |
| --- | --- | --- | --- | --- | --- |
| Q+ | 人机协同增强 | 20h | 2.5天 | 变量字典 + 变量选择面板 | v5.0 新增:医生注入临床领域知识,AI→人机协同 |
| 总计 | 150.5h | ~22.5天 | Q-P-E-R + 人机协同 + 队列研究全套 | 主线闭环后启动 Phase Q+ |
里程碑时间线
Week 1 ──────────────────────────────────
Day 1-2: Phase E+ (Block-based)
Day 3-5: Phase Q (Query 层前半:Prompt 注册 + QueryService)
Week 2 ──────────────────────────────────
Day 6-7: Phase Q (Query 层后半:DataDiagnostic + 前端追问 + 联调)
Day 8-11: Phase P (Planner 层)
Week 3 ──────────────────────────────────
Day 12-14: Phase R (Reflection 层)
Day 15-19: Phase Deploy (原子工具补齐 + ST_BASELINE_TABLE 复合工具 + 部署)
Day 20: 队列研究端到端验证(Table 1→2→3 全流程)
Week 4 ──────────────────────────────────
✅ Q-P-E-R 主线闭环上线(里程碑 1:含队列研究全套分析能力)
Day 20: 收集 AI 基线准确率数据(无人机协同下的意图识别准确率)
Week 4-5 ────────────────────────────────
Day 19-21: Phase Q+ (变量字典 + 变量选择面板)
✅ 人机协同增强上线(里程碑 2)
对比量化:人机协同 vs 纯 AI 的准确率提升
7. 风险管理
| 风险 | 概率 | 影响 | 应对 |
|---|---|---|---|
| LLM 意图提取准确率不足 | 中 | 高 | 低置信度时追问,不猜测;保留正则兜底(WorkflowPlannerService.parseUserIntent 作为 fallback) |
| 决策表覆盖率不足 | 低 | 中 | 先覆盖 10 工具,后续 Excel 可热加载扩展;评估使用已有 SsaDecisionTable 数据库表 |
| LLM 结论"幻觉"虚构统计量 | 中 | 高 | 统计量槽位注入机制(3.9 节):所有数值通过 {{slot}} 从 R 输出渲染,LLM 被剥夺生成数值 Token 的权限;Prompt 中明确标注"不得修改、四舍五入或重新表述任何数字" |
| Reflection 延迟过高(LLM 调用) | 中 | 中 | 通过平台 StreamingService 流式输出,用户先看到数字结果,结论异步加载 |
| Q→P→E 串联复杂度 | 低 | 中 | 每层独立可测试,接口契约明确 |
| 新增:LLM 服务不可用 | 中 | 高 | Q 层降级到正则匹配,R 层降级到规则拼接(ConclusionGeneratorService),系统功能不中断 |
| 新增:Prisma 迁移遗漏 | 低 | 高 | 新增字段(如 report_blocks 存储)需通过 npx prisma migrate dev 正式迁移,禁止 db push --force-reset;每个 Phase 完成时检查 schema 变更 |
| 新增:AnalysisPlan 接口破坏 Execute 层 | 低 | 高 | AnalysisStep extends WorkflowStep,保持向后兼容;E 层不做任何接口改动 |
| 新增:旧组件过早删除 | 中 | 中 | DescriptiveResultView 等现有组件(2026-02-20 新建)在 Block-based 未完全验证前保留作为 fallback,不提前删除 |
| 新增:R 引擎运行时崩溃(Runtime Crash) | 中 | 中 | 区分"统计降级"(R 内部 if-else 处理)与"运行时崩溃"(NA 值/列名错误/Fatal Error);后者通过错误分类映射表转化为友好提示,Phase R 不做跨层 Self-healing,完整重试推迟至 Phase Deploy |
| 新增:敏感性分析结论冲突 | 中 | 高 | 主分析与敏感性分析显著性不一致时,Reflection Prompt 硬编码冲突处理准则:必须在局限性中报告,严禁强行拼凑显著性(3.10 节) |
| 新增:LLM Reflection 输出结构残缺 | 中 | 中 | jsonrepair + Zod Schema 三层防御(3.11 节);校验失败自动降级到 ConclusionGeneratorService 规则拼接 |
7.1 回退策略(Fallback Plan)
| 层级 | 正常路径 | 降级路径 | 触发条件 |
|---|---|---|---|
| Q 层 | QueryService(LLM 意图解析) |
WorkflowPlannerService.parseUserIntent()(正则匹配) |
LLM 超时/不可用/解析失败 |
| P 层 | PlannerService(决策表+模板) |
WorkflowPlannerService.generateSteps()(硬编码 if/else) |
决策表无匹配 |
| E 层 | WorkflowExecutorService(不变) |
错误分类映射 → 友好用户提示 | R 引擎运行时崩溃(NA/列名/Fatal Error) |
| R 层 | ReflectionService(LLM 论文结论) |
ConclusionGeneratorService(规则拼接) |
LLM 超时/不可用/Zod 校验失败 |
| 前端 | DynamicReport(Block-based 渲染) |
现有自定义渲染组件 | report_blocks 为空时 |
原则: 每个 QPER 层都有明确的降级路径,确保 LLM 不可用时系统仍然可用(退化为 Phase 2A 水平)。R 层新增 Zod 校验失败作为降级触发条件——LLM 输出结构不完整时,自动切回规则拼接,前端始终收到有效的
ConclusionReport结构。
8. 验收场景
8.1 核心验收(5 个场景)
| # | 用户输入 | 期望 Q 输出 | 期望 P 输出 | 期望 R 输出 |
|---|---|---|---|---|
| 1 | "比较两组血压" | goal=difference, design=independent | 描述统计 → T检验 → Mann-Whitney | "两组差异显著(P<0.001),中等效应(d=0.52)" |
| 2 | "分析 sex 与 Yqol 的关系" | goal=association, Y=Yqol(categorical), X=sex | 描述统计 → 卡方检验 | "性别与 Yqol 存在显著关联(χ²=8.3, P=0.004)" |
| 3 | "age、smoke 对 Yqol 的影响" | goal=prediction, Y=Yqol(binary) | 描述统计 → Logistic 回归 | "Logistic 回归显示 smoke 是显著预测因子(OR=2.1, P=0.03)" |
| 4 | "描述一下数据" | goal=description | 描述统计 | 各变量的集中趋势和离散程度汇总 |
| 5 | "有没有效" | confidence<0.7 → 追问 | 等待用户澄清后规划 | — |
8.2 智能化对比(改造前 vs 改造后)
| 场景 | 改造前 | 改造后 |
|---|---|---|
| 用户说"有没有效" | ❌ 无法理解 | ✅ 追问后正确规划 |
| 数据不正态 | 🟡 R 内部降级,用户不知 | ✅ 规划阶段就选非参数方法,告知理由 |
| 分析结果 | P=0.015 + 数字表格 | 论文级结论:"两组差异具有统计学意义..." |
| 分析流程 | 1 个方法 | 描述统计 → 主分析 → 敏感性分析 |
| Word 报告 | 表格 + 数字 | 完整论文段落 + 方法学说明 |
9. 与旧计划的关系
| 旧计划内容 | 处理方式 | 理由 |
|---|---|---|
| 配置中台(Excel 导入体系) | 延后 | 10 个工具用 JSON 配置足够,100+ 工具时再做 |
| 咨询模式(无数据 SAP) | 延后 | 独立功能,不影响核心智能分析 |
| 决策表概念 | 保留并简化 | 从 Excel 配置中台简化为内置 JSON |
| Brain-Hand 命名 | 升级为 Q-P-E-R | 更精确地描述四层职责 |
| 10 工具目标 | 扩展为 11 工具 | 原 10 个原子工具 + 1 个复合工具 ST_BASELINE_TABLE(v6.0) |
| SAE 部署 | 保留 | Phase Deploy 中完成 |
文档维护者: SSA 架构团队
创建日期: 2026-02-20
最后更新: 2026-02-21(v8.0 — Phase R 架构增强)
下一步行动: Phase E+/Q/P 已完成,按 R1→R7 顺序启动 Phase R 开发
变更日志
| 版本 | 日期 | 变更内容 |
|---|---|---|
| v1.0 | 2026-02-20 | 初版:QPER 架构设计 + 5 Phase 开发计划 |
| v2.0 | 2026-02-21 | 代码审查后修订:① 核心原则新增"复用平台通用能力层";② ReflectionService 修正为重构;③ 目录结构改为渐进式平铺;④ 伪代码使用 LLMFactory + PromptService;⑤ AnalysisStep extends WorkflowStep;⑥ 新增已有数据库资产盘点;⑦ 新增全链路回退策略表;⑧ 工时 108.5h→114h |
| v3.0 | 2026-02-21 | 外部调研审查后修订(综合4份报告):① 架构红线(禁止 LangGraph/AutoGen/LLM 生成 R 代码/多智能体辩论);② Context Pruning 上下文裁剪;③ 封闭式追问;④ decision_trace 决策审计日志;⑤ 重试短路机制;⑥ 统计量槽位注入反幻觉;⑦ Tracer Bullet 探路测试;⑧ 工时 114h→118h |
| v4.0 | 2026-02-21 | 工程护航修订(依据《QPER V3.0 架构审查与工程护航报告》):① DataProfile 会话级缓存;② 显式状态机(ExecutionStatus 14 态);③ QPER 级 SSE 全链路状态推送;④ Intent Prompt Few-Shot 示例;⑤ 工时 118h→119.5h |
| v5.0 | 2026-02-21 | 人机协同增强修订(依据《架构与产品委员会综合评估报告》):① 新增 Phase Q+(变量字典 + 变量选择面板,20h/2.5天);② 状态机扩展 DICT_EDITING + VARIABLE_CONFIRMING(含 feature flag 自动跳过);③ Intent Prompt 增加忽略非分析变量指令;④ 总工时 119.5h→139.5h |
| v6.0 | 2026-02-21 | 复合工具扩展修订(依据队列研究 Table 1-3 终态验证 +《SSA-Pro 架构诊断与复合工具扩展方案》审查):① Phase Deploy 新增复合 R 工具 ST_BASELINE_TABLE(基于 gtsummary 封装,一次遍历所有变量 + 自动选方法 + 合并出表,同时覆盖表1基线比较和表2单因素筛选);② 新增 gtsummary → report_blocks 转换层(4h,含合并行/分组列头的结构化提取);③ 前端三线表渲染增强(4h,DynamicReport.tsx 支持 rowspan/colspan/P值标星/横向滚动);④ 新增 cohort_study_standard 流程模板(表1→表2→表3 三步流程,表3自变量由用户确认而非自动 P<0.05 筛选);⑤ 决策表新增 cohort_study 场景行;⑥ Q 层 Intent Prompt goal 扩展支持 cohort_study 值(识别"出一套完整报告"等触发词);⑦ 工具总数从 10 扩展为 11(10 原子 + 1 复合);⑧ Phase Deploy 工时 25h→37h(+12h),总工时 139.5h→151.5h |
| v7.0 | 2026-02-21 | Phase P 架构增强(进入开发前的设计审查):① Expected/Actual 双层审计日志 — P 层生成 PlannedTrace(策略),E 层 R trace_log 提供 Actual Trace(事实),R 层合并两者生成方法学说明;P 层绝不做正态性预检;② Repository 模式 — DecisionTableService 通过 IDecisionTableRepo 接口解耦,初期 JSON 实现,后期可切 DB,核心业务逻辑零改动;③ 参数检验优先原则 — 决策表 Primary 始终为参数检验(效力更高),Fallback 为非参数(安全网),新增 switch_condition 列描述触发条件;④ EPV 变量上限防护 — 队列研究 Table 3 采用"全量推入 + EPV 截断 + 免责声明"策略,防止过拟合和 R 引擎崩溃;⑤ 流程模板合并 — two_group_comparison + association_analysis 合并为 standard_analysis,最终 4+1 模板 |
| v7.1 | 2026-02-21 | 新增核心原则"领域知识可配置化" + Phase P 配置化基础设施:① 核心原则第 6 条 — "QPER 四层的所有领域知识由统计学方法学团队配置,不写死在代码中","可配置"作为贯穿所有 Phase 的架构约束,IT 团队搭引擎、方法学团队填内容;② Zod Schema 严格校验 — 方法学团队编辑 JSON 时的拼写/结构错误在加载时立即拦截;③ 热更新 API — POST /reload-config 无需重启服务即可生效,校验失败保留旧配置不影响线上;④ 领域文件物理拆分 — tools_registry.json(E 层)、decision_tables.json(P 层)、flow_templates.json(P 层)、narrative_templates.json(R 层),每文件有明确的方法学团队所有者;⑤ Phase P 后端任务新增任务 0(ConfigLoader 基础设施,2h)+ 任务 1(工具注册表,2h),总任务数 7→9 |
| v8.0 | 2026-02-21 | Phase R 架构增强(进入开发前的设计审查,依据架构委员会建议):① 敏感性分析结论冲突 Prompt 策略(3.10 节) — 主分析与敏感性分析显著性不一致时,Reflection Prompt 硬编码冲突处理准则,严禁强行拼凑显著性,必须在局限性中报告稳健性问题;② Zod Schema 强校验 LLM 输出(3.11 节) — 延续 Phase Q 的 jsonrepair + Zod 三层防御范式,校验失败自动降级到 ConclusionGeneratorService 规则拼接;③ Reflection 输出交付策略调整(3.12 节) — 不做字符级流式推送,采用"后端完整收集 + Zod 校验 + 一次性 SSE 推送 reflection_complete + 前端逐 section 渐入动画"方案,原 reflection_stream 事件改为 reflection_complete;④ 运行时崩溃优雅处理(3.8 节重构) — 区分"统计降级"与"运行时崩溃",Phase R 仅做错误分类映射(R 报错关键词→友好用户提示),完整重试短路机制(MAX_RETRIES + 参数级修复 + 方法级降级)推迟至 Phase Deploy;⑤ ReflectionService 伪代码更新 — 加入 Zod Schema 定义、qper_status 状态推送、reflection_complete SSE 事件、Zod 校验失败降级逻辑;⑥ 风险管理表新增 3 行 — R 运行时崩溃、敏感性分析冲突、LLM 输出结构残缺;⑦ 回退策略表更新 — R 层触发条件新增"Zod 校验失败",E 层新增运行时崩溃处理路径;⑧ Phase R 工时 23h→22h(-1h:重试机制简化) |