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>
6.2 KiB
IIT Manager Agent V2.8:记忆检索与路由逻辑详解
核心机制: 意图驱动的按需检索 (Intent-Driven Retrieval)
目的: 既保证 AI 懂当下(Hot),又保证 AI 懂历史(History),同时节省 Token。
1. 记忆存储全景图 (Storage Map)
在 V2.8 中,我们有三个核心存储位置,各司其职:
| 记忆类型 | 存储表 | 字段 | 内容特征 | 更新频率 |
|---|---|---|---|---|
| 1. 流水账 (Raw Stream) | iit_conversation_history | content (JSON) | 未经加工的原始对话。 | 实时 (每秒) |
| 2. 热记忆 (Hot Context) | iit_project_memory | config (Markdown) | 用户偏好、当前状态、系统禁令。 | 每日 (AI 提炼) |
| 3. 历史书 (Weekly Reports) | iit_weekly_reports | summary (Text) | 高度浓缩的周报、关键决策、踩坑记录。 | 每周 (AI 归档) |
2. 调取顺序与逻辑 (Retrieval Logic)
当 PI 发问时,系统并不是一股脑把所有记忆都塞进去,而是分三步走:
第一步:无条件注入 (Always On)
无论 PI 问什么,必须先注入“热记忆”。
- 来源:iit_project_memory
- 内容:用户偏好(如“PI 喜欢简报”)、当前项目状态。
- 理由:这是 Agent 的“人设”和“底线”,一刻也不能忘。
第二步:意图识别 (Intent Detection)
系统分析 PI 的问题,判断他想问“现在”还是“过去”。
- 情况 A:问现在/执行任务 (如 "查下 P001", "生成本周周报")
- 动作:不调取 历史书。
- 理由:解决当下问题不需要翻阅 3 年前的老黄历,避免干扰 AI。
- Context = Hot Memory + Current Task Data
- 情况 B:问历史/趋势/回顾 (如 "回顾下去年的入组情况", "我们为什么暂停了筛选?")
- 动作:全量调取 历史书 (iit_weekly_reports)。
- 理由:需要上帝视角。
- Context = Hot Memory + All Weekly Reports
第三步:上下文组装 (Prompt Assembly)
最终发给 LLM 的 Prompt 是这样组装的:
[System Prompt]
你是一个临床研究助手...
[Hot Memory] (来自 iit_project_memory)
- 用户偏好: 简洁、数据驱动
- 当前状态: 入组阶段
[History Context] (仅在情况 B 下注入)
Week 1: 启动项目...
Week 2: 发现 P001 不良事件...
...
Week 50: 决定放宽标准...
[User Question]
我们之前为什么暂停筛选?
3. 实战场景演示 (Scenario Walkthrough)
场景 1:PI 问 "P001 入组了吗?"
- 加载 Hot Memory:获取偏好(简洁回复)。
- 意图识别:QUERY_DATA (查数据)。
- 决策:不需要 查历史书。
- 行动:调用 read_clinical_data 工具去 REDCap 查实时数据。
- 回答:"已入组,时间是 2026-02-05。"
场景 2:PI 问 "最近入组太慢了,我们之前有没有讨论过怎么解决?"
- 加载 Hot Memory:获取偏好。
- 意图识别:QUERY_HISTORY (查历史决策)。
- 决策:需要 查历史书。
- 行动:
- 从 iit_weekly_reports 拉取过去 20 周的 summary。
- 拼接成 3000 字的文本。
- 喂给 LLM。
- LLM 思考:阅读周报,发现 Week 12 记录了“增加受试者交通补贴”的决策,Week 15 记录了“在门诊增派 CRC”的决策。
- 回答:"我们曾在第 12 周尝试增加补贴,第 15 周增派了 CRC,当时效果有短暂提升..."
场景 3:PI 问 "我上次跟你说的那个只要看结果的规矩,你记得吗?"
- 加载 Hot Memory:获取偏好。
- AI 自检:在 Hot Memory 里看到了 - [PI]: 只要看结果 这条记录。
- 回答:"记得的,教授。您要求汇报时只列数据结论,不要冗长的过程描述。我会严格遵守。"
- 注意:这个问题不需要查周报,也不需要查流水账,直接看 Hot Memory 就行。
4. 总结:给开发者的伪代码
// ChatService.ts
async handleMessage(userId, message) {
// 1. 总是加载热记忆 (Hot)
const hotMem = await prisma.iitProjectMemory.findUnique(...);
// 2. 意图识别
const intent = await this.intentService.detect(message);
let historyContext = "";
// 3. 按需加载历史书 (History)
if (intent.type === 'QUERY_HISTORY' || intent.type === 'ANALYZE_TREND') {
const reports = await prisma.iitWeeklyReport.findMany({
orderBy: { weekNumber: 'asc' }
});
historyContext = reports.map(r => `[W${r.weekNumber}]: ${r.summary}`).join('\n');
}
// 4. 组装最终 Prompt
const finalPrompt = `
${hotMem.content}
${historyContext}
User: ${message}
`;
// 5. 调用 LLM
return await this.llm.chat(finalPrompt);
}
记住这个口诀:
“偏好时刻带,历史按需查,流水账只用来生成周报。”
5. 复杂度控制与防失控指南 (Safety Guardrails)
为了防止系统变得“复杂不可控”,请严格遵守以下开发军规:
5.1 容量限制 (The Cap)
- Hot Memory: 限制在 2000 Tokens 以内。如果超标,触发 MemoryPruningJob (记忆修剪任务),让 AI 自动总结或通知管理员手动删除。
- History Book: 每次加载不超过 50 周 的周报。如果项目运行了 10 年,只加载最近 1 年的周报,或者先让 AI 生成“年度总结”。
5.2 隔离原则 (Isolation)
- 任务隔离:执行 QC_TASK (质控) 时,严禁加载 History Context。质控必须基于当下的事实,不能受历史干扰。
- 数据隔离:LLM 永远没有权限直接读取 iit_conversation_history 表。这条物理隔绝保证了 Agent 永远不会被海量噪音淹没。
5.3 人工介入 (The Kill Switch)
- 可读可改:后台必须提供 Hot Memory 的编辑器。如果 Agent 记住了错误的规则(例如“不需要查年龄”),医生可以直接进去删掉那一行 Markdown。这是系统失控时的“急停按钮”。