diff --git a/backend/src/common/auth/auth.controller.ts b/backend/src/common/auth/auth.controller.ts index 2ec97130..a9c6667b 100644 --- a/backend/src/common/auth/auth.controller.ts +++ b/backend/src/common/auth/auth.controller.ts @@ -197,6 +197,142 @@ export async function changePassword( } } +/** + * 更新头像(URL方式) + * + * PUT /api/v1/auth/me/avatar + */ +export async function updateAvatar( + request: FastifyRequest<{ Body: { avatarUrl: string } }>, + reply: FastifyReply +) { + try { + if (!request.user) { + return reply.status(401).send({ + success: false, + error: 'Unauthorized', + message: '未认证', + }); + } + + const { avatarUrl } = request.body; + + if (!avatarUrl) { + return reply.status(400).send({ + success: false, + error: 'BadRequest', + message: '请提供头像URL', + }); + } + + const result = await authService.updateAvatar(request.user.userId, avatarUrl); + + return reply.status(200).send({ + success: true, + data: result, + }); + } catch (error) { + const message = error instanceof Error ? error.message : '更新头像失败'; + logger.warn('更新头像失败', { error: message, userId: request.user?.userId }); + + return reply.status(400).send({ + success: false, + error: 'BadRequest', + message, + }); + } +} + +/** + * 上传头像(文件上传方式) + * + * POST /api/v1/auth/me/avatar/upload + * + * 接收 multipart/form-data,上传到 staticStorage(公开访问) + */ +export async function uploadAvatar( + request: FastifyRequest, + reply: FastifyReply +) { + try { + if (!request.user) { + return reply.status(401).send({ + success: false, + error: 'Unauthorized', + message: '未认证', + }); + } + + // 获取上传的文件 + const data = await request.file(); + + if (!data) { + return reply.status(400).send({ + success: false, + error: 'BadRequest', + message: '请上传头像文件', + }); + } + + // 检查文件类型 + const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; + if (!allowedMimeTypes.includes(data.mimetype)) { + return reply.status(400).send({ + success: false, + error: 'BadRequest', + message: '仅支持 JPG、PNG、GIF、WebP 格式的图片', + }); + } + + // 获取文件内容 + const buffer = await data.toBuffer(); + + // 检查文件大小(最大 5MB) + if (buffer.length > 5 * 1024 * 1024) { + return reply.status(400).send({ + success: false, + error: 'BadRequest', + message: '头像文件大小不能超过 5MB', + }); + } + + // 生成存储 Key + const { randomUUID } = await import('crypto'); + const path = await import('path'); + const uuid = randomUUID().replace(/-/g, '').substring(0, 16); + const ext = path.extname(data.filename).toLowerCase() || '.jpg'; + const storageKey = `avatars/${request.user.userId}/${uuid}${ext}`; + + // 上传到 staticStorage(公开访问) + const { staticStorage } = await import('../storage/index.js'); + const avatarUrl = await staticStorage.upload(storageKey, buffer); + + // 更新数据库 + const result = await authService.updateAvatar(request.user.userId, avatarUrl); + + logger.info('头像上传成功', { + userId: request.user.userId, + storageKey, + avatarUrl, + fileSize: buffer.length + }); + + return reply.status(200).send({ + success: true, + data: result, + }); + } catch (error) { + const message = error instanceof Error ? error.message : '头像上传失败'; + logger.error('头像上传失败', { error: message, userId: request.user?.userId }); + + return reply.status(500).send({ + success: false, + error: 'InternalServerError', + message, + }); + } +} + /** * 刷新 Token * diff --git a/backend/src/common/auth/auth.routes.ts b/backend/src/common/auth/auth.routes.ts index 3d0564e3..379eac4c 100644 --- a/backend/src/common/auth/auth.routes.ts +++ b/backend/src/common/auth/auth.routes.ts @@ -12,6 +12,8 @@ import { getCurrentUser, getUserModules, changePassword, + updateAvatar, + uploadAvatar, refreshToken, logout, } from './auth.controller.js'; @@ -65,6 +67,16 @@ const changePasswordSchema = { }, }; +const updateAvatarSchema = { + body: { + type: 'object', + required: ['avatarUrl'], + properties: { + avatarUrl: { type: 'string', description: '头像URL(OSS地址)' }, + }, + }, +}; + const refreshTokenSchema = { body: { type: 'object', @@ -128,6 +140,22 @@ export async function authRoutes( preHandler: [authenticate], }, getUserModules); + /** + * 更新头像(URL方式) + */ + fastify.put('/me/avatar', { + preHandler: [authenticate], + schema: updateAvatarSchema, + }, updateAvatar as any); + + /** + * 上传头像(文件上传方式) + * 接收 multipart/form-data + */ + fastify.post('/me/avatar/upload', { + preHandler: [authenticate], + }, uploadAvatar as any); + /** * 修改密码 */ diff --git a/backend/src/common/auth/auth.service.ts b/backend/src/common/auth/auth.service.ts index 57845a43..6275ddb6 100644 --- a/backend/src/common/auth/auth.service.ts +++ b/backend/src/common/auth/auth.service.ts @@ -56,6 +56,13 @@ export interface UserInfoResponse { isDefaultPassword: boolean; permissions: string[]; modules: string[]; // 用户可访问的模块代码列表 + // 2026-01-28: 个人中心扩展字段 + avatarUrl?: string | null; + status?: string; + kbQuota?: number; + kbUsed?: number; + isTrial?: boolean; + trialEndsAt?: Date | null; } /** @@ -279,6 +286,13 @@ export class AuthService { isDefaultPassword: user.is_default_password, permissions, modules, // 新增:返回模块列表 + // 2026-01-28: 个人中心扩展字段 + avatarUrl: user.avatarUrl, + status: user.status, + kbQuota: user.kbQuota, + kbUsed: user.kbUsed, + isTrial: user.isTrial, + trialEndsAt: user.trialEndsAt, }; } @@ -330,6 +344,30 @@ export class AuthService { logger.info('用户修改密码成功', { userId }); } + /** + * 更新用户头像 + * + * @param userId 用户ID + * @param avatarUrl 头像URL(OSS地址) + */ + async updateAvatar(userId: string, avatarUrl: string): Promise<{ avatarUrl: string }> { + const user = await prisma.user.findUnique({ + where: { id: userId }, + }); + + if (!user) { + throw new Error('用户不存在'); + } + + await prisma.user.update({ + where: { id: userId }, + data: { avatarUrl }, + }); + + logger.info('用户更新头像成功', { userId, avatarUrl }); + return { avatarUrl }; + } + /** * 发送验证码 */ diff --git a/docs/03-业务模块/ADMIN-运营管理端/00-系统设计/Prompt管理系统升级:知识库集成方案.md b/docs/03-业务模块/ADMIN-运营管理端/00-系统设计/Prompt管理系统升级:知识库集成方案.md new file mode 100644 index 00000000..9648ae96 --- /dev/null +++ b/docs/03-业务模块/ADMIN-运营管理端/00-系统设计/Prompt管理系统升级:知识库集成方案.md @@ -0,0 +1,125 @@ +# **Prompt 管理系统升级:知识库集成 (RAG) 方案** + +## **1\. 背景与需求** + +统计学专家及其他业务方提出,Prompt 需要能够动态引用外部知识库(如统计学规范、ICD-10 编码手册、CRF 设计指南)。为了避免代码硬编码,我们需要在 Prompt 管理后台提供“知识库绑定”能力。 + +## **2\. 核心变更** + +### **2.1 数据库 Schema 变更** + +修改 capability\_schema.prompt\_templates 表,新增 knowledge\_config 字段。 + +我们引入 injection\_mode 字段,支持 **RAG 检索** 和 **全量注入** 两种策略。 + +model prompt\_templates { + // ... + // 存储 JSON 配置 + // 示例: + // { + // "enabled": true, + // "source\_type": "KB", + // "kb\_codes": \["STAT\_SAS\_GUIDE", "STAT\_R\_GUIDE"\], + // + // // ✨ 新增:注入模式 + // // "RAG": 向量检索 TopK (适合海量文档, \>20篇) + // // "FULL": 全量上下文注入 (适合少量核心文档, \<10篇, 精度最高) + // "injection\_mode": "FULL", + // + // "query\_field": "user\_question", // RAG模式必填 + // "target\_variable": "reference\_context", + // "top\_k": 3, // RAG模式生效 + // "min\_score": 0.6 // RAG模式生效 + // } + knowledge\_config Json? +} + +### **2.2 管理端 UI 升级 (Prompt Editor)** + +在 Prompt 编辑器右侧边栏增加 **"知识增强 (RAG)"** 面板。 + +#### **面板功能:** + +1. **开关**:启用/禁用知识库引用。 +2. **知识库选择**:下拉选择已存在的知识库。 +3. **注入模式选择 (✨ 新增)**: + * **智能检索 (RAG)**:推荐用于大型知识库。只检索最相关的片段,节省 Token,响应快。 + * **全量注入 (Full Context)**:推荐用于小型核心知识库(如\<10个文档)。将所有文档内容直接作为上下文发送给模型,**准确率最高,无检索损失**,但消耗 Token 较多。 +4. **检索触发词**:(仅 RAG 模式显示) 选择 Prompt 变量中的哪一个作为搜索关键词。 +5. **注入变量名**:指定内容放入哪个变量(默认 {{context}})。 + +### **2.3 渲染逻辑流程 (更新版)** + +业务侧调用 promptService.get 时,根据 injection\_mode 走不同分支: + +**分支 A:全量注入模式 (Full Context) —— 专家推荐** + +1. 读取绑定的知识库(如 "SAS 9.4 手册")。 +2. 直接读取该知识库下所有文档的**全文内容**(需注意总 Token 限制,可设置上限如 100k)。 +3. 拼接全文赋值给 variables.context。 +4. **优势**:模型能看到文档全貌,跨章节推理能力极强,完全避免"检索不到"的问题。 + +**分支 B:智能检索模式 (RAG)** + +1. 提取检索词(如 user\_requirement)。 +2. 调用向量数据库检索 Top K 片段。 +3. 拼接片段赋值给 variables.context。 +4. **优势**:便宜,快,适合从几千本书里找答案。 + +## **3\. 开发任务清单** + +* \[ \] **DB**: 更新 Prisma Schema,添加 knowledge\_config 字段。 +* \[ \] **Backend**: + * \[ \] PromptService 引入 RagService 和 DocumentService。 + * \[ \] **新增**:PromptService.get 实现 injection\_mode 分流逻辑。 + * \[ \] 实现全量拉取文档内容的逻辑 (Cache 优化)。 + * \[ \] 管理端 API 支持保存 knowledge\_config。 +* \[ \] **Frontend**: + * \[ \] PromptEditor 新增知识库配置侧边栏。 + * \[ \] **新增**:注入模式切换开关 (RAG / FULL)。 +* \[ \] **Verification**: 使用统计学 SAS 代码生成场景进行验证,对比两种模式的效果。 + +## **4\. 常见问答 (Q\&A)** + +**Q: 全量注入模式会不会太贵?** + +A: 取决于文档量。目前 DeepSeek-V3 输入价格约 1元/百万Token。假设 5 个文档共 5万 Token,单次调用成本约 0.05 元。对于专家级辅助工具,这个成本是完全可以接受的。 + +**Q: 全量注入模式有延迟吗?** + +A: 首字延迟会比 RAG 略高(因为预填充处理时间长),但目前 LLM 推理速度很快,体验差异通常在 1-2 秒内。 + +## **5\. AIA 智能体实战配置指南 (基于 V3.1)** + +根据 AIA 模块的 10 个核心智能体,建议的知识库绑定策略如下: + +### **Phase 1: 选题优化** + +此阶段重点在于**创新性**和**临床价值**评估。 + +| Prompt Code | 智能体名称 | 建议绑定知识库 | 注入模式 | 理由 | +| :---- | :---- | :---- | :---- | :---- | +| AIA\_SCIENTIFIC\_QUESTION | 科学问题梳理 | **\[公共\] 临床研究方法学导论** | **FULL** | 方法学书不厚,全量读入能让 AI 像读过书的教授一样指导,避免断章取义。 | +| AIA\_PICO\_ANALYSIS | PICO 梳理 | **\[公共\] ICD-10/11 编码手册** | **RAG** | 编码手册是字典型的,成千上万条,**必须用 RAG**,全量读入会撑爆上下文且无必要。 | +| AIA\_TOPIC\_EVALUATION | 选题评价 | **\[公共\] 顶级期刊选题指南** | **FULL** | 指南通常只有几页纸,全量注入效果最佳。 | + +### **Phase 2: 方案设计** + +此阶段重点在于**规范性**和**标准化**。 + +| Prompt Code | 智能体名称 | 建议绑定知识库 | 注入模式 | 理由 | +| :---- | :---- | :---- | :---- | :---- | +| AIA\_OUTCOME\_DESIGN | 观察指标设计 | **\[公共\] COMET (Core Outcome Measures)** | **RAG** | COMET 数据库很大,适合检索特定疾病的指标集。 | +| AIA\_CRF\_DESIGN | CRF 设计 | **\[公共\] CDISC/CDASH 标准指南** | **FULL** | CDASH 核心字段集文档适中,全量注入能保证字段间的逻辑关系正确。 | +| AIA\_PROTOCOL\_WRITING | 方案撰写 | **\[公共\] SPIRIT 声明 (2013)** | **FULL** | SPIRIT 清单很短,必须全量参考。 | +| AIA\_SAMPLE\_SIZE | 样本量计算 | **\[公共\] 常用样本量计算公式手册** | **FULL** | 公式手册通常很精简。 | + +### **Phase 3: 方案预评审** + +此阶段重点在于**查漏补缺**。 + +| Prompt Code | 智能体名称 | 建议绑定知识库 | 注入模式 | 理由 | +| :---- | :---- | :---- | :---- | :---- | +| AIA\_METHODOLOGY\_REVIEW | 方法学评审 | **\[公共\] CONSORT 声明 (RCT)** | **FULL** | 评审需要对照 Checklist 的每一条,**必须全量注入**,RAG 如果漏检索一条就会导致评审不完整。 | + +*注:需要在运营管理端提前创建上述\[公共\]知识库,并导入相应的 PDF/Markdown 规范文档。* \ No newline at end of file diff --git a/docs/03-业务模块/ADMIN-运营管理端/03-UI设计/AILOGO.png b/docs/03-业务模块/ADMIN-运营管理端/03-UI设计/AILOGO.png new file mode 100644 index 00000000..3babaae8 Binary files /dev/null and b/docs/03-业务模块/ADMIN-运营管理端/03-UI设计/AILOGO.png differ diff --git a/docs/03-业务模块/ADMIN-运营管理端/04-开发计划/05-Prompt知识库集成开发计划.md b/docs/03-业务模块/ADMIN-运营管理端/04-开发计划/05-Prompt知识库集成开发计划.md new file mode 100644 index 00000000..c62da824 --- /dev/null +++ b/docs/03-业务模块/ADMIN-运营管理端/04-开发计划/05-Prompt知识库集成开发计划.md @@ -0,0 +1,490 @@ +# Prompt 知识库集成开发计划 + +> **版本:** v1.1 +> **创建日期:** 2026-01-28 +> **优先级:** P0(核心能力增强) +> **状态:** 📋 规划中 +> **预计工期:** 6-7 个工作日 +> **前置依赖:** Prompt 管理系统 (已完成)、RAG 引擎 (已完成) + +--- + +## 📋 目录 + +1. [项目概述](#1-项目概述) +2. [需求分析](#2-需求分析) +3. [技术方案](#3-技术方案) +4. [数据库设计](#4-数据库设计) +5. [UI 设计](#5-ui-设计) +6. [开发任务清单](#6-开发任务清单) +7. [AIA 智能体配置指南](#7-aia-智能体配置指南) +8. [测试计划](#8-测试计划) +9. [风险与应对](#9-风险与应对) + +--- + +## 1. 项目概述 + +### 1.1 背景 + +当前 Prompt 管理系统已支持: +- ✅ 数据库存储与版本管理 +- ✅ 灰度预览(DRAFT/ACTIVE) +- ✅ 变量渲染(Handlebars) +- ✅ 三级容灾(数据库→缓存→兜底) + +**缺失能力:** Prompt 无法动态引用外部知识库(如方法学规范、GCP 指南、统计学手册)。 + +### 1.2 目标 + +构建 **Prompt + 知识库** 集成能力,实现: + +- 🎯 在 Prompt 管理后台配置知识库绑定(非硬编码) +- 🎯 支持两种注入模式:**RAG 检索** 和 **全量注入** +- 🎯 运行时自动将知识库内容注入到 Prompt 变量中 +- 🎯 为 AIA 10 个智能体配置最佳知识库策略 + +### 1.3 核心价值 + +| 痛点 | 解决方案 | +|------|---------| +| 专家知识只能硬编码到 Prompt | 知识库绑定,动态引用 | +| RAG 检索可能遗漏关键内容 | 支持 FULL 全量注入模式 | +| 每个智能体配置分散在代码中 | 统一后台配置,运营可调整 | + +--- + +## 2. 需求分析 + +### 2.1 业务需求 + +| 需求方 | 需求描述 | 优先级 | +|--------|---------|--------| +| 方法学专家 | 方法学评审需要完整参考 CONSORT 声明 | P0 | +| 统计专家 | 样本量计算需要参考公式手册 | P0 | +| 产品经理 | 可在后台配置和调整知识库绑定 | P0 | +| 运营人员 | 无需开发即可为新 Prompt 配置知识库 | P1 | + +### 2.2 技术需求 + +| 需求 | 描述 | +|------|------| +| 两种注入模式 | RAG(向量检索)+ FULL(全量注入) | +| 配置化 | 在 Prompt 管理后台 UI 配置 | +| 变量注入 | 自动将内容注入到指定 Prompt 变量 | +| 缓存优化 | FULL 模式需要缓存知识库全文 | + +### 2.3 已有能力复用 + +| 能力 | 位置 | 状态 | +|------|------|------| +| PromptService | `backend/src/common/prompt/` | ✅ 可扩展 | +| RAG 引擎 | `backend/src/common/rag/` | ✅ 可复用 | +| PKB 知识库 | `backend/src/modules/pkb/` | ✅ 可复用 | +| Prompt 管理 UI | `frontend-v2/src/pages/admin/` | ✅ 可扩展 | + +--- + +## 3. 技术方案 + +### 3.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Prompt 管理后台(运营端) │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Prompt 编辑器 │ │ +│ │ ┌─────────────────┐ ┌─────────────────────────────┐ │ │ +│ │ │ 内容编辑区域 │ │ 🆕 知识库增强配置面板 │ │ │ +│ │ │ {{context}} │ │ ☑️ 启用知识库增强 │ │ │ +│ │ │ {{question}} │ │ 📚 知识库:[CONSORT声明] │ │ │ +│ │ │ ... │ │ 🔄 模式:FULL / RAG │ │ │ +│ │ └─────────────────┘ │ 📝 注入变量:context │ │ │ +│ │ └─────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────────┘ │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ PromptService(增强版) │ +│ │ +│ get(code, variables, userId, userQuery?) │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ 1. 获取 Prompt 模板 + knowledge_config │ │ +│ │ 2. 检查 knowledge_config.enabled │ │ +│ │ ├─ 未启用 → 直接渲染返回 │ │ +│ │ └─ 已启用 → 根据 injection_mode 分支处理 │ │ +│ │ ├─ FULL → 全量加载知识库文档 │ │ +│ │ └─ RAG → 向量检索 Top K │ │ +│ │ 3. 将内容注入 variables[target_variable] │ │ +│ │ 4. 渲染完整 Prompt 返回 │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ┌─────────────┴─────────────┐ + │ │ + ▼ ▼ +┌──────────────────────┐ ┌──────────────────────────────────┐ +│ FULL 模式 │ │ RAG 模式 │ +│ DocumentService │ │ RagEngine │ +│ - 全量加载文档 │ │ - 向量检索 │ +│ - 缓存优化 │ │ - Top K + 相似度过滤 │ +└──────────────────────┘ └──────────────────────────────────┘ +``` + +### 3.2 注入模式对比 + +| 特性 | FULL 全量注入 | RAG 向量检索 | +|------|--------------|-------------| +| **适用场景** | 小型核心知识库(<10 篇) | 大型知识库(>20 篇) | +| **准确率** | ⭐⭐⭐⭐⭐ 最高 | ⭐⭐⭐⭐ 较高 | +| **Token 消耗** | 较多(全文) | 较少(片段) | +| **响应速度** | 略慢(预填充) | 较快 | +| **典型用例** | CONSORT 声明、SPIRIT 清单 | ICD-10 编码、文献库 | + +### 3.3 数据流 + +``` +用户提问 + │ + ▼ +业务模块调用 promptService.get(code, vars, userId, userQuery) + │ + ▼ +┌─────────────────────────────────────────┐ +│ PromptService.get() │ +│ │ +│ 1. 查询 prompt_templates 获取配置 │ +│ 2. 检查 knowledge_config │ +└─────────────┬───────────────────────────┘ + │ + ┌─────────┴─────────┐ + │ │ + ▼ ▼ +enabled: false enabled: true + │ │ + ▼ ▼ +直接渲染 判断 injection_mode + │ + ┌─────────────┴─────────────┐ + │ │ + ▼ ▼ + mode: "FULL" mode: "RAG" + │ │ + ▼ ▼ + 加载知识库全文 向量检索 Top K + (DocumentService) (RagEngine) + │ │ + └─────────┬─────────────────┘ + │ + ▼ + 注入到 variables[target_variable] + │ + ▼ + Handlebars 渲染 + │ + ▼ + 返回完整 Prompt +``` + +--- + +## 4. 数据库设计 + +### 4.1 Schema 变更 + +**修改表:** `capability_schema.prompt_templates` + +```prisma +model prompt_templates { + id Int @id @default(autoincrement()) + code String @unique @db.VarChar(100) + name String @db.VarChar(200) + description String? @db.Text + module String @db.VarChar(50) + variables Json? + model_config Json? @map("model_config") + + // 🆕 知识库配置 + knowledge_config Json? @map("knowledge_config") + + created_at DateTime @default(now()) @map("created_at") + updated_at DateTime @updatedAt @map("updated_at") + + versions prompt_versions[] + + @@map("prompt_templates") + @@schema("capability_schema") +} +``` + +### 4.2 knowledge_config 结构 + +```typescript +interface KnowledgeConfig { + enabled: boolean; + kb_codes: string[]; // 关联的知识库编码 + injection_mode: 'FULL' | 'RAG'; + target_variable: string; // 默认 'context' + // RAG 模式配置 + query_field?: string; + top_k?: number; + min_score?: number; +} +``` + +### 4.3 系统知识库表(新建) + +```sql +-- 系统知识库 +CREATE TABLE capability_schema.system_knowledge_bases ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + code VARCHAR(50) UNIQUE NOT NULL, + name VARCHAR(100) NOT NULL, + description TEXT, + category VARCHAR(50), + document_count INT DEFAULT 0, + total_tokens INT DEFAULT 0, + status VARCHAR(20) DEFAULT 'active', + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); + +-- 知识库文档 +CREATE TABLE capability_schema.system_kb_documents ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + kb_id UUID REFERENCES capability_schema.system_knowledge_bases(id), + filename VARCHAR(255) NOT NULL, + file_path VARCHAR(500), + file_size INT, + token_count INT DEFAULT 0, + status VARCHAR(20) DEFAULT 'pending', + created_at TIMESTAMP DEFAULT NOW() +); +``` + +--- + +## 5. UI 设计 + +### 5.1 系统知识库管理 + +**入口:** 运营管理端 → 系统知识库 + +| 功能 | 说明 | +|------|------| +| 知识库列表 | 查看、搜索、按分类筛选 | +| 创建知识库 | 编码、名称、分类、描述 | +| 文档管理 | 上传/删除文档 | +| 状态查看 | 文档数、Token 数 | + +### 5.2 Prompt 编辑器(方案 A:右侧独立卡片) + +在现有右侧面板新增「📚 知识库增强」卡片: + +``` +┌───────────────────────────────────┬─────────────────────────┐ +│ 📝 Prompt 内容 │ ⚙️ 配置 │ +│ ┌─────────────────────────────┐ │ 模块 / 状态 / 版本 │ +│ │ {{context}} │ ├─────────────────────────┤ +│ │ 你是一位方法学专家... │ │ 📚 知识库增强 │ +│ └─────────────────────────────┘ │ ☑️ 启用 │ +│ │ 知识库: [CONSORT ▼] │ +│ 🧪 测试渲染 │ 模式: ● FULL ○ RAG │ +│ │ 注入变量: [context ▼] │ +│ ├─────────────────────────┤ +│ │ 🔤 变量列表 │ +└───────────────────────────────────┴─────────────────────────┘ +``` + +--- + +## 6. 开发任务清单 + +### 6.1 总体时间线 + +``` +Day 1: 数据库设计 + 迁移 +Day 2: 系统知识库管理(后端 API) +Day 3: 系统知识库管理(前端页面) +Day 4: PromptService 增强(FULL/RAG) +Day 5: Prompt 编辑器 UI(知识库配置卡片) +Day 6: AIA 智能体配置 + 集成测试 +Day 7: 优化 + 文档 + 上线 +``` + +### 6.2 详细任务 + +#### Phase 1: 数据库(Day 1) + +| ID | 任务 | 状态 | +|----|------|------| +| 1.1 | prompt_templates 添加 knowledge_config 字段 | ⏳ | +| 1.2 | 创建 system_knowledge_bases 表 | ⏳ | +| 1.3 | 创建 system_kb_documents 表 | ⏳ | +| 1.4 | 执行 Prisma 迁移 | ⏳ | + +#### Phase 2: 系统知识库管理(Day 2-3) + +| ID | 任务 | 状态 | +|----|------|------| +| 2.1 | 知识库 CRUD API | ⏳ | +| 2.2 | 文档上传/删除 API | ⏳ | +| 2.3 | 文档向量化集成 | ⏳ | +| 2.4 | 知识库列表页 | ⏳ | +| 2.5 | 知识库详情页(文档管理) | ⏳ | + +#### Phase 3: PromptService 增强(Day 4) + +| ID | 任务 | 状态 | +|----|------|------| +| 3.1 | 扩展 get() 方法支持 knowledge_config | ⏳ | +| 3.2 | 实现 FULL 模式(全量加载) | ⏳ | +| 3.3 | 实现 RAG 模式(向量检索) | ⏳ | +| 3.4 | 添加缓存优化 | ⏳ | + +#### Phase 4: 前端 UI(Day 5) + +| ID | 任务 | 状态 | +|----|------|------| +| 4.1 | PromptEditor 新增知识库配置卡片 | ⏳ | +| 4.2 | 知识库选择器组件 | ⏳ | +| 4.3 | 注入模式切换 | ⏳ | +| 4.4 | 保存/加载配置联调 | ⏳ | + +#### Phase 5: 联调收尾(Day 6-7) + +| ID | 任务 | 状态 | +|----|------|------| +| 5.1 | 配置 AIA 智能体的 knowledge_config | ⏳ | +| 5.2 | 端到端测试 | ⏳ | +| 5.3 | 上线部署 | ⏳ | + +--- + +## 7. AIA 智能体配置指南 + +### 7.1 Phase 1: 选题优化 + +| Prompt Code | 智能体 | 知识库 | 模式 | 理由 | +|-------------|--------|--------|------|------| +| `AIA_SCIENTIFIC_QUESTION` | 科学问题梳理 | 临床研究方法学导论 | **FULL** | 方法学书籍需要全量理解 | +| `AIA_PICO_ANALYSIS` | PICO 梳理 | ICD-10/11 编码手册 | **RAG** | 编码手册数据量大,需检索 | +| `AIA_TOPIC_EVALUATION` | 选题评价 | 顶级期刊选题指南 | **FULL** | 指南内容精简,全量最佳 | + +### 7.2 Phase 2: 方案设计 + +| Prompt Code | 智能体 | 知识库 | 模式 | 理由 | +|-------------|--------|--------|------|------| +| `AIA_OUTCOME_DESIGN` | 观察指标设计 | COMET 核心指标集 | **RAG** | COMET 数据库较大 | +| `AIA_CRF_DESIGN` | CRF 设计 | CDISC/CDASH 标准 | **FULL** | 字段逻辑需要完整参考 | +| `AIA_PROTOCOL_WRITING` | 方案撰写 | SPIRIT 2013 声明 | **FULL** | 清单必须完整参考 | +| `AIA_SAMPLE_SIZE` | 样本量计算 | 样本量公式手册 | **FULL** | 公式手册内容精简 | + +### 7.3 Phase 3: 方案预评审 + +| Prompt Code | 智能体 | 知识库 | 模式 | 理由 | +|-------------|--------|--------|------|------| +| `AIA_METHODOLOGY_REVIEW` | 方法学评审 | CONSORT 2010 声明 | **FULL** | ⭐ **必须全量**,漏检会导致评审不完整 | + +### 7.4 Phase 5: 写作助手 + +| Prompt Code | 智能体 | 知识库 | 模式 | 理由 | +|-------------|--------|--------|------|------| +| `AIA_PAPER_POLISH` | 论文润色 | - | 无 | 纯语言处理,无需知识库 | +| `AIA_PAPER_TRANSLATE` | 论文翻译 | - | 无 | 纯翻译任务,无需知识库 | + +--- + +## 8. 测试计划 + +### 8.1 单元测试 + +| 测试项 | 用例 | +|--------|------| +| PromptService.get() | 知识库未启用时正常返回 | +| PromptService.get() | FULL 模式正确加载全文 | +| PromptService.get() | RAG 模式正确检索 Top K | +| PromptService.get() | 知识库不存在时降级处理 | + +### 8.2 集成测试 + +| 场景 | 步骤 | 预期 | +|------|------|------| +| 方法学评审 | 调用 AIA_METHODOLOGY_REVIEW | 返回包含 CONSORT 全文的 Prompt | +| PICO 梳理 | 输入疾病名称 | 返回包含相关 ICD 编码的 Prompt | +| 无知识库 | 调用 AIA_PAPER_POLISH | 正常返回,无知识库内容 | + +### 8.3 效果对比测试 + +| 智能体 | FULL 模式效果 | RAG 模式效果 | 结论 | +|--------|--------------|-------------|------| +| 方法学评审 | 完整覆盖所有条目 | 可能遗漏 | 使用 FULL | +| PICO 梳理 | Token 超限 | 精准命中 | 使用 RAG | + +--- + +## 9. 风险与应对 + +### 9.1 技术风险 + +| 风险 | 影响 | 概率 | 应对 | +|------|------|------|------| +| FULL 模式 Token 超限 | 请求失败 | 中 | 设置 max_tokens 限制,超限警告 | +| RAG 检索不准确 | 内容遗漏 | 中 | 提供 FULL 模式备选 | +| 知识库加载慢 | 用户等待 | 低 | 缓存 + 预加载 | + +### 9.2 业务风险 + +| 风险 | 影响 | 应对 | +|------|------|------| +| 知识库内容过时 | 引用错误规范 | 定期更新机制 | +| 配置错误 | 智能体效果下降 | 灰度预览 + 测试 | + +### 9.3 成本分析 + +| 模式 | 典型场景 | Token 消耗 | 成本估算 | +|------|---------|-----------|---------| +| FULL | 5 篇文档,共 5 万 Token | 5 万 | ¥0.05/次 | +| RAG | Top 5 片段,共 5000 Token | 5000 | ¥0.005/次 | + +> DeepSeek-V3 输入价格:约 ¥1/百万 Token + +--- + +## 📎 附录 + +### A. 相关文档 + +- [Prompt 管理系统设计方案](../00-系统设计/Prompt管理系统升级:知识库集成方案.md) +- [Prompt 管理系统开发计划](./02-Prompt管理系统开发计划.md) +- [AIA 模块状态文档](../../AIA-AI智能问答/00-模块当前状态与开发指南.md) + +### B. 代码位置 + +| 类型 | 路径 | +|------|------| +| PromptService | `backend/src/common/prompt/prompt.service.ts` | +| RAG 引擎 | `backend/src/common/rag/` | +| 前端编辑器 | `frontend-v2/src/pages/admin/PromptEditorPage.tsx` | +| 数据库 Schema | `backend/prisma/schema.prisma` | + +### C. 知识库命名规范 + +``` +{CATEGORY}_{NAME}_{VERSION} + +示例: +- METHODOLOGY_CONSORT_2010 +- METHODOLOGY_SPIRIT_2013 +- STATISTICS_SAMPLE_SIZE_FORMULAS +- CRF_CDASH_V2 +``` + +--- + +*最后更新:2026-01-28* + +**🚀 准备好开始了吗?从 Phase 1 数据库设计开始!** diff --git a/frontend-v2/index.html b/frontend-v2/index.html index 4d871072..6134b70d 100644 --- a/frontend-v2/index.html +++ b/frontend-v2/index.html @@ -1,10 +1,10 @@ - +
- + -
AI临床研究平台
@@ -133,14 +132,15 @@ const TopNavigation = () => {
})}
- {/* 用户菜单 - 显示真实用户信息 */}
+ {/* 用户菜单 - 显示真实用户信息和头像 */}