docs(iit): Add IIT Manager Agent V2.9 development plan with multi-agent architecture

Features:
- Add V2.9 enhancements: Cron Skill, User Profiling, Feedback Loop, Multi-Intent Handling
- Create modular development plan documents (database, engines, services, memory, tasks)
- Add V2.5/V2.6/V2.8/V2.9 design documents for architecture evolution
- Add system design white papers and implementation guides

Architecture:
- Dual-Brain Architecture (SOP + ReAct engines)
- Three-layer memory system (Flow Log, Hot Memory, History Book)
- ProfilerService for personalized responses
- SchedulerService with Cron Skill support

Also includes:
- Frontend nginx config updates
- Backend test scripts for WeChat signature
- Database backup files

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-05 22:33:26 +08:00
parent 4b9b90ffb8
commit 0c590854b5
27 changed files with 7279 additions and 7 deletions

View File

@@ -0,0 +1,436 @@
# IIT Manager Agent 数据库设计
> **版本:** V2.9
> **更新日期:** 2026-02-05
> **关联文档:** [IIT Manager Agent V2.6 综合开发计划](./IIT%20Manager%20Agent%20V2.6%20综合开发计划.md)
>
> **V2.9 更新**
> - 扩展 `iit_skills` 表支持 Cron Skill主动提醒
> - 扩展 `iit_conversation_history` 表增加反馈字段
> - 更新 `iit_project_memory` 内容结构(用户画像)
---
## 1. 数据库表总览
| 表名 | 用途 | Phase | 优先级 |
|------|------|-------|--------|
| `iit_skills` | Skill 配置存储 | 1 | P0 |
| `iit_field_mapping` | 字段名映射字典 | 1 | P0 |
| `iit_task_run` | SOP 任务执行记录 | 2 | P0 |
| `iit_pending_actions` | 待处理的违规记录 | 2 | P0 |
| `iit_conversation_history` | 对话历史(流水账) | 2 | P1 |
| `iit_project_memory` | 项目级热记忆Markdown | 2 | P1 |
| `iit_weekly_reports` | 周报归档(历史书) | 4 | P1 |
| `iit_agent_trace` | ReAct 推理轨迹 | 5 | P2 |
| `iit_form_templates` | 表单模板(视觉识别) | 6 | 延后 |
---
## 2. Phase 1基础配置表
### 2.1 iit_skills - Skill 配置存储
```prisma
model IitSkill {
id String @id @default(uuid())
projectId String // 绑定项目
skillType String // qc_process | daily_briefing | general_chat | weekly_report | visit_reminder
name String // 技能名称
config Json // 核心配置 JSONSOP 流程图)
isActive Boolean @default(true)
version Int @default(1)
// V2.9 新增:主动触发能力
triggerType String @default("webhook") // 'webhook' | 'cron' | 'event'
cronSchedule String? // Cron 表达式,如 "0 9 * * *" (每天9点)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([projectId, skillType])
@@map("iit_skills")
@@schema("iit_schema")
}
```
**触发类型说明**
| triggerType | 触发方式 | 示例场景 |
|-------------|----------|----------|
| `webhook` | 用户消息触发(默认) | 质控任务、问答查询 |
| `cron` | 定时触发 | 访视提醒、周报生成 |
| `event` | 事件触发(预留) | AE 预警、数据变更通知 |
**Skill 配置示例SOP 流程图)**
```json
{
"name": "肺癌研究入组质控",
"start_node": "baseline_check",
"nodes": {
"baseline_check": {
"type": "hard_rule",
"rules": [
{ "field": "age", "logic": { ">=": [{"var":"age"}, 18] }, "message": "年龄<18岁" },
{ "field": "age", "logic": { "<=": [{"var":"age"}, 75] }, "message": "年龄>75岁" },
{ "field": "ecog", "logic": { "<=": [{"var":"ecog"}, 2] }, "message": "ECOG>2" }
],
"on_pass": "history_check",
"on_fail": "end_with_violation"
},
"history_check": {
"type": "soft_instruction",
"instruction": "检查既往史,排除间质性肺炎、活动性感染、严重心血管疾病。",
"tools": ["read_clinical_data"],
"on_pass": "medication_check",
"on_fail": "end_review_required"
},
"human_review": {
"type": "human_review",
"description": "需要 CRC 人工复核",
"on_approve": "end_success",
"on_reject": "end_rejected"
}
}
}
```
**Cron Skill 配置示例V2.9 新增)**
```json
{
"skillType": "visit_reminder",
"name": "每日访视提醒",
"triggerType": "cron",
"cronSchedule": "0 9 * * *",
"config": {
"start_node": "check_upcoming_visits",
"nodes": {
"check_upcoming_visits": {
"type": "soft_instruction",
"instruction": "查询未来 3 天内到期的访视,生成提醒列表",
"tools": ["read_clinical_data"],
"on_pass": "send_reminder",
"on_fail": "end_no_visits"
},
"send_reminder": {
"type": "soft_instruction",
"instruction": "根据用户画像选择合适的通知方式和语气,发送提醒",
"tools": ["send_message"],
"on_pass": "end_success"
}
}
}
}
```
---
### 2.2 iit_field_mapping - 字段名映射字典
```prisma
model IitFieldMapping {
id String @id @default(uuid())
projectId String // 项目级别映射
aliasName String // LLM 可能传的名称(如 "gender", "性别"
actualName String // REDCap 实际字段名(如 "sex"
createdAt DateTime @default(now())
@@unique([projectId, aliasName])
@@index([projectId])
@@map("iit_field_mapping")
@@schema("iit_schema")
}
```
**初始化示例**
```sql
INSERT INTO iit_field_mapping (project_id, alias_name, actual_name) VALUES
('project-uuid', 'age', 'age_calculated'),
('project-uuid', '年龄', 'age_calculated'),
('project-uuid', 'ecog', 'ecog_score'),
('project-uuid', '既往史', 'medical_history_text'),
('project-uuid', 'history', 'medical_history_text'),
('project-uuid', '性别', 'sex'),
('project-uuid', 'gender', 'sex');
```
---
## 3. Phase 2SOP 执行与记忆表
### 3.1 iit_task_run - SOP 任务执行记录
```prisma
model IitTaskRun {
id String @id @default(uuid())
projectId String
skillId String // 关联的 Skill
recordId String? // 关联的患者(如有)
triggeredBy String // 触发者 userId
status String // RUNNING | SUSPENDED | COMPLETED | FAILED
currentNode String? // 当前执行到的节点
trace Json? // 执行轨迹
resumeCallback String? // SUSPENDED 时,恢复后的下一步
rejectCallback String? // SUSPENDED 被拒绝时的下一步
suspendedAt DateTime?
resumedAt DateTime?
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([projectId, status])
@@index([recordId])
@@map("iit_task_run")
@@schema("iit_schema")
}
```
---
### 3.2 iit_pending_actions - 待处理的违规记录
```prisma
model IitPendingAction {
id String @id @default(uuid())
projectId String
taskRunId String // 来源任务
recordId String? // 关联患者
actionType String // violation | warning | review_required
field String? // 违规字段
message String // 违规描述
severity String // error | warning | info
resolvedBy String? // 处理人
resolvedAt DateTime?
resolution String? // 处理结论
createdAt DateTime @default(now())
@@index([projectId, actionType])
@@index([recordId])
@@map("iit_pending_actions")
@@schema("iit_schema")
}
```
---
### 3.3 iit_conversation_history - 对话历史(流水账)
> **V2.8 设计**:这是原始对话流水,不直接注入 Prompt只用于生成周报
>
> **V2.9 新增**:增加反馈字段,支持用户点赞/点踩
```prisma
model IitConversationHistory {
id String @id @default(uuid())
projectId String
userId String
recordId String? // 关联的患者(如有)
role String // user | assistant
content String @db.Text
intent String? // 识别出的意图类型
entities Json? // 提取的实体 { record_id, visit, ... }
// V2.9 新增:反馈循环
feedback String? // 'thumbs_up' | 'thumbs_down' | null
feedbackReason String? // 点踩原因:'too_long' | 'inaccurate' | 'unclear'
createdAt DateTime @default(now())
@@index([projectId, userId])
@@index([projectId, recordId])
@@index([createdAt])
@@map("iit_conversation_history")
@@schema("iit_schema")
}
```
---
### 3.4 iit_project_memory - 项目级热记忆
> **V2.8 核心表**:存储 Markdown 格式的热记忆,每次对话都注入 System Prompt
>
> **V2.9 扩展**:增加用户画像结构
```prisma
model IitProjectMemory {
id String @id @default(uuid())
projectId String @unique
content String @db.Text // Markdown 格式的热记忆
lastUpdatedBy String // 'system_daily_job' | 'admin_user_id' | 'profiler_job'
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("iit_project_memory")
@@schema("iit_schema")
}
```
**内容示例V2.9 增强版)**
```markdown
# 用户画像 (User Profiles)
## 张医生 (user_id: zhangyi)
- **角色**: PI
- **偏好**: 简洁汇报,只看结论,不要废话
- **关注点**: AE、入组进度
- **最佳通知时间**: 08:30
- **禁令**: 回复不超过 100 字
- **反馈统计**: 👍 12 / 👎 1
## 王护士 (user_id: wanghushi)
- **角色**: CRC
- **偏好**: 详细步骤,需要解释
- **关注点**: 访视安排、数据录入
- **最佳通知时间**: 09:00
# 当前状态 (Active Context)
- 当前阶段:入组冲刺期
- 重点关注P005 患者依从性差,需每日提醒
- 本周目标:完成 3 例入组
- P003 SAE 已判定为"可能无关"2月5日 PI 决策)
# 常见问题 (FAQ)
- 访视窗口V1 Day 1±3, V2 Day 28±7
# 系统禁令 (Rules)
- 严禁在未授权情况下删除数据
- 写操作必须经过人工确认
```
---
## 4. Phase 4周报归档
### 4.1 iit_weekly_reports - 周报归档(历史书)
> **V2.8 核心表**:存储每周的关键决策、进度、踩坑记录
```prisma
model IitWeeklyReport {
id String @id @default(uuid())
projectId String
weekNumber Int // 第几周(从项目开始计算)
weekStart DateTime // 周起始日期
weekEnd DateTime // 周结束日期
summary String @db.Text // Markdown 格式的周报内容
metrics Json? // 结构化指标 { enrolled: 3, queries: 5, ... }
createdBy String // 'system_scheduler' | 'admin_user_id'
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([projectId, weekNumber])
@@index([projectId])
@@map("iit_weekly_reports")
@@schema("iit_schema")
}
```
**内容示例**
```markdown
## Week 5 (2026-02-03 ~ 2026-02-09)
### 进度
- 本周新入组3 例
- 累计入组15 / 30 例
- 完成率50%
### 关键决策
- 2026-02-05: PI 会议决定放宽入排标准,允许 ECOG 3 分患者入组
- 2026-02-07: 确认 P003 AE 与研究药物"可能无关"
### 踩坑记录
- 曾尝试自动录入化验单,因 OCR 精度不足失败,已回退为人工复核
### 待办
- 清理 1 月份遗留的 Query
- 准备 2 月底期中分析数据
```
---
## 5. Phase 5ReAct 追踪表
### 5.1 iit_agent_trace - ReAct 推理轨迹
> 用于调试,不发送给用户,仅在 Admin 后台查看
```prisma
model IitAgentTrace {
id String @id @default(uuid())
projectId String
userId String
query String @db.Text // 用户原始问题
intentType String? // 识别的意图类型
trace Json // ReAct 的完整思考过程
tokenUsage Int? // 消耗的 Token 数
duration Int? // 执行时长ms
success Boolean
createdAt DateTime @default(now())
@@index([projectId, createdAt])
@@index([userId])
@@map("iit_agent_trace")
@@schema("iit_schema")
}
```
---
## 6. Phase 6视觉能力表延后到 V3.0
### 6.1 iit_form_templates - 表单模板
```prisma
model IitFormTemplate {
id String @id @default(uuid())
projectId String
formName String // REDCap 表单名称
fieldSchema Json // 表单字段结构
keywords String[] // 用于匹配的关键词
createdAt DateTime @default(now())
@@map("iit_form_templates")
@@schema("iit_schema")
}
```
---
## 7. 数据库迁移命令
```bash
# 生成迁移
npx prisma db push
# 生成客户端
npx prisma generate
# 查看表结构
npx prisma studio
```
---
## 8. 索引设计总结
| 表 | 索引 | 用途 |
|----|------|------|
| `iit_skills` | `[projectId, skillType]` (unique) | 按项目查询 Skill |
| `iit_field_mapping` | `[projectId, aliasName]` (unique) | 字段映射查询 |
| `iit_task_run` | `[projectId, status]` | 查询运行中/挂起的任务 |
| `iit_conversation_history` | `[projectId, userId]` | 按用户查询对话 |
| `iit_conversation_history` | `[projectId, recordId]` | 按患者查询对话 |
| `iit_conversation_history` | `[createdAt]` | 按时间范围查询 |
| `iit_weekly_reports` | `[projectId, weekNumber]` (unique) | 按周查询报告 |
| `iit_agent_trace` | `[projectId, createdAt]` | 按时间查询调试日志 |
---
**文档维护人**AI Agent
**最后更新**2026-02-05

View File

@@ -0,0 +1,731 @@
# IIT Manager Agent 核心引擎实现指南
> **版本:** V2.9
> **更新日期:** 2026-02-05
> **关联文档:** [IIT Manager Agent V2.6 综合开发计划](./IIT%20Manager%20Agent%20V2.6%20综合开发计划.md)
>
> **V2.9 更新**ReActEngine Prompt 优化支持多意图处理Chain of Thought
---
## 1. 引擎总览
| 引擎 | 职责 | 执行方式 | Phase |
|------|------|----------|-------|
| `HardRuleEngine` | 执行硬规则JSON Logic | CPU 执行,无 LLM | 1 |
| `SoftRuleEngine` | 执行软指令LLM 推理) | LLM + 工具调用 | 2 |
| `SopEngine` | SOP 状态机调度 | 编排 Hard/Soft 引擎 | 2 |
| `ReActEngine` | 多步推理(思考-行动-观察) | LLM + 循环推理 | 5 |
```
┌─────────────────────────────────────────────────────────────────────┐
│ SopEngine (状态机) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ 节点A: HardRuleEngine → 节点B: SoftRuleEngine → 节点C: ... │ │
│ └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ ToolsService (工具层) │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 2. HardRuleEngine - 硬规则引擎
> **文件路径**: `backend/src/modules/iit-manager/engines/HardRuleEngine.ts`
### 2.1 核心职责
- 执行 JSON Logic 规则,无需 LLM
- 返回结构化的违规列表
- 执行时间 < 100ms
### 2.2 完整实现
```typescript
import jsonLogic from 'json-logic-js';
export interface HardRule {
field: string;
logic: object; // JSON Logic 表达式
message: string;
severity?: 'error' | 'warning' | 'info';
}
export interface RuleResult {
field: string;
message: string;
severity: string;
value?: any;
}
export class HardRuleEngine {
/**
* 执行硬规则检查
* @param rules 规则数组
* @param data 待检查的数据
* @returns 违规列表(空数组表示全部通过)
*/
run(rules: HardRule[], data: Record<string, any>): RuleResult[] {
const errors: RuleResult[] = [];
for (const rule of rules) {
try {
const passed = jsonLogic.apply(rule.logic, data);
if (!passed) {
errors.push({
field: rule.field,
message: rule.message,
severity: rule.severity || 'error',
value: data[rule.field]
});
}
} catch (error) {
// 规则执行异常,记录但不中断
errors.push({
field: rule.field,
message: `规则执行异常: ${error.message}`,
severity: 'error'
});
}
}
return errors;
}
/**
* 检查是否全部通过
*/
isAllPassed(rules: HardRule[], data: Record<string, any>): boolean {
return this.run(rules, data).length === 0;
}
}
```
### 2.3 JSON Logic 常用表达式
```javascript
// 范围检查
{ "and": [
{ ">=": [{ "var": "age" }, 18] },
{ "<=": [{ "var": "age" }, 75] }
]}
// 非空检查
{ "!!": { "var": "informed_consent_date" } }
// 日期比较(需自定义操作符)
{ "<=": [{ "var": "icf_date" }, { "var": "enrollment_date" }] }
// 枚举值检查
{ "in": [{ "var": "ecog" }, [0, 1, 2]] }
// 字符串包含
{ "in": ["肺炎", { "var": "medical_history" }] }
```
---
## 3. SoftRuleEngine - 软规则引擎
> **文件路径**: `backend/src/modules/iit-manager/engines/SoftRuleEngine.ts`
### 3.1 核心职责
- 执行需要 LLM 推理的软指令
- 支持工具调用
- 实现自我修正回路(最多 3 次重试)
### 3.2 完整实现
```typescript
import { LLMFactory } from '../../common/llm/adapters/LLMFactory';
import { ToolsService } from '../services/ToolsService';
export interface SoftRuleResult {
passed: boolean;
reason: string;
confidence?: number;
evidence?: any;
}
export class SoftRuleEngine {
private llm = LLMFactory.create('qwen');
private tools: ToolsService;
constructor(tools: ToolsService) {
this.tools = tools;
}
/**
* 执行软指令,带自我修正回路
*/
async runWithRetry(
instruction: string,
context: any,
maxRetries: number = 3
): Promise<SoftRuleResult> {
const systemPrompt = `你是一个临床研究质控专家。请根据以下指令和数据进行判断。
指令: ${instruction}
请返回 JSON 格式:
{
"passed": true/false,
"reason": "判断理由",
"confidence": 0.0-1.0,
"evidence": "支持判断的证据"
}`;
let history: Message[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: `数据: ${JSON.stringify(context)}` }
];
for (let i = 0; i < maxRetries; i++) {
const response = await this.llm.chat(history, {
tools: this.tools.getToolDefinitions()
});
// AI 决定调用工具
if (response.toolCalls && response.toolCalls.length > 0) {
for (const toolCall of response.toolCalls) {
try {
const result = await this.tools.executeTool(
toolCall.name,
toolCall.args
);
history.push({
role: 'tool',
toolCallId: toolCall.id,
content: JSON.stringify(result)
});
} catch (error) {
// ⚠️ 自我修正:告诉 LLM 它错了
history.push({
role: 'user',
content: `工具调用失败: ${error.message}。请检查参数并重试,或直接根据已有信息判断。`
});
continue;
}
}
} else {
// AI 返回最终答案
return this.parseResult(response.content);
}
}
return {
passed: false,
reason: '多次重试后仍失败,需人工复核',
confidence: 0
};
}
private parseResult(content: string): SoftRuleResult {
try {
// 提取 JSON可能被 Markdown 包裹)
const jsonMatch = content.match(/\{[\s\S]*\}/);
if (jsonMatch) {
return JSON.parse(jsonMatch[0]);
}
} catch (e) {
// 解析失败
}
// 回退:尝试从文本推断
const passed = content.includes('通过') || content.includes('符合');
return {
passed,
reason: content.slice(0, 200),
confidence: 0.5
};
}
}
```
---
## 4. SopEngine - SOP 状态机引擎
> **文件路径**: `backend/src/modules/iit-manager/engines/SopEngine.ts`
### 4.1 核心职责
- 解析 Skill 配置中的 SOP 流程图
- 按顺序执行节点Hard → Soft → Human Review
- 实现状态持久化(防止服务重启丢失进度)
- 实现 SUSPENDED 挂起机制(解决"死锁"风险)
### 4.2 类型定义
```typescript
interface SopConfig {
name: string;
start_node: string;
nodes: {
[nodeId: string]: SopNode;
};
}
interface SopNode {
type: 'hard_rule' | 'soft_instruction' | 'human_review';
// hard_rule 类型
rules?: HardRule[];
// soft_instruction 类型
instruction?: string;
tools?: string[];
// human_review 类型
description?: string;
// 流转
on_pass: string;
on_fail: string;
on_approve?: string; // human_review 专用
on_reject?: string; // human_review 专用
on_error?: string;
}
interface SopResult {
status: 'COMPLETED' | 'SUSPENDED' | 'FAILED';
finalState: string;
trace: TraceItem[];
taskRunId?: string;
message?: string;
}
interface TraceItem {
node: string;
timestamp: Date;
result?: any;
}
```
### 4.3 完整实现
```typescript
import PgBoss from 'pg-boss';
import { prisma } from '../../common/prisma';
import { HardRuleEngine } from './HardRuleEngine';
import { SoftRuleEngine } from './SoftRuleEngine';
export class SopEngine {
private hardEngine: HardRuleEngine;
private softEngine: SoftRuleEngine;
private pgBoss: PgBoss;
constructor(
hardEngine: HardRuleEngine,
softEngine: SoftRuleEngine,
pgBoss: PgBoss
) {
this.hardEngine = hardEngine;
this.softEngine = softEngine;
this.pgBoss = pgBoss;
}
/**
* 执行 SOP 流程
*/
async run(
skillConfig: SopConfig,
data: any,
taskRunId?: string
): Promise<SopResult> {
// 创建或恢复任务记录
const task = taskRunId
? await this.resumeTask(taskRunId)
: await this.createTask(skillConfig, data);
let currentNodeId = task.currentNode || skillConfig.start_node;
let context = { ...data };
const trace: TraceItem[] = task.trace ? JSON.parse(task.trace) : [];
while (currentNodeId && !currentNodeId.startsWith('end')) {
const node = skillConfig.nodes[currentNodeId];
trace.push({ node: currentNodeId, timestamp: new Date() });
// ⚠️ 每步持久化,防止服务重启丢失进度
await prisma.iitTaskRun.update({
where: { id: task.id },
data: {
currentNode: currentNodeId,
trace: JSON.stringify(trace),
updatedAt: new Date()
}
});
// 检查是否需要人工介入
if (node.type === 'human_review') {
return await this.handleHumanReview(task.id, node, data, trace);
}
// 执行节点
let result: NodeResult;
try {
if (node.type === 'hard_rule') {
const errors = this.hardEngine.run(node.rules || [], context);
result = { passed: errors.length === 0, errors };
} else {
result = await this.softEngine.runWithRetry(
node.instruction || '',
context
);
}
} catch (error) {
// 执行异常,走 on_error 分支
currentNodeId = node.on_error || 'end_error';
continue;
}
// 记录违规
if (!result.passed) {
await this.savePendingAction(task.id, data.recordId, result);
}
// 状态流转
currentNodeId = result.passed ? node.on_pass : node.on_fail;
}
// 完成任务
await prisma.iitTaskRun.update({
where: { id: task.id },
data: {
status: 'COMPLETED',
currentNode: currentNodeId,
completedAt: new Date()
}
});
return {
status: 'COMPLETED',
finalState: currentNodeId,
trace
};
}
/**
* ⚠️ 处理人工复核节点 - SUSPENDED 挂起机制
*/
private async handleHumanReview(
taskRunId: string,
node: SopNode,
data: any,
trace: TraceItem[]
): Promise<SopResult> {
// 挂起任务,不再占用 Worker
await prisma.iitTaskRun.update({
where: { id: taskRunId },
data: {
status: 'SUSPENDED',
suspendedAt: new Date(),
resumeCallback: node.on_approve,
rejectCallback: node.on_reject || 'end_rejected'
}
});
// 通知相关人员
await this.notifyReviewRequired(data, node);
return {
status: 'SUSPENDED',
finalState: 'human_review',
trace,
taskRunId,
message: '任务已挂起,等待人工复核'
};
}
/**
* ⚠️ 唤醒机制 - CRC 确认后继续执行
*/
async resumeFromSuspended(
taskRunId: string,
decision: 'approve' | 'reject'
): Promise<void> {
const task = await prisma.iitTaskRun.findUnique({
where: { id: taskRunId }
});
if (!task || task.status !== 'SUSPENDED') {
throw new Error('任务不在挂起状态');
}
const nextNode = decision === 'approve'
? task.resumeCallback
: task.rejectCallback || 'end_rejected';
// 更新状态
await prisma.iitTaskRun.update({
where: { id: taskRunId },
data: {
status: 'RUNNING',
currentNode: nextNode,
resumedAt: new Date()
}
});
// 创建新的 Job 继续执行
await this.pgBoss.send('sop-continue', { taskRunId });
}
// ... 辅助方法省略
}
```
---
## 5. ReActEngine - 多步推理引擎
> **文件路径**: `backend/src/modules/iit-manager/engines/ReActEngine.ts`
### 5.1 核心职责
- 处理模糊查询,支持多步推理
- 循环执行"思考 → 行动 → 观察"
- **只允许调用只读工具**(安全约束)
- **只返回 Final Answer**(解决"多嘴"问题)
- **V2.9 新增**:支持多意图处理(用户一句话包含多个任务)
### 5.2 安全约束
```typescript
// 工具白名单ReAct 只能调用只读工具
private readonly READONLY_TOOLS = [
'read_clinical_data',
'search_protocol',
'get_project_stats',
'check_visit_window'
];
// 资源限制
private maxIterations = 5; // 最大迭代次数
private maxTokens = 4000; // Token 预算
```
### 5.3 完整实现
```typescript
import { LLMFactory } from '../../common/llm/adapters/LLMFactory';
import { ToolsService } from '../services/ToolsService';
import { prisma } from '../../common/prisma';
export interface ReActResult {
success: boolean;
content: string;
trace: TraceItem[];
}
interface TraceItem {
iteration: number;
thought?: string;
action?: string;
observation?: string;
}
export class ReActEngine {
private llm = LLMFactory.create('qwen');
private tools: ToolsService;
private readonly READONLY_TOOLS = [
'read_clinical_data',
'search_protocol',
'get_project_stats',
'check_visit_window'
];
private maxIterations = 5;
private maxTokens = 4000;
private tokenCounter = 0;
constructor(tools: ToolsService) {
this.tools = tools;
}
async run(query: string, context: AgentContext): Promise<ReActResult> {
this.tokenCounter = 0;
// V2.9 优化:支持多意图处理的 Prompt
const systemPrompt = `你是一个临床研究智能助手。你可以使用以下工具回答问题:
${this.formatToolDescriptions(this.READONLY_TOOLS)}
请按照 ReAct 模式思考:
1. 思考:分析问题,决定下一步
2. 行动:调用工具获取信息
3. 观察:查看工具返回结果
4. 重复以上步骤,直到能回答用户问题
## 多任务处理原则 (V2.9)
当用户的消息包含多个任务时,请遵循以下步骤:
**Step 1: 意图拆解**
- 识别用户消息中的所有独立意图
- 按依赖关系排序:先处理前置任务
- 示例:"帮我查一下 P003 的 ECOG然后录入今天的访视数据"
→ 意图1: 查询 P003 ECOG只读
→ 意图2: 录入访视数据(需要引导)
**Step 2: 顺序执行**
- 每次只聚焦处理一个意图
- 完成后明确告知用户,并继续下一个
- 遇到写操作,暂停并引导用户确认
**Step 3: 统一回复**
- 在最终回复中按顺序总结所有任务结果
- 格式:
1. [任务1] 已完成 / 结果:...
2. [任务2] 需要确认 / 引导操作
注意:你只能查询数据,不能修改数据。如果用户需要修改操作,请引导他们使用正式的质控流程。`;
let messages: Message[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: query }
];
const trace: TraceItem[] = [];
for (let i = 0; i < this.maxIterations; i++) {
// Token 预算检查
if (this.tokenCounter > this.maxTokens) {
return {
success: false,
content: '抱歉,这个问题比较复杂,请尝试更具体的描述。',
trace
};
}
const response = await this.llm.chat(messages, {
tools: this.getReadonlyToolDefinitions()
});
this.tokenCounter += response.usage?.total_tokens || 0;
trace.push({ iteration: i, thought: response.content });
// AI 决定结束,返回 Final Answer
if (!response.toolCalls || response.toolCalls.length === 0) {
return { success: true, content: response.content, trace };
}
// 执行工具调用
let errorCount = 0;
for (const toolCall of response.toolCalls) {
// ⚠️ 安全检查:只允许只读工具
if (!this.READONLY_TOOLS.includes(toolCall.name)) {
messages.push({
role: 'tool',
toolCallId: toolCall.id,
content: `错误:工具 ${toolCall.name} 不在允许列表中。你只能使用只读工具查询数据。如果需要修改数据,请引导用户使用"质控"命令。`
});
errorCount++;
continue;
}
try {
const result = await this.tools.executeTool(toolCall.name, toolCall.args);
messages.push({
role: 'tool',
toolCallId: toolCall.id,
content: JSON.stringify(result)
});
trace[i].observation = JSON.stringify(result).slice(0, 200);
} catch (error) {
errorCount++;
messages.push({
role: 'tool',
toolCallId: toolCall.id,
content: `工具调用失败: ${error.message}`
});
}
}
// ⚠️ 幻觉熔断:连续 2 次工具调用失败
if (errorCount >= 2) {
return {
success: false,
content: '抱歉,我遇到了一些技术问题,无法获取相关信息。请稍后重试或联系管理员。',
trace
};
}
}
return {
success: false,
content: '抱歉,我无法在有限步骤内完成这个查询。请尝试更具体的问题。',
trace
};
}
/**
* ⚠️ 保存 Trace 到数据库(仅供 Admin 调试)
*/
async saveTrace(
projectId: string,
userId: string,
query: string,
result: ReActResult
): Promise<void> {
await prisma.iitAgentTrace.create({
data: {
projectId,
userId,
query,
trace: result.trace,
tokenUsage: this.tokenCounter,
success: result.success,
createdAt: new Date()
}
});
}
private getReadonlyToolDefinitions() {
return this.tools.getToolDefinitions()
.filter(t => this.READONLY_TOOLS.includes(t.name));
}
private formatToolDescriptions(toolNames: string[]): string {
return toolNames.map(name => {
const def = this.tools.getToolDefinition(name);
return `- ${name}: ${def?.description || ''}`;
}).join('\n');
}
}
```
---
## 6. 引擎集成示意
```typescript
// 初始化
const hardEngine = new HardRuleEngine();
const toolsService = new ToolsService(redcapAdapter, difyClient);
const softEngine = new SoftRuleEngine(toolsService);
const sopEngine = new SopEngine(hardEngine, softEngine, pgBoss);
const reactEngine = new ReActEngine(toolsService);
// 在 ChatService 中使用
async handleMessage(userId: string, message: string) {
const intent = await this.intentService.detect(message);
if (intent.type === 'QC_TASK') {
// 走 SOP 引擎
return await this.sopEngine.run(skillConfig, data);
} else if (intent.type === 'QA_QUERY') {
// 走 ReAct 引擎
const result = await this.reactEngine.run(message, context);
// ⚠️ 只返回 Final Answer不返回中间思考
await this.reactEngine.saveTrace(projectId, userId, message, result);
return result.content;
}
}
```
---
**文档维护人**AI Agent
**最后更新**2026-02-05

View File

@@ -0,0 +1,552 @@
# IIT Manager Agent 记忆系统实现指南 (V2.8)
> **版本:** V2.8
> **更新日期:** 2026-02-05
> **关联文档:** [IIT Manager Agent V2.6 综合开发计划](./IIT%20Manager%20Agent%20V2.6%20综合开发计划.md)
---
## 1. 记忆架构概览
### 1.1 设计原则
临床研究项目周期长达 1-3 年,需要"项目级长期记忆"来跨会话保持上下文。V2.8 架构采用**三层记忆体系**
| 层级 | 名称 | 存储位置 | 生命周期 | 检索方式 |
|------|------|----------|----------|----------|
| L1 | 流水账 | conversation_history | 30天 | 按需向量检索 |
| L2 | 热记忆 | project_memory | 持久 | 每次注入 |
| L3 | 历史书 | weekly_reports | 持久 | 按意图检索 |
> **注意**:用户偏好和患者关键信息统一存储在 `project_memory` 的 Markdown 中,无需单独表。
### 1.2 架构图
```
┌─────────────────────────────────────────────────────────────────────┐
│ MemoryService │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────────────┐ │
│ │ 流水账(L1) │ │ 热记忆(L2) │ │ 历史书(L3) │ │
│ │ conversation_ │ │ project_memory │ │ weekly_reports │ │
│ │ history │ │ │ │ │ │
│ │ │ │ - 项目元信息 │ │ - 周报卷叠 │ │
│ │ 30天自动过期 │ │ - 当前状态 │ │ - 关键决策归档 │ │
│ │ 向量化存储 │ │ - 关键决策 │ │ │ │
│ └────────────────┘ └────────────────┘ └────────────────────────┘ │
│ │ │ │ │
│ └───────────────────┴───────────────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ getContext │ │
│ │ ForPrompt() │ │
│ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 2. 数据模型
### 2.1 流水账 (conversation_history)
```prisma
model iit_conversation_history {
id String @id @default(cuid())
project_id String
user_id String
role String // 'user' | 'assistant'
content String
intent String? // 意图标记
embedding Unsupported("vector(1536)")?
created_at DateTime @default(now())
expires_at DateTime // 30天后过期
@@index([project_id, user_id, created_at])
@@index([project_id, expires_at])
}
```
### 2.2 热记忆 (project_memory)
```prisma
model iit_project_memory {
id String @id @default(cuid())
project_id String
type String // 'meta' | 'status' | 'decision' | 'preference'
key String
value Json
priority Int @default(0) // 优先级,高的先注入
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@unique([project_id, type, key])
@@index([project_id, type])
}
```
### 2.3 历史书 - 周报 (weekly_reports)
```prisma
model iit_weekly_reports {
id String @id @default(cuid())
project_id String
week_start DateTime
week_end DateTime
summary String // 周报摘要Markdown
key_events Json // 关键事件 JSON
metrics Json // 统计指标
embedding Unsupported("vector(1536)")?
created_at DateTime @default(now())
@@unique([project_id, week_start])
@@index([project_id, week_start])
}
```
---
## 3. MemoryService 完整实现
> **文件路径**: `backend/src/modules/iit-manager/services/MemoryService.ts`
```typescript
import { prisma } from '../../common/prisma';
import { OpenAIEmbeddings } from '../../common/llm/embeddings';
import { LLMFactory } from '../../common/llm/adapters/LLMFactory';
export class MemoryService {
private embeddings: OpenAIEmbeddings;
private llm = LLMFactory.create('qwen');
constructor() {
this.embeddings = new OpenAIEmbeddings();
}
// ===== 1. 流水账操作 =====
async saveConversation(data: {
projectId: string;
userId: string;
role: 'user' | 'assistant';
content: string;
intent?: string;
}): Promise<void> {
const embedding = await this.embeddings.embed(data.content);
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + 30);
await prisma.iit_conversation_history.create({
data: {
project_id: data.projectId,
user_id: data.userId,
role: data.role,
content: data.content,
intent: data.intent,
embedding: embedding,
expires_at: expiresAt
}
});
}
async searchConversations(
projectId: string,
query: string,
limit: number = 5
): Promise<ConversationResult[]> {
const queryEmbedding = await this.embeddings.embed(query);
const results = await prisma.$queryRaw<ConversationResult[]>`
SELECT id, content, role, intent, created_at,
1 - (embedding <=> ${queryEmbedding}::vector) as similarity
FROM iit_conversation_history
WHERE project_id = ${projectId}
AND expires_at > NOW()
ORDER BY embedding <=> ${queryEmbedding}::vector
LIMIT ${limit}
`;
return results;
}
// ===== 2. 热记忆操作 =====
async getHotMemory(projectId: string): Promise<HotMemory> {
const memories = await prisma.iit_project_memory.findMany({
where: { project_id: projectId },
orderBy: { priority: 'desc' }
});
return {
meta: memories.filter(m => m.type === 'meta'),
status: memories.filter(m => m.type === 'status'),
decisions: memories.filter(m => m.type === 'decision'),
preferences: memories.filter(m => m.type === 'preference')
};
}
async updateHotMemory(
projectId: string,
type: string,
key: string,
value: any,
priority: number = 0
): Promise<void> {
await prisma.iit_project_memory.upsert({
where: {
project_id_type_key: { project_id: projectId, type, key }
},
update: { value, priority },
create: {
project_id: projectId,
type,
key,
value,
priority
}
});
}
async refreshHotMemory(projectId: string): Promise<void> {
// 从最近的对话中提取关键信息更新热记忆
const recentConversations = await prisma.iit_conversation_history.findMany({
where: { project_id: projectId },
orderBy: { created_at: 'desc' },
take: 50
});
if (recentConversations.length === 0) return;
// 使用 LLM 提取关键信息
const prompt = `分析以下对话,提取需要长期记住的关键信息:
${recentConversations.map(c => `${c.role}: ${c.content}`).join('\n')}
请提取以下类别的信息JSON格式
1. status: 项目当前状态变化
2. decisions: 重要决策
3. preferences: 用户偏好
返回格式:
{
"status": [{"key": "...", "value": "...", "priority": 0-10}],
"decisions": [...],
"preferences": [...]
}`;
const response = await this.llm.chat([{ role: 'user', content: prompt }]);
try {
const extracted = JSON.parse(response.content);
for (const [type, items] of Object.entries(extracted)) {
for (const item of items as any[]) {
await this.updateHotMemory(projectId, type, item.key, item.value, item.priority);
}
}
} catch (e) {
console.error('[MemoryService] 热记忆提取失败:', e);
}
}
// ===== 3. 历史书操作 =====
async saveWeeklyReport(projectId: string, report: string): Promise<void> {
const weekStart = this.getWeekStart();
const weekEnd = new Date(weekStart);
weekEnd.setDate(weekStart.getDate() + 6);
const embedding = await this.embeddings.embed(report);
await prisma.iit_weekly_reports.upsert({
where: {
project_id_week_start: { project_id: projectId, week_start: weekStart }
},
update: {
summary: report,
embedding
},
create: {
project_id: projectId,
week_start: weekStart,
week_end: weekEnd,
summary: report,
key_events: {},
metrics: {},
embedding
}
});
}
async searchWeeklyReports(
projectId: string,
query: string,
limit: number = 3
): Promise<WeeklyReport[]> {
const queryEmbedding = await this.embeddings.embed(query);
return prisma.$queryRaw<WeeklyReport[]>`
SELECT id, week_start, week_end, summary,
1 - (embedding <=> ${queryEmbedding}::vector) as similarity
FROM iit_weekly_reports
WHERE project_id = ${projectId}
ORDER BY embedding <=> ${queryEmbedding}::vector
LIMIT ${limit}
`;
}
async rollupWeeklyMemory(projectId: string): Promise<void> {
const weekStart = this.getWeekStart();
const weekEnd = new Date(weekStart);
weekEnd.setDate(weekStart.getDate() + 6);
// 获取本周对话
const conversations = await prisma.iit_conversation_history.findMany({
where: {
project_id: projectId,
created_at: { gte: weekStart, lte: weekEnd }
},
orderBy: { created_at: 'asc' }
});
if (conversations.length === 0) return;
// 使用 LLM 生成周报摘要
const prompt = `你是一个临床研究项目的记录员。请根据本周的对话记录,生成一份周报摘要。
对话记录:
${conversations.map(c => `[${c.created_at.toISOString()}] ${c.role}: ${c.content}`).join('\n')}
要求:
1. 提取关键事件和决策
2. 统计主要指标
3. 记录重要问题和解决方案
4. 简洁明了不超过500字`;
const response = await this.llm.chat([{ role: 'user', content: prompt }]);
await this.saveWeeklyReport(projectId, response.content);
}
// ===== 4. 意图驱动的上下文组装 =====
async getContextForPrompt(
projectId: string,
intent: IntentResult
): Promise<string> {
const parts: string[] = [];
// ⚠️ L2 热记忆:始终注入
const hotMemory = await this.getHotMemory(projectId);
parts.push(this.formatHotMemory(hotMemory));
// ⚠️ L3 历史书:按意图检索
if (intent.type === 'QA_QUERY') {
// 模糊查询需要历史上下文
const relatedReports = await this.searchWeeklyReports(projectId, intent.entities?.query || '', 2);
if (relatedReports.length > 0) {
parts.push('## 相关历史记录\n' + relatedReports.map(r => r.summary).join('\n---\n'));
}
}
// ⚠️ L1 流水账:仅按需检索(当历史书不足时)
if (parts.length < 3 && intent.type === 'QA_QUERY') {
const relatedConversations = await this.searchConversations(projectId, intent.entities?.query || '', 3);
if (relatedConversations.length > 0) {
parts.push('## 相关对话记录\n' + relatedConversations.map(c => `${c.role}: ${c.content}`).join('\n'));
}
}
return parts.join('\n\n');
}
private formatHotMemory(hotMemory: HotMemory): string {
const sections: string[] = [];
if (hotMemory.meta.length > 0) {
sections.push('## 项目信息\n' + hotMemory.meta.map(m => `- ${m.key}: ${JSON.stringify(m.value)}`).join('\n'));
}
if (hotMemory.status.length > 0) {
sections.push('## 当前状态\n' + hotMemory.status.map(s => `- ${s.key}: ${JSON.stringify(s.value)}`).join('\n'));
}
if (hotMemory.decisions.length > 0) {
sections.push('## 关键决策\n' + hotMemory.decisions.map(d => `- ${d.key}: ${JSON.stringify(d.value)}`).join('\n'));
}
return sections.join('\n\n');
}
private getWeekStart(): Date {
const now = new Date();
const weekStart = new Date(now);
weekStart.setDate(now.getDate() - now.getDay() + 1);
weekStart.setHours(0, 0, 0, 0);
return weekStart;
}
// ===== 5. 清理过期数据 =====
async cleanupExpiredData(): Promise<void> {
await prisma.iit_conversation_history.deleteMany({
where: { expires_at: { lt: new Date() } }
});
}
}
// ===== 类型定义 =====
interface HotMemory {
meta: Array<{ key: string; value: any }>;
status: Array<{ key: string; value: any }>;
decisions: Array<{ key: string; value: any }>;
preferences: Array<{ key: string; value: any }>;
}
interface ConversationResult {
id: string;
content: string;
role: string;
intent: string | null;
created_at: Date;
similarity: number;
}
interface WeeklyReport {
id: string;
week_start: Date;
week_end: Date;
summary: string;
similarity: number;
}
interface IntentResult {
type: string;
entities?: {
record_id?: string;
query?: string;
};
}
```
---
## 4. 记忆信息映射
### 4.1 信息类型与存储位置
| 信息类型 | 存储位置 | 更新机制 |
|----------|----------|----------|
| 项目名称、PI、入组目标 | project_memory (meta) | 初始化时写入 |
| 当前入组人数、进度百分比 | project_memory (status) | 每日定时更新 |
| 用户做出的关键决策 | project_memory (decision) | 对话中实时提取 |
| 用户偏好设置 | project_memory (preference) | 用户明确表达时 |
| 每次对话原文 | conversation_history | 对话实时写入 |
| 每周总结 | weekly_reports | 周一凌晨卷叠 |
| 患者特殊情况 | project_memory (当前状态) | 在热记忆中维护 |
### 4.2 检索策略
```
┌─────────────────────────────────────────────────────────────┐
│ 意图识别结果 │
└───────────────────────────┬─────────────────────────────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
QC_TASK QA_QUERY PROTOCOL_QA
│ │ │
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 热记忆 + SOP │ │热记忆 + 历史书│ │ 热记忆 + RAG │
│ 状态同步 │ │ + 流水账检索 │ │ 知识库检索 │
└──────────────┘ └──────────────┘ └──────────────┘
```
---
## 5. 性能优化建议
### 5.1 索引设计
```sql
-- 向量索引(用于相似度搜索)
CREATE INDEX idx_conversation_embedding
ON iit_conversation_history
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
CREATE INDEX idx_weekly_reports_embedding
ON iit_weekly_reports
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 50);
-- 复合索引(用于过滤)
CREATE INDEX idx_conversation_project_user_time
ON iit_conversation_history (project_id, user_id, created_at DESC);
```
### 5.2 缓存策略
```typescript
// 热记忆缓存(使用 Redis
class MemoryCache {
private redis: Redis;
async getHotMemory(projectId: string): Promise<HotMemory | null> {
const cached = await this.redis.get(`hot_memory:${projectId}`);
return cached ? JSON.parse(cached) : null;
}
async setHotMemory(projectId: string, memory: HotMemory): Promise<void> {
await this.redis.set(
`hot_memory:${projectId}`,
JSON.stringify(memory),
'EX', 300 // 5分钟缓存
);
}
}
```
### 5.3 Token 预算控制
```typescript
// 限制记忆上下文的 token 数量
async getContextForPrompt(projectId: string, intent: IntentResult): Promise<string> {
const MAX_TOKENS = 2000;
let context = '';
let tokenCount = 0;
// 优先注入热记忆
const hotMemory = await this.getHotMemory(projectId);
const hotMemoryStr = this.formatHotMemory(hotMemory);
tokenCount += this.estimateTokens(hotMemoryStr);
context += hotMemoryStr;
// 按优先级继续添加
if (tokenCount < MAX_TOKENS) {
// 添加历史书内容...
}
return context;
}
```
---
## 6. 验收标准
| 功能 | 验收标准 |
|------|----------|
| 流水账存储 | 对话消息 100ms 内写入成功 |
| 向量检索 | 相似度搜索 500ms 内返回 |
| 热记忆注入 | 每次请求正确注入项目上下文 |
| 周报卷叠 | 周一凌晨自动生成周报 |
| 过期清理 | 30天前的对话自动删除 |
---
**文档维护人**AI Agent
**最后更新**2026-02-05

View File

@@ -0,0 +1,281 @@
# IIT Manager Agent 开发阶段与任务清单
> **版本:** V2.9
> **更新日期:** 2026-02-05
> **关联文档:** [IIT Manager Agent V2.6 综合开发计划](./IIT%20Manager%20Agent%20V2.6%20综合开发计划.md)
>
> **V2.9 更新**
> - Phase 3 新增反馈循环任务
> - Phase 4 新增 ProfilerService 和 Cron Skill 任务
> - Phase 5 新增多意图处理任务
---
## 1. 开发阶段总览
```
Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 基础工具层 │ ──▶ │ SOP 引擎 │ ──▶ │ ReAct 引擎 │ ──▶ │ 调度系统 │ ──▶ │ 智能路由 │ ──▶ │ 视觉能力 │
│ │ │ + 记忆L2 │ │ + 记忆L1 │ │ + 记忆L3 │ │ │ │ (延后) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
▼ ▼ ▼ ▼ ▼ ▼
ToolsService SopEngine ReActEngine SchedulerService IntentService VisionService
FieldMapping HotMemory FlowMemory WeeklyReports MixedRouting (Postponed)
HardRuleEngine SoftRuleEngine AgentTrace ReportService StreamingFB
```
---
## 2. Phase 1: 基础工具层
### 2.1 目标
- 搭建可复用的工具框架
- 实现字段映射机制
- 建立硬规则引擎
### 2.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P1-01 | 创建 `iit_skills` 表 | 高 | 待开始 | - |
| P1-02 | 创建 `iit_field_mapping` 表 | 高 | 待开始 | - |
| P1-03 | 实现 `ToolsService` | 高 | 待开始 | P1-01 |
| P1-04 | 实现 `read_clinical_data` 工具 | 高 | 待开始 | P1-03 |
| P1-05 | 实现 `search_protocol` 工具 | 高 | 待开始 | P1-03 |
| P1-06 | 实现 `HardRuleEngine` | 高 | 待开始 | - |
| P1-07 | 集成字段映射到 ToolsService | 中 | 待开始 | P1-02, P1-03 |
| P1-08 | 单元测试覆盖 | 中 | 待开始 | P1-01~P1-07 |
### 2.3 验收标准
- [ ] 工具可通过名称调用
- [ ] 字段映射正确生效LLM 用 "年龄" → 实际调用 "dem_age"
- [ ] 硬规则拦截生效
- [ ] 测试覆盖率 > 80%
---
## 3. Phase 2: SOP 引擎 + 热记忆
### 3.1 目标
- 实现状态机驱动的 SOP 执行
- 搭建热记忆层L2
- 支持人工确认机制
### 3.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P2-01 | 创建 `iit_task_run` 表 | 高 | 待开始 | - |
| P2-02 | 创建 `iit_pending_actions` 表 | 高 | 待开始 | - |
| P2-03 | 创建 `iit_project_memory` 表 | 高 | 待开始 | - |
| P2-04 | 实现 `SopEngine` 核心状态机 | 高 | 待开始 | P2-01 |
| P2-05 | 实现 `SoftRuleEngine` | 高 | 待开始 | - |
| P2-06 | 集成 SoftRuleEngine 到 SOP | 高 | 待开始 | P2-04, P2-05 |
| P2-07 | 实现 SUSPENDED 状态机制 | 高 | 待开始 | P2-04 |
| P2-08 | 实现人工确认流程 | 高 | 待开始 | P2-02, P2-07 |
| P2-09 | 实现 `MemoryService` 热记忆 | 中 | 待开始 | P2-03 |
| P2-10 | 集成热记忆到 SOP 上下文 | 中 | 待开始 | P2-04, P2-09 |
| P2-11 | 端到端测试:质控 SOP | 中 | 待开始 | P2-01~P2-10 |
### 3.3 验收标准
- [ ] 质控任务可自动执行完整 SOP
- [ ] 写操作正确等待人工确认
- [ ] SUSPENDED 状态正确持久化
- [ ] 热记忆正确注入 SOP 上下文
- [ ] 手动恢复执行成功
---
## 4. Phase 3: ReAct 引擎 + 流水账
### 4.1 目标
- 实现 ReAct 模式的灵活查询
- 搭建流水账层L1
- 实现只读安全约束
### 4.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P3-01 | 创建 `iit_conversation_history` 表 | 高 | 待开始 | - |
| P3-02 | 创建 `iit_agent_trace` 表 | 中 | 待开始 | - |
| P3-03 | 实现 `ReActEngine` 核心循环 | 高 | 待开始 | P1-03 |
| P3-04 | 实现只读工具白名单 | 高 | 待开始 | P3-03 |
| P3-05 | 实现 `MemoryService` 流水账 | 高 | 待开始 | P3-01 |
| P3-06 | 实现向量化存储pgvector | 中 | 待开始 | P3-05 |
| P3-07 | 实现相似度检索 | 中 | 待开始 | P3-06 |
| P3-08 | 实现 Trace 记录机制 | 中 | 待开始 | P3-02, P3-03 |
| P3-09 | 实现流式反馈机制 | 高 | 待开始 | P3-03 |
| P3-10 | 实现 "正在思考" 状态提示 | 中 | 待开始 | P3-09 |
| P3-11 | 集成流水账到 ReAct 上下文 | 中 | 待开始 | P3-03, P3-05 |
| P3-12 | **[V2.9]** 扩展对话表支持反馈字段 | 中 | 待开始 | P3-01 |
| P3-13 | **[V2.9]** 实现反馈收集接口 | 中 | 待开始 | P3-12 |
| P3-14 | 端到端测试:模糊查询 | 中 | 待开始 | P3-01~P3-13 |
### 4.3 验收标准
- [ ] ReAct 可正确推理并调用工具
- [ ] 只读约束生效(无法调用写入工具)
- [ ] 流水账正确存储和检索
- [ ] Trace 记录可供调试
- [ ] 流式反馈 < 2秒首字节
- [ ] "正在思考" 状态正确显示
- [ ] **[V2.9]** 反馈按钮可正确收集用户反馈
---
## 5. Phase 4: 调度系统 + 历史书
### 5.1 目标
- 实现定时任务调度
- 实现周报生成
- 搭建历史书层L3
### 5.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P4-01 | 创建 `iit_weekly_reports` 表 | 高 | 待开始 | - |
| P4-02 | 实现 `SchedulerService`pg-boss | 高 | 待开始 | - |
| P4-03 | 实现 `ReportService` | 高 | 待开始 | P4-01 |
| P4-04 | 实现周报自动生成 | 高 | 待开始 | P4-02, P4-03 |
| P4-05 | 实现记忆卷叠机制 | 中 | 待开始 | P4-01, P3-05 |
| P4-06 | 实现历史书检索 | 中 | 待开始 | P4-01 |
| P4-07 | 集成历史书到上下文组装 | 中 | 待开始 | P4-06 |
| P4-08 | **[V2.9]** 实现 `ProfilerService` | 中 | 待开始 | P2-03 |
| P4-09 | **[V2.9]** 扩展 Skill 表支持 Cron 触发 | 中 | 待开始 | P1-01 |
| P4-10 | **[V2.9]** 实现 Cron Skill 调度 | 中 | 待开始 | P4-02, P4-09 |
| P4-11 | **[V2.9]** 实现访视提醒 Skill | 中 | 待开始 | P4-10 |
| P4-12 | **[V2.9]** 集成用户画像到通知个性化 | 低 | 待开始 | P4-08, P4-11 |
| P4-13 | 端到端测试:周报生成 | 中 | 待开始 | P4-01~P4-12 |
### 5.3 验收标准
- [ ] 周报每周一自动生成
- [ ] 记忆卷叠每日自动执行
- [ ] 历史书检索正确召回
- [ ] **[V2.9]** 用户画像正确存储在 project_memory
- [ ] **[V2.9]** Cron Skill 按时触发
- [ ] **[V2.9]** 访视提醒正确发送给目标用户
---
## 6. Phase 5: 智能路由
### 6.1 目标
- 实现意图识别服务
- 实现混合路由(正则 + LLM
- 实现追问机制
### 6.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P5-01 | 实现 `IntentService` | 高 | 待开始 | - |
| P5-02 | 实现正则快速通道 | 高 | 待开始 | P5-01 |
| P5-03 | 实现 LLM 意图识别 | 高 | 待开始 | P5-01 |
| P5-04 | 实现降级策略 | 中 | 待开始 | P5-01~P5-03 |
| P5-05 | 实现追问机制 | 中 | 待开始 | P5-01 |
| P5-06 | 扩展 `ChatService` 集成路由 | 高 | 待开始 | P5-01~P5-05 |
| P5-07 | **[V2.9]** 优化 ReAct Prompt 支持多意图 | 中 | 待开始 | P3-03 |
| P5-08 | 端到端测试:路由分发 | 中 | 待开始 | P5-01~P5-07 |
### 6.3 验收标准
- [ ] 简单指令 < 50ms 命中快速通道
- [ ] 复杂句子正确识别意图
- [ ] UNCLEAR 情况正确追问
- [ ] LLM 不可用时正确降级
- [ ] **[V2.9]** 多意图消息正确拆分并顺序执行
---
## 7. Phase 6: 视觉能力(延后)
> ⚠️ **注意**:根据风险评估,视觉能力延后到核心功能稳定后再开发。
### 7.1 目标
- 实现图片识别能力
- 支持知情同意书识别
- 支持 CRF 扫描件识别
### 7.2 任务清单
| 任务ID | 任务名称 | 优先级 | 状态 | 前置依赖 |
|--------|----------|--------|------|----------|
| P6-01 | 评估 GPT-4V / 通义千问-VL | 低 | 延后 | P1~P5 完成 |
| P6-02 | 实现 `VisionService` | 低 | 延后 | P6-01 |
| P6-03 | 集成到 ChatService | 低 | 延后 | P6-02 |
| P6-04 | 端到端测试 | 低 | 延后 | P6-03 |
### 7.3 延后原因
1. 核心功能优先级更高
2. 视觉能力成本较高
3. 需要更多真实场景验证
---
## 8. 里程碑与依赖关系
```mermaid
gantt
title IIT Manager Agent 开发里程碑
dateFormat YYYY-MM-DD
section Phase 1
基础工具层 :p1, 2026-02-10, 14d
section Phase 2
SOP 引擎 + 热记忆 :p2, after p1, 21d
section Phase 3
ReAct 引擎 + 流水账 :p3, after p2, 14d
section Phase 4
调度系统 + 历史书 :p4, after p3, 14d
section Phase 5
智能路由 :p5, after p4, 7d
section Phase 6
视觉能力 :p6, after p5, 14d
```
---
## 9. 风险与对策
| 风险 | 影响 | 对策 | 已整合 |
|------|------|------|--------|
| ReAct 决策链过长 | 延迟 > 10秒 | 流式反馈 + "正在思考" 状态 | ✅ |
| 混合意图难分类 | 用户困惑 | UNCLEAR + 追问机制 | ✅ |
| ReAct 误调写入工具 | 数据风险 | 只读工具白名单 | ✅ |
| UI 无响应感 | 体验差 | 流式反馈 + 状态提示 | ✅ |
| SOP 中途被打断 | 任务丢失 | SUSPENDED 状态 + 恢复机制 | ✅ |
| 视觉能力分散精力 | 核心功能延迟 | 延后到 Phase 6 | ✅ |
| **[V2.9]** 用户多意图混乱 | 任务遗漏 | ReAct Prompt 多意图拆分 | ✅ |
| **[V2.9]** 回复不符用户偏好 | 体验差 | 反馈循环 + 用户画像 | ✅ |
| **[V2.9]** 主动提醒打扰用户 | 用户投诉 | 最佳通知时间 + 个性化 | ✅ |
---
## 10. 性能指标
| 指标 | 目标值 | 测量方法 |
|------|--------|----------|
| 快速通道响应 | < 50ms | 正则匹配耗时 |
| LLM 意图识别 | < 1s | API 调用耗时 |
| SOP 单步执行 | < 2s | 包含工具调用 |
| ReAct 完整推理 | < 10s | 最多 5 轮循环 |
| 流式首字节 | < 2s | 第一个 token |
| 周报生成 | < 30s | 后台任务 |
| 向量检索 | < 500ms | Top-5 结果 |
---
**文档维护人**AI Agent
**最后更新**2026-02-05

View File

@@ -0,0 +1,327 @@
# IIT Manager Agent V2.6 综合开发计划
> **版本:** V2.9(极简架构 + SOP状态机 + 双脑路由 + 三层记忆 + 主动性增强)
> **日期:** 2026-02-05
> **团队规模:** 2人
> **预估周期:** 6周
> **核心目标:** 实现数据质控 Agent 的完整闭环 + 智能化交互 + 长期记忆 + 主动提醒 + 个性化
---
## 📚 文档导航
本开发计划已拆分为多个专项文档,便于查阅和维护:
| 文档 | 内容 | 适用场景 |
|------|------|----------|
| **本文档** | 架构总览、设计原则、验收标准 | 项目概览、立项汇报 |
| [01-数据库设计](./01-数据库设计.md) | Prisma 模型、索引设计、初始化 SQL | 数据库开发 |
| [02-核心引擎实现指南](./02-核心引擎实现指南.md) | HardRuleEngine、SoftRuleEngine、SopEngine、ReActEngine | 引擎开发 |
| [03-服务层实现指南](./03-服务层实现指南.md) | ToolsService、ChatService、IntentService 等 | 服务开发 |
| [04-记忆系统实现指南](./04-记忆系统实现指南.md) | V2.8 三层记忆架构、MemoryService | 记忆功能开发 |
| [05-开发阶段与任务清单](./05-开发阶段与任务清单.md) | Phase 1-6 详细任务、里程碑、验收标准 | 项目管理、进度跟踪 |
---
## 0. 架构适配性评估
本架构设计充分考虑了临床研究的多种业务场景,通过 **SOP状态机 + 双引擎 + 可扩展工具层** 的设计,实现了良好的适配性和扩展性。
### 0.1 目标场景覆盖度
| 场景 | 覆盖度 | 核心支撑组件 | 备注 |
|------|--------|-------------|------|
| **1. 拍照识别 + 自动录入** | 🟡 60% | VisionService + ToolsService | 延后到 V3.0 |
| **2. 数据质控** | 🟢 95% | HardRuleEngine + SoftRuleEngine | 核心场景 |
| **3. 入排标准判断** | 🟢 90% | SopEngine + 硬规则配置 | 配置 Skill 即可 |
| **4. 方案偏离检测** | 🟢 80% | SoftRuleEngine + search_protocol | 需配置访视窗口规则 |
| **5. AE事件检测** | 🟢 80% | 硬规则触发 + 软指令评估 | 需配置AE识别规则 |
| **6. 伦理合规检测** | 🟢 80% | HardRuleEngine | 配置伦理规则即可 |
| **7. 定期报告生成** | 🟡 50% | SchedulerService + ReportService | Phase 4 实现 |
### 0.2 架构扩展性评价
| 扩展维度 | 实现方式 | 复杂度 |
|----------|----------|--------|
| **新增质控规则** | 在 `iit_skills` 表插入 JSON 配置 | ⭐ 低 |
| **新增业务场景** | 新增 Skill 类型 + 配置 SOP 流程 | ⭐⭐ 中低 |
| **新增工具能力** | 在 ToolsService 增加工具定义 | ⭐⭐ 中低 |
| **新增数据源** | 新增 Adapter如 OdmAdapter | ⭐⭐⭐ 中 |
---
## 1. 架构决策总结
本计划基于以下架构设计文档的综合审查:
| 文档 | 核心观点 | 状态 |
|------|----------|------|
| **架构决策白皮书** | Postgres-Only + Service-First | ✅ 认可 |
| **V2.2 实施指南** | 混合双引擎(硬规则 + 软指令) | ✅ 认可 |
| **V2.2 工具泛化** | 3-5 个通用工具替代 100 个专用工具 | ✅ 认可 |
| **V2.3 健壮性设计** | 三层防御(映射 + 重试 + 兜底) | ✅ 认可 |
| **V2.4 SOP状态机** | 粗粒度 SOP 节点 + 节点内 ReAct | ✅ 认可 |
| **V2.8 记忆系统** | 三层记忆(流水账 + 热记忆 + 历史书) | ✅ 认可 |
| **V2.9 主动性增强** | Cron Skill + 用户画像 + 反馈循环 | ✅ 认可 |
### 1.0 V2.9 核心增强(新)
> **目标**:让 Agent 从"被动应答"进化为"主动协作",同时根据用户反馈持续优化
```
┌─────────────────────────────────────────────────────────────────────┐
│ V2.9 新增能力 │
├──────────────────┬──────────────────┬───────────────────────────────┤
│ 🔔 Cron Skill │ 👤 用户画像 │ 📊 反馈循环 │
│ 主动触发 SOP │ 个性化响应 │ 持续优化 │
│ 定时访视提醒 │ 最佳通知时间 │ 偏好自动调整 │
└──────────────────┴──────────────────┴───────────────────────────────┘
```
| 能力 | 实现方式 | 价值 |
|------|----------|------|
| **Cron Skill** | `iit_skills.triggerType = 'cron'` + pg-boss 调度 | 访视提醒、周报自动发送 |
| **用户画像** | `project_memory` 中存储用户偏好 Markdown | 回复风格个性化 |
| **反馈循环** | `conversation_history.feedback` 字段 | 持续改进回复质量 |
| **多意图处理** | ReAct Prompt 优化 + Chain of Thought | 一句话多任务 |
### 1.1 双脑路由模型
> **核心理念**:左脑(SOP) 保证严谨合规,右脑(ReAct) 提供灵活智能
```
┌─────────────────────────────────────────────────────────────────────┐
│ 企业微信 / 前端入口 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 🧠 意图路由层 (IntentService) │
│ 混合路由:正则快速通道 + LLM 后备 │
└─────────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 📐 左脑 (SOP) │ │ 🎨 右脑 (ReAct) │ │ ❓ 追问机制 │
│ 结构化任务 │ │ 开放性查询 │ │ 信息不全 │
│ 写操作必经 │ │ 只读不写 │ │ 主动澄清 │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ ToolsService (工具层) │
│ 🔓 只读工具 (ReAct 可用) │ 🔒 读写工具 (仅 SOP 可用) │
└─────────────────────────────────────────────────────────────────────┘
```
**双脑对比**
| 维度 | 左脑 (SOP 状态机) | 右脑 (ReAct Agent) |
|------|-------------------|-------------------|
| **擅长** | 执行标准流程、合规检查 | 处理模糊提问、多步查询 |
| **典型指令** | "对 P001 进行入排质控" | "帮我查下最近那个发烧的病人" |
| **数据权限** | 读写皆可 | **只读 (Read-Only)** |
### 1.2 核心设计原则
| 原则 | 描述 |
|------|------|
| **Postgres-Only** | 无 Redis用 pg-boss 替代队列 |
| **Service-First** | 不用 MCP Server用 Service Class |
| **混合双引擎** | 硬规则(CPU) + 软指令(LLM) |
| **SOP 状态机** | 粗粒度节点 + 节点内灵活性 |
| **主动协作 (V2.9)** | Cron Skill 主动触发 + 用户画像个性化 |
| **反馈驱动 (V2.9)** | 用户反馈自动调整偏好 |
| **三层防御** | 字段映射 + 自我修正 + 空结果兜底 |
| **三层记忆** | 流水账(L1) + 热记忆(L2) + 历史书(L3) |
### 1.3 三层记忆架构 (V2.8)
> **关键洞察**:临床研究项目持续 1-3 年Agent 必须具备长期记忆能力
| 层级 | 名称 | 存储位置 | 生命周期 | 检索方式 |
|------|------|----------|----------|----------|
| L1 | 流水账 | conversation_history | 30天 | 按需向量检索 |
| L2 | 热记忆 | project_memory | 持久 | 每次注入 |
| L3 | 历史书 | weekly_reports | 持久 | 按意图检索 |
> 📖 详细实现请参阅 [04-记忆系统实现指南](./04-记忆系统实现指南.md)
---
## 2. 组件总览
### 2.1 已完成组件
| 组件 | 路径 | 状态 |
|------|------|------|
| ChatService | `services/ChatService.ts` | ✅ 需扩展 |
| SessionMemory | `agents/SessionMemory.ts` | ✅ 可复用 |
| RedcapAdapter | `adapters/RedcapAdapter.ts` | ✅ 可复用 |
| WechatService | `services/WechatService.ts` | ✅ 可复用 |
| DifyClient | `common/rag/DifyClient.ts` | ✅ 可复用 |
| LLMFactory | `common/llm/adapters/LLMFactory.ts` | ✅ 可复用 |
### 2.2 待开发组件
| 组件 | 优先级 | Phase | 详细文档 |
|------|--------|-------|----------|
| `iit_skills` 表 | P0 | 1 | [01-数据库设计](./01-数据库设计.md) |
| `iit_field_mapping` 表 | P0 | 1 | [01-数据库设计](./01-数据库设计.md) |
| `ToolsService` 类 | P0 | 1 | [03-服务层实现指南](./03-服务层实现指南.md) |
| `HardRuleEngine` 类 | P0 | 1 | [02-核心引擎实现指南](./02-核心引擎实现指南.md) |
| `SoftRuleEngine` 类 | P1 | 2 | [02-核心引擎实现指南](./02-核心引擎实现指南.md) |
| `SopEngine` 类 | P1 | 2 | [02-核心引擎实现指南](./02-核心引擎实现指南.md) |
| `MemoryService` 类 | P1 | 2-3 | [04-记忆系统实现指南](./04-记忆系统实现指南.md) |
| `ReActEngine` 类 | P1 | 3 | [02-核心引擎实现指南](./02-核心引擎实现指南.md) |
| `IntentService` 类 | P1 | 5 | [03-服务层实现指南](./03-服务层实现指南.md) |
| `SchedulerService` 类 | P2 | 4 | [03-服务层实现指南](./03-服务层实现指南.md) |
---
## 3. 开发阶段总览
> 📖 详细任务清单请参阅 [05-开发阶段与任务清单](./05-开发阶段与任务清单.md)
| Phase | 名称 | 周期 | 核心交付物 |
|-------|------|------|-----------|
| **Phase 1** | 基础工具层 | Week 1 | ToolsService, HardRuleEngine, 字段映射 |
| **Phase 2** | SOP 引擎 + 热记忆 | Week 2 | SopEngine, SoftRuleEngine, L2 热记忆 |
| **Phase 3** | ReAct 引擎 + 流水账 | Week 3 | ReActEngine, L1 流水账, 向量检索 |
| **Phase 4** | 调度系统 + 历史书 | Week 4 前半 | SchedulerService, ReportService, L3 历史书 |
| **Phase 5** | 智能路由 | Week 4 后半 - Week 5 | IntentService, 混合路由, 追问机制 |
| **Phase 6** | 视觉能力 | Week 6 (延后) | VisionService (延后到 V3.0) |
```
Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ 基础工具 │ ──▶ │SOP引擎 │ ──▶ │ReAct │ ──▶ │ 调度 │ ──▶ │智能路由 │ ──▶ │视觉能力 │
│ 层 │ │+ 热记忆 │ │+ 流水账│ │+ 历史书│ │ │ │(延后) │
└────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘
```
---
## 4. 风险与应对
### 4.1 已采纳的风险对策
| 风险 | 已采纳对策 | 状态 |
|------|------------|------|
| **意图路由延迟感** | 混合路由(正则+LLM+ 流式反馈 | ✅ 已整合 |
| **ReAct 多嘴** | 只返回 Final AnswerTrace 存日志 | ✅ 已整合 |
| **SOP 状态机死锁** | SUSPENDED 挂起机制 + 唤醒机制 | ✅ 已整合 |
| **Phase 6 过早** | 延后到 V3.0 | ✅ 已标记 |
### 4.2 聚焦清单P0 优先级)
| 优先级 | 功能 | 理由 |
|--------|------|------|
| **P0** | ToolsService 健壮性 | 字段映射是地基 |
| **P0** | 每日早报 (Morning Brief) | 用户感知最强 |
| **P0** | 意图路由混合模式 | 保证响应速度 + 降低成本 |
### 4.3 主要风险矩阵
| 风险类别 | 风险 | 应对措施 |
|----------|------|----------|
| **基础架构** | LLM 响应慢 | 硬规则先行 + 混合路由 |
| **双脑架构** | ReAct 死循环 | 最大迭代 5 次 + Token 预算 |
| **双脑架构** | ReAct 调用写工具 | 工具白名单(只读) |
| **SOP 状态机** | 人工复核死锁 | SUSPENDED + 唤醒机制 |
| **扩展能力** | 视觉模型识别错误 | 低置信度人工确认 |
---
## 5. 成功标准
### 5.1 核心验收标准
| 阶段 | 验收标准 |
|------|----------|
| **Phase 1-3** | 质控任务 3秒内响应服务重启后任务可恢复对话历史持久化 |
| **Phase 4** | 周报每周一自动生成;定时任务连续 7 天无故障 |
| **Phase 5** | 意图识别准确率 > 85%;用户只收到 Final Answer |
| **Phase 6** | 图片识别准确率 > 85%(延后到 V3.0 |
### 5.2 性能指标
| 指标 | 目标值 |
|------|--------|
| 硬规则执行时间 | < 100ms |
| 软指令执行时间 | < 3s |
| 端到端响应时间 | < 5s |
| 正则快速通道延迟 | < 50ms |
| 意图识别时间LLM | < 1s |
| 向量检索延迟 | < 100ms |
| ReAct 平均迭代次数 | < 3 |
---
## 6. 文件路径清单
```
backend/src/modules/iit-manager/
├── services/
│ ├── ChatService.ts # 扩展:双脑路由 + 记忆集成
│ ├── IntentService.ts # 新建:意图识别 (Phase 5)
│ ├── ToolsService.ts # 新建:统一工具管理 (Phase 1)
│ ├── MemoryService.ts # 新建:三层记忆管理 (Phase 2-3)
│ ├── SchedulerService.ts # 新建:定时任务调度 (Phase 4)
│ └── ReportService.ts # 新建:报告生成 (Phase 4)
├── engines/
│ ├── HardRuleEngine.ts # 新建JSON Logic 执行器 (Phase 1)
│ ├── SoftRuleEngine.ts # 新建LLM 推理引擎 (Phase 2)
│ ├── SopEngine.ts # 新建:状态机调度器 (Phase 2)
│ └── ReActEngine.ts # 新建:多步推理引擎 (Phase 3)
├── agents/
│ └── SessionMemory.ts # 扩展:实体记忆 (Phase 5)
└── adapters/
└── RedcapAdapter.ts # 扩展writeRecord()
```
### 数据库新增表
> 📖 详细 Schema 请参阅 [01-数据库设计](./01-数据库设计.md)
| 表名 | 用途 | Phase |
|------|------|-------|
| `iit_skills` | Skill 配置存储 | 1 |
| `iit_field_mapping` | 字段名映射 | 1 |
| `iit_task_run` | SOP 任务执行记录 | 2 |
| `iit_pending_actions` | 待确认操作 | 2 |
| `iit_project_memory` | 热记忆L2 | 2 |
| `iit_conversation_history` | 流水账L1 | 2 |
| `iit_weekly_reports` | 历史书-周报L3 | 4 |
| `iit_agent_trace` | ReAct 推理轨迹 | 3 |
---
## 7. 参考文档
### 架构设计文档
1. [架构决策白皮书:极简主义的胜利](../00-系统设计/IIT%20Manager%20Agent%20架构决策白皮书极简主义的胜利.md)
2. [V2.2 落地实施指南](../00-系统设计/IIT%20Manager%20Agent%20V2.2%20落地实施指南.md)
3. [V2.3 健壮性设计与最佳实践](../00-系统设计/IIT%20Manager%20Agent%20V2.3.md)
4. [V2.4 SOP 状态机推荐](../00-系统设计/IIT%20Manager%20Agent%20V2.4.md)
5. [V2.6 双脑架构](../00-系统设计/IIT%20Manager%20Agent%20V2.6.md)
### 审核文档
1. [潜在的具体风险与问题](../05-测试文档/潜在的具体风险与问题.md)
2. [V2.8 记忆系统设计](../05-测试文档/IIT%20Manager%20Agent%20V2.8.md)
---
**文档维护人**AI Agent
**最后更新**2026-02-05
### 更新日志
| 版本 | 日期 | 更新内容 |
|------|------|----------|
| V2.6 | 2026-02-02 | 整合双脑架构 + 三层记忆体系 |
| V2.6.1 | 2026-02-05 | 整合团队风险审查建议;拆分为多个专项文档 |
| V2.6.2 | 2026-02-05 | 简化表结构:删除 `iit_user_preferences``iit_patient_notes`(合并到 `project_memory` |
| V2.9 | 2026-02-05 | 主动性增强Cron Skill、用户画像、反馈循环、多意图处理 |