P1 Architecture: Lightweight ReAct (Function Calling loop, max 3 rounds) Core changes: - Add ToolDefinition/ToolCall types to LLM adapters (DeepSeek + CloseAI + Claude) - Replace 6 old tools with 4 semantic tools: read_report, look_up_data, check_quality, search_knowledge - Create ChatOrchestrator (~160 lines) replacing ChatService (1,442 lines) - Wire WechatCallbackController to ChatOrchestrator, deprecate ChatService - Fix nullable content (string | null) across 12+ LLM consumer files E2E test results: 8/8 scenarios passed (100%) - QC report query, critical issues, patient data, trend, on-demand QC - Knowledge base search, project overview, data modification refusal Net code reduction: ~1,100 lines Tested: E2E P1 chat test 8/8 passed with DeepSeek API Made-with: Cursor
9.1 KiB
9.1 KiB
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 是"决策者"(自主选择工具、组合调用)
- 支持多轮推理和自动降级
🔑 关键设计决策
- 轻量 ReAct vs 完整 QPER:选择轻量 ReAct(max 3 轮 FC loop),因为 CRA 场景工具空间有限(4 个)、数据预计算、延迟要求低
- 报告优先策略:
read_report覆盖 80% 问题,避免冗余 REDCap 查询 content: string | null:适配 LLM Function Calling 标准(tool_calls 时 content 可为 null)- ChatService 保留不删:重命名为
.deprecated.ts,作为参考保留 - 数据库手动迁移:为避免 Prisma
db push的数据丢失风险,采用手动 SQL + 迁移文件方式
⚠️ 已知限制
- REDCap 本地实例未启动时,
look_up_data和check_quality会优雅降级 - 会话记忆为内存存储(SessionMemory),重启后丢失
- 单项目模式(活跃项目自动解析),暂不支持多项目切换
- 平均响应 ~5.7s(含 2 次 DeepSeek API 调用),可通过缓存优化