Files
AIclinicalresearch/docs/03-业务模块/SSA-智能统计分析/00-系统设计/SSA-Pro 四层七工具实现机制详解.md
HaHafeng bf10dec4c8 docs(ssa): Complete intelligent dialogue and tool system architecture design
Architecture Design:
- Add intent recognition and dialogue architecture design (Intent Router + DataContext)
- Add tool system planning (4-layer 7-tool fusion solution: READ/INTERACT/THINK/ACT)
- Add 4-layer 7-tool implementation mechanism details (Conversation Layer LLM + Node.js orchestration)

Development Plan (v1.2):
- Create 6-phase development plan (134h/22 days) for intelligent dialogue system
- Add 8 architectural constraints (C1-C8): no Function Calling, Postgres-Only cache,
  streaming output, context guard, Zod dynamic validation
- Correct Session Blackboard to use CacheFactory (Postgres-Only, no Redis)

Status Updates:
- Update SSA module status: QPER complete + dialogue architecture design complete
- Update system-level status: add SSA architecture design milestone

Other:
- R tools minor fixes (chi_square, correlation, logistic_binary, mann_whitney, t_test_paired)
- Frontend AIA chat workspace style adjustment

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 10:05:14 +08:00

55 KiB
Raw Blame History

SSA-Pro 四层七工具实现机制详解

文档版本: v1.1
创建日期: 2026-02-21
最后更新: 2026-02-21v1.1 — 新增对话层 LLM 架构说明)
文档类型: 架构说明 (Architecture Reference)
目标读者: 开发团队
前置文档: SSA-Pro 工具体系规划方案(团队讨论稿).md(定义了"做什么"),本文档说明"怎么做"
核心问题: 每个工具的内部实现机制是什么?哪些依赖 LLM哪些依赖规则引擎哪些是纯计算对话层 LLM 如何保证多轮对话的连贯性?


1. 三层架构全貌:对话层 LLM 是核心大脑

1.1 架构中的三个层次

系统不是简单的"Node.js 调工具",而是三层协同:

┌─────────────────────────────────────────────────────────────────────┐
│                                                                      │
│  第一层Node.js 编排层(交通指挥)                                    │
│  ────────────────────────────────                                    │
│  职责:意图路由 → 工具调度 → 流程控制 → Session 黑板读写              │
│  特点:确定性、无 LLM、零 Token 成本                                  │
│  类比:交通警察,决定车(工具)往哪走,但不理解乘客(用户)在说什么     │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  第二层:对话层 LLM全局大脑         ← 这是架构的核心               │
│  ────────────────────────────                                        │
│  职责:理解用户意图 → 组织工具输出 → 生成连贯自然语言回复              │
│  特点:全局状态感知、多轮对话记忆、知识推理                            │
│  类比:统计顾问本人,读过你的数据,记得之前聊了什么,知道什么时候该问    │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  第三层:工具层(专业手脚)                                           │
│  ────────────────────────                                            │
│  职责执行具体任务统计计算、规则匹配、R 脚本执行)                  │
│  特点:无状态函数,输入→输出,不关心对话上下文                         │
│  类比:实验室设备,按按钮出结果,但不知道实验的完整背景                 │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

1.2 一次完整交互的真实流程

以用户说 "帮我看看各组的样本分布" 为例:

用户消息: "帮我看看各组的样本分布"
       │
       ▼
  ┌─ 第一层Node.js 编排 ──────────────────────────────────────────┐
  │  IntentRouter 分类 → explore                                    │
  │  决定调用 get_data_overview若缓存未命中                       │
  └──────────────┬──────────────────────────────────────────────────┘
                 │ 工具调用
                 ▼
  ┌─ 第三层:工具层 ────────────────────────────────────────────────┐
  │  get_data_overview → DataProfileService(Python) 返回结构化 JSON  │
  │  { total_rows: 200, categorical_vars: [...], ... }              │
  └──────────────┬──────────────────────────────────────────────────┘
                 │ 结构化输出
                 ▼
  ┌─ 第二层:对话层 LLM ────────────────────────────────────────────┐
  │                                                                  │
  │  System Prompt:                                                  │
  │    "你是 SSA-Pro 智能统计分析助手...                               │
  │     用户数据全貌: {DataContext}                                   │
  │     请基于数据摘要为用户解读数据特征。"                             │
  │                                                                  │
  │  对话历史:                                                       │
  │    [user] 上传了数据 xxx.csv                                     │
  │    [assistant] 您的数据已上传成功...                               │
  │    [user] 帮我看看各组的样本分布          ← 当前消息               │
  │                                                                  │
  │  工具输出(注入为上下文):                                         │
  │    get_data_overview 返回: { ... }                                │
  │                                                                  │
  │  → LLM 生成连贯的自然语言回复:                                    │
  │    "您的数据共 200 例,分为 treatment 组103 例)和               │
  │     control 组97 例)。各组分布如下:                            │
  │     - treatment 组平均年龄 54.3 岁SD=11.2...                  │
  │     需要我进一步看某个具体变量吗?"                                │
  │                                                                  │
  └──────────────────────────────────────────────────────────────────┘

关键点:工具返回的是结构化 JSON但用户看到的是自然语言。中间的翻译者就是对话层 LLM。

1.3 对话层 LLM 的六大职责

# 职责 靠 Node.js 能做到吗? 说明
1 自然语言生成 把结构化 JSON 变成"像人说的话"
2 多轮对话记忆 "刚才那个变量"→ 理解指的是上一轮讨论的 BMI
3 上下文推理 用户说"有没有效"→ 结合 DataContext 推理出想比较什么
4 主动引导 分析完主动问"需要做敏感性分析吗?"
5 知识融合 结合统计学知识解释"为什么选 T 检验而不是 ANOVA"
6 语气和策略 对医生用临床语言,对统计师用技术语言

结论Node.js 编排层绝对不够。对话层 LLM 是不可或缺的核心大脑。Node.js 管"做什么"LLM 管"怎么说"和"怎么想"。


2. 对话层 LLM 的技术实现

2.1 System Prompt 架构

对话层 LLM 有一个持久的 System Prompt在整个会话生命周期内持续生效并根据意图和状态动态组装

┌─ System Prompt始终存在────────────────────────────────────────┐
│                                                                    │
│  [基础角色](固定)                                                │
│  你是 SSA-Pro 智能统计分析助手,专注于临床研究统计分析。             │
│  你了解用户上传的数据,可以回答关于数据的问题,推荐分析方法,        │
│  解读分析结果。你的风格是专业但易懂的统计顾问。                     │
│                                                                    │
│  [数据全貌](上传数据后始终注入,~200 Token                       │
│  用户上传了一份数据集:                                             │
│  {DataContext.summary — 行数/列数/缺失率/类型/结构}                 │
│                                                                    │
│  [PICO 分类](推断后注入,~150 Token                              │
│  根据数据特征,推断/确认的 PICO 分类如下:                          │
│  {DataContext.pico — population/intervention/outcome}               │
│                                                                    │
│  [变量字典](逐步丰富,~50 Token/变量,裁剪后注入)                 │
│  各变量的定义和角色:                                               │
│  {DataContext.variableDictionary — 裁剪策略控制}                    │
│                                                                    │
│  [意图特定指令](每次请求动态切换)                                  │
│  ┌──────────────────────────────────────────────────┐              │
│  │ chat:     请基于统计知识和用户数据回答。不要主动建议分析。│              │
│  │ explore:  请基于数据摘要解读数据特征。可以推断 PICO。  │              │
│  │ consult:  请推荐分析方法,给出理由和前提。不要执行。   │              │
│  │ analyze:  以下是工具执行结果,请向用户说明进展。      │              │
│  │ discuss:  以下是分析结果: {结果}。请帮助用户解读。    │              │
│  │ feedback: 以下是完整 QPER 记录: {trace}。请分析问题。 │              │
│  └──────────────────────────────────────────────────┘              │
│                                                                    │
│  [工具输出](本轮工具调用的结果,动态注入)                          │
│  {get_data_overview / method_consult / run_step 等的结构化输出}      │
│                                                                    │
│  [分析结果]discuss/feedback 时注入,~500 Token/步骤)              │
│  {最近的 AnalysisRecord 摘要}                                       │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

┌─ 对话历史(最近 N 轮,滑动窗口)─────────────────────────────────────┐
│  [user] 上传了 clinical_trial.csv                                    │
│  [assistant] 您的数据已上传,共 200 行 15 列...                       │
│  [user] 帮我看看各组的样本分布                                        │
│  [assistant] treatment 组 103 例control 组 97 例...                 │
│  [user] BMI 的分布怎样?                                              │
│  [assistant] BMI 均值 25.3,标准差 4.1...                             │
│  [user] 这两组 BMI 有差异吗?应该怎么分析?         ← 当前消息        │
└──────────────────────────────────────────────────────────────────────┘

2.2 对话层 LLM 在每种意图中的角色

意图 Node.js 编排做了什么 对话层 LLM 做了什么
chat 几乎不介入(不调工具) 完全主导:纯 LLM 对话,基于 DataContext + 统计知识回答
explore 调用 get_data_overview 或 get_variable_detail 翻译 + 解读:把结构化 JSON 变成易懂的数据解读
consult 调用 method_consult决策表匹配 融合 + 解释:把匹配结果变成完整的方法推荐(带理由、前提、替代)
analyze 调用 analysis_plan → run_step ×N → write_report 进度播报 + 过渡衔接:每步执行后生成进展说明,衔接步骤间的上下文
discuss 提取最近的 AnalysisRecord 深度解读:回答"p 值说明什么""置信区间为什么宽"等统计学问题
feedback 注入 qperTrace 到 LLM 问题诊断:分析完整记录,找出问题根因,建议新方案

2.3 对话连贯性保障机制

┌─ 保障机制 1对话历史注入 ────────────────────────────────────────┐
│                                                                    │
│  每次 LLM 调用都携带最近 N 轮对话历史(滑动窗口)                   │
│  → 用户说"刚才那个变量" → LLM 从历史中知道指的是 BMI               │
│  → 用户说"按你说的方案执行" → LLM 从历史中知道之前推荐了 T 检验    │
│                                                                    │
│  窗口大小:根据 Token 预算动态调整                                  │
│  - 简单对话:保留最近 10 轮                                        │
│  - 长对话(含分析结果):保留最近 5 轮 + 关键事件摘要              │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

┌─ 保障机制 2Session 黑板持久化 ──────────────────────────────────┐
│                                                                    │
│  对话历史有滑动窗口(会丢失早期内容),但关键决策结果不会丢失:      │
│  - PICO 确认结果 → 写入 blackboard.confirmedPico → 始终可用        │
│  - 变量角色确认 → 写入 blackboard.variableDictionary → 始终可用    │
│  - 分析方案 → 写入 blackboard.currentPlan → 始终可用               │
│  - 执行结果 → 写入 blackboard.stepResults → 始终可用               │
│                                                                    │
│  → 即使对话历史中早期的讨论被裁剪,结论仍在 Session 黑板中          │
│  → LLM 通过 DataContext 注入随时可以引用这些结论                    │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

┌─ 保障机制 3意图切换时的上下文衔接 ──────────────────────────────┐
│                                                                    │
│  用户从 consult 转到 analyze 时:                                  │
│                                                                    │
│  [consult 阶段对话]                                                │
│  user: "我想比较两组血压差异,用什么方法?"                          │
│  assistant: "建议独立样本 T 检验,理由是..."                        │
│  user: "好的,按这个方案执行"                                       │
│                                                                    │
│  → IntentRouter 识别为 analyze                                     │
│  → Node.js 编排层从 Session 黑板读取 consult 阶段的结论             │
│  → 对话层 LLM 收到完整上下文:                                      │
│    System Prompt含 DataContext + "用户已确认 T 检验方案"         │
│    + 对话历史(包含 consult 阶段的讨论)                            │
│    + 意图特定指令("正在执行分析,请向用户说明进展"                │
│  → LLM 生成衔接回复:                                               │
│    "好的,我来按之前讨论的方案执行。分析计划如下:                   │
│     步骤 1: 描述统计(两组基线特征)                                │
│     步骤 2: 独立样本 T 检验(比较血压差异)                         │
│     确认开始执行吗?"                                               │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

2.4 对话层 LLM 的技术参数

参数 说明
模型 deepseek-v3 全系统统一模型
Temperature 0.7(对话)/ 0.3(报告生成) 对话允许自然变化,报告追求稳定
System Prompt 持久注入 整个会话生命周期内持续生效
对话历史 滑动窗口5-10 轮) Token 预算内尽量多保留
DataContext 始终注入 通过 Session 黑板注入,保证数据感知
Prompt 管理 DB 存储 + Seed 脚本 方法学团队可编辑,不写死在代码中

3. 编排层 vs 对话层的职责划分

3.1 什么事 Node.js 编排层做

职责 说明 举例
意图路由 决定这条消息走哪个处理路径 "比较两组" → analyze
工具调度 决定调用哪些工具、什么顺序 analyze → plan → run_step ×N → report
Session 黑板读写 工具输出写入黑板,工具输入从黑板读 PICO 写入 → plan 读取
Token 控制 注入 LLM 前裁剪上下文 变量字典 >20 → 只注入已确认的
data_source 注入 R 引擎调用前自动注入数据源 OSS 预签名 URL
错误分类 run_step 出错后决定重试还是报告 "Column not found" → 可自愈
流程控制 ask_user 中断/恢复、重试计数 MAX 2 次 → 停止重试

3.2 什么事对话层 LLM 做

职责 说明 举例
自然语言生成 把结构化输出变成人话 JSON → "您的数据共 200 例..."
多轮对话连贯 理解指代、省略、上下文引用 "刚才那个" → BMI
知识推理 基于统计学知识回答专业问题 "为什么选 T 检验?"
PICO 推断 基于临床知识推断数据角色 推断 outcome 可能是 bp_change
方法解释 解释决策表的匹配结果 "选 T 检验是因为..."
结果解读 深度解释统计结果的含义 "p=0.03 说明..."
主动引导 在合适时机引导用户下一步 "需要做敏感性分析吗?"
反思分析 分析 QPER 全记录找问题根因 "样本量不足导致检验效能低"

3.3 协作模型

Node.js 编排层                     对话层 LLM
─────────────                     ──────────

"这条消息是 explore 意图"    →
                                   
"调用 get_data_overview"     →
                                   
"工具返回了 JSON 结果"       →     "把 JSON + DataContext + 对话历史
                                    组装成 Prompt生成自然语言解读"
                                   
                              ←    "您的数据共 200 例,分为..."
                                   
"把回复返回给前端"           →

─── 下一轮 ───

"这条消息是 consult 意图"    →
                                   
"调用 method_consult          →
 (DecisionTable 匹配)"
                                   
"匹配结果: T 检验"           →     "把匹配结果 + DataContext + 对话历史
                                    组装成 Prompt生成方法推荐 + 理由"
                                   
                              ←    "建议独立样本 T 检验,因为..."

核心原则Node.js 决定"做什么"LLM 决定"怎么说"和"怎么想"。两者缺一不可。


4. 意图 → 编排流程 → LLM 角色映射

意图 Node.js 编排流程 对话层 LLM 角色
chat 几乎不介入 完全主导直接回答DataContext 保证数据感知
explore 调用 READ 层工具 翻译+解读JSON → 自然语言数据解读
consult 调用 method_consult 融合+解释:决策表结果 → 完整方法推荐
analyze 调用 THINK+ACT 全链路 播报+衔接:步骤进展说明,上下文衔接
discuss 提取分析结果 深度解读:统计学问题的专业解答
feedback 注入 QPER 记录 诊断+建议:问题根因分析,新方案建议

5. 四层七工具实现机制总览

5.1 四层七工具实现机制一览

工具 实现机制 LLM 参与 核心引擎 风险/成本
READ get_data_overview Python 计算 + LLM 推断 部分 DataProfileService (Python) 零风险
READ get_variable_detail 纯 Python 计算 DataProfileService (Python) 零风险
READ method_consult 匹配引擎 + LLM 补充 部分 DecisionTableService (规则) 零风险
INTERACT ask_user 纯系统机制 Node.js → 前端 → 用户 零风险
THINK analysis_plan 匹配引擎 + 模板填充 DecisionTable + FlowTemplate 低风险
ACT run_step 纯 R 引擎执行 WorkflowExecutor → R Plumber 有计算成本
ACT write_report LLM 生成 + 槽位注入 核心 ReflectionService (LLM) 有 Token 成本

5.2 辅助机制

机制 实现方式 LLM 参与
意图路由器 规则引擎优先 + LLM 兜底(混合路由) 部分
反思 — 自动重试 错误分类器(规则) + LLM 修正参数 部分
反思 — 手动触发 LLM 分析完整 QPER 记录 → 新方案 核心
Session 黑板 Node.js 内存缓存
Token 控制 代码裁剪函数
data_source 注入 Node.js 编排层自动注入

6. READ 层 — 只读,零风险

6.1 get_data_overview

实现机制Python 统计计算 + LLM PICO 推断(两步串联)

                    ┌──────────────────────────────────┐
  session_id ──→   │  Step 1: DataProfileService       │  ← 纯 Python 计算
                    │  Python pandas 统计分析)         │     无 LLM
                    │  输出:行数/列数/缺失率/类型/分布    │
                    └──────────────┬───────────────────┘
                                   │ 结构化 JSON
                                   ▼
                    ┌──────────────────────────────────┐
                    │  Step 2: LLM PICO 推断            │  ← LLM Prompt
                    │  输入:统计摘要 + 临床知识          │     纯推理,无工具调用
                    │  输出population / intervention /  │
                    │        outcome 候选 + 置信度        │
                    └──────────────┬───────────────────┘
                                   │ 合并
                                   ▼
                         写入 Session 黑板

实现细节:

环节 引擎 说明
统计摘要生成 Pythonpandas 调用已有 DataProfileService,返回结构化 JSON
PICO 推断 LLM Prompt 将统计摘要注入 PromptLLM 基于临床知识推断 PICO 分类
结果缓存 Node.js 内存 写入 Session 黑板,后续工具直接读缓存

关键约束:

  • Step 1统计计算和 LLM 完全无关,是确定性结果
  • Step 2PICO 推断)标记为 inference,必须经 ask_user 确认后才变为 confirmed
  • 已有实现基础:DataProfileService 已能生成统计摘要并缓存

6.2 get_variable_detail

实现机制:纯 Python 计算(零 LLM

  session_id + variable_name
       │
       ▼
  ┌────────────────────────────────┐
  │  DataProfileService            │  ← 纯 Python 计算
  │  按需查询单列                    │     无 LLM
  │  输出:分布/直方图/异常值/样本值  │     确定性结果
  └────────────────────────────────┘

实现细节:

环节 引擎 说明
单列统计分析 Pythonpandas 计算分布、异常值、直方图分箱等

关键约束:

  • 整个工具内部没有 LLM 参与,完全是 Python 数值计算
  • get_data_overview 的按需 drill-down解决大数据集 Token 爆炸问题
  • 需要在 Python 侧新增"单列查询" API当前 DataProfileService 只有全量 profile

6.3 method_consult

实现机制:决策表四维匹配 + LLM 推理补充(双引擎)

  research_question + outcome_var + predictors + DataContext
       │
       ├──→ ┌─────────────────────────────────────────┐
       │    │  引擎 A: DecisionTableService             │  ← 规则匹配引擎
       │    │  四维匹配 Goal × OutcomeType ×             │     无 LLM
       │    │  PredictorType × Design                   │     确定性结果
       │    │  输出primaryTool + fallbackTool           │
       │    └──────────────┬──────────────────────────┘
       │                   │ 匹配结果
       │                   ▼
       └──→ ┌─────────────────────────────────────────┐
            │  引擎 B: LLM 推理补充                     │  ← LLM Prompt
            │  输入:匹配结果 + DataContext + 统计知识    │     纯推理
            │  输出:                                    │
            │    rationale选择理由                    │
            │    prerequisites前提条件                │
            │    limitations局限性                    │
            │    alternatives替代方案 + 适用场景)       │
            └─────────────────────────────────────────┘

实现细节:

环节 引擎 说明
方法选择(选什么) DecisionTableService 四维规则匹配JSON 驱动,确定性、可审计
解释说明(为什么选) LLM Prompt 利用 LLM 统计学知识生成自然语言解释

关键约束:

  • 核心决策(选什么方法)由规则引擎决定,不由 LLM 决定 — 确保可审计、可配置
  • LLM 只负责"润色"和"补充" — 生成人类可读的理由和替代方案说明
  • 决策表当前 ~10 条规则,覆盖 7 个 R 工具JSON 驱动,方法学团队可编辑
  • 未来工具扩展到 30+ 时,可在决策表前加一层 RAG Top-K 检索
  • 已有实现基础:DecisionTableService.match() 已实现四维匹配

7. INTERACT 层 — 人机交互,零风险

7.1 ask_user

实现机制纯系统机制Node.js 请求-响应模式,零 LLM

  Node.js 编排层决定需要提问
       │
       ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 1: Node.js 生成 ClarificationCard JSON      │  ← 无 LLM
  │  question + options + context                  │     Node.js 代码构造
  └──────────────┬───────────────────────────────────┘
                 │ SSE 推送 / HTTP Response
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 2: 前端 ClarificationCard 组件渲染           │  ← 前端 React
  │  用户看到选择卡片 → 点击选择 → 提交                 │
  └──────────────┬───────────────────────────────────┘
                 │ HTTP POST用户选择结果
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 3: Node.js 从 Session 黑板恢复上下文          │  ← 无 LLM
  │  将用户选择写入黑板 → 继续后续流程                    │
  └──────────────────────────────────────────────────┘

实现细节:

环节 引擎 说明
卡片生成 Node.js 代码 根据当前流程上下文构造问题和选项
卡片渲染 前端 React ClarificationCard 组件,支持单选/多选/自由文本
上下文恢复 Session 黑板 用户响应后,从黑板恢复上下文继续流程

关键约束:

  • 工具本身完全不涉及 LLM — 它是一个"人机交互通道"
  • 但"什么时候问、问什么"是由 Node.js 编排层决定的
  • 当前实现为"请求-响应模式"Node.js 发送卡片 → 中断等待 → 下一次 HTTP 请求恢复
  • 不是 LLM Function Calling 挂起模式(那是 Phase 4+ 的预研方向)
  • 已有实现基础:QueryService.generateClarificationCards() + ClarificationCard 前端组件

8. THINK 层 — 生成方案,低风险

8.1 analysis_plan

实现机制:决策表匹配 + 流程模板填充(确定性引擎,零 LLM

  confirmed_question + confirmed_methods + variable_mapping + DataContext
       │
       ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 1: DecisionTableService.match()              │  ← 规则匹配引擎
  │  四维匹配 → 命中规则 → 得到 templateId              │     无 LLM
  └──────────────┬───────────────────────────────────┘
                 │ matchResult { templateId, primaryTool, fallbackTool }
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 2: FlowTemplateService.fill()                │  ← 模板引擎
  │  选择模板 → 填充参数 → EPV 防护 → 有序步骤列表      │     无 LLM
  │  输出:[{order, tool_code, params, depends_on}]    │     确定性结果
  └──────────────────────────────────────────────────┘

实现细节:

环节 引擎 说明
规则匹配 DecisionTableService 四维匹配Goal × OutcomeType × PredictorType × Design
模板填充 FlowTemplateService flow_templates.json 加载模板,填入变量名和参数
EPV 防护 FlowTemplateService 检查事件数/自变量比,超限自动截断并生成免责声明

关键约束:

  • 整个工具内部没有 LLM 参与 — 完全是规则匹配 + 模板填充的确定性计算
  • 方法选择在 method_consult 阶段已完成并经用户确认,analysis_plan 只负责"编排顺序 + 填充参数"
  • 输出包含确定的 tool_code + 完整 paramsrun_step 只需傻瓜式执行
  • 生成后展示给用户审查,用户确认后才进入 ACT 层
  • 已有实现基础:FlowTemplateService.fill() + decision_tables.json + flow_templates.json

9. ACT 层 — 执行,有成本

9.1 run_step

实现机制:纯 R 引擎执行(傻瓜式 API 转发,零 LLM

  step_definition { tool_code, params } + session_id
       │
       ▼
  ┌──────────────────────────────────────────────────┐
  │  Node.js 编排层:自动注入 data_source              │  ← 无 LLM
  │  从 Session 黑板取 dataOssKey → 生成预签名 URL      │     系统机制
  │  注入 params.data_source = { type:'oss', oss_url } │
  └──────────────┬───────────────────────────────────┘
                 │
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  WorkflowExecutorService → RClientService          │
  │  HTTP POST 给 R Plumber API                        │  ← 无 LLM
  │  R 脚本执行统计分析                                  │     纯 R 引擎计算
  │  返回 ReportBlock[] + figures + r_code              │
  └──────────────────────────────────────────────────┘

实现细节:

环节 引擎 说明
data_source 注入 Node.js 编排层 从 Session 黑板取 dataOssKey,生成预签名 URL 自动注入
R 脚本执行 R Plumber API 接收 tool_code + params → 执行统计计算 → 返回结构化结果
结果标准化 R Block Helpers R 端输出标准化为 ReportBlock[] 格式

关键约束:

  • 整个工具内部没有 LLM 参与 — 纯粹的 HTTP 转发 + R 引擎执行
  • 是"傻瓜式 API 转发器",不做任何方法选择决策
  • data_source 由 Node.js 编排层自动注入LLM 和 analysis_plan 全程不感知数据文件位置
  • 错误处理由编排层接管(双轨反思机制)
  • 已有实现基础:WorkflowExecutorService + RClientService + resolveDataSource() 全部已实现

9.2 write_report

实现机制LLM 生成叙述 + 统计量槽位注入 + Zod 校验LLM 为核心引擎)

generate 模式(论文级报告)

  step_results + DataContext
       │
       ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 1: 提取 Key Findings                        │  ← 无 LLM
  │  从 stepResults 中提取 p 值、置信区间、效应量等      │     纯代码提取
  │  生成 {{ slot }} 映射表                             │
  └──────────────┬───────────────────────────────────┘
                 │
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 2: LLM 生成叙述框架                         │  ← LLM 核心
  │  Prompt: "根据以下统计结果,生成论文级结论"          │     生成自然语言叙述
  │  LLM 输出包含 {{ slot }} 占位符                    │
  │  LLM 被禁止生成任何数值(反幻觉机制)               │
  └──────────────┬───────────────────────────────────┘
                 │
                 ▼
  ┌──────────────────────────────────────────────────┐
  │  Step 3: jsonrepair + Zod 校验 + 槽位渲染         │  ← 无 LLM
  │  校验 LLM 输出结构完整性                            │     确定性后处理
  │  用真实统计数值替换 {{ slot }} 占位符                │
  │  校验失败 → 降级到 ConclusionGeneratorService      │
  └──────────────────────────────────────────────────┘

interpret 模式(结果解读)

  user_question + step_results + DataContext
       │
       ▼
  ┌──────────────────────────────────────────────────┐
  │  LLM 深度解读                                     │  ← LLM 核心
  │  Prompt: DataContext + 分析结果 + 用户具体问题      │     纯推理
  │  输出:针对用户问题的统计学解读                      │
  └──────────────────────────────────────────────────┘

实现细节:

环节 引擎 说明
Key Findings 提取 Node.js 代码 从 R 输出中提取关键统计量,构建槽位映射表
叙述框架生成 LLM (deepseek-v3) 生成论文级叙述,用 {{ slot }} 占位符替代数值
输出校验 jsonrepair + Zod 修复 JSON 格式 → Schema 强校验 → 确保结构完整
槽位渲染 Node.js 代码 用真实统计数值替换占位符
降级兜底 ConclusionGeneratorService Zod 校验失败时,规则拼接生成基础结论

关键约束:

  • 这是 7 个工具中 LLM 参与度最高的LLM 是核心引擎
  • 但 LLM 不是"裸奔"的:统计量通过槽位注入从 R 输出渲染LLM 被禁止生成数值(反幻觉)
  • 三层防御:jsonrepairZod SchemaConclusionGeneratorService(规则拼接兜底)
  • 已有实现基础:ReflectionService + ConclusionGeneratorService 全部已实现

10. 辅助机制详解

10.1 意图路由器IntentRouterService

实现机制:规则引擎优先 + LLM 兜底(混合路由)

  用户消息 + Session 上下文
       │
       ▼
  ┌──────────────────────────────────────┐
  │  Step 1: 规则匹配器                   │  ← 无 LLM
  │  关键词匹配 + 上下文状态推断           │     确定性、零延迟
  │  "执行""分析一下" → analyze            │
  │  "应该用什么方法" → consult             │
  │  "帮我看看" → explore                  │
  │  "p 值说明什么"(有结果) → discuss       │
  └──────────────┬───────────────────────┘
                 │
                 ├── 命中 → 直接返回意图(不调 LLM
                 │
                 └── 未命中 ──→ ┌──────────────────────────┐
                                │  Step 2: LLM 轻量分类     │  ← LLM Prompt
                                │  仅做分类,不生成长文       │     低 Token 成本
                                │  输出intent + confidence  │
                                └──────────────┬───────────┘
                                               │
                                               ├── confidence 足够 → 返回
                                               └── confidence 不足 → 默认 chat

关键约束:

  • 规则优先:明确场景走规则,零延迟、零 Token 成本
  • LLM 兜底:模糊场景走轻量级 LLM 分类(仅输出 intent + confidence不生成长文
  • 默认安全:无法判断时 → chat最安全的兜底不触发任何流水线

10.2 反思机制(编排层逻辑,非工具)

自动反思(静默重试)

  run_step 返回 error
       │
       ▼
  ┌──────────────────────────────────────┐
  │  错误分类器                            │  ← 无 LLM
  │  读取 error_classification.json        │     规则匹配
  │  R 报错关键词 → 分类                    │
  └──────────┬──────────┬────────────────┘
             │          │
     可自愈(参数级)  不可自愈(方法级)
             │          │
             ▼          ▼
  ┌──────────────┐  ┌──────────────────────────┐
  │  LLM 修正参数 │  │  报告用户 + 建议替代方案   │
  │  注入错误日志  │  │  不重试                    │
  │  + DataContext │  └──────────────────────────┘
  │  → 重试(MAX 2) │
  └──────────────┘
       ← LLM Prompt

手动反思(用户驱动)

  用户: "结果不对" / "换个方法试试"
       │
       ▼
  IntentRouter → feedback 意图
       │
       ▼
  ┌──────────────────────────────────────┐
  │  LLM 分析完整 QPER 记录              │  ← LLM 核心
  │  注入 qperTrace滑动窗口摘要       │     深度推理
  │  分析问题根因 → 生成新方案建议         │
  └──────────────┬───────────────────────┘
                 │
                 ▼
            ask_user → 新 analysis_plan → run_step → write_report

10.3 Session 黑板(纯系统基础设施)

┌─ Session Blackboard ─────────────────────────────────────┐
│  sessionId                                                │
│  dataOverview ← get_data_overview 写入                    │
│  confirmedPico ← ask_user 确认后写入                       │
│  variableDictionary ← 对话中逐步丰富                       │
│  dataOssKey ← 上传时写入run_step 自动注入用)             │
│  currentPlan ← analysis_plan 写入                         │
│  stepResults ← run_step 每步追加                          │
│  report ← write_report 写入                               │
│  qperTrace ← 所有工具调用记录(反思用)                     │
└──────────────────────────────────────────────────────────┘

实现:纯 Node.js 内存缓存,无 LLM 参与
Token 控制:注入 LLM 前的裁剪函数(纯代码逻辑)

11. LLM 在架构中的准确定位

11.1 三层分类

┌─────────────────────────────────────────────────────────────┐
│                     完全不用 LLM 的                           │
│                                                              │
│  get_variable_detail — 纯 Python 计算                        │
│  ask_user — 纯系统机制Node.js → 前端 → 用户)              │
│  analysis_plan — 纯规则匹配 + 模板填充                       │
│  run_step — 纯 R 引擎执行                                    │
│  Session 黑板 / Token 控制 / data_source 注入                │
│                                                              │
│  → 这些是"管道和基础设施",确定性、可审计、零 Token 成本       │
├─────────────────────────────────────────────────────────────┤
│                     部分使用 LLM 的                           │
│                                                              │
│  get_data_overview — Python 计算(主) + LLM PICO 推断(辅)  │
│  method_consult — 决策表匹配(选什么) + LLM解释为什么选   │
│  意图路由器 — 规则优先(确定性) + LLM 兜底(模糊场景)       │
│  反思-自动重试 — 规则分类错误 + LLM 修正参数                  │
│                                                              │
│  → 这些是"引擎 + LLM 增强",核心决策不依赖 LLM              │
├─────────────────────────────────────────────────────────────┤
│                     LLM 为核心的                              │
│                                                              │
│  write_report(generate) — LLM 生成叙述(但槽位注入防幻觉)   │
│  write_report(interpret) — LLM 深度解读用户问题               │
│  反思-手动触发 — LLM 分析完整 QPER 记录                      │
│  chat / explore 对话 — LLM(DataContext) 直接回复              │
│                                                              │
│  → 这些是"LLM 的主场",充分发挥 LLM 知识和推理能力           │
└─────────────────────────────────────────────────────────────┘

11.2 LLM 调用点清单

调用点 LLM 角色 模型 防护机制
PICO 推断 临床知识推理 deepseek-v3 ask_user 人工确认
method_consult 补充 统计学知识解释 deepseek-v3 决策表为主LLM 只补充说明
意图路由 LLM 兜底 意图分类 deepseek-v3 规则优先LLM 只处理模糊场景
write_report(generate) 论文级叙述生成 deepseek-v3 槽位注入 + Zod 校验 + 规则拼接兜底
write_report(interpret) 结果深度解读 deepseek-v3 DataContext 约束回答范围
反思-自动修正 参数级错误修复 deepseek-v3 MAX 2 次重试限制
反思-手动分析 QPER 全记录分析 deepseek-v3 ask_user 确认新方案
chat/explore 对话 自由知识对话 deepseek-v3 DataContext 注入提供约束

12. 架构哲学总结

12.1 核心协作模型

┌─────────────────────────────────────────────────────────────────┐
│                                                                  │
│                    Node.js 编排层(交通指挥)                      │
│                    ┌────────────────────────┐                    │
│                    │  意图路由 → 工具调度      │                    │
│                    │  Session 黑板读写         │                    │
│                    │  Token 控制 + 流程控制    │                    │
│                    └──┬──────────────┬──────┘                    │
│                       │              │                           │
│            ┌──────────┘              └──────────┐                │
│            ▼                                    ▼                │
│   ┌────────────────┐                  ┌────────────────┐        │
│   │  工具层(手脚)  │                  │  用户           │        │
│   │                │    结构化输出      │                │        │
│   │ Python 计算    │ ──────────────→   │  ask_user      │        │
│   │ DecisionTable  │                  │  PICO 确认     │        │
│   │ FlowTemplate   │                  │  方案审查      │        │
│   │ R 引擎         │                  │  反思决策      │        │
│   │ ErrorClassify  │                  └────────────────┘        │
│   └────────┬───────┘                                            │
│            │ 结构化输出                                          │
│            ▼                                                     │
│   ┌────────────────────────────────────────────────────┐        │
│   │           对话层 LLM全局大脑                      │        │
│   │                                                     │        │
│   │  System Prompt角色 + DataContext + 意图指令)       │        │
│   │  + 对话历史(滑动窗口)                               │        │
│   │  + 工具输出(结构化 JSON                            │        │
│   │                                                     │        │
│   │  → 自然语言生成    → 多轮对话连贯                     │        │
│   │  → 知识推理        → 主动引导                        │        │
│   │  → PICO 推断       → 结果解读                        │        │
│   │  → 方法解释        → 反思分析                        │        │
│   └────────────────────────────────────────────────────┘        │
│                       │                                          │
│                       ▼                                          │
│              自然语言回复 → 前端展示                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.2 一句话总结

确定性的事交给规则引擎决策表、模板、R 脚本、Python 计算)
需要知识和推理的事交给对话层 LLM(理解意图、组织回复、知识推理、结果解读)
需要判断和确认的事交给用户PICO 确认、方法选择、方案审查)
三者通过 Node.js 编排层和 Session 黑板协同工作

12.3 角色定位

角色类比 核心职责 Token 成本
Node.js 编排层 交通指挥 决定做什么、走哪条路
对话层 LLM 统计顾问本人 理解、推理、表达、引导 有(核心开销)
工具层 实验室设备 计算、匹配、执行 零(除 write_report
用户 最终决策者 确认、修正、决定方向

对话层 LLM 是系统的大脑和嘴巴 — 它理解用户在说什么,知道该怎么回答,把工具的结构化输出变成人类能理解的对话。没有它,系统只是一堆互不关联的 API 调用。



文档维护者: SSA 架构团队
创建日期: 2026-02-21
最后更新: 2026-02-21v1.1 — 新增对话层 LLM 架构说明,明确三层架构模型)
关联文档:

  • SSA-Pro 工具体系规划方案(团队讨论稿).md — 工具定义(做什么)
  • SSA-Pro 意图识别与对话架构设计.md — 意图路由 + System Prompt 策略
  • 04-开发计划/11-智能对话与工具体系开发计划.md — 开发落地计划

变更日志

版本 日期 变更内容
v1.0 2026-02-21 初版:四层七工具的内部实现机制
v1.1 2026-02-21 新增对话层 LLM 架构:① 明确三层架构(编排层 + 对话层 LLM + 工具层);② 新增 System Prompt 架构(基础角色 + DataContext 注入 + 意图指令 + 对话历史);③ 新增对话连贯性三大保障机制(对话历史注入 + Session 黑板持久化 + 意图切换上下文衔接);④ 新增编排层 vs 对话层职责划分表