Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 智能问答与混合检索解决方案 (ReAct 业务闭环版).md
HaHafeng 4794640f5d feat(iit): Phase 1.5 AI对话能力集成 - 复用通用能力层LLMFactory
新增功能
- SessionMemory: 会话记忆管理器(存储最近3轮对话)
- ChatService: AI对话服务(复用LLMFactory,支持DeepSeek-V3)
- WechatCallbackController: 集成AI对话 + '正在查询'即时反馈

 技术亮点
- 复用通用能力层LLMFactory(零配置,单例模式)
- 上下文记忆(SessionMemory,Node.js内存,自动清理过期会话)
- 即时反馈(立即回复'正在查询,请稍候...',规避5秒超时)
- 极简MVP(<300行代码,1天完成)

 文档更新
- Phase1.5开发计划文档(反映通用能力层复用优势)

 完成度
- Phase 1.5核心功能:100%
- 预估工作量:2-3天  实际:1天(LLM调用层已完善)

Scope: iit-manager
2026-01-03 16:42:46 +08:00

10 KiB
Raw Blame History

IIT Manager Agent 智能问答与混合检索解决方案 (ReAct 业务闭环版)

1. 核心需求与架构愿景

1.1 业务需求闭环

本方案旨在解决 PI主要研究者在企业微信中与 AI Agent 进行高频交互的三大核心场景:

  1. 静态规范查询询问研究方案、伦理资料、知情同意书、CRF表格等固定文档。
  2. 过程历史回溯:询问项目周报中记录的进展、问题汇总、历史数据快照。
  3. 动态数据穿透:询问 REDCap 中的实时录入情况、质控状态、特定患者不良反应。

1.2 核心架构:动静分离的“双脑模型”

为了满足上述需求,系统采用 ReAct (Reason + Act) 架构,将信息源分为“静态知识”与“动态数据”两类,分别存储与检索。

graph TD
User[PI (企业微信)] -->|提问| NodeBackend[Node.js ReAct 引擎]

subgraph "ReAct 智能分诊循环"  
NodeBackend \--\>|1. 思考 (Thought)| LLM\[DeepSeek-V3\]  
LLM \--\>|2. 决策 (Action)| ToolExec\[工具执行器\]  
  
%% 静态路径  
ToolExec \--\>|查方案/周报| DifyService\[工具A: 知识库检索\]  
DifyService \--\>|向量匹配| VectorDB\[(Dify 知识库)\]  
  
%% 动态路径  
ToolExec \--\>|查实时数据| RedcapAdapter\[工具B: 临床数据查询\]  
RedcapAdapter \--\>|API 调用| REDCap\[(REDCap 数据库)\]  
  
%% 反馈闭环  
VectorDB \-.-\>|返回文档片段| LLM  
REDCap \-.-\>|返回 JSON 数据| LLM  
end  
  
LLM \--\>|3. 最终回答 (Final Answer)| NodeBackend  
NodeBackend \--\>|推送| User

2. 详细数据存储与路由策略 (Storage & Routing)

AI 如何区分去哪里读取?取决于数据的时效性结构化程度

2.1 静态/半静态资料 -> 存入 Dify (知识库)

这部分内容适合 RAG (检索增强生成)

资料类型 具体内容 存储位置 Dify Metadata (元数据标签)
研究方案类 Protocol, 伦理批件, 知情同意书(ICF), CRF模板 Dify Knowledge Base doc_type: protocol
项目进度类 系统每周生成的周报 (PDF/Text), 会议纪要 Dify Knowledge Base doc_type: report, date: 2026-W01

关键技术点

  • 自动归档每周生成周报后Node.js 需调用 Dify API 将周报文本自动上传至知识库,实现“过程记忆”。
  • 元数据过滤检索时Agent 可根据问题类型(问方案还是问周报)通过 Metadata 缩小检索范围。

2.2 动态实时数据 -> 存入 REDCap (数据源)

这部分内容实时变化,适合 API Tool Calling

资料类型 具体内容 获取方式 工具函数定义
真实数据类 患者录入详情, 质控质疑(Query), 不良反应(AE) REDCap API query_clinical_data

3. Agent 定义与技术实现 (Implementation)

Step 1: 定义 AI Agent 的“工具箱” (Tools)

在 Node.js 代码中 (backend/src/modules/agent/tools.ts),我们将三类需求映射为两个核心工具:

export const agentTools = [
{
type: "function",
function: {
name: "search_knowledge_base",
description: "【查文档】用于查询静态资料或历史记录。包括1. 研究方案、伦理、ICF、CRF等规范文件2. 过往的项目周报、进度总结。",
parameters: {
type: "object",
properties: {
query: { type: "string", description: "搜索关键词" },
doc_category: {
type: "string",
enum: ["protocol", "report"],
description: "文档类型protocol=方案/伦理/规范report=周报/进展"
}
},
required: ["query"]
}
}
},
{
type: "function",
function: {
name: "query_clinical_data",
description: "【查数据】用于查询 REDCap 中的实时状态。包括:入组人数、特定患者(受试者)的录入情况、不良反应(AE)、质控质疑状态。",
parameters: {
type: "object",
properties: {
intent: {
type: "string",
enum: ["project_stats", "patient_detail", "qc_status"],
description: "查询意图project_stats=宏观进度patient_detail=患者详情qc_status=质控情况"
},
patient_id: { type: "string", description: "受试者编号 (如 P001)" }
},
required: ["intent"]
}
}
}
];

Step 2: 定义 AI Agent 的“人设” (System Prompt)

这是 AI 能够区分去哪个文档读取的核心逻辑。

# Role
你是由壹证循科技开发的“临床研究项目经理 AI”。你服务于项目的 PI主要研究者

# Capabilities & Routing Logic (路由逻辑)
你拥有两只“手”,请根据用户问题的性质精准选择:

1. **左手:查阅资料库 (search_knowledge_base)**
- **当用户问“规定”**:如“方案里的入排标准是什么?”、“伦理批件有效期多久?” -> 请查 `doc_category='protocol'`。
- **当用户问“历史”**:如“上周周报里提到的风险解决了没?”、“上个月入组慢的原因?” -> 请查 `doc_category='report'`。

2. **右手:查询实时数据 (query_clinical_data)**
- **当用户问“现状”**如“现在入组多少人了”、“P005 患者录完数据了吗?”、“有没有发生严重不良事件?” -> 请查 REDCap 实时数据。

3. **混合推理 (ReAct)**
- 如果问题涉及两者如“P001 的年龄(查数据)符合方案要求(查文档)吗?”),请分步调用两个工具,最后综合回答。

# Constraints
- **严禁编造**:实时数据必须通过工具获取。
- **隐私保护**:输出时隐去患者真实姓名,仅使用受试者编码。
- **专业性**:回答简练,核心数据加粗显示。

Step 3: ReAct 引擎执行逻辑 (Node.js Kernel)

在 backend/src/modules/agent/engine.ts 中实现循环调用:

// ... ReAct 循环伪代码 ...
while (turnCount < MAX_TURNS) {
// 1. AI 思考
const response = await llm.chat.completions.create({ tools: agentTools, ... });

// 2\. AI 决定行动  
if (toolCall) {  
    if (toolCall.name \=== 'search\_knowledge\_base') {  
        // 调用 Dify API根据 doc\_category 过滤  
        result \= await dify.search(query, filter={ type: args.doc\_category });  
    }   
    else if (toolCall.name \=== 'query\_clinical\_data') {  
        // 调用 RedcapAdapter  
        result \= await redcap.exportData(args);  
    }  
    // 3\. 将结果喂回给 AI (Observation)  
}  
// ...  

}

4. 场景闭环验证 (Scenario Walkthrough)

场景一:问研究方案 (资料类)

  • PI: “知情同意书里关于退出的条款是怎么写的?”
  • AI 思考: 关键词“知情同意书”、“条款” -> 属于静态规范 -> 调用 search_knowledge_base(query="退出条款", doc_category="protocol")。
  • 执行: Dify 检索 PDF。
  • AI 回答: “根据知情同意书第 5 节:受试者可随时撤回同意并退出研究,且不会受到任何不公正待遇...”

场景二:问项目进度 (历史类)

  • PI: “上周入组进度为什么滞后?”
  • AI 思考: 关键词“上周”、“滞后原因” -> 属于过程记录(周报) -> 调用 search_knowledge_base(query="入组滞后原因", doc_category="report")。
  • 执行: Dify 检索上周生成的周报文本。
  • AI 回答: “根据第 12 周周报记录:滞后主要原因为‘核磁共振设备故障导致筛选失败 3 例’。”

场景三:问真实数据 (实时类)

  • PI: “帮我看看 P003 有没有不良反应?”
  • AI 思考: 关键词“P003”、“不良反应” -> 属于特定患者实时状态 -> 调用 query_clinical_data(intent="patient_detail", patient_id="P003")。
  • 执行: Node.js 调用 REDCap API 导出 P003 的 AE 表单。
  • AI 回答: “查询 REDCap 实时数据P003 目前不良反应记录。”

5. 实施总结

通过这套 ReAct + 动静分离 的方案,我们完美覆盖了您的三大需求:

  1. 方案/伦理 -> Dify Protocol 库。
  2. 周报/进度 -> Dify Report 库 (系统自动归档)。
  3. 真实数据 -> REDCap API 实时工具。

6. 逐步分步骤开发建议 (Phased Development Recommendations)

为了降低开发风险,建议将此 ReAct 架构拆解为三个“里程碑 (Milestones)”,逐步点亮 AI 的能力。

阶段一:数据直连 (MVP - Day 3-4)

目标先让 AI 拥有“眼睛”。PI 问实时数据AI 必须能答上来。

  • 开发内容
    • 仅实现 query_clinical_data 工具。
    • 不接入 Dify任何关于文档的问题都回复“知识库正在构建中”。
    • System Prompt:简化为“你是一个只能查数据的助手”。
  • 价值PI 可以在微信里查入组人数了,解决了最高频痛点。

阶段二:知识接入 (Phase 1.5 - Day 7)

目标给 AI 装上“大脑”。接入 Dify回答方案问题。

  • 开发内容
    • 对接 Dify API实现 search_knowledge_base 工具。
    • 手动上传 1 份 PDF 方案进行测试。
    • 在 Node.js 中开启简单的 Router (单步路由):问数据走工具,问文档走 Dify。
  • 价值PI 可以开始问“入排标准”了。

阶段三:混合推理 (Phase 2 - Day 14+)

目标打通“任督二脉”。开启 ReAct 循环,处理复杂逻辑。

  • 开发内容
    • 实现 while 循环推理引擎。
    • 完善 System Prompt教 AI 如何拆解问题。
    • 实现“周报自动归档”到 Dify 的流程。
  • 价值PI 可以问“张三为什么违规”这种需要结合数据和方案的高级问题。

建议策略严守 MVP 边界。在 Day 4 演示时,只展示“阶段一”的数据查询能力即可,这已经足够震撼。不要试图一开始就调试复杂的 ReAct 循环。

文档版本V3.1 (分步落地版) | 适用阶段Phase 2