feat(aia): Protocol Agent MVP complete with one-click generation and Word export
- Add one-click research protocol generation with streaming output - Implement Word document export via Pandoc integration - Add dynamic dual-panel layout with resizable split pane - Implement collapsible content for StatePanel stages - Add conversation history management with title auto-update - Fix scroll behavior, markdown rendering, and UI layout issues - Simplify conversation creation logic for reliability
This commit is contained in:
@@ -310,3 +310,4 @@ Level 3: 兜底Prompt(缓存也失效)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
293
docs/03-业务模块/ADMIN-运营管理端/00-系统设计/运营体系设计方案-MVP-V3.0.md
Normal file
293
docs/03-业务模块/ADMIN-运营管理端/00-系统设计/运营体系设计方案-MVP-V3.0.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# **AI 临床科研平台 \- MVP 运营监控体系实施方案 V3.0**
|
||||
|
||||
**文档版本**:V3.0 (全景洞察版)
|
||||
|
||||
**面向对象**:核心开发团队 (2人)
|
||||
|
||||
**更新重点**:
|
||||
|
||||
1. **宏观**:确立 DAU/DAT 双核心指标,防止“假活跃”。
|
||||
2. **微观**:新增 **“用户 360 全景画像”**,支持查看单用户的资产存量与行为流水。
|
||||
3. **技术**:维持 Postgres-Only 极简架构,不引入新组件。
|
||||
|
||||
## **1\. 核心理念:关注“生存”与“真实价值”**
|
||||
|
||||
在 MVP 阶段,我们必须警惕“只有管理员登录”的假象。**医生用起来,才是真的活了。**
|
||||
|
||||
| 优先级 | 指标名称 | 定义 | 为什么关注? |
|
||||
| :---- | :---- | :---- | :---- |
|
||||
| **P0+** | **活跃医生数 (DAU)** | 今日有登录/使用行为的去重 user\_id 数。 | **真实价值线**。只有医生个人觉得好用,产品才有生命力。这是防止客户流失的前哨指标。 |
|
||||
| **P0** | **活跃租户数 (DAT)** | 今日有登录行为的去重 tenant\_id 数。 | **商务生死线**。代表医院客户的存活情况。 |
|
||||
| **P1** | **具体功能渗透率** | 例如:“选题助手”的使用次数 vs “论文润色”的使用次数。 | **产品迭代指引**。如果没人用“润色”,我们就别在这个功能上浪费时间开发了。 |
|
||||
| **P2** | **价值交付次数** | 用户点击 **“导出/下载”** 的次数。 | **北极星指标**。用户只有认可了 AI 的结果才会导出。这是交付价值的终点。 |
|
||||
|
||||
## **2\. 技术架构:Postgres-Only 极简方案**
|
||||
|
||||
### **2.1 数据库设计 (Schema)**
|
||||
|
||||
在 admin\_schema 下新增一张通用日志表。**不需要**做聚合表,**不需要**做定时统计任务,直接查表即可。
|
||||
|
||||
**文件路径**:backend/prisma/schema.prisma
|
||||
|
||||
// ... inside admin\_schema ...
|
||||
|
||||
/// 极简运营日志表 (MVP)
|
||||
model SimpleLog {
|
||||
id String @id @default(dbgenerated("gen\_random\_uuid()")) @db.Uuid
|
||||
createdAt DateTime @default(now()) @map("created\_at")
|
||||
|
||||
tenantId String @map("tenant\_id") @db.VarChar(50)
|
||||
userId String @map("user\_id") @db.Uuid
|
||||
userName String? @map("user\_name") @db.VarChar(50)
|
||||
|
||||
// V3.0 核心字段设计
|
||||
module String @db.VarChar(20) // 大模块: 'AIA', 'ASL', 'DC', 'PKB'
|
||||
feature String @db.VarChar(50) // 细分功能: 'Topic Agent', 'Tool C', 'RAG Chat'
|
||||
action String @db.VarChar(20) // 动作: 'USE', 'EXPORT', 'ERROR', 'LOGIN'
|
||||
|
||||
info String? @db.Text // 详情: "生成了3个选题" / "导出Excel"
|
||||
|
||||
@@index(\[createdAt\])
|
||||
@@index(\[tenantId\])
|
||||
@@index(\[userId\]) // V3.0 新增:支持查询单用户轨迹
|
||||
@@index(\[module, feature\]) // 支持按功能统计热度
|
||||
@@map("simple\_logs")
|
||||
@@schema("admin\_schema")
|
||||
}
|
||||
|
||||
### **2.2 后端服务实现 (ActivityService)**
|
||||
|
||||
负责写入日志和获取大盘数据。
|
||||
|
||||
**文件路径**:backend/src/common/services/activity.service.ts
|
||||
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
// 假设这是全局 Prisma 实例
|
||||
import { prisma } from '@/common/database/prisma';
|
||||
|
||||
export const activityService \= {
|
||||
/\*\*
|
||||
\* 核心埋点方法 (Fire-and-Forget 模式)
|
||||
\* @param feature 具体功能名称,如 'Topic Agent'
|
||||
\*/
|
||||
async log(
|
||||
tenantId: string,
|
||||
userId: string,
|
||||
userName: string,
|
||||
action: 'LOGIN' | 'USE' | 'EXPORT' | 'ERROR',
|
||||
module: 'AIA' | 'ASL' | 'DC' | 'PKB' | 'SYSTEM',
|
||||
feature: string, // 必填:细分功能
|
||||
info: any
|
||||
) {
|
||||
// 异步执行,不要 await,避免影响主接口性能
|
||||
prisma.simpleLog.create({
|
||||
data: {
|
||||
tenantId, userId, userName, action, module, feature,
|
||||
info: typeof info \=== 'object' ? JSON.stringify(info) : String(info),
|
||||
}
|
||||
}).catch(e \=\> console.error('埋点写入失败(可忽略):', e));
|
||||
},
|
||||
|
||||
/\*\*
|
||||
\* 运营看板:获取实时流水账
|
||||
\*/
|
||||
async getLiveFeed(limit \= 100\) {
|
||||
return prisma.simpleLog.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: limit
|
||||
});
|
||||
},
|
||||
|
||||
/\*\*
|
||||
\* 🟢 获取今日核心大盘数据 (DAU \+ DAT)
|
||||
\* 用于 Admin 首页顶部展示
|
||||
\*/
|
||||
async getTodayOverview() {
|
||||
const todayStart \= new Date();
|
||||
todayStart.setHours(0,0,0,0);
|
||||
|
||||
const stats \= await prisma.$queryRaw\`
|
||||
SELECT
|
||||
COUNT(DISTINCT user\_id) as dau,
|
||||
COUNT(DISTINCT tenant\_id) as dat,
|
||||
COUNT(CASE WHEN action \= 'EXPORT' THEN 1 END) as export\_count
|
||||
FROM admin\_schema.simple\_logs
|
||||
WHERE created\_at \>= ${todayStart}
|
||||
\`;
|
||||
|
||||
return {
|
||||
dau: Number(stats\[0\].dau),
|
||||
dat: Number(stats\[0\].dat),
|
||||
exportCount: Number(stats\[0\].export\_count)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
## **3\. 细粒度埋点实施清单 (直接复制给开发)**
|
||||
|
||||
为了满足运营需求,请在以下位置埋点,并务必带上 feature 参数。
|
||||
|
||||
### **🤖 3.1 AIA 模块 (12个智能体细分)**
|
||||
|
||||
**位置**:aia/services/chat.service.ts \-\> complete 方法 (AI回复完成时)
|
||||
|
||||
**逻辑**:根据当前对话的 agentId 记录不同的 feature。
|
||||
|
||||
// 示例映射表
|
||||
const agentNameMap \= {
|
||||
'topic-scoping': '科学问题梳理',
|
||||
'pico-analysis': 'PICO梳理',
|
||||
'topic-eval': '选题评价',
|
||||
'outcome-design': '观察指标设计',
|
||||
'crf-design': 'CRF设计',
|
||||
'sample-size': '样本量计算',
|
||||
'protocol-writing': '方案撰写',
|
||||
'methodology-review': '方法学评审',
|
||||
'paper-polish': '论文润色',
|
||||
'paper-translate': '论文翻译',
|
||||
// ... 其他智能体
|
||||
};
|
||||
const feature \= agentNameMap\[agentId\] || 'Unknown Agent';
|
||||
activityService.log(..., 'USE', 'AIA', feature, '生成完成');
|
||||
|
||||
### **🧹 3.2 DC 模块 (清洗工具细分)**
|
||||
|
||||
**位置**:dc/controllers/extraction.controller.ts
|
||||
|
||||
* **Tool B (自动提取)**: log(..., 'USE', 'DC', 'Tool B', '提取任务: 50条')
|
||||
* **Tool C (数据清洗)**: log(..., 'USE', 'DC', 'Tool C', '执行清洗操作')
|
||||
* **导出结果**: log(..., 'EXPORT', 'DC', 'Tool C', '导出 Excel')
|
||||
|
||||
### **📚 3.3 ASL 模块 (文献功能细分)**
|
||||
|
||||
**位置**:asl/controllers/research.controller.ts
|
||||
|
||||
* **智能检索**: log(..., 'USE', 'ASL', 'DeepSearch', '关键词: 肺癌')
|
||||
* **标题摘要筛选**: log(..., 'USE', 'ASL', 'Title/Abstract Screening', '筛选进度: 100/500')
|
||||
* **全文复筛**: log(..., 'USE', 'ASL', 'Fulltext Review', '复筛完成')
|
||||
|
||||
### **🧠 3.4 PKB 模块 (知识库行为)**
|
||||
|
||||
**位置**:pkb/controllers/...
|
||||
|
||||
* **上传文档**: log(..., 'USE', 'PKB', 'Document Upload', '上传: 3篇')
|
||||
* **RAG 问答**: log(..., 'USE', 'PKB', 'RAG Chat', '提问: 入排标准是什么?')
|
||||
* **批处理**: log(..., 'USE', 'PKB', 'Batch Process', '批量提取: 10篇')
|
||||
|
||||
## **4\. 运营看板设计 (Admin Portal) \- 宏观**
|
||||
|
||||
### **界面参考**
|
||||
|
||||
在 Admin 首页展示。
|
||||
|
||||
#### **\[ 顶部卡片区域 \]**
|
||||
|
||||
| 今日活跃医生 (DAU) | 今日活跃医院 (DAT) | 今日价值交付 (导出) |
|
||||
| :---- | :---- | :---- |
|
||||
| **12** 👨⚕️ | **3** 🏥 | **5** 🟢 |
|
||||
|
||||
#### **\[ 实时流水账区域 \]**
|
||||
|
||||
| 时间 | 医院 | 医生 | 模块 | 具体功能 | 动作 | 详情 |
|
||||
| :---- | :---- | :---- | :---- | :---- | :---- | :---- |
|
||||
| 10:05 | 协和 | 张主任 | **AIA** | **选题评价** | 🔵 USE | 评价得分: 85分 |
|
||||
| 10:03 | 协和 | 张主任 | **AIA** | **PICO梳理** | 🔵 USE | 梳理完成 |
|
||||
| 09:55 | 华西 | 李医生 | **DC** | **Tool C** | 🟢 **EXPORT** | 导出 Excel |
|
||||
|
||||
## **5\. 用户 360 全景画像 (User 360 View) \- 微观 🆕**
|
||||
|
||||
**新增模块**:当运营人员点击用户列表中的“详情”时,展示该用户的全生命周期数据。
|
||||
|
||||
### **5.1 后端聚合服务 (UserOverviewService)**
|
||||
|
||||
不建立宽表,利用 Prisma 并行查询实现\*\*“资产快照 \+ 行为流水”\*\*聚合。
|
||||
|
||||
**文件路径**:backend/src/modules/admin/services/user-overview.service.ts
|
||||
|
||||
import { prisma } from '@/common/database/prisma';
|
||||
|
||||
export const userOverviewService \= {
|
||||
async getUserProfile(userId: string) {
|
||||
// 并行查询,耗时取决于最慢的那个查询,通常 \< 200ms
|
||||
const \[user, aiaStats, kbs, dcStats, logs\] \= await Promise.all(\[
|
||||
// 1\. 基础信息
|
||||
prisma.user.findUnique({ where: { id: userId } }),
|
||||
|
||||
// 2\. AIA 资产 (会话数)
|
||||
prisma.conversation.count({ where: { userId, isDeleted: false } }),
|
||||
|
||||
// 3\. PKB 资产 (知识库数 \+ 文档数)
|
||||
prisma.knowledgeBase.findMany({
|
||||
where: { userId },
|
||||
include: { \_count: { select: { documents: true } } }
|
||||
}),
|
||||
|
||||
// 4\. DC 资产 (任务数)
|
||||
prisma.extractionTask.count({ where: { userId } }),
|
||||
|
||||
// 5\. 最近行为 (从 SimpleLog 查最近 20 条)
|
||||
prisma.simpleLog.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 20
|
||||
})
|
||||
\]);
|
||||
|
||||
// 计算文档总数
|
||||
const totalDocs \= kbs.reduce((sum, kb) \=\> sum \+ kb.\_count.documents, 0);
|
||||
|
||||
return {
|
||||
profile: user,
|
||||
assets: {
|
||||
aia: { conversationCount: aiaStats },
|
||||
pkb: { kbCount: kbs.length, docCount: totalDocs, kbs },
|
||||
dc: { taskCount: dcStats }
|
||||
},
|
||||
activities: logs
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
### **5.2 前端布局设计 (UserDetailPage)**
|
||||
|
||||
使用 Ant Design 组件库实现三段式布局。
|
||||
|
||||
#### **区域一:资产数字 (Asset Stats)**
|
||||
|
||||
| 💬 AIA 对话 | 📚 PKB 知识库 | 📄 上传文献 | 🧹 DC 清洗任务 |
|
||||
| :---- | :---- | :---- | :---- |
|
||||
| **158** 次 | **3** 个 | **450** 篇 | **12** 次 |
|
||||
|
||||
*(点击数字可展开查看具体列表,如查看 3 个知识库的名称)*
|
||||
|
||||
#### **区域二:行为时间轴 (Timeline)**
|
||||
|
||||
展示用户最近的操作轨迹,快速判断用户是否遇到困难。
|
||||
|
||||
* **10:30** \[AIA\] 使用了 **“选题评价”** (生成结果: 85分)
|
||||
* **10:15** \[PKB\] 上传了文档 lung\_cancer\_study.pdf 到 **“肺癌课题库”**
|
||||
* **09:50** \[DC\] 导出了 **Tool C** 清洗结果 (Excel)
|
||||
* **09:48** \[系统\] 登录系统
|
||||
|
||||
## **6\. 每日自动化巡检 (SAE Job)**
|
||||
|
||||
复用后端镜像,使用 SAE Job 功能,每天 06:00 执行。
|
||||
|
||||
* **检查项**:数据库连接、Python 微服务心跳、公网连通性 (NAT)。
|
||||
* **通知**:检查失败时发送企业微信报警。
|
||||
* **目的**:确保早上醒来时系统是健康的。
|
||||
|
||||
## **7\. 开发执行计划**
|
||||
|
||||
**总耗时预计:3-4 小时**
|
||||
|
||||
1. **\[DB\] (15min)**:
|
||||
* 更新 Prisma Schema (新增 feature 字段和索引)。
|
||||
* 执行 prisma db push。
|
||||
2. **\[Backend\] (60min)**:
|
||||
* 实现 activityService (埋点 \+ 大盘)。
|
||||
* 实现 userOverviewService (360 聚合)。
|
||||
* 在 AIA/DC/ASL/PKB 核心 Controller 插入 log() 代码。
|
||||
3. **\[Frontend\] (90min)**:
|
||||
* Admin 首页:实现大盘卡片 \+ 实时流水表格。
|
||||
* User 详情页:实现资产统计卡片 \+ 行为 Timeline。
|
||||
@@ -496,3 +496,4 @@ const pageSize = Number(query.pageSize) || 20;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -230,3 +230,4 @@ ADMIN-运营管理端/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user