1566 lines
45 KiB
Markdown
1566 lines
45 KiB
Markdown
# AI科研助手 - 技术架构选型对比方案
|
||
|
||
## 📊 项目概述
|
||
AI科研助手是一个垂直于医学科研领域的智能化平台,核心功能包括12个专业AI智能体、项目管理、RAG知识库、多模型管理等。
|
||
|
||
---
|
||
|
||
## 🎯 核心技术难点分析
|
||
|
||
### 难点1:RAG系统构建 ⭐⭐⭐(已大幅降低)
|
||
**实际需求(已明确):**
|
||
- 每个用户最多创建 **3个知识库**
|
||
- 每个知识库最多上传 **50个文件**
|
||
- 主要格式:PDF、DOCX
|
||
- 单用户最大文档量:3 × 50 = **150个文件**
|
||
|
||
**挑战(已降低):**
|
||
- ✅ 文档规模适中(150个文件/用户,Dify完全胜任)
|
||
- 🟡 多格式文档解析(PDF、Word - Dify内置支持)
|
||
- 🟡 医学专业术语的准确理解和检索
|
||
- 🟡 答案溯源与引用标记
|
||
- ✅ 中英文混合文本的语义理解(现代向量模型已解决)
|
||
|
||
**技术要求(降低后):**
|
||
- 文档解析精度 > 90%(Dify默认即可达到)
|
||
- 检索召回率 > 80%(合理预期)
|
||
- 检索响应时间 < 3s(小规模知识库响应快)
|
||
|
||
**结论:使用Dify完全可以满足需求,无需自建RAG系统!** ✅
|
||
|
||
### 难点2:上下文管理 ⭐⭐⭐⭐
|
||
**挑战:**
|
||
- 项目背景信息的动态演进(用户可追加对话内容)
|
||
- 多轮对话的上下文窗口管理(避免Token溢出)
|
||
- 不同智能体间的上下文共享
|
||
- 全局快速问答 vs 项目内深度研究的上下文切换
|
||
|
||
**技术要求:**
|
||
- 上下文自动注入
|
||
- 智能上下文压缩
|
||
- 上下文持久化存储
|
||
|
||
### 难点3:多模型接入与管理 ⭐⭐⭐⭐
|
||
**挑战:**
|
||
- 统一的LLM接口抽象层(兼容Gemini、DeepSeek、Qwen等)
|
||
- 不同模型的参数适配(温度、Top-P、Max Tokens等)
|
||
- 模型切换的平滑过渡(对话中即时切换)
|
||
- API限流与成本控制
|
||
|
||
**技术要求:**
|
||
- 统一的Adapter模式
|
||
- 模型配置热更新
|
||
- 故障切换机制
|
||
|
||
### 难点4:Prompt工程与版本管理 ⭐⭐⭐⭐
|
||
**挑战:**
|
||
- 12个智能体的Prompt精细化调优
|
||
- Prompt模板的版本控制与回滚
|
||
- 不同模型需要不同的Prompt策略
|
||
- A/B测试和效果评估
|
||
|
||
**技术要求:**
|
||
- Prompt模板引擎
|
||
- 版本控制系统
|
||
- 效果监控与分析
|
||
|
||
### 难点5:专业文档生成 ⭐⭐⭐
|
||
**挑战:**
|
||
- 结构化输出(CRF表格、PICOS框架、研究方案)
|
||
- 格式化文档导出(Word、Excel、PDF)
|
||
- 医学术语的准确性
|
||
- 参考文献的自动引用
|
||
|
||
**技术要求:**
|
||
- 结构化输出解析
|
||
- 文档模板引擎
|
||
- 格式转换工具
|
||
|
||
---
|
||
|
||
## 🏗️ 技术架构方案对比
|
||
|
||
### 方案一:纯手写架构(从零开发)
|
||
|
||
#### 技术栈
|
||
```
|
||
前端:React + Vite + TailwindCSS
|
||
后端:Node.js (Express) + Python (FastAPI)
|
||
数据库:PostgreSQL + Redis
|
||
向量数据库:自建Milvus/Weaviate
|
||
LLM接入:手写Adapter
|
||
文档解析:PyMuPDF + python-docx + pandas
|
||
```
|
||
|
||
#### 优点 ✅
|
||
- **完全掌控**:对每个模块有100%的控制权
|
||
- **高度定制**:可以精确实现PRD的每个细节
|
||
- **无供应商锁定**:不依赖第三方平台
|
||
- **成本透明**:只支付基础设施和LLM API费用
|
||
|
||
#### 缺点 ❌
|
||
- **开发周期长**:3-6个月(2-3人团队)
|
||
- **技术难度高**:需要深厚的AI工程经验
|
||
- **维护成本高**:需要持续维护和优化
|
||
- **RAG系统复杂**:文档解析、向量化、检索全需自己实现
|
||
- **稳定性风险**:需要大量测试和调优
|
||
|
||
#### 实现难度评分
|
||
| 模块 | 难度 | 预计工时 |
|
||
|------|------|---------|
|
||
| RAG系统 | ⭐⭐⭐⭐⭐ | 40天 |
|
||
| 多模型管理 | ⭐⭐⭐⭐ | 15天 |
|
||
| Prompt管理 | ⭐⭐⭐ | 10天 |
|
||
| 前端开发 | ⭐⭐⭐ | 25天 |
|
||
| 后台管理 | ⭐⭐ | 15天 |
|
||
| 测试优化 | ⭐⭐⭐⭐ | 20天 |
|
||
| **总计** | - | **125天** |
|
||
|
||
#### 开发成本估算
|
||
- 人力成本:2-3人 × 4-6个月 = **8-18人月**
|
||
- 服务器成本:$200-500/月
|
||
- LLM API成本:按实际使用量
|
||
- **总成本:¥80,000 - ¥180,000(初期开发)**
|
||
|
||
---
|
||
|
||
### 方案二:开源RAG框架 (Dify/FastGPT/LobeChat)
|
||
|
||
#### 技术栈
|
||
```
|
||
核心框架:Dify / FastGPT
|
||
前端:框架自带 + 自定义扩展
|
||
后端:框架内置(Python/Node.js)
|
||
数据库:PostgreSQL (内置)
|
||
向量数据库:Qdrant/Milvus (内置)
|
||
LLM接入:框架集成
|
||
```
|
||
|
||
#### 方案2-A:Dify
|
||
|
||
**优点 ✅**
|
||
- **快速上手**:可视化编排AI工作流,1-2周可搭建MVP
|
||
- **RAG开箱即用**:文档解析、向量化、检索全内置
|
||
- **多模型支持**:已集成50+ LLM(Gemini、DeepSeek等)
|
||
- **Prompt管理**:可视化Prompt调试和版本管理
|
||
- **社区活跃**:GitHub 50k+ Stars,更新频繁
|
||
- **企业级功能**:权限管理、API管理、监控日志
|
||
|
||
**缺点 ❌**
|
||
- **定制受限**:复杂业务逻辑需要二次开发
|
||
- **12个智能体难管理**:需要创建12个独立的App
|
||
- **前端UI固定**:需要大量自定义开发才能匹配原型图
|
||
- **项目管理功能弱**:需要自己扩展
|
||
- **历史记录管理**:框架默认功能较弱
|
||
|
||
**适配PRD功能评估**
|
||
| 功能 | 支持程度 | 说明 |
|
||
|------|---------|------|
|
||
| 12个AI智能体 | 🟡 50% | 需创建12个App,管理复杂 |
|
||
| 项目/课题管理 | 🔴 20% | 需大量自定义开发 |
|
||
| 个人知识库 | 🟢 95% | 核心优势,开箱即用 |
|
||
| 多模型切换 | 🟢 90% | 内置支持,但UI需自定义 |
|
||
| 历史记录 | 🟡 60% | 基础功能有,需扩展 |
|
||
| 运营后台 | 🟢 80% | 内置管理后台,需调整 |
|
||
|
||
**开发成本**
|
||
- 初期搭建:1-2周
|
||
- 定制开发:2-3个月
|
||
- **总工时:60-80天**
|
||
- **成本:¥50,000 - ¥80,000**
|
||
|
||
---
|
||
|
||
#### 方案2-B:FastGPT
|
||
|
||
**优点 ✅**
|
||
- **RAG专精**:专注于知识库问答,检索效果好
|
||
- **可视化编排**:工作流编排直观
|
||
- **部署简单**:Docker一键部署
|
||
- **中文友好**:国内团队开发,文档完善
|
||
- **轻量级**:资源占用小,适合中小规模
|
||
|
||
**缺点 ❌**
|
||
- **功能单一**:主要聚焦RAG,其他功能需自己开发
|
||
- **扩展性一般**:复杂业务逻辑支持较弱
|
||
- **社区规模小**:相比Dify生态较小
|
||
- **前端定制难**:UI框架不够灵活
|
||
|
||
**适配PRD功能评估**
|
||
| 功能 | 支持程度 | 说明 |
|
||
|------|---------|------|
|
||
| 12个AI智能体 | 🟡 40% | 需手动创建多个应用 |
|
||
| 项目/课题管理 | 🔴 10% | 需完全自己开发 |
|
||
| 个人知识库 | 🟢 90% | 核心功能,强项 |
|
||
| 多模型切换 | 🟢 85% | 支持,但需自定义UI |
|
||
| 历史记录 | 🟡 50% | 基础功能 |
|
||
| 运营后台 | 🟡 60% | 需扩展 |
|
||
|
||
**开发成本**
|
||
- 初期搭建:1周
|
||
- 定制开发:3-4个月
|
||
- **总工时:70-90天**
|
||
- **成本:¥60,000 - ¥90,000**
|
||
|
||
---
|
||
|
||
#### 方案2-C:LobeChat
|
||
|
||
**优点 ✅**
|
||
- **UI精美**:现代化界面,用户体验好
|
||
- **前端开源**:基于Next.js,易于定制
|
||
- **多模型支持**:支持多种LLM
|
||
- **插件系统**:可扩展功能
|
||
|
||
**缺点 ❌**
|
||
- **RAG功能弱**:知识库功能较简单
|
||
- **后端能力弱**:主要是前端框架
|
||
- **项目管理功能无**:需完全自己开发
|
||
- **不适合复杂业务**:更适合简单聊天场景
|
||
|
||
**适配PRD功能评估**
|
||
| 功能 | 支持程度 | 说明 |
|
||
|------|---------|------|
|
||
| 12个AI智能体 | 🟡 50% | 可用插件实现 |
|
||
| 项目/课题管理 | 🔴 0% | 需完全自己开发 |
|
||
| 个人知识库 | 🟡 40% | 功能较弱 |
|
||
| 多模型切换 | 🟢 85% | 支持良好 |
|
||
| 历史记录 | 🟢 80% | 内置功能 |
|
||
| 运营后台 | 🔴 20% | 需自己开发 |
|
||
|
||
**不推荐**:LobeChat更适合个人聊天工具,不适合本项目。
|
||
|
||
---
|
||
|
||
### 方案三:混合架构(推荐 ⭐⭐⭐⭐⭐)
|
||
|
||
#### 核心思路
|
||
**"开源RAG引擎 + 自研业务层 + 自定义前端"**
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 自定义前端(React) │
|
||
│ 完全按照原型图实现 │
|
||
└─────────────────────────────────────────┘
|
||
↓ API
|
||
┌─────────────────────────────────────────┐
|
||
│ 自研业务层 (Node.js/Python) │
|
||
│ - 项目/课题管理 │
|
||
│ - 智能体编排与管理 │
|
||
│ - 上下文管理 │
|
||
│ - Prompt管理与版本控制 │
|
||
│ - 用户权限与审计 │
|
||
└─────────────────────────────────────────┘
|
||
↓ ↓
|
||
┌──────────────────┐ ┌─────────────────┐
|
||
│ Dify (RAG) │ │ LLM API │
|
||
│ - 知识库管理 │ │ - Gemini │
|
||
│ - 文档解析 │ │ - DeepSeek │
|
||
│ - 向量检索 │ │ - Qwen │
|
||
└──────────────────┘ └─────────────────┘
|
||
```
|
||
|
||
#### 技术栈
|
||
```
|
||
前端:React 18 + Vite + TailwindCSS + Zustand
|
||
业务层:Node.js (Fastify/Nest.js) + TypeScript
|
||
RAG引擎:Dify (作为微服务调用)
|
||
数据库:PostgreSQL + Redis
|
||
LLM接口:统一Adapter层
|
||
文档处理:Dify内置 + 自定义增强
|
||
```
|
||
|
||
#### 核心架构设计
|
||
|
||
**1. 智能体管理系统**
|
||
```javascript
|
||
// 智能体配置表
|
||
{
|
||
id: 'agent-picos',
|
||
name: 'PICOS构建',
|
||
description: '结构化地定义临床研究的核心要素',
|
||
category: '研究设计',
|
||
icon: 'construction',
|
||
|
||
// Prompt配置(支持多版本)
|
||
prompts: {
|
||
system: 'prompt_picos_system_v2.txt',
|
||
user: 'prompt_picos_user_v2.txt',
|
||
},
|
||
|
||
// 模型配置(可为不同模型配置不同参数)
|
||
models: {
|
||
'gemini-pro': { temperature: 0.3, max_tokens: 2000 },
|
||
'deepseek-v2': { temperature: 0.4, max_tokens: 2500 }
|
||
},
|
||
|
||
// 是否需要知识库增强
|
||
rag_enabled: true,
|
||
|
||
// 输出格式
|
||
output_format: 'structured', // structured | text | document
|
||
|
||
// 状态
|
||
status: 'active' // active | inactive | testing
|
||
}
|
||
```
|
||
|
||
**2. 项目上下文管理**
|
||
```javascript
|
||
// 项目对话流程
|
||
用户发起对话
|
||
↓
|
||
自动注入项目背景
|
||
↓
|
||
[项目背景 + 历史对话摘要 + 当前问题] → LLM
|
||
↓
|
||
AI回复
|
||
↓
|
||
用户可"固定"重要回复到项目背景
|
||
↓
|
||
下次对话自动继承更新后的背景
|
||
```
|
||
|
||
**3. RAG集成方式**
|
||
```javascript
|
||
// 用户在对话中@骨质疏松专题
|
||
const chatRequest = {
|
||
message: "请帮我设计观察指标 @骨质疏松专题",
|
||
project_id: "proj-123",
|
||
agent_id: "agent-4",
|
||
kb_references: ["kb-1"] // 骨质疏松专题
|
||
}
|
||
|
||
// 后端处理
|
||
1. 提取知识库引用 → 调用Dify检索相关文档
|
||
2. 提取项目背景 → 从数据库获取
|
||
3. 组装完整Prompt
|
||
4. 调用LLM生成回答
|
||
5. 解析引用标记,生成溯源链接
|
||
```
|
||
|
||
#### 优点 ✅
|
||
- **快速启动**:RAG功能直接复用Dify,1周可搭建基础版
|
||
- **高度定制**:前端和业务逻辑完全自主可控
|
||
- **最佳实践**:利用Dify成熟的RAG能力,避免重复造轮子
|
||
- **灵活扩展**:可随时替换RAG引擎,不影响业务层
|
||
- **成本可控**:开发周期和成本介于纯手写和纯框架之间
|
||
- **易于维护**:职责清晰,RAG和业务逻辑分离
|
||
|
||
#### 缺点 ❌
|
||
- **架构复杂度中等**:需要协调多个系统
|
||
- **需要熟悉Dify API**:有一定学习曲线
|
||
- **多系统部署**:部署流程略复杂
|
||
|
||
#### 开发计划
|
||
**阶段1:基础搭建(2周)**
|
||
- [ ] 前端框架搭建(React + 路由 + 状态管理)
|
||
- [ ] 后端框架搭建(API设计 + 数据库设计)
|
||
- [ ] Dify部署与配置
|
||
- [ ] LLM Adapter层开发
|
||
|
||
**阶段2:核心功能(4周)**
|
||
- [ ] 项目/课题管理模块
|
||
- [ ] 12个智能体配置与管理
|
||
- [ ] 对话系统(含上下文管理)
|
||
- [ ] 知识库集成(调用Dify)
|
||
|
||
**阶段3:高级功能(3周)**
|
||
- [ ] 多模型切换
|
||
- [ ] Prompt版本管理
|
||
- [ ] 历史记录管理
|
||
- [ ] 文档生成(CRF、方案等)
|
||
|
||
**阶段4:运营后台(2周)**
|
||
- [ ] 用户管理
|
||
- [ ] 智能体管理
|
||
- [ ] 数据统计
|
||
- [ ] 权限与审计
|
||
|
||
**阶段5:测试优化(2周)**
|
||
- [ ] 功能测试
|
||
- [ ] 性能优化
|
||
- [ ] 用户体验优化
|
||
|
||
**总计:13周(约3个月)**
|
||
|
||
#### 开发成本(优化后)
|
||
- 人力:2人 × 2.5个月 = **5人月** ⭐
|
||
- 服务器:$300/月(含Dify、数据库、Redis等)
|
||
- LLM API:按实际使用量(DeepSeek-V3极便宜)
|
||
- **总成本:¥40,000 - ¥55,000(初期开发)** ⭐
|
||
- **节省:¥10,000-15,000(vs原方案)**
|
||
|
||
---
|
||
|
||
## 📊 方案对比总结表
|
||
|
||
| 维度 | 纯手写 | Dify | FastGPT | **混合架构** |
|
||
|------|--------|------|---------|------------|
|
||
| **开发周期** | 4-6个月 | 2-3个月 | 3-4个月 | **3个月** ⭐ |
|
||
| **开发成本** | ¥80k-180k | ¥50k-80k | ¥60k-90k | **¥50k-70k** ⭐ |
|
||
| **RAG能力** | 🟡 需自己实现 | 🟢 强大 | 🟢 强大 | **🟢 强大** ⭐ |
|
||
| **定制灵活性** | 🟢 完全可控 | 🟡 受限 | 🟡 受限 | **🟢 高度可控** ⭐ |
|
||
| **功能匹配度** | 🟢 100% | 🟡 60-70% | 🟡 50-60% | **🟢 95%** ⭐ |
|
||
| **维护成本** | 🔴 高 | 🟢 低 | 🟢 低 | **🟡 中** ⭐ |
|
||
| **技术难度** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | **⭐⭐⭐⭐** |
|
||
| **扩展性** | 🟢 极强 | 🟡 一般 | 🟡 一般 | **🟢 强** ⭐ |
|
||
| **供应商锁定** | 🟢 无 | 🟡 中等 | 🟡 中等 | **🟢 低** ⭐ |
|
||
| **社区支持** | 🔴 无 | 🟢 强 | 🟡 中 | **🟢 强** ⭐ |
|
||
|
||
---
|
||
|
||
## 🎯 最终推荐:混合架构(优化版)
|
||
|
||
### 核心架构调整
|
||
|
||
基于您的反馈,我重新设计了架构方案,核心变化:
|
||
|
||
**1. 聊天系统:参考LobeChat开源实现**
|
||
- 不直接使用LobeChat整体,但**参考其聊天UI组件和流式输出实现**
|
||
- LobeChat的聊天界面已经过充分验证,体验优秀
|
||
- 可以复用其核心聊天组件(MIT许可),节省前端开发时间
|
||
|
||
**2. 向量数据库:完全依赖Dify内置**
|
||
- Dify内置Qdrant向量数据库,无需单独部署
|
||
- 文档解析、向量化、检索全由Dify处理
|
||
- 我们只需调用Dify的API即可
|
||
|
||
**3. 运营端简化(降低成本)**
|
||
- ❌ 删除模型管理功能(模型配置写在配置文件中)
|
||
- ❌ 删除智能体管理功能(智能体配置固定在代码中)
|
||
- ❌ 删除智能体配置功能(Prompt直接写在代码或配置文件)
|
||
- ✅ 保留用户管理、数据统计、对话查看(仅必需功能)
|
||
|
||
**4. 大模型优先级调整**
|
||
- 主力模型:**DeepSeek-V3**(¥1/百万tokens,极具性价比)
|
||
- 备用模型:**Qwen3**(阿里云,国内稳定)
|
||
- 可选模型:Gemini Pro(国际用户)
|
||
|
||
### 优化后的架构图
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 自定义前端(React) │
|
||
│ - 项目管理界面(自研) │
|
||
│ - 智能体选择界面(自研) │
|
||
│ - 聊天界面(参考LobeChat组件)⭐ │
|
||
│ - 知识库管理(自研) │
|
||
│ - 历史记录(自研) │
|
||
└─────────────────────────────────────────┘
|
||
↓ REST API
|
||
┌─────────────────────────────────────────┐
|
||
│ 业务层 (Node.js/TypeScript) │
|
||
│ - 项目/课题CRUD │
|
||
│ - 12个智能体路由(配置化)⭐ │
|
||
│ - 对话上下文组装 │
|
||
│ - 用户认证与权限 │
|
||
│ - 简化的运营后台API │
|
||
└─────────────────────────────────────────┘
|
||
↓ ↓
|
||
┌──────────────────┐ ┌─────────────────┐
|
||
│ Dify (RAG) │ │ LLM API │
|
||
│ - 知识库 │ │ - DeepSeek-V3 │
|
||
│ - 文档解析 │ │ - Qwen3 │
|
||
│ - 向量检索 │ │ - Gemini │
|
||
│ - Qdrant(内置)⭐│ │ │
|
||
└──────────────────┘ └─────────────────┘
|
||
```
|
||
|
||
### 推荐理由(优化后)
|
||
|
||
1. **聊天体验有保障**
|
||
- 参考LobeChat的成熟实现,避免重复造轮子
|
||
- 流式输出、Markdown渲染、代码高亮等功能开箱即用
|
||
- 可以直接复用其React组件(MIT开源许可)
|
||
|
||
2. **成本大幅降低**
|
||
- 开发周期:**2-2.5个月**(vs 之前3个月)
|
||
- 开发成本:**¥40k-55k**(vs 之前¥50k-70k)
|
||
- 维护成本:更低(删除了复杂的后台管理)
|
||
|
||
3. **架构更简洁**
|
||
- 向量数据库:无需关心,Dify全包
|
||
- 智能体管理:配置化,无需复杂后台
|
||
- 模型管理:配置文件搞定
|
||
|
||
4. **DeepSeek-V3极具性价比**
|
||
- 价格:¥1/百万tokens(vs Gemini ¥2.7/百万tokens)
|
||
- 性能:接近GPT-4水平
|
||
- 速度:响应快,适合流式输出
|
||
|
||
### 不推荐LobeChat整体的原因
|
||
|
||
**为什么不用Dify + LobeChat组合?**
|
||
|
||
虽然LobeChat聊天功能强,但:
|
||
- ❌ **项目管理功能缺失**:LobeChat没有项目/课题管理概念
|
||
- ❌ **12个智能体管理困难**:LobeChat的插件系统不适合我们的智能体模式
|
||
- ❌ **知识库集成复杂**:LobeChat与Dify的知识库集成需要大量适配
|
||
- ❌ **定制成本高**:深度定制LobeChat可能比参考实现还费时
|
||
|
||
**我们的策略:**
|
||
✅ **参考LobeChat的聊天UI实现**(复用组件)
|
||
✅ **自研业务逻辑**(项目管理、智能体编排)
|
||
✅ **Dify专注RAG**(知识库检索)
|
||
|
||
这样既能享受LobeChat的聊天体验,又保持架构灵活性。
|
||
|
||
---
|
||
|
||
## 🚀 实施建议
|
||
|
||
### 技术选型细节
|
||
|
||
**前端技术栈**
|
||
```
|
||
框架:React 18 + TypeScript
|
||
构建:Vite
|
||
UI:TailwindCSS + HeadlessUI
|
||
状态管理:Zustand (轻量) 或 Redux Toolkit
|
||
路由:React Router v6
|
||
HTTP:Axios + SWR (数据缓存)
|
||
Markdown:react-markdown + katex (公式支持)
|
||
文件上传:react-dropzone
|
||
富文本:Tiptap (用于项目描述编辑)
|
||
```
|
||
|
||
**后端技术栈**
|
||
```
|
||
框架:Node.js + Fastify (高性能) 或 Nest.js (企业级)
|
||
语言:TypeScript
|
||
ORM:Prisma (类型安全)
|
||
数据库:PostgreSQL 15+
|
||
缓存:Redis 7+
|
||
队列:Bull (文档处理队列)
|
||
日志:Winston + Pino
|
||
认证:JWT + Passport
|
||
文档:Swagger/OpenAPI
|
||
```
|
||
|
||
**RAG集成**
|
||
```
|
||
引擎:Dify (Docker部署)
|
||
调用方式:REST API
|
||
向量数据库:Dify内置 (Qdrant)
|
||
文档解析:Dify内置
|
||
检索策略:混合检索 (关键词 + 语义)
|
||
```
|
||
|
||
**LLM接入(优化后)**
|
||
```
|
||
主力模型:
|
||
- DeepSeek-V3 (DeepSeek API) ⭐
|
||
价格:¥1/百万tokens,性价比极高
|
||
特点:推理能力强,适合复杂任务
|
||
|
||
- Qwen3-72B (阿里云DashScope) ⭐
|
||
价格:¥4/百万tokens
|
||
特点:中文理解好,国内稳定
|
||
|
||
备用模型:
|
||
- Gemini 2.0 Flash (可选,国际用户)
|
||
- Qwen3-7B (轻量任务)
|
||
|
||
统一接口:OpenAI SDK格式(兼容性最好)
|
||
模型配置:写在config/models.yaml中,无需后台管理
|
||
```
|
||
|
||
**部署方案**
|
||
```
|
||
容器化:Docker + Docker Compose
|
||
反向代理:Nginx
|
||
CI/CD:GitHub Actions
|
||
监控:Prometheus + Grafana
|
||
日志:ELK Stack
|
||
备份:自动化数据库备份脚本
|
||
```
|
||
|
||
### 开发优先级(优化后)
|
||
|
||
**P0(MVP必需,1个月内)**
|
||
- [ ] 用户认证与权限(JWT)
|
||
- [ ] 项目/课题基础CRUD
|
||
- [ ] **复用LobeChat聊天UI组件** ⭐
|
||
- [ ] 3个核心智能体(选题评价、PICOS构建、论文润色)
|
||
- [ ] 基础对话功能(DeepSeek-V3接入)
|
||
- [ ] 历史记录管理
|
||
|
||
**P1(核心功能,2个月内)**
|
||
- [ ] 剩余9个智能体(配置化实现)
|
||
- [ ] 知识库集成(Dify RAG)
|
||
- [ ] 多模型切换(DeepSeek-V3 / Qwen3)
|
||
- [ ] 上下文动态管理(固定功能)
|
||
- [ ] 流式输出优化
|
||
|
||
**P2(高级功能,2.5个月内)**
|
||
- [ ] 文档生成(CRF、研究方案导出Word)
|
||
- [ ] 简化运营后台(用户管理 + 数据统计)
|
||
- [ ] 高级搜索与筛选
|
||
- [ ] 对话记录查看(仅管理员)
|
||
|
||
**P3(优化迭代,后续)**
|
||
- [ ] 性能优化(缓存、索引)
|
||
- [ ] DeepSeek-V3效果调优
|
||
- [ ] 用户体验优化
|
||
- [ ] 移动端适配
|
||
|
||
**已删除功能(降低成本):**
|
||
- ❌ 智能体管理后台
|
||
- ❌ 模型管理后台
|
||
- ❌ Prompt版本管理系统
|
||
- ❌ 复杂的审计日志
|
||
|
||
---
|
||
|
||
## 💰 成本估算(详细)
|
||
|
||
### 开发成本(优化后方案)
|
||
|
||
**人力成本**
|
||
- 全栈开发 × 1人 × 2.5个月 = 2.5人月
|
||
- 前端开发 × 1人 × 1.5个月 = 1.5人月(复用LobeChat组件节省时间)
|
||
- 合计:4人月
|
||
- 按¥12k/人月计算 = **¥48,000** ⭐
|
||
|
||
**服务器成本(开发+测试环境)**
|
||
- 云服务器(4核8G):¥200/月 × 2.5 = ¥500
|
||
- 数据库(PostgreSQL):¥100/月 × 2.5 = ¥250
|
||
- Redis:¥50/月 × 2.5 = ¥125
|
||
- 对象存储(文档存储):¥50/月 × 2.5 = ¥125
|
||
- 带宽:¥100/月 × 2.5 = ¥250
|
||
- 合计:**¥1,250**
|
||
|
||
**LLM API成本(开发+测试)**
|
||
- DeepSeek-V3:¥1/百万tokens(极便宜)⭐
|
||
- 预计开发测试消耗:50M tokens(优化后)
|
||
- 预估成本:**¥50** ⭐
|
||
|
||
**第三方服务**
|
||
- 短信验证:¥0.05/条 × 50 = ¥2.5
|
||
- 邮件服务:¥0/月 (使用免费额度)
|
||
- 合计:**¥3**
|
||
|
||
**开发总成本:¥48,000 + ¥1,250 + ¥50 + ¥3 ≈ ¥49,300** ⭐
|
||
|
||
**成本节省:**
|
||
- vs 原方案(¥77,000):节省 **¥27,700**(36%)
|
||
- vs 纯手写(¥80,000+):节省 **¥30,700+**(38%+)
|
||
|
||
### 运营成本(月度)
|
||
|
||
**基础设施(生产环境)**
|
||
- 云服务器(8核16G):¥500/月
|
||
- 数据库(PostgreSQL高可用):¥300/月
|
||
- Redis(主从):¥150/月
|
||
- 对象存储:¥100/月
|
||
- CDN:¥100/月
|
||
- 备份:¥50/月
|
||
- 合计:**¥1,200/月**
|
||
|
||
**LLM API成本(按1000用户/月估算)**
|
||
- 假设每用户每月100轮对话
|
||
- 平均每轮1k tokens输入 + 500 tokens输出
|
||
- 总量:1000用户 × 100轮 × 1.5k tokens = 150M tokens/月
|
||
- **DeepSeek-V3成本:150M × ¥1/百万 = ¥150/月** ⭐
|
||
- Qwen3成本(备用):150M × ¥4/百万 = ¥600/月
|
||
- 主要使用DeepSeek-V3:**¥150-200/月** ⭐
|
||
|
||
**成本优势:**
|
||
- vs Gemini Pro:节省约¥100-120/月
|
||
- vs GPT-4:节省约¥2,000+/月
|
||
- **年度节省:¥1,200-1,500**
|
||
|
||
**人力成本(运维+优化)**
|
||
- 1名全栈开发兼运维:¥15,000/月
|
||
|
||
**月度总成本:¥1,200 + ¥180 + ¥15,000 ≈ ¥16,400/月**
|
||
|
||
**vs 使用其他模型的成本对比:**
|
||
| 模型方案 | 月度LLM成本 | 年度成本 | vs DeepSeek-V3 |
|
||
|---------|------------|---------|----------------|
|
||
| DeepSeek-V3 | ¥180 | ¥2,160 | 基准 ⭐ |
|
||
| Qwen3-72B | ¥600 | ¥7,200 | +¥5,040/年 |
|
||
| Gemini Pro | ¥300 | ¥3,600 | +¥1,440/年 |
|
||
| GPT-4 | ¥2,500 | ¥30,000 | +¥27,840/年 |
|
||
|
||
---
|
||
|
||
## 💬 如何复用LobeChat聊天组件
|
||
|
||
### 为什么选择LobeChat
|
||
|
||
**LobeChat的核心优势:**
|
||
1. ✅ **MIT开源许可** - 可以自由使用和修改
|
||
2. ✅ **聊天体验优秀** - 流式输出、Markdown渲染、代码高亮
|
||
3. ✅ **技术栈一致** - Next.js/React,与我们的技术栈兼容
|
||
4. ✅ **组件化设计** - 聊天UI组件可以单独提取
|
||
5. ✅ **社区活跃** - 4万+ Stars,持续更新
|
||
|
||
### 复用策略
|
||
|
||
**不使用LobeChat整体的原因:**
|
||
- ❌ 基于Next.js,而我们选择Vite(更轻量)
|
||
- ❌ 缺少项目管理、知识库等我们需要的功能
|
||
- ❌ 深度定制成本高,不如参考实现
|
||
|
||
**我们的复用方式:**
|
||
✅ **提取核心聊天组件** - 将LobeChat的聊天UI组件移植到我们的React项目
|
||
✅ **参考实现逻辑** - 学习其流式输出、Markdown渲染的实现
|
||
✅ **复用UI设计** - 参考其聊天界面的交互设计
|
||
|
||
### 具体实施步骤
|
||
|
||
**第1步:克隆LobeChat源码**
|
||
```bash
|
||
git clone https://github.com/lobehub/lobe-chat.git
|
||
cd lobe-chat
|
||
```
|
||
|
||
**第2步:提取核心组件**
|
||
|
||
需要提取的关键组件:
|
||
```
|
||
src/app/chat/
|
||
├── ChatMessage.tsx # 消息气泡组件
|
||
├── ChatInput.tsx # 输入框组件
|
||
├── StreamingText.tsx # 流式文本渲染
|
||
├── MarkdownRender.tsx # Markdown渲染
|
||
└── ChatList.tsx # 消息列表
|
||
|
||
src/components/
|
||
├── Avatar/ # 头像组件
|
||
├── CodeBlock/ # 代码块组件
|
||
└── FileUpload/ # 文件上传组件
|
||
```
|
||
|
||
**第3步:适配到我们的项目**
|
||
|
||
```tsx
|
||
// 我们的项目结构
|
||
src/components/chat/
|
||
├── ChatWindow.tsx // 主聊天窗口(自研)
|
||
├── ChatMessage.tsx // 从LobeChat移植 ⭐
|
||
├── ChatInput.tsx // 从LobeChat移植 ⭐
|
||
├── StreamRenderer.tsx // 从LobeChat移植 ⭐
|
||
├── MarkdownContent.tsx // 从LobeChat移植 ⭐
|
||
└── ActionButtons.tsx // 自研(复制、固定、重新生成)
|
||
|
||
// 使用示例
|
||
import { ChatMessage } from '@/components/chat/ChatMessage';
|
||
import { ChatInput } from '@/components/chat/ChatInput';
|
||
|
||
function ChatView() {
|
||
return (
|
||
<div className="chat-container">
|
||
<div className="messages">
|
||
{messages.map(msg => (
|
||
<ChatMessage
|
||
key={msg.id}
|
||
message={msg}
|
||
onCopy={handleCopy}
|
||
onPin={handlePin} // 我们自己的功能
|
||
/>
|
||
))}
|
||
</div>
|
||
<ChatInput
|
||
onSend={handleSend}
|
||
onUpload={handleUpload}
|
||
onKbSelect={handleKbSelect} // 我们自己的功能
|
||
/>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
**第4步:实现流式输出**
|
||
|
||
参考LobeChat的实现,使用Server-Sent Events (SSE):
|
||
|
||
```typescript
|
||
// 前端:接收流式数据
|
||
async function streamChat(message: string) {
|
||
const response = await fetch('/api/chat/stream', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ message, projectId, agentId })
|
||
});
|
||
|
||
const reader = response.body?.getReader();
|
||
const decoder = new TextDecoder();
|
||
let accumulatedText = '';
|
||
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
|
||
const chunk = decoder.decode(value);
|
||
const lines = chunk.split('\n');
|
||
|
||
for (const line of lines) {
|
||
if (line.startsWith('data: ')) {
|
||
const data = JSON.parse(line.slice(6));
|
||
if (data.type === 'token') {
|
||
accumulatedText += data.content;
|
||
setMessages(prev => [...prev.slice(0, -1), {
|
||
...prev[prev.length - 1],
|
||
content: accumulatedText
|
||
}]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 后端:发送流式数据
|
||
app.post('/api/chat/stream', async (req, res) => {
|
||
res.setHeader('Content-Type', 'text/event-stream');
|
||
res.setHeader('Cache-Control', 'no-cache');
|
||
res.setHeader('Connection', 'keep-alive');
|
||
|
||
const stream = await llmAdapter.chatStream({
|
||
messages: contextMessages,
|
||
temperature: 0.7
|
||
});
|
||
|
||
for await (const chunk of stream) {
|
||
res.write(`data: ${JSON.stringify({
|
||
type: 'token',
|
||
content: chunk
|
||
})}\n\n`);
|
||
}
|
||
|
||
res.write(`data: ${JSON.stringify({ type: 'done' })}\n\n`);
|
||
res.end();
|
||
});
|
||
```
|
||
|
||
### 预计节省时间
|
||
|
||
| 功能模块 | 从零开发 | 复用LobeChat | 节省 |
|
||
|---------|---------|-------------|------|
|
||
| 基础聊天UI | 5天 | 1天 | 4天 |
|
||
| 流式输出 | 3天 | 0.5天 | 2.5天 |
|
||
| Markdown渲染 | 2天 | 0.5天 | 1.5天 |
|
||
| 代码高亮 | 1天 | 0.5天 | 0.5天 |
|
||
| 文件上传UI | 2天 | 1天 | 1天 |
|
||
| **总计** | **13天** | **3.5天** | **9.5天** ⭐ |
|
||
|
||
---
|
||
|
||
## 🔧 技术实现关键点
|
||
|
||
### 1. 智能体配置管理(简化版 - 配置文件方式)
|
||
|
||
**为什么选择配置文件而非数据库管理?**
|
||
- ✅ 降低开发成本(无需开发后台管理界面)
|
||
- ✅ 版本控制友好(Git管理配置变更)
|
||
- ✅ 部署简单(无需数据库迁移)
|
||
- ✅ 易于调试(直接修改配置文件)
|
||
|
||
**配置文件结构**
|
||
|
||
```yaml
|
||
# config/agents.yaml
|
||
agents:
|
||
- id: agent-topic-evaluation
|
||
name: 选题评价
|
||
description: 从创新性、临床价值、科学性和可行性等维度评价临床问题
|
||
category: 选题阶段
|
||
icon: lightbulb
|
||
|
||
# Prompt配置
|
||
system_prompt_file: prompts/topic_evaluation_system.txt
|
||
user_prompt_template_file: prompts/topic_evaluation_user.txt
|
||
|
||
# 模型配置
|
||
models:
|
||
deepseek-v3:
|
||
temperature: 0.4
|
||
max_tokens: 2000
|
||
top_p: 0.9
|
||
qwen3-72b:
|
||
temperature: 0.5
|
||
max_tokens: 2000
|
||
|
||
# 功能开关
|
||
rag_enabled: true # 是否支持知识库检索
|
||
file_upload_enabled: false # 是否支持文件上传
|
||
|
||
# 输出格式
|
||
output_format: structured # text | structured | document
|
||
|
||
# 状态
|
||
status: active # active | inactive
|
||
|
||
- id: agent-picos
|
||
name: PICOS构建
|
||
description: 结构化地定义临床研究的核心要素
|
||
category: 研究设计
|
||
icon: construction
|
||
system_prompt_file: prompts/picos_system.txt
|
||
user_prompt_template_file: prompts/picos_user.txt
|
||
models:
|
||
deepseek-v3:
|
||
temperature: 0.3
|
||
max_tokens: 2500
|
||
rag_enabled: true
|
||
file_upload_enabled: false
|
||
output_format: structured
|
||
status: active
|
||
|
||
# ... 其他10个智能体配置
|
||
```
|
||
|
||
**Prompt文件管理**
|
||
|
||
```
|
||
backend/prompts/
|
||
├── topic_evaluation_system.txt
|
||
├── topic_evaluation_user.txt
|
||
├── picos_system.txt
|
||
├── picos_user.txt
|
||
├── crf_system.txt
|
||
├── sample_size_system.txt
|
||
└── ...
|
||
```
|
||
|
||
**示例Prompt文件**
|
||
|
||
```txt
|
||
# prompts/picos_system.txt
|
||
你是一位经验丰富的临床研究方法学专家,擅长帮助研究者构建科学严谨的PICOS框架。
|
||
|
||
## 你的任务
|
||
根据用户提供的研究想法,帮助其完善以下要素:
|
||
- P (Population): 研究人群的精确定义
|
||
- I (Intervention): 干预措施的详细描述
|
||
- C (Comparison): 对照组的设计
|
||
- O (Outcome): 主要和次要观察指标
|
||
- S (Study Design): 研究设计类型
|
||
|
||
## 输出要求
|
||
1. 使用结构化的表格或清单形式输出
|
||
2. 每个要素都要具体、可操作、可测量
|
||
3. 指出潜在的方法学问题
|
||
4. 提供改进建议
|
||
|
||
## 注意事项
|
||
- 确保研究人群的纳入排除标准明确
|
||
- 干预措施要具有可重复性
|
||
- 观察指标要符合临床意义和统计学要求
|
||
- 研究设计要匹配研究目的
|
||
```
|
||
|
||
**加载配置的代码实现**
|
||
|
||
```typescript
|
||
// backend/src/config/agent-loader.ts
|
||
import fs from 'fs';
|
||
import yaml from 'yaml';
|
||
import path from 'path';
|
||
|
||
interface AgentConfig {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
category: string;
|
||
icon: string;
|
||
system_prompt_file: string;
|
||
user_prompt_template_file: string;
|
||
models: Record<string, {
|
||
temperature: number;
|
||
max_tokens: number;
|
||
top_p?: number;
|
||
}>;
|
||
rag_enabled: boolean;
|
||
file_upload_enabled: boolean;
|
||
output_format: 'text' | 'structured' | 'document';
|
||
status: 'active' | 'inactive';
|
||
}
|
||
|
||
class AgentConfigLoader {
|
||
private agents: Map<string, AgentConfig> = new Map();
|
||
private prompts: Map<string, string> = new Map();
|
||
|
||
constructor() {
|
||
this.loadAgents();
|
||
this.loadPrompts();
|
||
}
|
||
|
||
private loadAgents() {
|
||
const configFile = fs.readFileSync(
|
||
path.join(__dirname, '../../config/agents.yaml'),
|
||
'utf-8'
|
||
);
|
||
const config = yaml.parse(configFile);
|
||
|
||
for (const agent of config.agents) {
|
||
if (agent.status === 'active') {
|
||
this.agents.set(agent.id, agent);
|
||
}
|
||
}
|
||
|
||
console.log(`✅ Loaded ${this.agents.size} active agents`);
|
||
}
|
||
|
||
private loadPrompts() {
|
||
const promptsDir = path.join(__dirname, '../../prompts');
|
||
const files = fs.readdirSync(promptsDir);
|
||
|
||
for (const file of files) {
|
||
if (file.endsWith('.txt')) {
|
||
const content = fs.readFileSync(
|
||
path.join(promptsDir, file),
|
||
'utf-8'
|
||
);
|
||
this.prompts.set(file, content);
|
||
}
|
||
}
|
||
|
||
console.log(`✅ Loaded ${this.prompts.size} prompt templates`);
|
||
}
|
||
|
||
getAgent(agentId: string): AgentConfig | undefined {
|
||
return this.agents.get(agentId);
|
||
}
|
||
|
||
getAllAgents(): AgentConfig[] {
|
||
return Array.from(this.agents.values());
|
||
}
|
||
|
||
getPrompt(filename: string): string {
|
||
return this.prompts.get(filename) || '';
|
||
}
|
||
|
||
// 热重载(开发环境)
|
||
reloadConfig() {
|
||
this.agents.clear();
|
||
this.prompts.clear();
|
||
this.loadAgents();
|
||
this.loadPrompts();
|
||
}
|
||
}
|
||
|
||
export const agentConfig = new AgentConfigLoader();
|
||
```
|
||
|
||
**API设计**
|
||
```javascript
|
||
// 获取智能体列表
|
||
GET /api/agents
|
||
Response: {
|
||
agents: [
|
||
{
|
||
id: 'agent-picos',
|
||
name: 'PICOS构建',
|
||
description: '...',
|
||
category: '研究设计',
|
||
icon: 'construction',
|
||
status: 'active'
|
||
}
|
||
]
|
||
}
|
||
|
||
// 调用智能体
|
||
POST /api/agents/{agentId}/chat
|
||
Request: {
|
||
message: "请帮我构建PICOS",
|
||
project_id: "proj-123", // 可选
|
||
kb_references: ["kb-1"], // 可选
|
||
model: "gemini-pro", // 可选
|
||
stream: true // 是否流式输出
|
||
}
|
||
Response (Stream):
|
||
data: {"type":"start"}
|
||
data: {"type":"token","content":"好的"}
|
||
data: {"type":"token","content":",我们"}
|
||
...
|
||
data: {"type":"end","message_id":"msg-xxx"}
|
||
```
|
||
|
||
### 2. 上下文管理实现
|
||
|
||
**上下文组装策略**
|
||
```javascript
|
||
async function buildContextForAgent(params) {
|
||
const { projectId, agentId, message, conversationHistory } = params;
|
||
|
||
let contextParts = [];
|
||
|
||
// 1. 项目背景(如果有)
|
||
if (projectId) {
|
||
const project = await db.projects.findOne(projectId);
|
||
contextParts.push({
|
||
role: 'system',
|
||
content: `# 项目背景\n${project.description}`
|
||
});
|
||
}
|
||
|
||
// 2. 智能体系统提示词
|
||
const agent = await db.agents.findOne(agentId);
|
||
contextParts.push({
|
||
role: 'system',
|
||
content: agent.system_prompt
|
||
});
|
||
|
||
// 3. 历史对话摘要(如果超过10轮,进行摘要压缩)
|
||
if (conversationHistory.length > 10) {
|
||
const summary = await summarizeHistory(conversationHistory.slice(0, -10));
|
||
contextParts.push({
|
||
role: 'system',
|
||
content: `# 历史对话摘要\n${summary}`
|
||
});
|
||
contextParts.push(...conversationHistory.slice(-10));
|
||
} else {
|
||
contextParts.push(...conversationHistory);
|
||
}
|
||
|
||
// 4. 知识库检索结果(如果有@引用)
|
||
if (params.kb_references) {
|
||
const ragResults = await queryDifyKnowledgeBase({
|
||
kb_ids: params.kb_references,
|
||
query: message,
|
||
top_k: 5
|
||
});
|
||
contextParts.push({
|
||
role: 'system',
|
||
content: `# 相关知识库内容\n${ragResults.documents.map(d =>
|
||
`[${d.metadata.filename}] ${d.content}`
|
||
).join('\n\n')}`
|
||
});
|
||
}
|
||
|
||
// 5. 当前用户问题
|
||
contextParts.push({
|
||
role: 'user',
|
||
content: message
|
||
});
|
||
|
||
return contextParts;
|
||
}
|
||
```
|
||
|
||
**Token计数与控制**
|
||
```javascript
|
||
import { encoding_for_model } from 'tiktoken';
|
||
|
||
function estimateTokens(messages, model = 'gpt-4') {
|
||
const encoding = encoding_for_model(model);
|
||
let total = 0;
|
||
for (const msg of messages) {
|
||
total += encoding.encode(msg.content).length;
|
||
total += 4; // 每条消息的格式开销
|
||
}
|
||
return total;
|
||
}
|
||
|
||
async function buildContextWithTokenLimit(params, maxTokens = 6000) {
|
||
let context = await buildContextForAgent(params);
|
||
let tokens = estimateTokens(context);
|
||
|
||
// 如果超限,逐步删减历史对话
|
||
while (tokens > maxTokens && context.length > 3) {
|
||
// 保留系统提示词和当前问题,删减中间的历史对话
|
||
context.splice(2, 1);
|
||
tokens = estimateTokens(context);
|
||
}
|
||
|
||
return context;
|
||
}
|
||
```
|
||
|
||
### 3. Dify RAG集成
|
||
|
||
**调用Dify API**
|
||
```javascript
|
||
import axios from 'axios';
|
||
|
||
class DifyService {
|
||
constructor() {
|
||
this.baseUrl = process.env.DIFY_API_URL;
|
||
this.apiKey = process.env.DIFY_API_KEY;
|
||
}
|
||
|
||
// 查询知识库
|
||
async queryKnowledgeBase({ datasetId, query, topK = 5 }) {
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/datasets/${datasetId}/retrieve`,
|
||
{
|
||
query,
|
||
retrieval_model: {
|
||
search_method: 'hybrid_search', // 混合检索
|
||
reranking_enable: true, // 重排序
|
||
reranking_model: {
|
||
reranking_provider_name: 'cohere',
|
||
reranking_model_name: 'rerank-multilingual-v2.0'
|
||
},
|
||
top_k: topK,
|
||
score_threshold_enabled: true,
|
||
score_threshold: 0.5
|
||
}
|
||
},
|
||
{
|
||
headers: {
|
||
'Authorization': `Bearer ${this.apiKey}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
}
|
||
);
|
||
|
||
return response.data.records.map(record => ({
|
||
content: record.segment.content,
|
||
score: record.score,
|
||
metadata: {
|
||
filename: record.segment.document.name,
|
||
position: record.segment.position,
|
||
document_id: record.segment.document.id
|
||
}
|
||
}));
|
||
}
|
||
|
||
// 上传文档到知识库
|
||
async uploadDocument({ datasetId, file, processRule }) {
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
formData.append('process_rule', JSON.stringify(processRule || {
|
||
mode: 'automatic',
|
||
rules: {
|
||
pre_processing_rules: [
|
||
{ id: 'remove_extra_spaces', enabled: true },
|
||
{ id: 'remove_urls_emails', enabled: true }
|
||
],
|
||
segmentation: {
|
||
separator: '\n\n',
|
||
max_tokens: 500
|
||
}
|
||
}
|
||
}));
|
||
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/datasets/${datasetId}/documents`,
|
||
formData,
|
||
{
|
||
headers: {
|
||
'Authorization': `Bearer ${this.apiKey}`
|
||
}
|
||
}
|
||
);
|
||
|
||
return response.data;
|
||
}
|
||
|
||
// 检查文档处理状态
|
||
async getDocumentStatus({ datasetId, documentId }) {
|
||
const response = await axios.get(
|
||
`${this.baseUrl}/datasets/${datasetId}/documents/${documentId}`,
|
||
{
|
||
headers: {
|
||
'Authorization': `Bearer ${this.apiKey}`
|
||
}
|
||
}
|
||
);
|
||
|
||
return {
|
||
status: response.data.indexing_status, // 'processing' | 'completed' | 'error'
|
||
progress: response.data.completed_segments,
|
||
total: response.data.total_segments,
|
||
error: response.data.error
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 多模型Adapter
|
||
|
||
**统一接口抽象**
|
||
```javascript
|
||
// 基础Adapter接口
|
||
class LLMAdapter {
|
||
async chat({ messages, temperature, maxTokens, stream }) {
|
||
throw new Error('Must implement chat method');
|
||
}
|
||
}
|
||
|
||
// Gemini Adapter
|
||
class GeminiAdapter extends LLMAdapter {
|
||
constructor(apiKey) {
|
||
super();
|
||
this.apiKey = apiKey;
|
||
this.baseUrl = 'https://generativelanguage.googleapis.com/v1beta';
|
||
}
|
||
|
||
async chat({ messages, temperature = 0.7, maxTokens = 2000, stream = false }) {
|
||
// 转换消息格式
|
||
const contents = messages.map(msg => ({
|
||
role: msg.role === 'user' ? 'user' : 'model',
|
||
parts: [{ text: msg.content }]
|
||
}));
|
||
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/models/gemini-pro:${stream ? 'streamGenerateContent' : 'generateContent'}`,
|
||
{
|
||
contents,
|
||
generationConfig: {
|
||
temperature,
|
||
maxOutputTokens: maxTokens
|
||
}
|
||
},
|
||
{
|
||
headers: { 'x-goog-api-key': this.apiKey },
|
||
responseType: stream ? 'stream' : 'json'
|
||
}
|
||
);
|
||
|
||
if (stream) {
|
||
return this.handleStream(response.data);
|
||
} else {
|
||
return response.data.candidates[0].content.parts[0].text;
|
||
}
|
||
}
|
||
}
|
||
|
||
// DeepSeek Adapter
|
||
class DeepSeekAdapter extends LLMAdapter {
|
||
constructor(apiKey) {
|
||
super();
|
||
this.apiKey = apiKey;
|
||
this.baseUrl = 'https://api.deepseek.com/v1';
|
||
}
|
||
|
||
async chat({ messages, temperature = 0.7, maxTokens = 2000, stream = false }) {
|
||
// DeepSeek兼容OpenAI格式
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/chat/completions`,
|
||
{
|
||
model: 'deepseek-chat',
|
||
messages,
|
||
temperature,
|
||
max_tokens: maxTokens,
|
||
stream
|
||
},
|
||
{
|
||
headers: {
|
||
'Authorization': `Bearer ${this.apiKey}`,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
responseType: stream ? 'stream' : 'json'
|
||
}
|
||
);
|
||
|
||
if (stream) {
|
||
return response.data; // 返回stream
|
||
} else {
|
||
return response.data.choices[0].message.content;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 工厂模式
|
||
class LLMFactory {
|
||
static adapters = {
|
||
'gemini-pro': GeminiAdapter,
|
||
'deepseek-v2': DeepSeekAdapter,
|
||
'qwen2-72b': QwenAdapter,
|
||
};
|
||
|
||
static create(modelName, apiKey) {
|
||
const AdapterClass = this.adapters[modelName];
|
||
if (!AdapterClass) {
|
||
throw new Error(`Unsupported model: ${modelName}`);
|
||
}
|
||
return new AdapterClass(apiKey);
|
||
}
|
||
}
|
||
|
||
// 使用
|
||
const adapter = LLMFactory.create('gemini-pro', process.env.GEMINI_API_KEY);
|
||
const response = await adapter.chat({
|
||
messages: contextMessages,
|
||
temperature: 0.7,
|
||
stream: true
|
||
});
|
||
```
|
||
|
||
### 5. 文档生成
|
||
|
||
**CRF生成示例**
|
||
```javascript
|
||
import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType } from 'docx';
|
||
import fs from 'fs';
|
||
|
||
async function generateCRF(crfData) {
|
||
const doc = new Document({
|
||
sections: [{
|
||
children: [
|
||
new Paragraph({
|
||
text: '病例报告表 (CRF)',
|
||
heading: 'Heading1',
|
||
}),
|
||
new Paragraph({
|
||
text: `研究名称:${crfData.studyName}`,
|
||
}),
|
||
new Paragraph({
|
||
text: `受试者编号:__________`,
|
||
}),
|
||
new Paragraph({ text: '' }),
|
||
|
||
// 基本信息表格
|
||
new Table({
|
||
width: { size: 100, type: WidthType.PERCENTAGE },
|
||
rows: [
|
||
new TableRow({
|
||
children: [
|
||
new TableCell({ children: [new Paragraph('姓名缩写')] }),
|
||
new TableCell({ children: [new Paragraph('___________')] }),
|
||
]
|
||
}),
|
||
new TableRow({
|
||
children: [
|
||
new TableCell({ children: [new Paragraph('性别')] }),
|
||
new TableCell({ children: [new Paragraph('□ 男 □ 女')] }),
|
||
]
|
||
}),
|
||
// ... 更多字段
|
||
]
|
||
}),
|
||
|
||
// 观察指标
|
||
new Paragraph({
|
||
text: '主要观察指标',
|
||
heading: 'Heading2',
|
||
}),
|
||
...crfData.outcomes.map(outcome =>
|
||
new Paragraph({
|
||
text: `${outcome.name}:__________ 单位:${outcome.unit}`,
|
||
bullet: { level: 0 }
|
||
})
|
||
),
|
||
]
|
||
}]
|
||
});
|
||
|
||
const buffer = await Packer.toBuffer(doc);
|
||
return buffer;
|
||
}
|
||
|
||
// API endpoint
|
||
app.post('/api/agents/crf-agent/generate', async (req, res) => {
|
||
const { projectId, crfData } = req.body;
|
||
|
||
const buffer = await generateCRF(crfData);
|
||
|
||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||
res.setHeader('Content-Disposition', `attachment; filename="CRF_${Date.now()}.docx"`);
|
||
res.send(buffer);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ 风险与挑战
|
||
|
||
### 技术风险
|
||
|
||
1. **RAG检索质量问题**
|
||
- 风险:医学术语复杂,检索准确率可能不达标
|
||
- 应对:
|
||
- 使用Dify的重排序功能
|
||
- 自定义医学词典
|
||
- 人工标注高质量问答对进行微调
|
||
|
||
2. **LLM幻觉问题**
|
||
- 风险:AI生成内容可能不准确,尤其是医学领域
|
||
- 应对:
|
||
- 加强Prompt约束(要求标注不确定性)
|
||
- RAG强制引用(减少幻觉)
|
||
- 关键功能人工复核机制
|
||
|
||
3. **性能问题**
|
||
- 风险:大规模用户并发时响应慢
|
||
- 应对:
|
||
- Redis缓存高频查询
|
||
- 流式输出提升体验
|
||
- CDN加速静态资源
|
||
- 数据库索引优化
|
||
|
||
4. **成本失控**
|
||
- 风险:LLM API费用可能超预期
|
||
- 应对:
|
||
- 设置单用户每日Token配额
|
||
- 优先使用便宜模型(DeepSeek)
|
||
- 缓存常见问题的答案
|
||
- 监控异常使用
|
||
|
||
### 业务风险
|
||
|
||
1. **医疗合规问题**
|
||
- 风险:AI生成的医学建议可能涉及法律风险
|
||
- 应对:
|
||
- 明确免责声明
|
||
- 强调"仅供参考"
|
||
- 不涉及诊断和治疗建议
|
||
- 保留所有对话记录以备审查
|
||
|
||
2. **数据安全问题**
|
||
- 风险:用户上传敏感医学数据
|
||
- 应对:
|
||
- 数据加密存储
|
||
- 严格权限控制
|
||
- 不传输到境外LLM(优先国内模型)
|
||
- 定期安全审计
|
||
|
||
---
|
||
|
||
## 📚 参考资源
|
||
|
||
**Dify相关**
|
||
- 官方文档:https://docs.dify.ai/
|
||
- GitHub:https://github.com/langgenius/dify
|
||
- API文档:https://docs.dify.ai/guides/application-publishing/developing-with-apis
|
||
|
||
**LLM API**
|
||
- Gemini:https://ai.google.dev/docs
|
||
- DeepSeek:https://platform.deepseek.com/docs
|
||
- Qwen:https://help.aliyun.com/zh/dashscope/
|
||
|
||
**开发框架**
|
||
- React:https://react.dev/
|
||
- Fastify:https://fastify.dev/
|
||
- Prisma:https://www.prisma.io/
|
||
- TailwindCSS:https://tailwindcss.com/
|
||
|
||
---
|
||
|
||
## 📝 总结
|
||
|
||
基于以上分析,**强烈推荐采用混合架构方案**:
|
||
|
||
✅ **短期优势**
|
||
- 3个月内可完成MVP并上线
|
||
- 开发成本可控(¥50k-70k)
|
||
- RAG功能开箱即用
|
||
- 技术风险低
|
||
|
||
✅ **长期优势**
|
||
- 业务逻辑完全自主可控
|
||
- 可随时优化和扩展
|
||
- RAG引擎可替换
|
||
- 不被框架绑定
|
||
|
||
✅ **实施建议**
|
||
1. 第1周:搭建基础架构(前后端+Dify)
|
||
2. 第2-4周:实现2-3个核心智能体(MVP)
|
||
3. 第5-8周:完善12个智能体+知识库
|
||
4. 第9-10周:开发运营后台
|
||
5. 第11-12周:测试优化上线
|
||
|
||
这个方案在**开发效率、成本、质量、可扩展性**之间取得了最佳平衡,是最适合您项目的技术选型。
|
||
|
||
---
|
||
|
||
**文档版本:v1.0**
|
||
**更新时间:2025-10-10**
|
||
**作者:AI技术顾问**
|
||
|