# 2026-02-26 CRA Agent V3.0 P0 + P1 完整开发记录 > **开发日期:** 2026-02-25 ~ 2026-02-26 > **开发人员:** AI Assistant > **版本:** V3.0 > **状态:** ✅ P0 + P1 全部完成,E2E 测试通过 --- ## 📋 开发概述 本次开发完成了 CRA Agent V3.0 开发计划中的 **P0(自驱动质控流水线)** 和 **P1(对话层 Tool Use 改造)** 两个里程碑,实现了从"关键词路由 ChatService"到"LLM 原生 Function Calling ChatOrchestrator"的完整架构升级。 --- ## 🎯 P0:自驱动质控流水线 ### P0-1:REDCap 变量清单导入 + 可视化 **改动文件:** | 文件 | 改动内容 | |------|---------| | `frontend-v2/src/modules/iit/pages/FieldMetadataPage.tsx` | 变量清单页面(搜索、分组、表单筛选) | | `frontend-v2/src/modules/iit/api/iitProjectApi.ts` | 前端 API:变量清单接口 | | `backend/src/modules/admin/iit-projects/iitFieldMetadataController.ts` | 后端控制器:变量清单 CRUD | | `backend/src/modules/admin/iit-projects/iitFieldMetadataRoutes.ts` | 后端路由注册 | ### P0-2:规则配置增强 **改动文件:** | 文件 | 改动内容 | |------|---------| | `frontend-v2/src/modules/iit/pages/RulesPage.tsx` | 规则管理页面(4 类规则、变量关联) | | `backend/src/modules/admin/iit-projects/iitRulesController.ts` | 规则 CRUD 控制器 | | `backend/src/modules/admin/iit-projects/iitRuleSuggestionService.ts` | AI 辅助规则建议(LLM 提取) | ### P0-3:定时质控 + 报告生成 + eQuery 闭环 **新增数据库表:** - `iit_schema.equery` — eQuery 电子疑问单(状态机:open → responded → ai_reviewing → resolved / reopened) - `iit_schema.critical_events` — 重大事件归档(SAE、方案偏离) - `iit_schema.projects` 新增 `cron_enabled` / `cron_expression` 列 **改动文件:** | 文件 | 改动内容 | |------|---------| | `backend/src/modules/iit-manager/services/DailyQcOrchestrator.ts` | **新增** 定时质控编排器(质控 → 报告 → eQuery 派发 → 重大事件归档 → 企微推送) | | `backend/src/modules/admin/iit-projects/iitEqueryService.ts` | **新增** eQuery 服务(CRUD + 状态机 + AI 复核) | | `backend/src/modules/admin/iit-projects/iitEqueryController.ts` | **新增** eQuery 控制器 | | `backend/src/modules/admin/iit-projects/iitEqueryRoutes.ts` | **新增** eQuery 路由 | | `backend/src/modules/iit-manager/index.ts` | 注册 `iit_daily_qc` cron + `iit_equery_review` worker | | `backend/prisma/schema.prisma` | 新增 `IitEquery` + `IitCriticalEvent` 模型 | | `backend/prisma/migrations/20260226_add_equery_critical_events_cron/migration.sql` | 手动 SQL 迁移脚本 | ### P0-4:统一质控驾驶舱 + AI Stream **改动文件:** | 文件 | 改动内容 | |------|---------| | `frontend-v2/src/modules/iit/pages/DashboardPage.tsx` | 统一驾驶舱(健康分、核心指标、重大事件、趋势图、风险热力图) | | `frontend-v2/src/modules/iit/pages/AiStreamPage.tsx` | AI Agent 工作时间线 | | `frontend-v2/src/modules/iit/pages/EQueryPage.tsx` | **新增** eQuery 管理页面 | | `frontend-v2/src/modules/iit/pages/ReportsPage.tsx` | 新增"重大事件归档"Tab | | `backend/src/modules/admin/iit-projects/iitQcCockpitController.ts` | 新增 timeline / critical-events / trend 接口 | | `backend/src/modules/admin/iit-projects/iitQcCockpitRoutes.ts` | 新增驾驶舱路由 | ### P0 E2E 测试 - **测试脚本:** `backend/tests/e2e-p0-test.ts` - **结果:** 46/46 全部通过 - **覆盖:** 变量清单 → 规则配置 → 报告 → eQuery → 驾驶舱 → Timeline → 重大事件 --- ## 🎯 P1:对话层 Tool Use 改造 ### P1-Step 1:LLM Adapter 扩展 Function Calling **核心改动:** 让 LLM 适配器支持原生 Tool Use / Function Calling。 | 文件 | 改动内容 | |------|---------| | `backend/src/common/llm/adapters/types.ts` | 新增 `ToolDefinition`、`ToolCall` 类型;`Message.role` 增加 `'tool'`;`LLMOptions` 增加 `tools`/`tool_choice`;`LLMResponse.content` 改为 `string \| null`,新增 `toolCalls` | | `backend/src/common/llm/adapters/DeepSeekAdapter.ts` | `chat()` 支持 `tools`/`tool_choice` 参数,解析 `tool_calls` | | `backend/src/common/llm/adapters/CloseAIAdapter.ts` | OpenAI 路径支持 function calling;Claude 路径转换为 Anthropic `tool_use` 格式 | **级联修复(`content: string | null` 引起):** 12+ 个文件添加 `?? ''` null 安全处理。 ### P1-Step 2:ToolsService 重构(6 旧 → 4 新) **删除的工具(~300 行):** - `read_clinical_data` / `run_quality_check` / `batch_quality_check` / `get_project_info` / `count_records` / `search_protocol` **新增的工具(~200 行):** | 工具名 | 描述 | 数据源 | |--------|------|--------| | `read_report` | 质控报告查阅(80% 的问题用这个回答) | `QcReportService` | | `look_up_data` | 原始临床数据查询 | `RedcapAdapter` | | `check_quality` | 即时质控检查(单条/全量) | `HardRuleEngine` / `SkillRunner` | | `search_knowledge` | 知识库检索 | `pgvector RAG` | ### P1-Step 3:ChatOrchestrator 创建 **新文件:** `backend/src/modules/iit-manager/services/ChatOrchestrator.ts`(~160 行) **核心架构:** 轻量 ReAct(带循环的 Function Calling,max 3 轮) ``` 用户提问 → system prompt + history + tools → LLM ├── LLM 返回 tool_calls → 并行执行工具 → 追加结果 → 下一轮 LLM ├── LLM 返回 tool_calls → ... → 下一轮(最多 3 轮) └── LLM 返回 stop / 达到上限 → 返回文本回答 ``` **System Prompt 核心指令:** - 优先使用 `read_report`(80%) - 所有回答必须基于工具结果,不得伪造数据 - 中文回复,简洁 ≤200 字 - 拒绝数据修改请求 ### P1-Step 4:入口接线 + ChatService 废弃 | 文件 | 改动内容 | |------|---------| | `backend/src/modules/iit-manager/controllers/WechatCallbackController.ts` | `ChatService` → `ChatOrchestrator`(懒初始化) | | `backend/src/modules/iit-manager/services/index.ts` | 导出改为 `ChatOrchestrator` | | `backend/src/modules/iit-manager/services/ChatService.ts` | 重命名为 `ChatService.deprecated.ts` | ### P1 E2E 测试 - **测试脚本:** `backend/tests/e2e-p1-chat-test.ts` - **结果:** 8/8 全部通过(100%) - **平均响应时间:** 5,676ms | 场景 | 输入 | 工具调用 | 结果 | |------|------|---------|------| | 1. 质控报告 | "最新质控报告怎么样" | `read_report(summary)` | ✅ 返回通过率、问题数 | | 2. 严重违规 | "有几条严重违规" | 利用上下文记忆直接回答 | ✅ "69条严重问题" | | 3. 患者数据 | "003 的数据" | `look_up_data` → 失败 → `read_report` 降级 | ✅ 多轮 ReAct | | 4. 趋势查询 | "通过率比上周好了吗" | `read_report(trend)` | ✅ 趋势分析 | | 5. 即时质控 | "帮我检查一下 005" | `check_quality(005)` | ✅ 优雅降级 | | 6. 知识库 | "入排标准是什么" | `search_knowledge` | ✅ 精确返回纳入/排除标准 | | 7. 项目概览 | "项目整体怎么样" | `read_report(summary)` | ✅ 汇总项目状况 | | 8. 拒绝修改 | "帮我修改 003 的数据" | 无工具调用 | ✅ 礼貌拒绝 | --- ## 📊 代码变更统计 | 指标 | 数值 | |------|------| | P0 新增文件 | ~15 个 | | P1 新增文件 | 2 个(ChatOrchestrator + E2E test) | | P1 删除代码 | ~1,742 行(ChatService 1,442 + 旧工具 300) | | P1 新增代码 | ~655 行(types 40 + adapters 30 + 新工具 200 + Orchestrator 160 + tests 155 + wiring 10 + null fixes 60) | | P1 净减少 | ~1,100 行 | | E2E 测试 | P0: 46/46 + P1: 8/8 = **54/54(100%)** | --- ## 🏗️ 架构变化总结 ### 旧架构(V2.x ChatService) ``` 用户消息 → 10 个正则意图路由 → 9 个硬编码处理方法 → LLM 格式化文本 → 回复 ``` - 1,442 行代码,102 行正则匹配 - LLM 只是"文本格式化器" - 不支持多工具组合 ### 新架构(V3.0 ChatOrchestrator) ``` 用户消息 → system prompt + 4 tools → LLM 自主选择 → 工具执行 → LLM 总结(max 3 轮) ``` - ~160 行代码 - LLM 是"决策者"(自主选择工具、组合调用) - 支持多轮推理和自动降级 --- ## 🔑 关键设计决策 1. **轻量 ReAct vs 完整 QPER**:选择轻量 ReAct(max 3 轮 FC loop),因为 CRA 场景工具空间有限(4 个)、数据预计算、延迟要求低 2. **报告优先策略**:`read_report` 覆盖 80% 问题,避免冗余 REDCap 查询 3. **`content: string | null`**:适配 LLM Function Calling 标准(tool_calls 时 content 可为 null) 4. **ChatService 保留不删**:重命名为 `.deprecated.ts`,作为参考保留 5. **数据库手动迁移**:为避免 Prisma `db push` 的数据丢失风险,采用手动 SQL + 迁移文件方式 --- ## ⚠️ 已知限制 1. REDCap 本地实例未启动时,`look_up_data` 和 `check_quality` 会优雅降级 2. 会话记忆为内存存储(SessionMemory),重启后丢失 3. 单项目模式(活跃项目自动解析),暂不支持多项目切换 4. 平均响应 ~5.7s(含 2 次 DeepSeek API 调用),可通过缓存优化