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:
436
docs/03-业务模块/IIT Manager Agent/04-开发计划/01-数据库设计.md
Normal file
436
docs/03-业务模块/IIT Manager Agent/04-开发计划/01-数据库设计.md
Normal 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 // 核心配置 JSON(SOP 流程图)
|
||||
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 2:SOP 执行与记忆表
|
||||
|
||||
### 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 5:ReAct 追踪表
|
||||
|
||||
### 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
|
||||
731
docs/03-业务模块/IIT Manager Agent/04-开发计划/02-核心引擎实现指南.md
Normal file
731
docs/03-业务模块/IIT Manager Agent/04-开发计划/02-核心引擎实现指南.md
Normal 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
|
||||
1123
docs/03-业务模块/IIT Manager Agent/04-开发计划/03-服务层实现指南.md
Normal file
1123
docs/03-业务模块/IIT Manager Agent/04-开发计划/03-服务层实现指南.md
Normal file
File diff suppressed because it is too large
Load Diff
552
docs/03-业务模块/IIT Manager Agent/04-开发计划/04-记忆系统实现指南.md
Normal file
552
docs/03-业务模块/IIT Manager Agent/04-开发计划/04-记忆系统实现指南.md
Normal 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
|
||||
281
docs/03-业务模块/IIT Manager Agent/04-开发计划/05-开发阶段与任务清单.md
Normal file
281
docs/03-业务模块/IIT Manager Agent/04-开发计划/05-开发阶段与任务清单.md
Normal 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 Answer,Trace 存日志 | ✅ 已整合 |
|
||||
| **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、用户画像、反馈循环、多意图处理 |
|
||||
Reference in New Issue
Block a user