commit bdc7de80436bbdf3823f4366914fa143b2c2f3a8 Author: AI Clinical Dev Team Date: Fri Oct 10 15:14:54 2025 +0800 chore: project initialization - Day 4 environment setup diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..49385780 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Testing +coverage/ + +# Production +build/ +dist/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Docker +docker-compose.override.yml + +# Prisma +prisma/.env +*.db +*.db-journal + +# Temporary files +tmp/ +temp/ +*.tmp + diff --git a/AI Clinical Research PRD.txt b/AI Clinical Research PRD.txt new file mode 100644 index 00000000..8662d4f2 --- /dev/null +++ b/AI Clinical Research PRD.txt @@ -0,0 +1,90 @@ +AI科研助手产品需求文档 (PRD) + + 1. 产品概述 +1.1 产品简介 +AI科研助手是一款专注于赋能临床及科研人员的智能化平台。它通过集成一系列基于大语言模型的AI智能体,为科研工作者在从课题选择、方案设计、数据收集、论文撰写到最终发表的全流程中提供精准、高效、专业的AI辅助,旨在解决科研过程中耗时耗力、信息壁垒、方法学门槛高等痛点,全面提升科研工作的效率与质量。 +1.2 目标用户 +本平台的核心用户群体包括: +(1)临床医生/科研人员: 需要在繁忙的临床工作之余,高效开展高质量科学研究的核心人群。 +(2)在读硕/博士研究生: 在科研学习阶段,需要专业指导和高效工具来完成研究课题与毕业论文的学生。 +(3)医药企业研发人员(R&D): 从事新药研发、临床试验等工作,需要快速获取文献信息、设计研究方案的专业人士。 +1.3 产品目标 + +(1)打造一套覆盖临床研究核心流程的AI智能体工具集,解决用户在选题、研究设计及论文写作阶段的关键需求。 +(2)优化人机交互体验,确保用户可以低门槛、便捷地使用各项功能。 + (3)发展成为科研领域内领先的一站式AI解决方案平台。 +(4)后期考虑,增加基于大规模(1000篇以内)文献的读取、识别、内容提取的工作 + + + +2. 功能需求详述 (Functional Requirements) +2.1 用户端功能 + +2.1.1 核心功能:项目/课题管理 (Context Persistence) +为解决用户需要反复输入背景信息的问题,引入项目制管理,确保AI对话的上下文连贯性。 +(1)项目创建与管理: 用户可以创建、编辑和删除不同的“项目”或“课题”。 +(2)项目背景信息预设: 在每个项目中,用户可以预先填入该项目的核心背景信息。 +(3)上下文自动关联: 在特定项目内发起的所有AI智能体对话,都将自动继承该项目的背景信息。 +● 动态背景信息管理: +(1)宏观编辑: 在项目主页,用户可通过点击编辑按钮,在弹出的模态框中对项目背景信息进行全面的、多行的编辑与修改。 +(2)微观追加: 在项目内的对话中,用户可将AI生成的关键回答(如PICOS框架、核心结论等)通过“固定”操作,一键追加到当前项目的背景信息中,实现项目信息的动态演进。 + + +2.1.2 核心功能:AI智能体 (Agent) +AI智能体是产品的核心,用户可以通过以下两种主要路径与智能体进行交互: +1. 全局快速问答 (Global Quick Chat): 用户可直接在主界面访问所有智能体,用于处理与特定项目无关的一次性问题。 +2. 项目内深度研究 (In-Project Deep Research): 用户进入一个具体的“项目/课题”空间后调用智能体,所有对话将自动继承该项目的背景信息。 + +(重点)智能体功能列表: + + (1)选题评价 智能体:从创新性、临床价值、科学性和可行性等维度,对用户提出的临床问题进行全面评价,并提供初步的SWOT分析。 用户输入的临床问题描述(自由文本),可关联项目背景。 结构化的评价报告,包含创新性、临床价值、科学性、可行性分析及综合建议。 + (2)科学问题梳理智能体: 辅助用户将一个模糊或宽泛的研究想法,提炼成一个清晰、具体、可验证的科学问题。 一个初步的研究想法,如“研究肠道菌群与抑郁症的关系”。 多个精炼后的科学问题选项,供用户选择或参考。 + (3)PICOS构建智能体: 引导用户按照PICOS原则来结构化地定义临床研究的核心要素。 引导式表单或自由文本描述的研究问题。 一个标准化的PICOS表格,清晰列出各项具体内容。 + (4)观察指标设计智能体: 基于研究设计和因果关系,为用户的研究推荐合适的主要、次要及安全性观察指标集。 已确定的PICOS框架或研究问题。 包含具体指标、定义、测量方法建议的清单。 + (5)CRF制定智能体: 基于研究方案和观察指标,自动生成一份结构化、符合规范的病例报告表(CRF)框架。 研究方案、观察指标清单。 一份可下载的CRF框架草稿(如Word/Excel格式)。 + (6)样本量计算智能体: 根据研究类型、检验水准、把握度、效应量等核心参数,提供科学合理的样本量估算结果。 引导式表单输入研究设计、α、β、效应量等。 详细的样本量计算结果,包含公式、参数说明和最终建议样本量。 + (7)临床研究方案撰写智能体: 基于科学问题、PICOS等信息,自动生成一份初步但结构完整的临床研究设计方案。 已确定的科学问题、PICOS、样本量等。 一份包含研究背景、目的、设计、流程等章节的Word文档初稿。 + (8)论文润色智能体: 针对用户上传的稿件,提供专业级的语言润色,修正语法、拼写和表达方式。 上传的论文稿件(Word/Text),目标期刊名称(可选)。 一份带修订标记的润色后文稿及修改摘要说明。 + (9)论文翻译智能体: 提供专业、精准的中英互译服务,特别针对医学科研领域的术语进行优化。 上传的论文稿件(Word/Text),选择源语言和目标语言。 翻译完成的稿件,保留原格式。 + (10)方法学评审智能体: 从研究问题、方案设计、实施可行性和临床意义等维度,对研究方案或论文进行全面的方法学评审。 上传的研究方案或论文稿件。 一份评审报告,分点列出方法学上的优点、潜在缺陷及改进建议。 + (11)期刊方法学评审智能体: 模拟期刊审稿人视角,针对投稿文章中可能存在的统计学、方法学问题进行提问和挑战。 上传的论文稿件,目标期刊。 一份模拟的“审稿意见”,列出可能被挑战的问题点。 + (12)期刊稿约评审智能体: 依据目标期刊的投稿要求,自动检查文章在格式、字数、参考文献规范等方面是否符合标准。 上传的论文稿件,目标期刊的投稿指南。 一份格式审查报告,清晰列出所有不符合项和修改建议。 + +在智能体对话中的重点功能: + (1)对话交互: 模型即时切换 在对话界面,用户可随时通过下拉菜单切换当前对话所使用的大语言模型(如Gemini, DeepSeek等),以应对不同任务。用户选择模型,后续对话由新选定的模型驱动。 + (2)临时附件上传: 在对话输入框旁提供上传按钮,支持用户上传临时文件(如PDF, Word)供AI进行一次性分析、总结或评审。 用户上传的单个文件。 AI基于该附件内容进行回答。 + (3)知识库融合对话: 在任何对话窗口中,用户可随时通过“@”操作调用个人知识库中的分类,让AI优先基于所选内容回答。 @骨质疏松专题 融合了私有知识和通用知识的回答。 + (4)答案溯源与引用: 当AI回答引用自个人知识库时,必须生成清晰、可点击的引用标记。 - 回答中包含指向源文档具体位置的引用。 + (5)对话内追加背景: 在项目对话中,提供将AI回答“固定”到项目背景的功能。 用户点击“固定”按钮。 该条回答被追加到项目描述中。 + (6)历史对话管理: 自动保存所有对话记录,支持用户在独立的“历史记录”页面中进行查看、搜索和筛选。: + +2.1.3 核心功能:个人知识库 (Personal Knowledge Base) +个人知识库是用户专属的、私密的知识管理中心。 +(1)层级化管理: 采用两级结构进行管理。第一级为知识库列表,用户可在此创建、编辑知识库分类;第二级为知识库详情页,用户点击某个知识库后,可查看和管理该库内的所有文件。 +(2)文档上传与处理: 支持在知识库详情页上传多种格式的文档。 +(3)文档处理状态透明化: 每份上传的文档都应有明确的状态标识:“处理中”、“已就绪”、“处理失败”。 +(4)失败原因提示: 若文档处理失败,系统需向用户提供清晰的原因说明。 +用户在智能体问答过程中,可以基于创建的个人知识库来进行问答 + +2.1.4 核心功能:历史记录 (History) +提供一个独立的顶级功能入口,用于管理用户的所有对话。 +(1)统一列表: 按时间倒序展示用户所有的对话记录。 +(2)来源标识: 每条记录都清晰标识其来源是“全局快速问答”还是具体的某个“项目”。 +(3)搜索与筛选: 提供强大的搜索框,并支持按项目、智能体、日期范围进行筛选,帮助用户快速定位历史对话。 +2.1.5 辅助功能 (Support) +(1)快速上手: 在侧边栏提供独立入口,点击后展示产品核心功能引导和使用教程。 +(2)帮助中心: 在侧边栏提供独立入口,点击后展示FAQ和详细的用户手册。 + +2.2 运营端/后台功能 + +(1)仪表盘: 核心数据概览 以图表形式展示关键运营指标,如:今日活跃用户、7日活跃用户、总用户数、今日对话数等。 方便运营人员快速了解产品状态。 +(2)智能体管理: 智能体列表 以列表形式展示所有前端可用的AI智能体,支持上下线操作。 +(3)智能体配置: 管理员可新增、编辑智能体,配置其名称、图标、描述、所属分类等。 +(4)Prompt管理 核心功能。管理员可为每个智能体精细化地调试和优化其背后的系统级提示词(System Prompt),并进行版本管理。 这是保障智能体专业性的关键。 +(5)模型管理 模型接入与配置 管理后台接入的各类大语言模型(如Gemini, DeepSeek),并可配置其API密钥、调用参数、启用/禁用状态。 +(6)用户管理 用户列表与检索 查看所有用户信息(ID, 手机号/邮箱, 注册时间, 状态),并支持多条件搜索。 +(7)账户详情与操作 管理员可查看单个用户的详情,并进行操作,如: - 设置/延长试用期。 - 启用或禁用账户。 - 查看操作日志。 +(8)数据统计 用户行为统计 查看用户的登录历史记录(登录时间),以及各个核心功能(如不同智能体)的使用频次统计。 帮助分析用户偏好和功能热度。 +(9)对话管理 :用户历史对话查看, 需建立严格的权限分级。只有在处理用户申诉或技术排障时,由授权的高级管理员在获得审批后,才能查看经过脱敏和屏蔽隐私信息的对话数据。 安全与隐私强化。所有查看行为必须记录在案,以备审计。 + + diff --git a/README.md b/README.md new file mode 100644 index 00000000..33adcc50 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# AI科研助手 + +> 专注于赋能临床及科研人员的智能化平台 + +## 📚 项目文档 + +完整的项目文档位于 `docs/` 目录: + +- [产品需求文档(PRD)](./docs/00-项目概述/产品需求文档(PRD).md) +- [技术架构总览](./docs/00-项目概述/技术架构总览.md) +- [数据库设计文档](./docs/01-设计文档/数据库设计文档.md) +- [API设计规范](./docs/01-设计文档/API设计规范.md) +- [开发里程碑](./docs/04-开发计划/开发里程碑.md) + +## 🏗️ 技术栈 + +### 前端 +- React 18 + TypeScript +- Vite +- TailwindCSS +- Zustand +- LobeChat组件 + +### 后端 +- Node.js + Fastify + TypeScript +- Prisma ORM +- PostgreSQL +- Redis + +### 第三方服务 +- Dify(RAG知识库) +- DeepSeek-V3(主力LLM) +- Qwen3(备用LLM) + +## 🚀 快速开始 + +### 1. 启动基础服务 + +```bash +# 启动PostgreSQL和Redis +docker-compose up -d +``` + +### 2. 后端开发 + +```bash +cd backend +npm install +npm run dev +``` + +### 3. 前端开发 + +```bash +cd frontend +npm install +npm run dev +``` + +## 📦 目录结构 + +``` +AIclinicalresearch/ +├── frontend/ # 前端项目 +├── backend/ # 后端项目 +├── docs/ # 项目文档 +├── docker-compose.yml # Docker配置 +└── README.md # 本文件 +``` + +## 🔑 环境变量 + +请参考 `.env.example` 文件配置环境变量。 + +## 📖 开发指南 + +请查看 [开发里程碑](./docs/04-开发计划/开发里程碑.md) 了解详细的开发计划。 + +## 📄 License + +MIT + +--- + +**当前开发阶段:** 里程碑1 - Day 4(环境搭建) +**开发进度:** 设计阶段已完成,正在进行基础搭建 + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..9bc6be72 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,48 @@ +version: '3.8' + +services: + # PostgreSQL 数据库 + postgres: + image: postgres:15-alpine + container_name: ai-clinical-postgres + environment: + POSTGRES_DB: ai_clinical_research + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres123 + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - ai-clinical-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 + + # Redis 缓存 + redis: + image: redis:7-alpine + container_name: ai-clinical-redis + ports: + - "6379:6379" + volumes: + - redis_data:/data + networks: + - ai-clinical-network + command: redis-server --appendonly yes + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: + redis_data: + +networks: + ai-clinical-network: + driver: bridge + diff --git a/docs/00-项目概述/产品需求文档(PRD).md b/docs/00-项目概述/产品需求文档(PRD).md new file mode 100644 index 00000000..745c6bad --- /dev/null +++ b/docs/00-项目概述/产品需求文档(PRD).md @@ -0,0 +1,359 @@ +# AI科研助手产品需求文档 (PRD) + +> **版本:** v1.0 +> **创建日期:** 2025-10-10 +> **文档状态:** 正式版 + +--- + +## 📋 目录 + +1. [产品概述](#产品概述) +2. [功能需求详述](#功能需求详述) +3. [用户端功能](#用户端功能) +4. [运营端/后台功能](#运营端后台功能) + +--- + +## 1. 产品概述 + +### 1.1 产品简介 + +**AI科研助手**是一款专注于赋能临床及科研人员的智能化平台。它通过集成一系列基于大语言模型的AI智能体,为科研工作者在从课题选择、方案设计、数据收集、论文撰写到最终发表的全流程中提供精准、高效、专业的AI辅助,旨在解决科研过程中耗时耗力、信息壁垒、方法学门槛高等痛点,全面提升科研工作的效率与质量。 + +### 1.2 目标用户 + +本平台的核心用户群体包括: + +**(1) 临床医生/科研人员** +- 需要在繁忙的临床工作之余,高效开展高质量科学研究的核心人群 + +**(2) 在读硕/博士研究生** +- 在科研学习阶段,需要专业指导和高效工具来完成研究课题与毕业论文的学生 + +**(3) 医药企业研发人员(R&D)** +- 从事新药研发、临床试验等工作,需要快速获取文献信息、设计研究方案的专业人士 + +### 1.3 产品目标 + +**(1) 工具集覆盖** +- 打造一套覆盖临床研究核心流程的AI智能体工具集,解决用户在选题、研究设计及论文写作阶段的关键需求 + +**(2) 交互优化** +- 优化人机交互体验,确保用户可以低门槛、便捷地使用各项功能 + +**(3) 行业领先** +- 发展成为科研领域内领先的一站式AI解决方案平台 + +**(4) 未来规划** +- 后期考虑,增加基于大规模(1000篇以内)文献的读取、识别、内容提取的工作 + +--- + +## 2. 功能需求详述 (Functional Requirements) + +### 2.1 用户端功能 + +#### 2.1.1 核心功能:项目/课题管理 (Context Persistence) + +为解决用户需要反复输入背景信息的问题,引入项目制管理,确保AI对话的上下文连贯性。 + +**基础功能:** + +**(1) 项目创建与管理** +- 用户可以创建、编辑和删除不同的"项目"或"课题" + +**(2) 项目背景信息预设** +- 在每个项目中,用户可以预先填入该项目的核心背景信息 + +**(3) 上下文自动关联** +- 在特定项目内发起的所有AI智能体对话,都将自动继承该项目的背景信息 + +**动态背景信息管理:** + +**(1) 宏观编辑** +- 在项目主页,用户可通过点击编辑按钮,在弹出的模态框中对项目背景信息进行全面的、多行的编辑与修改 + +**(2) 微观追加** +- 在项目内的对话中,用户可将AI生成的关键回答(如PICOS框架、核心结论等)通过"固定"操作,一键追加到当前项目的背景信息中,实现项目信息的动态演进 + +--- + +#### 2.1.2 核心功能:AI智能体 (Agent) + +AI智能体是产品的核心,用户可以通过以下两种主要路径与智能体进行交互: + +**交互路径:** + +**1. 全局快速问答 (Global Quick Chat)** +- 用户可直接在主界面访问所有智能体,用于处理与特定项目无关的一次性问题 + +**2. 项目内深度研究 (In-Project Deep Research)** +- 用户进入一个具体的"项目/课题"空间后调用智能体,所有对话将自动继承该项目的背景信息 + +--- + +**(重点)智能体功能列表:** + +##### 选题阶段 + +**① 选题评价智能体** +- **功能描述:** 从创新性、临床价值、科学性和可行性等维度,对用户提出的临床问题进行全面评价,并提供初步的SWOT分析 +- **输入:** 用户输入的临床问题描述(自由文本),可关联项目背景 +- **输出:** 结构化的评价报告,包含创新性、临床价值、科学性、可行性分析及综合建议 + +**② 科学问题梳理智能体** +- **功能描述:** 辅助用户将一个模糊或宽泛的研究想法,提炼成一个清晰、具体、可验证的科学问题 +- **输入:** 一个初步的研究想法,如"研究肠道菌群与抑郁症的关系" +- **输出:** 多个精炼后的科学问题选项,供用户选择或参考 + +##### 研究设计阶段 + +**③ PICOS构建智能体** +- **功能描述:** 引导用户按照PICOS原则来结构化地定义临床研究的核心要素 +- **输入:** 引导式表单或自由文本描述的研究问题 +- **输出:** 一个标准化的PICOS表格,清晰列出各项具体内容 + +**④ 观察指标设计智能体** +- **功能描述:** 基于研究设计和因果关系,为用户的研究推荐合适的主要、次要及安全性观察指标集 +- **输入:** 已确定的PICOS框架或研究问题 +- **输出:** 包含具体指标、定义、测量方法建议的清单 + +**⑤ CRF制定智能体** +- **功能描述:** 基于研究方案和观察指标,自动生成一份结构化、符合规范的病例报告表(CRF)框架 +- **输入:** 研究方案、观察指标清单 +- **输出:** 一份可下载的CRF框架草稿(如Word/Excel格式) + +**⑥ 样本量计算智能体** +- **功能描述:** 根据研究类型、检验水准、把握度、效应量等核心参数,提供科学合理的样本量估算结果 +- **输入:** 引导式表单输入研究设计、α、β、效应量等 +- **输出:** 详细的样本量计算结果,包含公式、参数说明和最终建议样本量 + +**⑦ 临床研究方案撰写智能体** +- **功能描述:** 基于科学问题、PICOS等信息,自动生成一份初步但结构完整的临床研究设计方案 +- **输入:** 已确定的科学问题、PICOS、样本量等 +- **输出:** 一份包含研究背景、目的、设计、流程等章节的Word文档初稿 + +##### 论文阶段 + +**⑧ 论文润色智能体** +- **功能描述:** 针对用户上传的稿件,提供专业级的语言润色,修正语法、拼写和表达方式 +- **输入:** 上传的论文稿件(Word/Text),目标期刊名称(可选) +- **输出:** 一份带修订标记的润色后文稿及修改摘要说明 + +**⑨ 论文翻译智能体** +- **功能描述:** 提供专业、精准的中英互译服务,特别针对医学科研领域的术语进行优化 +- **输入:** 上传的论文稿件(Word/Text),选择源语言和目标语言 +- **输出:** 翻译完成的稿件,保留原格式 + +**⑩ 方法学评审智能体** +- **功能描述:** 从研究问题、方案设计、实施可行性和临床意义等维度,对研究方案或论文进行全面的方法学评审 +- **输入:** 上传的研究方案或论文稿件 +- **输出:** 一份评审报告,分点列出方法学上的优点、潜在缺陷及改进建议 + +**⑪ 期刊方法学评审智能体** +- **功能描述:** 模拟期刊审稿人视角,针对投稿文章中可能存在的统计学、方法学问题进行提问和挑战 +- **输入:** 上传的论文稿件,目标期刊 +- **输出:** 一份模拟的"审稿意见",列出可能被挑战的问题点 + +**⑫ 期刊稿约评审智能体** +- **功能描述:** 依据目标期刊的投稿要求,自动检查文章在格式、字数、参考文献规范等方面是否符合标准 +- **输入:** 上传的论文稿件,目标期刊的投稿指南 +- **输出:** 一份格式审查报告,清晰列出所有不符合项和修改建议 + +--- + +**在智能体对话中的重点功能:** + +**(1) 模型即时切换** +- 在对话界面,用户可随时通过下拉菜单切换当前对话所使用的大语言模型(如Gemini, DeepSeek等),以应对不同任务 +- 用户选择模型,后续对话由新选定的模型驱动 + +**(2) 临时附件上传** +- 在对话输入框旁提供上传按钮,支持用户上传临时文件(如PDF, Word)供AI进行一次性分析、总结或评审 +- 用户上传的单个文件 +- AI基于该附件内容进行回答 + +**(3) 知识库融合对话** ⭐ +- 在任何对话窗口中,用户可随时通过"@"操作调用个人知识库中的分类,让AI优先基于所选内容回答 +- 示例:`@骨质疏松专题` +- 输出:融合了私有知识和通用知识的回答 + +**(4) 答案溯源与引用** +- 当AI回答引用自个人知识库时,必须生成清晰、可点击的引用标记 +- 回答中包含指向源文档具体位置的引用 + +**(5) 对话内追加背景** +- 在项目对话中,提供将AI回答"固定"到项目背景的功能 +- 用户点击"固定"按钮 +- 该条回答被追加到项目描述中 + +**(6) 历史对话管理** +- 自动保存所有对话记录,支持用户在独立的"历史记录"页面中进行查看、搜索和筛选 + +--- + +#### 2.1.3 核心功能:个人知识库 (Personal Knowledge Base) + +个人知识库是用户专属的、私密的知识管理中心。 + +**(1) 层级化管理** +- 采用两级结构进行管理 +- **第一级:** 知识库列表,用户可在此创建、编辑知识库分类 +- **第二级:** 知识库详情页,用户点击某个知识库后,可查看和管理该库内的所有文件 + +**(2) 文档上传与处理** +- 支持在知识库详情页上传多种格式的文档 + +**(3) 文档处理状态透明化** +- 每份上传的文档都应有明确的状态标识 +- 状态:**"处理中"**、**"已就绪"**、**"处理失败"** + +**(4) 失败原因提示** +- 若文档处理失败,系统需向用户提供清晰的原因说明 + +**(5) 在对话中使用** +- 用户在智能体问答过程中,可以基于创建的个人知识库来进行问答 + +--- + +#### 2.1.4 核心功能:历史记录 (History) + +提供一个独立的顶级功能入口,用于管理用户的所有对话。 + +**(1) 统一列表** +- 按时间倒序展示用户所有的对话记录 + +**(2) 来源标识** +- 每条记录都清晰标识其来源是"全局快速问答"还是具体的某个"项目" + +**(3) 搜索与筛选** +- 提供强大的搜索框 +- 支持按项目、智能体、日期范围进行筛选 +- 帮助用户快速定位历史对话 + +--- + +#### 2.1.5 辅助功能 (Support) + +**(1) 快速上手** +- 在侧边栏提供独立入口 +- 点击后展示产品核心功能引导和使用教程 + +**(2) 帮助中心** +- 在侧边栏提供独立入口 +- 点击后展示FAQ和详细的用户手册 + +--- + +### 2.2 运营端/后台功能 + +#### (1) 仪表盘 + +**核心数据概览** +- 以图表形式展示关键运营指标 +- 指标包括: + - 今日活跃用户 + - 7日活跃用户 + - 总用户数 + - 今日对话数等 +- 目的:方便运营人员快速了解产品状态 + +--- + +#### (2) 智能体管理 + +**智能体列表** +- 以列表形式展示所有前端可用的AI智能体 +- 支持上下线操作 + +--- + +#### (3) 智能体配置 + +**配置管理** +- 管理员可新增、编辑智能体 +- 配置项:名称、图标、描述、所属分类等 + +--- + +#### (4) Prompt管理 + +**核心功能** ⭐ +- 管理员可为每个智能体精细化地调试和优化其背后的系统级提示词(System Prompt) +- 支持版本管理 +- **重要性:** 这是保障智能体专业性的关键 + +--- + +#### (5) 模型管理 + +**模型接入与配置** +- 管理后台接入的各类大语言模型(如Gemini, DeepSeek) +- 可配置: + - API密钥 + - 调用参数 + - 启用/禁用状态 + +--- + +#### (6) 用户管理 + +**用户列表与检索** +- 查看所有用户信息 +- 信息包括:ID、手机号/邮箱、注册时间、状态 +- 支持多条件搜索 + +**账户详情与操作** +- 管理员可查看单个用户的详情 +- 可进行的操作: + - 设置/延长试用期 + - 启用或禁用账户 + - 查看操作日志 + +--- + +#### (7) 数据统计 + +**用户行为统计** +- 查看用户的登录历史记录(登录时间) +- 各个核心功能的使用频次统计(如不同智能体) +- 目的:帮助分析用户偏好和功能热度 + +--- + +#### (8) 对话管理 + +**用户历史对话查看** +- ⚠️ **重要:** 需建立严格的权限分级 +- 访问条件: + - 只有在处理用户申诉或技术排障时 + - 由授权的高级管理员 + - 在获得审批后 + - 才能查看经过脱敏和屏蔽隐私信息的对话数据 + +**安全与隐私强化** +- 所有查看行为必须记录在案,以备审计 + +--- + +## 附录 + +### 版本变更记录 + +| 版本 | 日期 | 变更内容 | 修改人 | +|------|------|---------|--------| +| v1.0 | 2025-10-10 | 初始版本,从TXT转换为MD格式 | 项目团队 | + +### 相关文档 + +- [数据库设计文档](../01-设计文档/数据库设计文档.md) +- [API设计规范](../01-设计文档/API设计规范.md) +- [核心业务规则](../03-业务规则/核心业务规则总览.md) +- [用户端原型图](../01-设计文档/用户端原型图.html) + +--- + +**文档维护者:** 产品经理 +**最后更新:** 2025-10-10 + diff --git a/docs/00-项目概述/技术架构总览.md b/docs/00-项目概述/技术架构总览.md new file mode 100644 index 00000000..23cc1730 --- /dev/null +++ b/docs/00-项目概述/技术架构总览.md @@ -0,0 +1,419 @@ +# AI科研助手 - 技术架构总览 + +> **最后更新:2025-10-10** +> **方案版本:v2.0(最终优化版)** +> **文档说明:** 本文档是技术架构的快速参考指南,适合新人快速了解整体技术方案 + +--- + +## 📊 核心数据一览 + +| 指标 | 数值 | +|------|------| +| **开发周期** | 2.5个月(10周) | +| **开发成本** | ¥49,300 | +| **技术难度** | ⭐⭐⭐(中等) | +| **月度成本** | ¥16,520(1000用户) | +| **团队规模** | 2人(1全栈 + 1前端) | + +--- + +## 🎯 关键需求澄清 + +### 知识库规模(重要变更) + +| 项目 | 限制 | +|------|------| +| 知识库数量 | 3个/用户 | +| 文件数量 | 50个/知识库 | +| 文件格式 | PDF、DOCX | +| 单用户最大 | 150个文件 | + +**影响:** 技术难度从⭐⭐⭐⭐⭐降至⭐⭐⭐,Dify完全满足需求! + +--- + +## 🏗️ 技术架构(一图看懂) + +``` +┌─────────────────────────────────────────┐ +│ 前端(React + Vite) │ +│ - 项目管理(自研) │ +│ - 智能体选择(自研) │ +│ - 聊天界面(参考LobeChat)⭐ │ +│ - 知识库管理(自研) │ +└─────────────────────────────────────────┘ + ↓ REST API +┌─────────────────────────────────────────┐ +│ 业务层 (Node.js/TypeScript) │ +│ - 对话逻辑(自研)⭐ │ +│ - 项目/课题管理 │ +│ - 智能体路由(配置化)⭐ │ +│ - 简化运营后台⭐ │ +└─────────────────────────────────────────┘ + ↓ ↓ +┌──────────────────┐ ┌─────────────────┐ +│ Dify │ │ LLM API │ +│ (仅RAG)⭐ │ │ - DeepSeek-V3⭐│ +│ - 知识库检索 │ │ - Qwen3 ⭐ │ +│ - Qdrant(内置)⭐ │ │ │ +└──────────────────┘ └─────────────────┘ +``` + +--- + +## 🔑 核心决策 + +### 1. 聊天功能实现方式 + +| 方案 | 选择 | 原因 | +|------|------|------| +| **前端UI** | 参考LobeChat组件 ✅ | 成熟稳定,节省9.5天 | +| **对话逻辑** | 自研(调用LLM API)✅ | 业务可控,核心只要4步 | +| Dify对话功能 | ❌ 不用 | 不适合12个智能体管理 | +| LobeChat整体 | ❌ 不用 | 缺少项目管理功能 | + +### 2. RAG系统 + +| 功能 | 方案 | +|------|------| +| **知识库管理** | Dify ✅ | +| **文档解析** | Dify内置 ✅ | +| **向量数据库** | Dify内置Qdrant ✅ | +| **检索** | Dify API ✅ | +| 自建RAG | ❌ 不需要 | + +### 3. 运营后台 + +| 功能 | 状态 | 实现方式 | +|------|------|---------| +| 用户管理 | ✅ 保留 | 简化版 | +| 数据统计 | ✅ 保留 | 基础仪表盘 | +| 模型管理 | ❌ 删除 | `config/models.yaml` | +| 智能体管理 | ❌ 删除 | `config/agents.yaml` | +| Prompt配置 | ❌ 删除 | `prompts/*.txt` | + +### 4. 大模型选择 + +| 优先级 | 模型 | 价格 | 用途 | +|--------|------|------|------| +| **主力** | DeepSeek-V3 | ¥1/百万tokens | 90%的请求 | +| **备用** | Qwen3-72B | ¥4/百万tokens | 需要更强中文理解时 | +| 可选 | Gemini 2.0 | ¥2.7/百万tokens | 国际用户 | + +--- + +## 💰 成本明细 + +### 开发成本 + +| 项目 | 金额 | +|------|------| +| 人力(4人月) | ¥48,000 | +| 服务器(开发环境) | ¥1,250 | +| LLM API(测试) | ¥50 | +| **总计** | **¥49,300** | + +### 月度运营成本(1000用户) + +| 项目 | 金额 | +|------|------| +| 基础设施(服务器) | ¥1,200 | +| LLM API(DeepSeek-V3) | ¥180 | +| 对象存储(知识库) | ¥140 | +| 人力(1人运维) | ¥15,000 | +| **总计** | **¥16,520/月** | + +### 知识库存储详情 + +``` +单用户:150个文件 × 5MB = 750MB +1000用户:750GB总存储 + +对象存储(阿里云OSS): +- 存储费:¥90/月 +- 流量费:¥50/月 +- 总计:¥140/月 +``` + +--- + +## 📅 开发计划(10周) + +| 阶段 | 时间 | 主要任务 | +|------|------|---------| +| **阶段1** | 1.5周 | 基础搭建 + 复用LobeChat组件 | +| **阶段2** | 3.5周 | 核心功能(12个智能体 + 对话) | +| **阶段3** | 2周 | 高级功能(RAG + 文档生成) | +| **阶段4** | 1周 | 简化运营后台 | +| **阶段5** | 2周 | 测试优化 | + +### 阶段1:基础搭建(1.5周) +- [ ] 前端框架(React + Vite + TailwindCSS) +- [ ] **复用LobeChat聊天UI组件** ⭐ +- [ ] 后端框架(Fastify + Prisma + PostgreSQL) +- [ ] Dify部署(Docker) +- [ ] DeepSeek-V3 + Qwen3接入 + +### 阶段2:核心功能(3.5周) +- [ ] 用户认证(JWT) +- [ ] 项目/课题CRUD +- [ ] 12个智能体配置(`agents.yaml`) +- [ ] 对话系统(上下文组装 + 流式输出) +- [ ] 知识库集成(Dify API) + +### 阶段3:高级功能(2周) +- [ ] 多模型切换(DeepSeek/Qwen) +- [ ] 历史记录管理 +- [ ] 固定到项目背景功能 +- [ ] 文档生成(CRF、研究方案) + +### 阶段4:简化运营后台(1周) +- [ ] 用户列表与管理 +- [ ] 基础数据统计 +- [ ] 对话记录查看 + +### 阶段5:测试优化(2周) +- [ ] 功能测试 +- [ ] 性能优化 +- [ ] DeepSeek-V3效果调优 + +--- + +## 🛠️ 技术栈 + +### 前端 +``` +- React 18 + TypeScript +- Vite(构建工具) +- TailwindCSS(UI框架) +- Zustand(状态管理) +- LobeChat组件(聊天UI)⭐ +- react-markdown(Markdown渲染) +``` + +### 后端 +``` +- Node.js + Fastify + TypeScript +- Prisma(ORM) +- PostgreSQL(数据库) +- Redis(缓存) +``` + +### 第三方服务 +``` +- Dify(RAG知识库)⭐ +- DeepSeek-V3(主力LLM)⭐ +- Qwen3(备用LLM)⭐ +- 阿里云OSS(对象存储) +``` + +--- + +## ✅ 核心优势 + +### 1. 开发效率高 +- ✅ 复用LobeChat聊天UI:节省9.5天 +- ✅ 使用Dify RAG:节省40天 +- ✅ 配置化智能体:节省5天 +- ✅ 总节省:**约54.5天** + +### 2. 成本可控 +- ✅ 开发成本:¥49,300(vs 纯手写¥80k+) +- ✅ 月度LLM成本:¥180(vs GPT-4 ¥2,500) +- ✅ 知识库存储:¥140/月(适度规模) + +### 3. 技术风险低 +- ✅ Dify:50k+ Stars,生产级稳定 +- ✅ LobeChat:40k+ Stars,成熟方案 +- ✅ DeepSeek-V3:性价比极高 + +### 4. 架构灵活 +- ✅ 业务逻辑完全可控 +- ✅ 可随时替换RAG引擎 +- ✅ 可随时增减LLM模型 + +--- + +## 📋 核心文件结构 + +``` +项目根目录/ +├── frontend/ # 前端 +│ ├── src/ +│ │ ├── components/ +│ │ │ ├── chat/ # 聊天组件(参考LobeChat)⭐ +│ │ │ │ ├── ChatMessage.tsx +│ │ │ │ ├── ChatInput.tsx +│ │ │ │ └── StreamRenderer.tsx +│ │ │ ├── project/ # 项目管理 +│ │ │ └── kb/ # 知识库管理 +│ │ ├── pages/ +│ │ └── services/ +│ └── package.json +│ +├── backend/ # 后端 +│ ├── src/ +│ │ ├── services/ +│ │ │ ├── chat.service.ts # 对话服务 ⭐ +│ │ │ ├── kb.service.ts # 知识库服务 +│ │ │ └── project.service.ts +│ │ ├── adapters/ +│ │ │ └── llm-factory.ts # LLM适配器 ⭐ +│ │ ├── clients/ +│ │ │ └── dify.ts # Dify客户端 +│ │ └── config/ +│ │ └── agent-loader.ts # 智能体配置加载 ⭐ +│ ├── config/ +│ │ ├── agents.yaml # 智能体配置 ⭐ +│ │ └── models.yaml # 模型配置 ⭐ +│ ├── prompts/ # Prompt文件 ⭐ +│ │ ├── picos_system.txt +│ │ ├── topic_evaluation_system.txt +│ │ └── ...(共12个智能体) +│ └── package.json +│ +└── docker-compose.yml # Dify部署 +``` + +--- + +## 🚀 快速启动 + +### 1. 准备工作 + +**申请API Key:** +- [ ] DeepSeek API Key (https://platform.deepseek.com) +- [ ] 阿里云DashScope Key (https://dashscope.aliyun.com) +- [ ] 阿里云OSS (https://oss.console.aliyun.com) + +**准备服务器:** +- [ ] 云服务器 4核8G(开发环境) +- [ ] PostgreSQL 数据库 +- [ ] Redis 缓存 + +### 2. 部署Dify + +```bash +# 克隆Dify +git clone https://github.com/langgenius/dify.git +cd dify/docker + +# 启动 +docker-compose up -d + +# 访问 http://localhost:3000 +# 创建账号并获取API Key +``` + +### 3. 后端开发 + +```bash +cd backend +npm install + +# 配置环境变量 +cp .env.example .env +# 填入: +# - DATABASE_URL +# - REDIS_URL +# - DEEPSEEK_API_KEY +# - DASHSCOPE_API_KEY +# - DIFY_API_KEY + +# 运行数据库迁移 +npx prisma migrate dev + +# 启动开发服务器 +npm run dev +``` + +### 4. 前端开发 + +```bash +cd frontend +npm install + +# 配置API地址 +# .env.local +VITE_API_URL=http://localhost:3001 + +# 启动开发服务器 +npm run dev +``` + +--- + +## 📚 相关文档 + +### 设计文档 +- [产品需求文档(PRD)](./产品需求文档(PRD).md) - 完整的产品需求 +- [数据库设计文档](../01-设计文档/数据库设计文档.md) - 数据库表结构 +- [API设计规范](../01-设计文档/API设计规范.md) - 所有API定义 +- [代码规范](../02-开发规范/代码规范.md) - 代码风格规范 +- [核心业务规则](../03-业务规则/核心业务规则总览.md) - 业务逻辑规则 + +### 开发计划 +- [开发里程碑](../04-开发计划/开发里程碑.md) - 详细的10周开发计划 + +### 参考文档 +- **技术架构选型对比方案.md** - 完整技术方案(在项目根目录) +- **对话系统实现方案对比.md** - 对话功能详细说明(在项目根目录) +- **知识库需求调整说明.md** - 知识库实现方案(在项目根目录) + +--- + +## 🎯 关键决策清单 + +**在开始开发前,请确认:** + +- [ ] **聊天实现方式:** 参考LobeChat + 自研对话逻辑 ✅ +- [ ] **RAG系统:** 使用Dify(无需自建)✅ +- [ ] **向量数据库:** Dify内置Qdrant(无需关心)✅ +- [ ] **运营后台:** 简化版(配置文件管理)✅ +- [ ] **主力LLM:** DeepSeek-V3 ✅ +- [ ] **备用LLM:** Qwen3 ✅ +- [ ] **知识库限制:** 3个/用户,50个文件/库 ✅ +- [ ] **开发周期:** 2.5个月 ✅ +- [ ] **团队规模:** 2人 ✅ + +--- + +## 💡 常见问题 FAQ + +### Q1: 为什么不直接用Dify的对话功能? +**A:** Dify对话功能需要为每个智能体创建独立应用,12个智能体管理复杂,且缺少项目管理功能。我们只用Dify做RAG检索。 + +### Q2: 对话功能自己实现会很复杂吗? +**A:** 不复杂!核心只要4步:接收消息 → 组装上下文 → 调用LLM → 返回流式结果。参考LobeChat的实现,约需4天。 + +### Q3: 150个文件/用户,Dify够用吗? +**A:** 完全够用!Dify单个知识库支持上万个文档片段,我们的需求远低于上限。 + +### Q4: 为什么选择DeepSeek-V3? +**A:** 性价比极高(¥1/百万tokens),性能接近GPT-4,年度可节省¥27,840。 + +### Q5: 2.5个月真的能完成吗? +**A:** 可以!通过复用LobeChat组件、使用Dify RAG、配置化智能体,我们节省了约54天开发时间。 + +--- + +## 🎉 总结 + +**这是一个经过充分优化、成本可控、技术可行的方案:** + +✅ **开发周期:** 2.5个月 +✅ **开发成本:** ¥49,300 +✅ **月度成本:** ¥16,520(1000用户) +✅ **技术难度:** ⭐⭐⭐(中等) +✅ **风险等级:** 低(使用成熟组件和服务) + +**立即可以开始!** 🚀 + +--- + +**文档版本:v2.0** +**最后更新:2025-10-10** +**文档位置:** `docs/00-项目概述/技术架构总览.md` +**作者:** AI技术顾问 + diff --git a/docs/00-项目概述/设计文档完成总结.md b/docs/00-项目概述/设计文档完成总结.md new file mode 100644 index 00000000..0d235e60 --- /dev/null +++ b/docs/00-项目概述/设计文档完成总结.md @@ -0,0 +1,297 @@ +# 设计文档完成总结 + +> **完成时间:** 2025-10-10 +> **耗时:** 约3小时 +> **状态:** ✅ 已完成 + +--- + +## 🎉 恭喜!核心设计文档已全部完成 + +我们按照您提出的专业开发流程,成功创建了完整的设计文档体系。这为接下来的开发工作奠定了坚实的基础。 + +--- + +## 📚 已完成的文档清单 + +### ✅ 1. 文档目录结构 +**文件:** `docs/README.md` + +- 建立了8个文档分类目录 +- 清晰的文档导航系统 +- 文档维护指南 + +### ✅ 2. 数据库设计文档(771行) +**文件:** `docs/01-设计文档/数据库设计文档.md` + +**包含内容:** +- 7个核心数据表设计 +- 完整的ER图 +- 字段说明和约束 +- 索引设计 +- Prisma Schema +- 数据安全策略 +- 性能优化建议 + +**核心表:** +1. users - 用户表 +2. projects - 项目/课题表 +3. conversations - 对话表 +4. messages - 消息表 +5. knowledge_bases - 知识库表 +6. documents - 文档表 +7. admin_logs - 管理员日志表 + +### ✅ 3. API设计规范(1023行) +**文件:** `docs/01-设计文档/API设计规范.md` + +**包含内容:** +- RESTful API设计原则 +- 完整的8个模块API定义 +- 请求/响应格式规范 +- 错误处理规范 +- 认证授权机制 +- 分页规范 +- 性能优化建议 + +**API模块:** +1. 认证模块(注册/登录/刷新Token) +2. 用户模块(个人信息管理) +3. 项目管理模块 +4. 对话管理模块(含流式输出) +5. 智能体模块 +6. 知识库模块 +7. 历史记录模块 +8. 管理后台模块 + +### ✅ 4. 开发里程碑(586行) +**文件:** `docs/04-开发计划/开发里程碑.md` + +**包含内容:** +- 10周详细开发计划 +- 5个里程碑定义 +- 每日任务分解(Day 1-70) +- 验收标准 +- 风险管理 +- 进度跟踪机制 + +**里程碑:** +- 设计阶段:Day 1-3 ✅ +- 里程碑1:基础架构 + 用户认证(Week 1-2) +- 里程碑2:项目管理 + 3个智能体(Week 3-4) +- 里程碑3:12个智能体 + 知识库(Week 5-6) +- 里程碑4:历史记录 + 文档生成(Week 7-8) +- 里程碑5:运营后台 + 测试优化(Week 9-10) + +### ✅ 5. 代码规范(600+行) +**文件:** `docs/02-开发规范/代码规范.md` + +**包含内容:** +- TypeScript规范 +- React组件规范 +- Node.js后端规范 +- 命名规范 +- 注释规范 +- Git提交规范 +- ESLint/Prettier配置 +- Code Review检查清单 + +### ✅ 6. 核心业务规则(700+行) +**文件:** `docs/03-业务规则/核心业务规则总览.md` + +**包含内容:** +- 用户管理规则(注册/登录/权限) +- 项目管理规则(CRUD/权限验证) +- 智能体管理规则(配置/Prompt) +- 对话管理规则(上下文/流式输出) +- 知识库管理规则(配额/文档处理) +- 权限控制规则(RBAC/数据隔离) +- 配额限制规则(知识库/API限流) + +**关键规则:** +- BR-K001: 每用户最多3个知识库 +- BR-K002: 每知识库最多50个文档 +- BR-K003: 只支持PDF和DOCX格式 +- BR-K004: 单文件最大50MB +- BR-C003: 项目背景自动注入上下文 +- BR-C006: 固定消息到项目背景 + +--- + +## 📊 文档统计 + +| 文档类型 | 文件数 | 总行数 | 状态 | +|---------|-------|--------|------| +| 数据库设计 | 1 | 771 | ✅ | +| API设计 | 1 | 1,023 | ✅ | +| 开发计划 | 1 | 586 | ✅ | +| 代码规范 | 1 | 600+ | ✅ | +| 业务规则 | 1 | 700+ | ✅ | +| **总计** | **5** | **3,680+** | **✅** | + +--- + +## 🎯 设计文档的核心价值 + +### 1. 为前后端开发提供契约 +- ✅ API设计规范是前后端协作的契约 +- ✅ 可以并行开发,互不阻塞 +- ✅ 避免接口频繁变更 + +### 2. 避免开发过程中的返工 +- ✅ 数据库设计提前确定,改动成本低 +- ✅ 业务规则明确,减少理解偏差 +- ✅ 代码规范统一,提高质量 + +### 3. 提高团队协作效率 +- ✅ 新成员快速上手 +- ✅ 减少沟通成本 +- ✅ Review有据可依 + +### 4. 便于后期维护和扩展 +- ✅ 文档化的设计决策 +- ✅ 清晰的业务逻辑 +- ✅ 可追溯的变更历史 + +--- + +## 🚀 下一步行动 + +### 立即可做(今天) + +**1. Review设计文档** +- [ ] 仔细阅读数据库设计文档 +- [ ] 仔细阅读API设计规范 +- [ ] 仔细阅读业务规则 +- [ ] 提出疑问和优化建议 + +**2. 团队讨论(如有团队)** +- [ ] 召开设计Review会议 +- [ ] 确认技术细节 +- [ ] 调整不合理的地方 + +**3. 准备开发环境** +- [ ] 安装Docker Desktop ✅(已完成) +- [ ] 申请DeepSeek API Key ✅(已完成) +- [ ] 申请Qwen API Key ✅(已完成) + +### 明天开始 + +**Day 4: 环境搭建** +- [ ] 创建项目目录结构 +- [ ] 启动Docker服务 +- [ ] 初始化Git仓库 +- [ ] 验证所有服务 + +**Day 5-7: 基础框架** +- [ ] 后端框架搭建 +- [ ] 前端框架搭建 +- [ ] 数据库迁移 + +--- + +## 📂 文档位置 + +所有文档都保存在: +``` +AIclinicalresearch/docs/ +├── README.md # 文档导航 +├── 00-项目概述/ +│ └── 设计文档完成总结.md # 本文档 +├── 01-设计文档/ +│ ├── 数据库设计文档.md ⭐ +│ └── API设计规范.md ⭐ +├── 02-开发规范/ +│ └── 代码规范.md ⭐ +├── 03-业务规则/ +│ └── 核心业务规则总览.md ⭐ +└── 04-开发计划/ + └── 开发里程碑.md ⭐ +``` + +--- + +## 💡 使用建议 + +### 对于开发者 +1. **开发前必读:** + - 数据库设计文档(了解表结构) + - API设计规范(了解接口定义) + - 代码规范(统一代码风格) + +2. **开发中参考:** + - 业务规则总览(理解业务逻辑) + - 开发里程碑(明确当前任务) + +3. **遇到问题时:** + - 先查阅相关文档 + - 文档不清楚时再讨论 + - 讨论结果更新文档 + +### 对于项目经理 +1. **进度管理:** + - 参考开发里程碑 + - 每周更新进度 + - 风险及时沟通 + +2. **质量把控:** + - Code Review参考代码规范 + - 验收参考验收标准 + - 业务逻辑参考业务规则 + +--- + +## ✅ 验收检查 + +### 设计文档质量检查 +- [x] 数据库设计完整,包含所有核心表 +- [x] API设计覆盖所有功能模块 +- [x] 业务规则清晰,无二义性 +- [x] 开发计划详细,可执行性强 +- [x] 代码规范全面,有示例代码 + +### 可用性检查 +- [x] 文档结构清晰,易于查找 +- [x] 术语统一,无矛盾之处 +- [x] 有充足的示例和说明 +- [x] 便于维护和更新 + +--- + +## 🎊 总结 + +**我们完成了一件非常重要的工作!** + +通过这3小时的努力,我们建立了: +- ✅ **完整的文档体系**(5个核心文档,3680+行) +- ✅ **清晰的开发路线图**(10周70天详细计划) +- ✅ **统一的技术规范**(数据库、API、代码) +- ✅ **明确的业务规则**(70+条业务规则) + +**这些文档的价值:** +- 💰 **节省时间**:避免后期返工,预计节省15-20天 +- 📈 **提高质量**:统一规范,代码质量更高 +- 🤝 **降低风险**:设计明确,技术风险可控 +- 🚀 **加快开发**:任务清晰,并行开发更高效 + +--- + +## 🎯 现在可以信心满满地开始开发了! + +**基于这些文档,我们可以:** +1. ✅ 前后端并行开发(API已定义) +2. ✅ 数据库结构稳定(很少需要迁移) +3. ✅ 业务逻辑明确(减少理解偏差) +4. ✅ 代码风格统一(便于协作和Review) +5. ✅ 进度可控(每日任务清晰) + +--- + +**准备好了吗?让我们开始Day 4的开发工作吧!** 🚀 + +--- + +**文档版本:** v1.0 +**完成时间:** 2025-10-10 +**创建者:** AI技术顾问 + 项目团队 + diff --git a/docs/01-设计文档/API设计规范.md b/docs/01-设计文档/API设计规范.md new file mode 100644 index 00000000..87ec45d4 --- /dev/null +++ b/docs/01-设计文档/API设计规范.md @@ -0,0 +1,1022 @@ +# API设计规范 + +> **版本:** v1.0 +> **创建日期:** 2025-10-10 +> **API风格:** RESTful API +> **基础URL:** `http://localhost:3001/api/v1` + +--- + +## 📋 目录 + +1. [设计原则](#设计原则) +2. [通用规范](#通用规范) +3. [认证与授权](#认证与授权) +4. [API端点设计](#api端点设计) +5. [错误处理](#错误处理) +6. [数据格式](#数据格式) + +--- + +## 设计原则 + +### API First原则 +- ✅ 先设计API,再实现功能 +- ✅ API是前后端的契约 +- ✅ API变更需要版本控制 + +### RESTful设计 +- ✅ 使用HTTP动词表示操作(GET、POST、PUT、DELETE) +- ✅ URL表示资源,不表示动作 +- ✅ 使用复数名词表示资源集合 +- ✅ 嵌套资源不超过2层 + +### 命名规范 +- ✅ URL使用小写字母和连字符(kebab-case) +- ✅ 查询参数使用驼峰命名(camelCase) +- ✅ JSON字段使用驼峰命名(camelCase) + +--- + +## 通用规范 + +### HTTP方法 + +| 方法 | 用途 | 是否幂等 | +|------|------|---------| +| GET | 获取资源 | ✅ | +| POST | 创建资源 | ❌ | +| PUT | 完整更新资源 | ✅ | +| PATCH | 部分更新资源 | ❌ | +| DELETE | 删除资源 | ✅ | + +### 状态码规范 + +| 状态码 | 含义 | 使用场景 | +|--------|------|---------| +| 200 | OK | 成功返回数据 | +| 201 | Created | 成功创建资源 | +| 204 | No Content | 成功但无返回数据(如删除) | +| 400 | Bad Request | 请求参数错误 | +| 401 | Unauthorized | 未认证 | +| 403 | Forbidden | 无权限 | +| 404 | Not Found | 资源不存在 | +| 409 | Conflict | 资源冲突(如重复创建) | +| 422 | Unprocessable Entity | 语义错误(如验证失败) | +| 429 | Too Many Requests | 请求过于频繁 | +| 500 | Internal Server Error | 服务器错误 | + +### 响应格式 + +**成功响应:** +```json +{ + "success": true, + "data": { + // 实际数据 + }, + "message": "操作成功", + "timestamp": "2025-10-10T10:00:00.000Z" +} +``` + +**错误响应:** +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "参数验证失败", + "details": [ + { + "field": "email", + "message": "邮箱格式不正确" + } + ] + }, + "timestamp": "2025-10-10T10:00:00.000Z" +} +``` + +### 分页规范 + +**请求参数:** +``` +GET /api/v1/projects?page=1&pageSize=20&sortBy=createdAt&sortOrder=desc +``` + +**响应格式:** +```json +{ + "success": true, + "data": { + "items": [...], + "pagination": { + "page": 1, + "pageSize": 20, + "total": 100, + "totalPages": 5, + "hasNext": true, + "hasPrev": false + } + } +} +``` + +--- + +## 认证与授权 + +### JWT认证 + +**登录获取Token:** +```http +POST /api/v1/auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "password123" +} + +Response: +{ + "success": true, + "data": { + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "expiresIn": 604800, + "user": { + "id": "user-123", + "email": "user@example.com", + "name": "张三", + "role": "user" + } + } +} +``` + +**使用Token:** +```http +GET /api/v1/projects +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +### 权限控制 + +| 端点 | 需要认证 | 角色要求 | +|------|---------|---------| +| `/auth/login` | ❌ | 无 | +| `/auth/register` | ❌ | 无 | +| `/users/me` | ✅ | user | +| `/projects/*` | ✅ | user | +| `/admin/*` | ✅ | admin | + +--- + +## API端点设计 + +### 1. 认证模块 + +#### 1.1 用户注册 +```http +POST /api/v1/auth/register +Content-Type: application/json + +Request: +{ + "email": "user@example.com", + "password": "password123", + "name": "张三" +} + +Response: 201 Created +{ + "success": true, + "data": { + "userId": "user-123", + "email": "user@example.com", + "message": "注册成功,请登录" + } +} +``` + +#### 1.2 用户登录 +```http +POST /api/v1/auth/login +Content-Type: application/json + +Request: +{ + "email": "user@example.com", + "password": "password123" +} + +Response: 200 OK +{ + "success": true, + "data": { + "accessToken": "eyJhbG...", + "refreshToken": "eyJhbG...", + "expiresIn": 604800, + "user": { + "id": "user-123", + "email": "user@example.com", + "name": "张三", + "role": "user" + } + } +} +``` + +#### 1.3 刷新Token +```http +POST /api/v1/auth/refresh +Content-Type: application/json + +Request: +{ + "refreshToken": "eyJhbG..." +} + +Response: 200 OK +{ + "success": true, + "data": { + "accessToken": "new_token...", + "expiresIn": 604800 + } +} +``` + +#### 1.4 退出登录 +```http +POST /api/v1/auth/logout +Authorization: Bearer {token} + +Response: 204 No Content +``` + +--- + +### 2. 用户模块 + +#### 2.1 获取当前用户信息 +```http +GET /api/v1/users/me +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "user-123", + "email": "user@example.com", + "name": "张三", + "role": "user", + "kbQuota": 3, + "kbUsed": 1, + "isTrial": true, + "trialEndsAt": "2025-11-10T00:00:00.000Z", + "createdAt": "2025-10-01T00:00:00.000Z" + } +} +``` + +#### 2.2 更新用户信息 +```http +PATCH /api/v1/users/me +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "name": "李四", + "avatarUrl": "https://..." +} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "user-123", + "name": "李四", + "avatarUrl": "https://..." + } +} +``` + +#### 2.3 修改密码 +```http +POST /api/v1/users/me/change-password +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "oldPassword": "old123", + "newPassword": "new456" +} + +Response: 200 OK +{ + "success": true, + "message": "密码修改成功" +} +``` + +--- + +### 3. 项目管理模块 + +#### 3.1 获取项目列表 +```http +GET /api/v1/projects?page=1&pageSize=20 +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": { + "items": [ + { + "id": "proj-123", + "name": "XX药物III期临床试验", + "description": "项目背景描述...", + "conversationCount": 5, + "createdAt": "2025-10-01T00:00:00.000Z", + "updatedAt": "2025-10-10T00:00:00.000Z" + } + ], + "pagination": { + "page": 1, + "pageSize": 20, + "total": 2, + "totalPages": 1, + "hasNext": false, + "hasPrev": false + } + } +} +``` + +#### 3.2 创建项目 +```http +POST /api/v1/projects +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "name": "骨质疏松研究", + "description": "探索肠道菌群与骨质疏松的关系..." +} + +Response: 201 Created +{ + "success": true, + "data": { + "id": "proj-456", + "name": "骨质疏松研究", + "description": "探索肠道菌群与骨质疏松的关系...", + "conversationCount": 0, + "createdAt": "2025-10-10T10:00:00.000Z" + } +} +``` + +#### 3.3 获取项目详情 +```http +GET /api/v1/projects/:id +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "proj-123", + "name": "XX药物III期临床试验", + "description": "项目背景描述...", + "conversationCount": 5, + "createdAt": "2025-10-01T00:00:00.000Z", + "updatedAt": "2025-10-10T00:00:00.000Z" + } +} +``` + +#### 3.4 更新项目 +```http +PUT /api/v1/projects/:id +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "name": "XX药物III期临床试验(更新)", + "description": "更新后的项目背景..." +} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "proj-123", + "name": "XX药物III期临床试验(更新)", + "description": "更新后的项目背景...", + "updatedAt": "2025-10-10T11:00:00.000Z" + } +} +``` + +#### 3.5 删除项目 +```http +DELETE /api/v1/projects/:id +Authorization: Bearer {token} + +Response: 204 No Content +``` + +--- + +### 4. 对话管理模块 + +#### 4.1 获取对话列表 +```http +GET /api/v1/conversations?projectId=proj-123&page=1&pageSize=20 +Authorization: Bearer {token} + +Query Parameters: +- projectId (可选): 筛选特定项目的对话,不传则返回所有对话 +- agentId (可选): 筛选特定智能体的对话 +- page: 页码 +- pageSize: 每页数量 + +Response: 200 OK +{ + "success": true, + "data": { + "items": [ + { + "id": "conv-123", + "title": "PICOS构建", + "agentId": "agent-picos", + "agentName": "PICOS构建智能体", + "projectId": "proj-123", + "projectName": "XX药物研究", + "modelName": "deepseek-v3", + "messageCount": 10, + "totalTokens": 5000, + "createdAt": "2025-10-10T09:00:00.000Z", + "updatedAt": "2025-10-10T10:00:00.000Z" + } + ], + "pagination": {...} + } +} +``` + +#### 4.2 创建对话 +```http +POST /api/v1/conversations +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "projectId": "proj-123", // 可选,全局快速问答时不传 + "agentId": "agent-picos", + "title": "PICOS构建", + "modelName": "deepseek-v3" // 可选,默认deepseek-v3 +} + +Response: 201 Created +{ + "success": true, + "data": { + "id": "conv-456", + "title": "PICOS构建", + "agentId": "agent-picos", + "projectId": "proj-123", + "modelName": "deepseek-v3", + "messageCount": 0, + "createdAt": "2025-10-10T10:00:00.000Z" + } +} +``` + +#### 4.3 获取对话详情(含消息) +```http +GET /api/v1/conversations/:id +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "conv-123", + "title": "PICOS构建", + "agentId": "agent-picos", + "projectId": "proj-123", + "modelName": "deepseek-v3", + "messageCount": 2, + "messages": [ + { + "id": "msg-1", + "role": "user", + "content": "请帮我构建PICOS框架", + "createdAt": "2025-10-10T09:00:00.000Z" + }, + { + "id": "msg-2", + "role": "assistant", + "content": "好的,我们开始构建PICOS...", + "isPinned": false, + "tokens": 500, + "createdAt": "2025-10-10T09:00:05.000Z" + } + ], + "createdAt": "2025-10-10T09:00:00.000Z", + "updatedAt": "2025-10-10T09:00:05.000Z" + } +} +``` + +#### 4.4 发送消息(流式) +```http +POST /api/v1/conversations/:id/messages/stream +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "content": "请帮我构建PICOS框架", + "kbReferences": ["kb-123"] // 可选,引用的知识库 +} + +Response: 200 OK (Server-Sent Events) +Content-Type: text/event-stream + +data: {"type":"start","conversationId":"conv-123"} + +data: {"type":"token","content":"好"} + +data: {"type":"token","content":"的"} + +data: {"type":"token","content":","} + +data: {"type":"done","messageId":"msg-456","tokens":500} +``` + +#### 4.5 固定消息到项目背景 +```http +POST /api/v1/messages/:id/pin +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "message": "已固定到项目背景" +} +``` + +#### 4.6 删除对话 +```http +DELETE /api/v1/conversations/:id +Authorization: Bearer {token} + +Response: 204 No Content +``` + +--- + +### 5. 智能体模块 + +#### 5.1 获取智能体列表 +```http +GET /api/v1/agents +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": [ + { + "id": "agent-picos", + "name": "PICOS构建", + "description": "结构化地定义临床研究的核心要素", + "category": "研究设计", + "icon": "construction", + "ragEnabled": true, + "fileUploadEnabled": false, + "status": "active" + }, + { + "id": "agent-topic-evaluation", + "name": "选题评价", + "description": "从创新性、临床价值等维度评价研究选题", + "category": "选题阶段", + "icon": "lightbulb", + "ragEnabled": true, + "fileUploadEnabled": false, + "status": "active" + } + ] +} +``` + +#### 5.2 获取智能体详情 +```http +GET /api/v1/agents/:id +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": { + "id": "agent-picos", + "name": "PICOS构建", + "description": "结构化地定义临床研究的核心要素", + "category": "研究设计", + "icon": "construction", + "ragEnabled": true, + "fileUploadEnabled": false, + "outputFormat": "structured", + "models": { + "deepseek-v3": { + "temperature": 0.3, + "maxTokens": 2500 + }, + "qwen3-72b": { + "temperature": 0.4, + "maxTokens": 2500 + } + }, + "status": "active" + } +} +``` + +--- + +### 6. 知识库模块 + +#### 6.1 获取知识库列表 +```http +GET /api/v1/knowledge-bases +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": [ + { + "id": "kb-123", + "name": "骨质疏松专题", + "description": "关于骨质疏松的文献资料", + "fileCount": 15, + "totalSizeMB": 45.6, + "quota": { + "used": 15, + "limit": 50 + }, + "createdAt": "2025-10-01T00:00:00.000Z", + "updatedAt": "2025-10-10T00:00:00.000Z" + } + ], + "quota": { + "used": 1, + "limit": 3 + } +} +``` + +#### 6.2 创建知识库 +```http +POST /api/v1/knowledge-bases +Authorization: Bearer {token} +Content-Type: application/json + +Request: +{ + "name": "肺癌研究资料", + "description": "肺癌相关的临床研究文献" +} + +Response: 201 Created +{ + "success": true, + "data": { + "id": "kb-456", + "name": "肺癌研究资料", + "description": "肺癌相关的临床研究文献", + "fileCount": 0, + "difyDatasetId": "dify-dataset-xxx", + "createdAt": "2025-10-10T10:00:00.000Z" + } +} +``` + +#### 6.3 上传文档 +```http +POST /api/v1/knowledge-bases/:id/documents +Authorization: Bearer {token} +Content-Type: multipart/form-data + +Request: +- file: (binary) +- filename: "文献综述.pdf" + +Response: 201 Created +{ + "success": true, + "data": { + "id": "doc-123", + "filename": "文献综述.pdf", + "fileType": "pdf", + "fileSizeBytes": 2048000, + "status": "processing", + "progress": 0, + "uploadedAt": "2025-10-10T10:00:00.000Z" + } +} +``` + +#### 6.4 获取文档列表 +```http +GET /api/v1/knowledge-bases/:id/documents +Authorization: Bearer {token} + +Response: 200 OK +{ + "success": true, + "data": [ + { + "id": "doc-123", + "filename": "文献综述.pdf", + "fileType": "pdf", + "fileSizeMB": 2.0, + "status": "completed", + "progress": 100, + "segmentsCount": 50, + "tokensCount": 10000, + "uploadedAt": "2025-10-10T10:00:00.000Z", + "processedAt": "2025-10-10T10:02:00.000Z" + } + ] +} +``` + +#### 6.5 删除文档 +```http +DELETE /api/v1/knowledge-bases/:kbId/documents/:docId +Authorization: Bearer {token} + +Response: 204 No Content +``` + +#### 6.6 删除知识库 +```http +DELETE /api/v1/knowledge-bases/:id +Authorization: Bearer {token} + +Response: 204 No Content +``` + +--- + +### 7. 历史记录模块 + +#### 7.1 获取历史记录(跨项目) +```http +GET /api/v1/history?page=1&pageSize=20&agentId=agent-picos&startDate=2025-10-01&endDate=2025-10-10 +Authorization: Bearer {token} + +Query Parameters: +- projectId (可选): 筛选特定项目 +- agentId (可选): 筛选特定智能体 +- startDate (可选): 开始日期 +- endDate (可选): 结束日期 +- keyword (可选): 关键词搜索 + +Response: 200 OK +{ + "success": true, + "data": { + "items": [ + { + "conversationId": "conv-123", + "title": "PICOS构建", + "agentId": "agent-picos", + "agentName": "PICOS构建智能体", + "projectId": "proj-123", + "projectName": "XX药物研究", + "source": "project", // project 或 global + "messageCount": 10, + "createdAt": "2025-10-10T09:00:00.000Z", + "lastMessageAt": "2025-10-10T10:00:00.000Z" + } + ], + "pagination": {...} + } +} +``` + +--- + +### 8. 管理后台模块(简化版) + +#### 8.1 获取用户列表(管理员) +```http +GET /api/v1/admin/users?page=1&pageSize=20&status=active&keyword=zhang +Authorization: Bearer {admin_token} + +Response: 200 OK +{ + "success": true, + "data": { + "items": [ + { + "id": "user-123", + "email": "user@example.com", + "name": "张三", + "role": "user", + "status": "active", + "kbUsed": 1, + "conversationCount": 25, + "lastLoginAt": "2025-10-10T09:00:00.000Z", + "createdAt": "2025-10-01T00:00:00.000Z" + } + ], + "pagination": {...} + } +} +``` + +#### 8.2 更新用户状态(管理员) +```http +PATCH /api/v1/admin/users/:id +Authorization: Bearer {admin_token} +Content-Type: application/json + +Request: +{ + "status": "suspended" // active, inactive, suspended +} + +Response: 200 OK +{ + "success": true, + "message": "用户状态已更新" +} +``` + +#### 8.3 获取数据统计(管理员) +```http +GET /api/v1/admin/statistics +Authorization: Bearer {admin_token} + +Response: 200 OK +{ + "success": true, + "data": { + "users": { + "total": 1000, + "active": 850, + "newToday": 15, + "new7Days": 120 + }, + "conversations": { + "total": 5000, + "today": 200, + "avgPerUser": 5 + }, + "agents": { + "mostUsed": [ + { + "agentId": "agent-picos", + "name": "PICOS构建", + "count": 800 + } + ] + }, + "knowledgeBases": { + "total": 300, + "totalDocuments": 4500, + "totalSizeGB": 12.5 + } + } +} +``` + +--- + +## 错误处理 + +### 错误代码规范 + +| 错误代码 | 说明 | HTTP状态码 | +|---------|------|-----------| +| VALIDATION_ERROR | 参数验证失败 | 422 | +| UNAUTHORIZED | 未认证 | 401 | +| FORBIDDEN | 无权限 | 403 | +| NOT_FOUND | 资源不存在 | 404 | +| CONFLICT | 资源冲突 | 409 | +| RATE_LIMIT | 请求过于频繁 | 429 | +| QUOTA_EXCEEDED | 配额超限 | 403 | +| INTERNAL_ERROR | 服务器错误 | 500 | + +### 错误响应示例 + +```json +{ + "success": false, + "error": { + "code": "QUOTA_EXCEEDED", + "message": "知识库数量已达上限", + "details": { + "resource": "knowledge_base", + "quota": 3, + "used": 3 + } + }, + "timestamp": "2025-10-10T10:00:00.000Z" +} +``` + +--- + +## 数据格式 + +### 时间格式 +- 使用ISO 8601格式:`2025-10-10T10:00:00.000Z` +- 统一使用UTC时区 + +### 文件大小 +- 使用字节(bytes)存储 +- 前端显示时转换为MB/GB + +### ID格式 +- 使用UUID v4 +- 格式:`user-123abc...` 或 `proj-456def...` + +--- + +## 版本控制 + +### API版本 +- 当前版本:`v1` +- URL格式:`/api/v1/...` +- 向后兼容:同一主版本内保持兼容 + +### 废弃策略 +- 提前3个月通知 +- 响应头标注:`X-API-Deprecated: true` +- 提供迁移指南 + +--- + +## 性能优化 + +### 缓存策略 +- 静态数据(智能体列表):缓存1小时 +- 用户数据:不缓存或缓存5分钟 +- 使用ETag实现条件请求 + +### 限流策略 +- 普通用户:100次/分钟 +- 管理员:500次/分钟 +- 登录接口:5次/分钟 + +--- + +## 安全性 + +### HTTPS +- 生产环境强制HTTPS +- 开发环境可使用HTTP + +### CORS +- 允许的域名列表(白名单) +- 不允许通配符 `*` + +### SQL注入防护 +- 使用Prisma ORM +- 永不拼接SQL + +### XSS防护 +- 所有用户输入转义 +- Content-Type正确设置 + +--- + +## 文档维护 + +- **更新频率:** API变更时必须同步更新 +- **Review:** 每个里程碑Review一次 +- **版本记录:** 记录重大变更 + +--- + +**最后更新:** 2025-10-10 +**维护者:** 开发团队 + diff --git a/docs/01-设计文档/数据库设计文档.md b/docs/01-设计文档/数据库设计文档.md new file mode 100644 index 00000000..6ece684c --- /dev/null +++ b/docs/01-设计文档/数据库设计文档.md @@ -0,0 +1,770 @@ +# 数据库设计文档 + +> **版本:** v1.0 +> **创建日期:** 2025-10-10 +> **数据库:** PostgreSQL 15+ +> **ORM:** Prisma + +--- + +## 📋 目录 + +1. [数据库概述](#数据库概述) +2. [ER图](#er图) +3. [表结构设计](#表结构设计) +4. [索引设计](#索引设计) +5. [数据约束](#数据约束) +6. [数据迁移策略](#数据迁移策略) + +--- + +## 数据库概述 + +### 设计原则 +- ✅ 遵循第三范式(3NF) +- ✅ 使用UUID作为主键 +- ✅ 所有表包含created_at和updated_at时间戳 +- ✅ 使用软删除(保留deleted_at字段,重要表) +- ✅ 外键约束使用CASCADE删除 +- ✅ 敏感字段加密存储(密码使用bcrypt) + +### 命名规范 +- 表名:复数形式,下划线分隔(如:`users`、`knowledge_bases`) +- 字段名:下划线分隔(如:`created_at`、`user_id`) +- 索引名:`idx_表名_字段名`(如:`idx_users_email`) +- 外键名:`fk_表名_关联表名`(如:`fk_projects_users`) + +--- + +## ER图 + +``` +┌─────────────┐ +│ Users │ +└──────┬──────┘ + │ + │ 1:N + ├─────────────────┐ + │ │ + ▼ ▼ +┌─────────────┐ ┌──────────────┐ +│ Projects │ │KnowledgeBases│ +└──────┬──────┘ └──────┬───────┘ + │ │ + │ 1:N │ 1:N + │ │ + ▼ ▼ +┌──────────────┐ ┌──────────────┐ +│Conversations │ │ Documents │ +└──────┬───────┘ └──────────────┘ + │ + │ 1:N + │ + ▼ +┌──────────────┐ +│ Messages │ +└──────────────┘ +``` + +--- + +## 表结构设计 + +### 1. users - 用户表 + +**用途:** 存储用户基本信息和认证信息 + +```sql +CREATE TABLE users ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + email VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, -- bcrypt加密 + name VARCHAR(100), + avatar_url TEXT, + + -- 角色和状态 + role VARCHAR(20) NOT NULL DEFAULT 'user', -- user, admin + status VARCHAR(20) NOT NULL DEFAULT 'active', -- active, inactive, suspended + + -- 配额(知识库限制) + kb_quota INTEGER DEFAULT 3, + kb_used INTEGER DEFAULT 0, + + -- 试用信息 + trial_ends_at TIMESTAMP, + is_trial BOOLEAN DEFAULT true, + + -- 时间戳 + last_login_at TIMESTAMP, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + + -- 索引 + CONSTRAINT check_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), + CONSTRAINT check_kb_quota CHECK (kb_used <= kb_quota) +); + +-- 索引 +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_users_status ON users(status); +CREATE INDEX idx_users_created_at ON users(created_at); + +-- 注释 +COMMENT ON TABLE users IS '用户表'; +COMMENT ON COLUMN users.role IS '用户角色:user-普通用户, admin-管理员'; +COMMENT ON COLUMN users.status IS '账户状态:active-激活, inactive-未激活, suspended-暂停'; +``` + +**字段说明:** +| 字段 | 类型 | 说明 | 必填 | 默认值 | +|------|------|------|------|--------| +| id | VARCHAR(50) | 用户ID(UUID) | ✅ | 自动生成 | +| email | VARCHAR(255) | 邮箱(登录名) | ✅ | - | +| password | VARCHAR(255) | 密码(bcrypt) | ✅ | - | +| name | VARCHAR(100) | 用户姓名 | ❌ | NULL | +| role | VARCHAR(20) | 角色 | ✅ | 'user' | +| status | VARCHAR(20) | 状态 | ✅ | 'active' | +| kb_quota | INTEGER | 知识库配额 | ✅ | 3 | +| kb_used | INTEGER | 已使用知识库数 | ✅ | 0 | + +--- + +### 2. projects - 项目/课题表 + +**用途:** 存储用户创建的研究项目/课题 + +```sql +CREATE TABLE projects ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + user_id VARCHAR(50) NOT NULL, + + -- 项目信息 + name VARCHAR(200) NOT NULL, + description TEXT NOT NULL, -- 项目背景信息(重要!用于上下文注入) + + -- 统计信息 + conversation_count INTEGER DEFAULT 0, + + -- 时间戳 + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + + -- 外键 + CONSTRAINT fk_projects_users FOREIGN KEY (user_id) + REFERENCES users(id) ON DELETE CASCADE +); + +-- 索引 +CREATE INDEX idx_projects_user_id ON projects(user_id); +CREATE INDEX idx_projects_created_at ON projects(created_at); + +-- 注释 +COMMENT ON TABLE projects IS '项目/课题表'; +COMMENT ON COLUMN projects.description IS '项目背景信息,会自动注入到对话上下文中'; +``` + +--- + +### 3. conversations - 对话表 + +**用途:** 存储用户与智能体的对话会话 + +```sql +CREATE TABLE conversations ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + user_id VARCHAR(50) NOT NULL, + project_id VARCHAR(50), -- 可选,全局快速问答时为NULL + agent_id VARCHAR(50) NOT NULL, -- 智能体ID(对应config/agents.yaml) + + -- 对话信息 + title VARCHAR(200) NOT NULL, + model_name VARCHAR(50) DEFAULT 'deepseek-v3', + + -- 统计信息 + message_count INTEGER DEFAULT 0, + total_tokens INTEGER DEFAULT 0, + + -- 时间戳 + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + + -- 外键 + CONSTRAINT fk_conversations_users FOREIGN KEY (user_id) + REFERENCES users(id) ON DELETE CASCADE, + CONSTRAINT fk_conversations_projects FOREIGN KEY (project_id) + REFERENCES projects(id) ON DELETE CASCADE +); + +-- 索引 +CREATE INDEX idx_conversations_user_id ON conversations(user_id); +CREATE INDEX idx_conversations_project_id ON conversations(project_id); +CREATE INDEX idx_conversations_agent_id ON conversations(agent_id); +CREATE INDEX idx_conversations_created_at ON conversations(created_at); + +-- 注释 +COMMENT ON TABLE conversations IS '对话会话表'; +COMMENT ON COLUMN conversations.project_id IS '项目ID,全局快速问答时为NULL'; +COMMENT ON COLUMN conversations.agent_id IS '智能体ID,对应配置文件中的智能体'; +``` + +--- + +### 4. messages - 消息表 + +**用途:** 存储对话中的每条消息 + +```sql +CREATE TABLE messages ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + conversation_id VARCHAR(50) NOT NULL, + + -- 消息内容 + role VARCHAR(20) NOT NULL, -- user, assistant + content TEXT NOT NULL, + + -- 元数据(可选) + metadata JSONB, -- 存储额外信息,如引用的知识库、模型参数等 + + -- 统计信息 + tokens INTEGER, + + -- 是否固定到项目背景 + is_pinned BOOLEAN DEFAULT false, + + -- 时间戳 + created_at TIMESTAMP DEFAULT NOW(), + + -- 外键 + CONSTRAINT fk_messages_conversations FOREIGN KEY (conversation_id) + REFERENCES conversations(id) ON DELETE CASCADE, + + -- 约束 + CONSTRAINT check_role CHECK (role IN ('user', 'assistant')) +); + +-- 索引 +CREATE INDEX idx_messages_conversation_id ON messages(conversation_id); +CREATE INDEX idx_messages_created_at ON messages(created_at); +CREATE INDEX idx_messages_is_pinned ON messages(is_pinned); + +-- 注释 +COMMENT ON TABLE messages IS '对话消息表'; +COMMENT ON COLUMN messages.is_pinned IS '是否固定到项目背景,用于动态更新项目描述'; +COMMENT ON COLUMN messages.metadata IS 'JSON格式,存储引用的知识库、使用的模型等'; +``` + +--- + +### 5. knowledge_bases - 知识库表 + +**用途:** 存储用户创建的个人知识库 + +```sql +CREATE TABLE knowledge_bases ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + user_id VARCHAR(50) NOT NULL, + + -- 知识库信息 + name VARCHAR(100) NOT NULL, + description TEXT, + + -- Dify集成 + dify_dataset_id VARCHAR(100) NOT NULL, -- Dify中的知识库ID + + -- 统计信息 + file_count INTEGER DEFAULT 0, + total_size_bytes BIGINT DEFAULT 0, + + -- 时间戳 + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + + -- 外键 + CONSTRAINT fk_kb_users FOREIGN KEY (user_id) + REFERENCES users(id) ON DELETE CASCADE, + + -- 约束:每个用户最多3个知识库 + CONSTRAINT check_kb_limit CHECK ( + (SELECT COUNT(*) FROM knowledge_bases WHERE user_id = knowledge_bases.user_id) <= 3 + ) +); + +-- 索引 +CREATE INDEX idx_kb_user_id ON knowledge_bases(user_id); +CREATE INDEX idx_kb_dify_dataset_id ON knowledge_bases(dify_dataset_id); + +-- 注释 +COMMENT ON TABLE knowledge_bases IS '知识库表,每个用户最多3个'; +COMMENT ON COLUMN knowledge_bases.dify_dataset_id IS 'Dify中对应的数据集ID'; +``` + +--- + +### 6. documents - 文档表 + +**用途:** 存储知识库中上传的文档 + +```sql +CREATE TABLE documents ( + id VARCHAR(50) PRIMARY KEY DEFAULT gen_random_uuid()::VARCHAR, + kb_id VARCHAR(50) NOT NULL, + user_id VARCHAR(50) NOT NULL, + + -- 文件信息 + filename VARCHAR(255) NOT NULL, + file_type VARCHAR(20) NOT NULL, -- pdf, docx + file_size_bytes BIGINT NOT NULL, + file_url TEXT NOT NULL, -- 对象存储URL + + -- Dify集成 + dify_document_id VARCHAR(100) NOT NULL, -- Dify中的文档ID + + -- 处理状态 + status VARCHAR(20) DEFAULT 'uploading', -- uploading, processing, completed, failed + progress INTEGER DEFAULT 0, -- 0-100 + error_message TEXT, + + -- 处理结果 + segments_count INTEGER, -- 切分的段落数 + tokens_count INTEGER, -- token数量 + + -- 时间戳 + uploaded_at TIMESTAMP DEFAULT NOW(), + processed_at TIMESTAMP, + + -- 外键 + CONSTRAINT fk_documents_kb FOREIGN KEY (kb_id) + REFERENCES knowledge_bases(id) ON DELETE CASCADE, + CONSTRAINT fk_documents_users FOREIGN KEY (user_id) + REFERENCES users(id) ON DELETE CASCADE, + + -- 约束:每个知识库最多50个文档 + CONSTRAINT check_doc_limit CHECK ( + (SELECT COUNT(*) FROM documents WHERE kb_id = documents.kb_id) <= 50 + ), + + -- 约束:状态和进度 + CONSTRAINT check_status CHECK (status IN ('uploading', 'processing', 'completed', 'failed')), + CONSTRAINT check_progress CHECK (progress >= 0 AND progress <= 100) +); + +-- 索引 +CREATE INDEX idx_documents_kb_id ON documents(kb_id); +CREATE INDEX idx_documents_user_id ON documents(user_id); +CREATE INDEX idx_documents_status ON documents(status); +CREATE INDEX idx_documents_dify_document_id ON documents(dify_document_id); + +-- 注释 +COMMENT ON TABLE documents IS '文档表,每个知识库最多50个文档'; +COMMENT ON COLUMN documents.status IS '处理状态:uploading-上传中, processing-处理中, completed-完成, failed-失败'; +``` + +--- + +### 7. admin_logs - 管理员操作日志表(可选) + +**用途:** 记录管理员的敏感操作 + +```sql +CREATE TABLE admin_logs ( + id SERIAL PRIMARY KEY, + admin_id VARCHAR(50) NOT NULL, + + -- 操作信息 + action VARCHAR(100) NOT NULL, -- 操作类型 + resource_type VARCHAR(50), -- 资源类型:user, conversation, etc. + resource_id VARCHAR(50), -- 资源ID + + -- 详细信息 + details JSONB, + ip_address VARCHAR(45), + user_agent TEXT, + + -- 时间戳 + created_at TIMESTAMP DEFAULT NOW(), + + -- 外键 + CONSTRAINT fk_admin_logs_users FOREIGN KEY (admin_id) + REFERENCES users(id) ON DELETE CASCADE +); + +-- 索引 +CREATE INDEX idx_admin_logs_admin_id ON admin_logs(admin_id); +CREATE INDEX idx_admin_logs_created_at ON admin_logs(created_at); +CREATE INDEX idx_admin_logs_action ON admin_logs(action); + +-- 注释 +COMMENT ON TABLE admin_logs IS '管理员操作日志表,用于审计'; +``` + +--- + +## 索引设计 + +### 主要索引 + +| 表名 | 索引字段 | 类型 | 用途 | +|------|---------|------|------| +| users | email | UNIQUE | 登录查询 | +| users | status | INDEX | 按状态筛选用户 | +| projects | user_id | INDEX | 查询用户的项目 | +| conversations | user_id | INDEX | 查询用户的对话 | +| conversations | project_id | INDEX | 查询项目的对话 | +| conversations | agent_id | INDEX | 统计智能体使用情况 | +| messages | conversation_id | INDEX | 查询对话消息 | +| knowledge_bases | user_id | INDEX | 查询用户的知识库 | +| documents | kb_id | INDEX | 查询知识库的文档 | +| documents | status | INDEX | 筛选处理状态 | + +### 复合索引(如需优化性能可添加) + +```sql +-- 按时间范围查询用户的对话 +CREATE INDEX idx_conversations_user_created + ON conversations(user_id, created_at DESC); + +-- 按项目查询特定智能体的对话 +CREATE INDEX idx_conversations_project_agent + ON conversations(project_id, agent_id); +``` + +--- + +## 数据约束 + +### 业务约束 + +1. **知识库数量限制** + - 每个用户最多3个知识库 + - 通过CHECK约束和应用层双重控制 + +2. **文档数量限制** + - 每个知识库最多50个文档 + - 通过CHECK约束和应用层双重控制 + +3. **邮箱格式验证** + - 使用正则表达式验证邮箱格式 + +4. **密码安全** + - 使用bcrypt加密,成本因子12 + - 密码长度至少8位(应用层验证) + +### 数据完整性 + +1. **级联删除** + - 删除用户 → 级联删除其项目、对话、知识库 + - 删除项目 → 级联删除其对话 + - 删除知识库 → 级联删除其文档 + +2. **外键约束** + - 所有外键都设置了ON DELETE CASCADE + - 保证数据一致性 + +--- + +## 数据迁移策略 + +### 初始化迁移 + +```bash +# 创建初始迁移 +npx prisma migrate dev --name init + +# 生成Prisma Client +npx prisma generate +``` + +### 迁移命名规范 + +``` +yyyymmdd_描述.sql +例如: +20251010_init.sql +20251015_add_admin_logs.sql +20251020_add_user_quotas.sql +``` + +### 生产环境迁移流程 + +1. 在开发环境测试迁移 +2. 备份生产数据库 +3. 执行迁移脚本 +4. 验证数据完整性 +5. 回滚计划(如有问题) + +--- + +## Prisma Schema + +### 完整的schema.prisma + +```prisma +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model User { + id String @id @default(uuid()) + email String @unique + password String + name String? + avatarUrl String? @map("avatar_url") + + role String @default("user") + status String @default("active") + + kbQuota Int @default(3) @map("kb_quota") + kbUsed Int @default(0) @map("kb_used") + + trialEndsAt DateTime? @map("trial_ends_at") + isTrial Boolean @default(true) @map("is_trial") + + lastLoginAt DateTime? @map("last_login_at") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + projects Project[] + conversations Conversation[] + knowledgeBases KnowledgeBase[] + documents Document[] + adminLogs AdminLog[] + + @@index([email]) + @@index([status]) + @@index([createdAt]) + @@map("users") +} + +model Project { + id String @id @default(uuid()) + userId String @map("user_id") + name String + description String @db.Text + conversationCount Int @default(0) @map("conversation_count") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + conversations Conversation[] + + @@index([userId]) + @@index([createdAt]) + @@map("projects") +} + +model Conversation { + id String @id @default(uuid()) + userId String @map("user_id") + projectId String? @map("project_id") + agentId String @map("agent_id") + title String + modelName String @default("deepseek-v3") @map("model_name") + messageCount Int @default(0) @map("message_count") + totalTokens Int @default(0) @map("total_tokens") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade) + messages Message[] + + @@index([userId]) + @@index([projectId]) + @@index([agentId]) + @@index([createdAt]) + @@map("conversations") +} + +model Message { + id String @id @default(uuid()) + conversationId String @map("conversation_id") + role String + content String @db.Text + metadata Json? + tokens Int? + isPinned Boolean @default(false) @map("is_pinned") + + createdAt DateTime @default(now()) @map("created_at") + + conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) + + @@index([conversationId]) + @@index([createdAt]) + @@index([isPinned]) + @@map("messages") +} + +model KnowledgeBase { + id String @id @default(uuid()) + userId String @map("user_id") + name String + description String? + difyDatasetId String @map("dify_dataset_id") + fileCount Int @default(0) @map("file_count") + totalSizeBytes BigInt @default(0) @map("total_size_bytes") + + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + documents Document[] + + @@index([userId]) + @@index([difyDatasetId]) + @@map("knowledge_bases") +} + +model Document { + id String @id @default(uuid()) + kbId String @map("kb_id") + userId String @map("user_id") + filename String + fileType String @map("file_type") + fileSizeBytes BigInt @map("file_size_bytes") + fileUrl String @map("file_url") + difyDocumentId String @map("dify_document_id") + status String @default("uploading") + progress Int @default(0) + errorMessage String? @map("error_message") + segmentsCount Int? @map("segments_count") + tokensCount Int? @map("tokens_count") + + uploadedAt DateTime @default(now()) @map("uploaded_at") + processedAt DateTime? @map("processed_at") + + knowledgeBase KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([kbId]) + @@index([userId]) + @@index([status]) + @@index([difyDocumentId]) + @@map("documents") +} + +model AdminLog { + id Int @id @default(autoincrement()) + adminId String @map("admin_id") + action String + resourceType String? @map("resource_type") + resourceId String? @map("resource_id") + details Json? + ipAddress String? @map("ip_address") + userAgent String? @map("user_agent") + + createdAt DateTime @default(now()) @map("created_at") + + admin User @relation(fields: [adminId], references: [id], onDelete: Cascade) + + @@index([adminId]) + @@index([createdAt]) + @@index([action]) + @@map("admin_logs") +} +``` + +--- + +## 数据字典 + +### 枚举值定义 + +**用户角色 (user.role)** +- `user` - 普通用户 +- `admin` - 管理员 + +**账户状态 (user.status)** +- `active` - 激活(正常使用) +- `inactive` - 未激活(注册但未验证邮箱) +- `suspended` - 暂停(违规或欠费) + +**消息角色 (message.role)** +- `user` - 用户消息 +- `assistant` - AI助手消息 + +**文档状态 (document.status)** +- `uploading` - 上传中 +- `processing` - Dify处理中 +- `completed` - 处理完成 +- `failed` - 处理失败 + +**文件类型 (document.file_type)** +- `pdf` - PDF文档 +- `docx` - Word文档 + +--- + +## 数据安全 + +### 敏感数据处理 + +1. **密码** + - 使用bcrypt加密(成本因子12) + - 不可逆加密,无法还原明文 + +2. **API Keys** + - 不存储在数据库中 + - 使用环境变量管理 + +3. **用户数据隔离** + - 所有查询必须包含user_id过滤 + - 防止越权访问 + +### 备份策略 + +1. **自动备份** + - 每日全量备份 + - 保留最近7天 + +2. **手动备份** + - 重大升级前手动备份 + - 保留3个版本 + +--- + +## 性能优化建议 + +### 查询优化 + +1. **分页查询** + - 使用 LIMIT + OFFSET + - 或使用游标分页(基于ID) + +2. **避免N+1查询** + - 使用Prisma的include和select + - 预加载关联数据 + +3. **合理使用索引** + - 频繁查询的字段建立索引 + - 定期检查索引使用情况 + +### 数据归档 + +1. **历史数据归档** + - 对话超过6个月自动归档 + - 归档数据移至单独的表 + +2. **日志清理** + - admin_logs保留3个月 + - 定期清理过期日志 + +--- + +## 版本变更记录 + +| 版本 | 日期 | 变更内容 | 作者 | +|------|------|---------|------| +| v1.0 | 2025-10-10 | 初始版本,定义所有核心表 | 开发团队 | + +--- + +**文档维护:** 数据库结构变更需同步更新本文档 +**Review频率:** 每个里程碑结束后Review一次 + diff --git a/docs/01-设计文档/用户端原型图.html b/docs/01-设计文档/用户端原型图.html new file mode 100644 index 00000000..a1a046d8 --- /dev/null +++ b/docs/01-设计文档/用户端原型图.html @@ -0,0 +1,537 @@ + + + + + + AI科研助手产品原型 V6 + + + + + + + + + + + +
+ +
+ + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/02-开发规范/代码规范.md b/docs/02-开发规范/代码规范.md new file mode 100644 index 00000000..9c64da12 --- /dev/null +++ b/docs/02-开发规范/代码规范.md @@ -0,0 +1,814 @@ +# 代码规范 + +> **版本:** v1.0 +> **创建日期:** 2025-10-10 +> **适用范围:** 前端(React/TypeScript)+ 后端(Node.js/TypeScript) + +--- + +## 📋 目录 + +1. [通用规范](#通用规范) +2. [TypeScript规范](#typescript规范) +3. [React规范](#react规范) +4. [Node.js后端规范](#nodejs后端规范) +5. [命名规范](#命名规范) +6. [注释规范](#注释规范) +7. [Git提交规范](#git提交规范) + +--- + +## 通用规范 + +### 代码风格 +- ✅ 使用ESLint和Prettier统一代码风格 +- ✅ 缩进:2个空格 +- ✅ 字符串:优先使用单引号 `'` +- ✅ 行尾:不加分号(除非必要) +- ✅ 单行最大长度:100字符 +- ✅ 使用尾随逗号(对象、数组) + +### 文件组织 +- ✅ 一个文件一个组件/类 +- ✅ 相关文件放在同一目录 +- ✅ 使用barrel exports(index.ts) +- ✅ 测试文件与源文件同目录 + +``` +src/ +├── components/ +│ ├── Button/ +│ │ ├── Button.tsx +│ │ ├── Button.test.tsx +│ │ ├── Button.styles.ts +│ │ └── index.ts # export { Button } from './Button' +``` + +### 代码注释 +- ✅ 复杂逻辑必须注释 +- ✅ 公共API必须注释 +- ✅ 避免无用注释 +- ✅ 使用JSDoc格式 + +--- + +## TypeScript规范 + +### 类型定义 + +**✅ 推荐:** +```typescript +// 使用interface定义对象结构 +interface User { + id: string + email: string + name?: string +} + +// 使用type定义联合类型 +type Status = 'active' | 'inactive' | 'suspended' + +// 使用enum定义常量集合 +enum UserRole { + USER = 'user', + ADMIN = 'admin', +} +``` + +**❌ 避免:** +```typescript +// 不要使用any +function process(data: any) { // ❌ + // ... +} + +// 应该明确类型 +function process(data: ProcessData) { // ✅ + // ... +} +``` + +### 类型导入导出 + +```typescript +// types.ts +export interface Project { + id: string + name: string + description: string +} + +export type ProjectStatus = 'active' | 'archived' + +// project.service.ts +import type { Project, ProjectStatus } from './types' +``` + +### 严格模式 +```json +// tsconfig.json +{ + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true + } +} +``` + +--- + +## React规范 + +### 组件定义 + +**✅ 推荐:函数组件 + Hooks** +```tsx +import { useState } from 'react' + +interface ButtonProps { + label: string + onClick: () => void + variant?: 'primary' | 'secondary' + disabled?: boolean +} + +export function Button({ + label, + onClick, + variant = 'primary', + disabled = false +}: ButtonProps) { + const [isLoading, setIsLoading] = useState(false) + + const handleClick = async () => { + setIsLoading(true) + try { + await onClick() + } finally { + setIsLoading(false) + } + } + + return ( + + ) +} +``` + +**❌ 避免:类组件** +```tsx +// 除非有特殊需求,否则不使用类组件 +class Button extends React.Component { ... } // ❌ +``` + +### Hooks规范 + +**✅ 推荐:自定义Hooks** +```typescript +// useProjects.ts +import { useState, useEffect } from 'react' +import { projectService } from '@/services' +import type { Project } from '@/types' + +export function useProjects() { + const [projects, setProjects] = useState([]) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + loadProjects() + }, []) + + const loadProjects = async () => { + setLoading(true) + setError(null) + try { + const data = await projectService.getProjects() + setProjects(data) + } catch (err) { + setError(err as Error) + } finally { + setLoading(false) + } + } + + return { projects, loading, error, reload: loadProjects } +} + +// 使用 +function ProjectList() { + const { projects, loading, error } = useProjects() + + if (loading) return + if (error) return + + return ( +
    + {projects.map(project => ( +
  • {project.name}
  • + ))} +
+ ) +} +``` + +### 组件组织 + +```tsx +// ✅ 推荐的组件结构 +import { useState, useEffect, useMemo, useCallback } from 'react' +import { useNavigate } from 'react-router-dom' +import { SomeComponent } from '@/components' +import { useCustomHook } from '@/hooks' +import type { SomeType } from '@/types' + +interface ComponentProps { + // props定义 +} + +export function Component({ prop1, prop2 }: ComponentProps) { + // 1. Hooks + const navigate = useNavigate() + const [state, setState] = useState() + const { data } = useCustomHook() + + // 2. 派生状态(useMemo) + const computedValue = useMemo(() => { + return heavyComputation(data) + }, [data]) + + // 3. 事件处理(useCallback) + const handleClick = useCallback(() => { + // 处理逻辑 + }, []) + + // 4. Effects + useEffect(() => { + // 副作用 + }, []) + + // 5. 早期返回(Loading/Error) + if (!data) return + + // 6. 渲染 + return ( +
+ {/* JSX */} +
+ ) +} +``` + +### 条件渲染 + +**✅ 推荐:** +```tsx +// 简单条件:使用 && +{isLoggedIn && } + +// if-else:使用三元运算符 +{isLoggedIn ? : } + +// 多条件:提取为函数或组件 +function renderContent() { + if (loading) return + if (error) return + if (data.length === 0) return + return +} + +return
{renderContent()}
+``` + +**❌ 避免:** +```tsx +// 避免复杂的嵌套三元运算符 +{condition1 ? ( + condition2 ? : +) : ( + condition3 ? : +)} // ❌ 难以理解 +``` + +--- + +## Node.js后端规范 + +### 文件组织 + +``` +backend/src/ +├── routes/ # 路由定义 +│ ├── auth.routes.ts +│ └── project.routes.ts +├── services/ # 业务逻辑 +│ ├── auth.service.ts +│ └── project.service.ts +├── controllers/ # 控制器(可选) +├── models/ # Prisma模型 +├── utils/ # 工具函数 +├── config/ # 配置加载 +├── types/ # 类型定义 +└── server.ts # 入口文件 +``` + +### 路由定义 + +```typescript +// routes/project.routes.ts +import { FastifyInstance } from 'fastify' +import { projectService } from '../services/project.service' +import { authMiddleware } from '../middleware/auth' + +export async function projectRoutes(server: FastifyInstance) { + // 获取项目列表 + server.get( + '/api/v1/projects', + { + preHandler: [authMiddleware], + schema: { + querystring: { + type: 'object', + properties: { + page: { type: 'number' }, + pageSize: { type: 'number' }, + }, + }, + }, + }, + async (request, reply) => { + const { page = 1, pageSize = 20 } = request.query as any + const userId = request.user.id + + const result = await projectService.getProjects(userId, { + page, + pageSize, + }) + + return reply.send({ + success: true, + data: result, + }) + } + ) + + // 创建项目 + server.post( + '/api/v1/projects', + { + preHandler: [authMiddleware], + schema: { + body: { + type: 'object', + required: ['name', 'description'], + properties: { + name: { type: 'string', minLength: 1, maxLength: 200 }, + description: { type: 'string', minLength: 1 }, + }, + }, + }, + }, + async (request, reply) => { + const userId = request.user.id + const data = request.body as CreateProjectDto + + const project = await projectService.createProject(userId, data) + + return reply.code(201).send({ + success: true, + data: project, + }) + } + ) +} +``` + +### Service层 + +```typescript +// services/project.service.ts +import { prisma } from '../lib/prisma' +import type { CreateProjectDto, UpdateProjectDto } from '../types' + +export class ProjectService { + /** + * 获取用户的项目列表 + */ + async getProjects(userId: string, options: PaginationOptions) { + const { page, pageSize } = options + + const [items, total] = await Promise.all([ + prisma.project.findMany({ + where: { userId }, + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: { createdAt: 'desc' }, + }), + prisma.project.count({ where: { userId } }), + ]) + + return { + items, + pagination: { + page, + pageSize, + total, + totalPages: Math.ceil(total / pageSize), + hasNext: page * pageSize < total, + hasPrev: page > 1, + }, + } + } + + /** + * 创建项目 + */ + async createProject(userId: string, data: CreateProjectDto) { + return prisma.project.create({ + data: { + userId, + name: data.name, + description: data.description, + }, + }) + } + + /** + * 更新项目 + */ + async updateProject( + userId: string, + projectId: string, + data: UpdateProjectDto + ) { + // 验证权限 + const project = await prisma.project.findFirst({ + where: { id: projectId, userId }, + }) + + if (!project) { + throw new Error('Project not found or unauthorized') + } + + return prisma.project.update({ + where: { id: projectId }, + data, + }) + } + + /** + * 删除项目 + */ + async deleteProject(userId: string, projectId: string) { + // 验证权限 + const project = await prisma.project.findFirst({ + where: { id: projectId, userId }, + }) + + if (!project) { + throw new Error('Project not found or unauthorized') + } + + await prisma.project.delete({ + where: { id: projectId }, + }) + } +} + +export const projectService = new ProjectService() +``` + +### 错误处理 + +```typescript +// utils/errors.ts +export class AppError extends Error { + constructor( + public code: string, + public message: string, + public statusCode: number = 400, + public details?: any + ) { + super(message) + this.name = 'AppError' + } +} + +export class ValidationError extends AppError { + constructor(message: string, details?: any) { + super('VALIDATION_ERROR', message, 422, details) + } +} + +export class UnauthorizedError extends AppError { + constructor(message: string = 'Unauthorized') { + super('UNAUTHORIZED', message, 401) + } +} + +export class NotFoundError extends AppError { + constructor(resource: string) { + super('NOT_FOUND', `${resource} not found`, 404) + } +} + +// 使用 +async function getProject(id: string) { + const project = await prisma.project.findUnique({ where: { id } }) + + if (!project) { + throw new NotFoundError('Project') + } + + return project +} +``` + +### 错误处理中间件 + +```typescript +// middleware/error-handler.ts +import { FastifyError, FastifyReply, FastifyRequest } from 'fastify' +import { AppError } from '../utils/errors' + +export async function errorHandler( + error: FastifyError | AppError, + request: FastifyRequest, + reply: FastifyReply +) { + // 记录错误 + request.log.error(error) + + // 自定义错误 + if (error instanceof AppError) { + return reply.code(error.statusCode).send({ + success: false, + error: { + code: error.code, + message: error.message, + details: error.details, + }, + timestamp: new Date().toISOString(), + }) + } + + // Prisma错误 + if (error.name === 'PrismaClientKnownRequestError') { + // 处理Prisma特定错误 + return reply.code(400).send({ + success: false, + error: { + code: 'DATABASE_ERROR', + message: 'Database operation failed', + }, + timestamp: new Date().toISOString(), + }) + } + + // 默认错误 + return reply.code(500).send({ + success: false, + error: { + code: 'INTERNAL_ERROR', + message: 'Internal server error', + }, + timestamp: new Date().toISOString(), + }) +} +``` + +--- + +## 命名规范 + +### 文件命名 + +| 类型 | 命名方式 | 示例 | +|------|---------|------| +| React组件 | PascalCase | `Button.tsx`, `ProjectList.tsx` | +| Hooks | camelCase + use前缀 | `useProjects.ts`, `useAuth.ts` | +| 工具函数 | camelCase | `formatDate.ts`, `api.ts` | +| 类型定义 | camelCase + .types | `user.types.ts`, `api.types.ts` | +| 常量 | camelCase + .constants | `routes.constants.ts` | +| 测试文件 | 同源文件 + .test | `Button.test.tsx` | + +### 变量命名 + +```typescript +// ✅ 推荐 +const userName = 'John' // camelCase +const USER_ROLE = 'admin' // 常量用UPPER_SNAKE_CASE +const isLoading = false // 布尔值用is/has/can前缀 +const hasPermission = true +const canEdit = false + +// ❌ 避免 +const user_name = 'John' // 不用snake_case +const loading = false // 布尔值缺少is前缀 +const x = 10 // 无意义的变量名 +``` + +### 函数命名 + +```typescript +// ✅ 推荐 +function getUser() { } // get: 获取数据 +function fetchProjects() { } // fetch: 异步获取 +function createProject() { } // create: 创建 +function updateProject() { } // update: 更新 +function deleteProject() { } // delete: 删除 +function handleClick() { } // handle: 事件处理 +function validateEmail() { } // validate: 验证 +function formatDate() { } // format: 格式化 + +// ❌ 避免 +function data() { } // 不清楚功能 +function doSomething() { } // 太模糊 +function process() { } // 不明确 +``` + +### 组件命名 + +```typescript +// ✅ 推荐 + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
+ + + + + + + + + + + diff --git a/优化方案总结.md b/优化方案总结.md new file mode 100644 index 00000000..4f466bc7 --- /dev/null +++ b/优化方案总结.md @@ -0,0 +1,416 @@ +# AI科研助手 - 优化方案总结 + +## 📋 需求澄清与方案调整 + +### 🔄 重要需求变更:知识库规模 + +**原PRD描述:** +> "后期考虑,增加基于大规模(1000篇以内)文献的读取、识别、内容提取的工作" + +**实际需求(已明确):** +- ✅ 每个用户最多创建 **3个知识库** +- ✅ 每个知识库最多上传 **50个文件** +- ✅ 主要格式:**PDF、DOCX** +- ✅ 单用户最大文档量:**150个文件** + +**影响:** +- 🎉 技术难度从 ⭐⭐⭐⭐⭐ 降至 ⭐⭐⭐ +- 🎉 **Dify完全满足需求**,无需自建RAG系统 +- 🎉 开发成本进一步降低 +- 🎉 性能优化需求降低 + +--- + +## 📋 您提出的问题与解决方案 + +### 问题1:聊天功能如何实现? + +**您的担忧:** 不用LobeChat整体,如何保证聊天功能稳定? + +**我的方案:** ✅ **参考LobeChat开源实现,复用核心聊天组件** + +``` +策略: +├── ❌ 不采用:LobeChat整体(缺少项目管理、知识库功能) +├── ❌ 不采用:Dify + LobeChat组合(集成复杂,定制成本高) +├── ✅ 采用:提取LobeChat的聊天UI组件到我们的React项目 +└── ✅ 采用:参考其流式输出、Markdown渲染的实现逻辑 +``` + +**具体实施:** +1. 克隆LobeChat源码(MIT开源许可,可自由使用) +2. 提取核心组件:ChatMessage、ChatInput、StreamRenderer、MarkdownContent +3. 移植到我们的React+Vite项目中 +4. 自研业务逻辑:项目管理、智能体编排、知识库集成 + +**优势:** +- 聊天体验有保障(LobeChat已被4万+用户验证) +- 节省开发时间(9.5天 → 见详细方案) +- 保持架构灵活性(不被整体框架绑定) + +--- + +### 问题2:向量数据库还需要考虑吗? + +**回答:** ❌ **完全不需要考虑** + +**原因:** +- Dify内置了Qdrant向量数据库 +- 文档解析、向量化、检索全由Dify处理 +- 我们只需调用Dify的REST API即可 + +**实际需求下更加确定:** +``` +知识库规模: +- 3个知识库/用户 +- 50个文件/知识库 +- 150个文件/用户最大 + +Dify的能力: +- 单个知识库支持上万个文档片段 +- 我们只需150个文件,远低于上限 +- Dify内置Qdrant完全够用!✅ +``` + +**我们需要做的:** +```javascript +// 只需调用Dify API +const results = await difyClient.queryKnowledgeBase({ + datasetId: 'kb-xxx', + query: '骨质疏松的治疗方案', + topK: 5 +}); + +// Dify自动处理: +// 1. 向量检索(Qdrant) +// 2. 混合检索(关键词+语义) +// 3. 重排序(Reranking) +// 4. 返回结果 +``` + +**数据库设计(业务层):** +```sql +-- 我们只需要管理知识库的元数据 +CREATE TABLE knowledge_bases ( + id VARCHAR(50) PRIMARY KEY, + user_id VARCHAR(50) NOT NULL, + name VARCHAR(100) NOT NULL, + dify_dataset_id VARCHAR(100) NOT NULL, -- Dify知识库ID + file_count INT DEFAULT 0, + -- 限制:每个用户最多3个 + CONSTRAINT check_kb_limit CHECK ( + (SELECT COUNT(*) FROM knowledge_bases WHERE user_id = user_id) <= 3 + ) +); + +-- 文档表 +CREATE TABLE documents ( + id VARCHAR(50) PRIMARY KEY, + kb_id VARCHAR(50) NOT NULL, + filename VARCHAR(255) NOT NULL, + file_size_bytes BIGINT NOT NULL, + status VARCHAR(20) DEFAULT 'processing', -- processing, completed, failed + dify_document_id VARCHAR(100) NOT NULL, + -- 限制:每个知识库最多50个 + CONSTRAINT check_doc_limit CHECK ( + (SELECT COUNT(*) FROM documents WHERE kb_id = kb_id) <= 50 + ) +); +``` + +--- + +### 问题3:删除运营端功能后的方案 + +**已删除功能:** ✅ 降低开发成本 + +| 功能 | 状态 | 替代方案 | +|------|------|---------| +| 模型管理 | ❌ 删除 | 配置文件:`config/models.yaml` | +| 智能体管理 | ❌ 删除 | 配置文件:`config/agents.yaml` | +| 智能体配置 | ❌ 删除 | Prompt文件:`prompts/*.txt` | +| Prompt版本管理 | ❌ 删除 | Git版本控制 | +| 用户管理 | ✅ 保留 | 简化版(列表、禁用、查看) | +| 数据统计 | ✅ 保留 | 简化版(基础仪表盘) | +| 对话查看 | ✅ 保留 | 仅管理员可查看 | + +**配置文件示例:** + +```yaml +# config/agents.yaml +agents: + - id: agent-picos + name: PICOS构建 + system_prompt_file: prompts/picos_system.txt + models: + deepseek-v3: + temperature: 0.3 + max_tokens: 2500 + rag_enabled: true + status: active +``` + +**优势:** +- 开发时间节省:约3周 +- 开发成本降低:¥77,000 → ¥49,300(节省36%) +- 维护更简单:直接修改配置文件,无需后台界面 +- 版本控制:所有配置由Git管理 + +--- + +### 问题4:大模型优先级 + +**您的要求:** 优先DeepSeek-V3和Qwen3 + +**已更新方案:** ✅ + +**模型配置:** +```yaml +# config/models.yaml +models: + primary: + - name: deepseek-v3 + provider: deepseek + api_key: ${DEEPSEEK_API_KEY} + base_url: https://api.deepseek.com/v1 + pricing: + input: 1 # ¥1/百万tokens + output: 2 # ¥2/百万tokens + features: + - reasoning # 推理能力强 + - long_context # 支持128k上下文 + + secondary: + - name: qwen3-72b + provider: aliyun + api_key: ${DASHSCOPE_API_KEY} + base_url: https://dashscope.aliyuncs.com/api/v1 + pricing: + input: 4 # ¥4/百万tokens + output: 4 + features: + - chinese # 中文理解好 + - stable # 国内稳定 + + optional: + - name: gemini-2.0-flash + provider: google + api_key: ${GEMINI_API_KEY} + # 可选,国际用户使用 +``` + +**成本对比(1000用户/月):** + +| 模型 | 月度成本 | 年度成本 | 性价比 | +|------|---------|---------|--------| +| **DeepSeek-V3** ⭐ | **¥150** | **¥1,800** | **最高** | +| Qwen3-72B | ¥600 | ¥7,200 | 高 | +| Gemini Pro | ¥300 | ¥3,600 | 中 | +| GPT-4 | ¥2,500 | ¥30,000 | 低 | + +**建议:** +- 90%的请求使用DeepSeek-V3(极具性价比) +- 10%的请求使用Qwen3(需要更强中文理解时) +- 年度可节省LLM成本:¥1,200-1,500 + +--- + +## 🎯 最终优化方案总结 + +### 核心架构 + +``` +┌─────────────────────────────────────────┐ +│ 自定义前端(React + Vite) │ +│ - 项目管理(自研) │ +│ - 智能体选择(自研) │ +│ - 聊天界面(参考LobeChat)⭐ │ +│ - 知识库管理(自研) │ +└─────────────────────────────────────────┘ + ↓ REST API +┌─────────────────────────────────────────┐ +│ 业务层 (Node.js/TypeScript) │ +│ - 智能体路由(配置化)⭐ │ +│ - 上下文组装 │ +│ - 用户认证 │ +│ - 简化运营后台⭐ │ +└─────────────────────────────────────────┘ + ↓ ↓ +┌──────────────────┐ ┌─────────────────┐ +│ Dify (RAG) │ │ LLM API │ +│ - 知识库 │ │ - DeepSeek-V3⭐│ +│ - 文档解析 │ │ - Qwen3 ⭐ │ +│ - Qdrant(内置)⭐│ │ - Gemini(可选) │ +└──────────────────┘ └─────────────────┘ +``` + +### 技术栈 + +**前端:** +- React 18 + TypeScript + Vite +- TailwindCSS + HeadlessUI +- Zustand(状态管理) +- **LobeChat聊天组件(复用)** ⭐ + +**后端:** +- Node.js + Fastify + TypeScript +- Prisma(ORM)+ PostgreSQL +- Redis(缓存) + +**RAG:** +- Dify(Docker部署,内置Qdrant)⭐ + +**LLM:** +- DeepSeek-V3(主力)⭐ +- Qwen3-72B(备用)⭐ + +**配置管理:** +- agents.yaml(智能体配置)⭐ +- models.yaml(模型配置)⭐ +- prompts/*.txt(Prompt文件)⭐ + +### 开发计划 + +| 阶段 | 内容 | 时间 | +|------|------|------| +| 阶段1 | 基础搭建 + 复用LobeChat组件 | 1.5周 | +| 阶段2 | 核心功能(12个智能体) | 3.5周 | +| 阶段3 | 高级功能(RAG、文档生成) | 2周 | +| 阶段4 | 简化运营后台 | 1周 | +| 阶段5 | 测试优化 | 2周 | +| **总计** | **10周(2.5个月)** | ⭐ | + +### 成本估算 + +**开发成本(知识库需求明确后):** +- 人力:4人月 × ¥12k = ¥48,000 +- 服务器(开发):¥1,250 +- LLM API(测试):¥50(DeepSeek-V3极便宜) +- **总计:¥49,300** ⭐ + +**月度运营成本(1000用户):** +- 基础设施:¥1,200 +- LLM API:¥180(主要用DeepSeek-V3) +- 对象存储(知识库文件):¥140(750GB存储 + 流量)⭐ +- 人力(运维):¥15,000 +- **总计:¥16,520/月** + +**成本节省:** +- vs 原方案(大规模文献):节省约 ¥500/月 +- vs 纯手写:节省 ¥30,700+(38%+) + +**知识库成本明细:** +``` +单用户:150个文件 × 5MB = 750MB +1000用户:750GB总存储 + +对象存储(阿里云OSS): +- 存储费:750GB × ¥0.12/GB = ¥90/月 +- 流量费:100GB × ¥0.5/GB = ¥50/月 +- 总计:¥140/月 + +注:比原估算的"大规模文献处理"节省60%成本 +``` + +--- + +## ✅ 优势总结 + +### 1. 聊天功能有保障 +- ✅ 参考LobeChat成熟实现 +- ✅ 流式输出、Markdown渲染开箱即用 +- ✅ 节省9.5天开发时间 + +### 2. 向量数据库无需关心(知识库需求明确后更加确定) +- ✅ Dify内置Qdrant,自动处理 +- ✅ 只需调用API,降低技术难度 +- ✅ 150个文件/用户,远低于Dify上限 +- ✅ 无需考虑性能优化 + +### 3. 开发成本大幅降低 +- ✅ 删除复杂后台功能,节省3周 +- ✅ 配置文件管理,易于维护 +- ✅ 总成本:¥49,300(vs ¥77,000) + +### 4. LLM成本最优 +- ✅ DeepSeek-V3:¥1/百万tokens +- ✅ 月度LLM成本:¥180(vs GPT-4的¥2,500) +- ✅ 年度节省:¥27,840 + +### 5. 开发周期短 +- ✅ 2.5个月可上线MVP +- ✅ 复用成熟组件,降低风险 + +--- + +## 📝 下一步行动 + +### 立即可做: + +**1. 确认技术方案** ✅ +- 是否采用优化后的混合架构? +- 是否同意删除后台管理功能? + +**2. 准备环境** +```bash +# 申请LLM API Key +- DeepSeek API Key (https://platform.deepseek.com) +- 阿里云DashScope Key (https://dashscope.aliyun.com) + +# 准备服务器 +- 云服务器 4核8G(开发环境) +- PostgreSQL 数据库 +- Redis 缓存 + +# 准备代码仓库 +- GitHub/GitLab 仓库 +``` + +**3. 组建团队** +- 1名全栈开发(Node.js + React) +- 1名前端开发(React + TailwindCSS) +- 预计:2.5个月完成 + +**4. 启动开发** + +**第1周:** +- [ ] 搭建前后端框架 +- [ ] 部署Dify(Docker) +- [ ] 克隆LobeChat,提取聊天组件 + +**第2-4周:** +- [ ] 实现3个核心智能体 +- [ ] 集成DeepSeek-V3 +- [ ] 完成基础对话功能 + +**第5-7周:** +- [ ] 完善12个智能体 +- [ ] 集成Dify RAG +- [ ] 项目管理功能 + +**第8-10周:** +- [ ] 简化运营后台 +- [ ] 测试优化 +- [ ] 上线MVP + +--- + +## 🎉 总结 + +**优化后的方案:** +- ✅ 聊天功能:参考LobeChat,稳定可靠 +- ✅ 向量数据库:Dify内置,无需关心 +- ✅ 运营后台:配置化,大幅简化 +- ✅ 大模型:DeepSeek-V3优先,成本最优 +- ✅ 开发周期:2.5个月 +- ✅ 开发成本:¥49,300 +- ✅ 月度成本:¥16,400(1000用户) + +**这是最适合您项目的技术方案!** 🚀 + +--- + +**文档版本:v2.0(优化版)** +**更新时间:2025-10-10** +**作者:AI技术顾问** + diff --git a/对话系统实现方案对比.md b/对话系统实现方案对比.md new file mode 100644 index 00000000..ca2d8d13 --- /dev/null +++ b/对话系统实现方案对比.md @@ -0,0 +1,857 @@ +# 对话系统实现方案详细对比 + +## 🎯 核心问题 + +**如果不使用LobeChat整体框架,基于大模型的对话聊天该怎么实现?** + +让我为您详细对比3种方案: + +--- + +## 方案A:使用Dify的对话功能 + +### Dify的对话能力 + +Dify确实提供了完整的对话功能,包括: +- ✅ LLM对话管理 +- ✅ 流式输出 +- ✅ 对话历史管理 +- ✅ RAG知识库集成 +- ✅ 提供WebApp界面 + +### 架构图 + +``` +用户浏览器 + ↓ +Dify自带的WebApp界面 + ↓ +Dify后端(对话+RAG) + ↓ +LLM API (DeepSeek/Qwen) +``` + +### 实现方式 + +**方式1:直接使用Dify的WebApp** +```bash +# 部署Dify后,直接访问其Web界面 +docker-compose up -d +# 访问 http://localhost:3000 +# 创建12个应用(对应12个智能体) +``` + +**方式2:通过Dify API集成** +```javascript +// 调用Dify的对话API +const response = await fetch('https://api.dify.ai/v1/chat-messages', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${DIFY_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + inputs: {}, + query: "请帮我构建PICOS", + response_mode: "streaming", // 流式输出 + conversation_id: "conv-xxx", // 对话ID + user: "user-123" + }) +}); + +// 接收流式响应 +const reader = response.body.getReader(); +while (true) { + const { done, value } = await reader.read(); + if (done) break; + // 处理流式数据 +} +``` + +### 优点 ✅ + +1. **开发成本极低** + - 不需要自己实现对话逻辑 + - 不需要自己实现流式输出 + - 不需要自己管理对话历史 + - RAG功能开箱即用 + +2. **功能完整** + - 对话管理 + - Prompt管理 + - 流式输出 + - 知识库集成 + - 文件上传 + +3. **快速上线** + - 1-2周即可搭建MVP + - 无需深入理解LLM API细节 + +### 缺点 ❌ + +1. **12个智能体管理复杂** + ``` + 问题:需要在Dify中创建12个独立的应用(App) + + Dify界面: + ├── 应用1: 选题评价 + ├── 应用2: PICOS构建 + ├── 应用3: 论文润色 + ├── ... (共12个) + └── 应用12: 期刊稿约评审 + + 影响: + - 用户需要在12个应用间切换(体验差) + - 无法统一管理对话历史 + - 无法共享项目上下文 + ``` + +2. **项目管理功能缺失** + ``` + 我们的需求: + - 用户创建"项目/课题" + - 在项目内使用多个智能体 + - 项目背景信息自动注入 + - 对话可"固定"到项目背景 + + Dify的能力: + - ❌ 没有"项目"概念 + - ❌ 无法跨应用共享上下文 + - ❌ 每个对话是独立的 + ``` + +3. **前端定制困难** + ``` + 我们的原型图: + - 左侧:项目列表 + 智能体列表 + - 中间:智能体卡片选择 + - 右侧:对话界面 + + Dify的界面: + - 固定的单应用界面 + - 定制需要修改Dify源码(复杂) + ``` + +4. **业务逻辑受限** + ``` + 我们的特殊需求: + - 全局快速问答 vs 项目内深度研究 + - 动态背景信息管理(固定功能) + - 对话溯源(引用知识库) + - 多模型即时切换 + + Dify的支持: + - 🟡 部分支持,但需要复杂配置 + - 🟡 或需要修改源码 + ``` + +### 适用场景 ✅ + +**适合:** 如果您的需求是: +- 简单的知识库问答 +- 单一的对话场景 +- 快速验证想法(MVP) + +**不适合:** 我们的项目 +- ❌ 12个智能体需要统一管理 +- ❌ 项目管理是核心功能 +- ❌ 需要高度定制的UI + +--- + +## 方案B:参考LobeChat + 自研后端(推荐 ⭐) + +### 核心思路 + +``` +前端:参考LobeChat的UI组件(不用整体框架) +后端:自己实现对话逻辑(调用LLM API) +RAG:使用Dify(专注知识库检索) +``` + +### 架构图 + +``` +┌─────────────────────────────────────────┐ +│ 前端(React + Vite) │ +│ ┌──────────────────────────────────┐ │ +│ │ 聊天UI(参考LobeChat实现) │ │ +│ │ - ChatMessage 组件 │ │ +│ │ - ChatInput 组件 │ │ +│ │ - StreamRenderer 组件 │ │ +│ │ - MarkdownContent 组件 │ │ +│ └──────────────────────────────────┘ │ +│ ┌──────────────────────────────────┐ │ +│ │ 业务界面(自己实现) │ │ +│ │ - 项目管理 │ │ +│ │ - 智能体选择 │ │ +│ │ - 历史记录 │ │ +│ └──────────────────────────────────┘ │ +└─────────────────────────────────────────┘ + ↓ REST API +┌─────────────────────────────────────────┐ +│ 后端(Node.js + TypeScript) │ +│ ┌──────────────────────────────────┐ │ +│ │ 对话服务(自己实现) │ │ +│ │ - 接收用户消息 │ │ +│ │ - 组装上下文(项目背景+历史) │ │ +│ │ - 调用LLM API │ │ +│ │ - 流式返回结果 │ │ +│ └──────────────────────────────────┘ │ +│ ┌──────────────────────────────────┐ │ +│ │ 业务服务(自己实现) │ │ +│ │ - 项目管理 │ │ +│ │ - 智能体路由 │ │ +│ │ - 权限控制 │ │ +│ └──────────────────────────────────┘ │ +└─────────────────────────────────────────┘ + ↓ ↓ +┌──────────────────┐ ┌─────────────────┐ +│ Dify (RAG) │ │ LLM API │ +│ - 知识库检索 │ │ - DeepSeek-V3 │ +│ (仅RAG) │ │ - Qwen3 │ +└──────────────────┘ └─────────────────┘ +``` + +### 详细实现 + +#### 1. 前端聊天UI(参考LobeChat) + +**提取LobeChat的核心组件:** + +```tsx +// src/components/chat/ChatMessage.tsx +// 从LobeChat移植,做少量修改 + +import React from 'react'; +import ReactMarkdown from 'react-markdown'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; + +interface Message { + id: string; + role: 'user' | 'assistant'; + content: string; + timestamp: number; +} + +export function ChatMessage({ message, onCopy, onPin }: Props) { + const isUser = message.role === 'user'; + + return ( +
+ {/* 头像 */} + + + {/* 消息内容 */} +
+
+ {isUser ? ( +

{message.content}

+ ) : ( + + {String(children).replace(/\n$/, '')} + + ) : ( + + {children} + + ); + } + }} + > + {message.content} + + )} +
+ + {/* 操作按钮 */} + {!isUser && ( +
+ + + +
+ )} +
+
+ ); +} +``` + +```tsx +// src/components/chat/ChatInput.tsx +// 从LobeChat移植 + +export function ChatInput({ onSend, onUpload, onKbSelect }: Props) { + const [message, setMessage] = useState(''); + + const handleSend = () => { + if (!message.trim()) return; + onSend(message); + setMessage(''); + }; + + return ( +
+