Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
229 lines
10 KiB
Markdown
229 lines
10 KiB
Markdown
# **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 |