Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
1617 lines
45 KiB
Markdown
1617 lines
45 KiB
Markdown
# AIclinicalresearch 现有系统技术摸底报告
|
||
|
||
> **报告日期:** 2025-11-06
|
||
> **报告人:** 技术团队
|
||
> **报告目的:** 全面梳理现有系统已完成的功能、技术架构、数据库设计和代码实现,为后续架构讨论提供基础
|
||
|
||
---
|
||
|
||
## 📊 执行摘要
|
||
|
||
### 项目基本信息
|
||
|
||
| 项目 | 信息 |
|
||
|------|------|
|
||
| **项目名称** | AI科研助手(AIclinicalresearch) |
|
||
| **开发周期** | 2025-10-10 至今(约1个月) |
|
||
| **开发模式** | 敏捷迭代,MVP优先 |
|
||
| **当前阶段** | 里程碑1-1.5完成,Phase2/3完成,稿件审查完成 |
|
||
| **代码量** | 后端~12,000行,前端~10,000行,Python微服务~2,100行 |
|
||
| **完成度** | 核心功能85%,基础架构100% |
|
||
|
||
### 核心成果
|
||
|
||
✅ **已完成5大核心功能模块**
|
||
✅ **完整的技术架构体系**
|
||
✅ **成熟的AI集成能力**
|
||
✅ **完善的文档体系**
|
||
|
||
---
|
||
|
||
## 🎯 已完成功能清单
|
||
|
||
### 1. **AI智能问答系统**(里程碑1核心)
|
||
|
||
#### 1.1 智能体配置系统
|
||
**完成时间:** Day 10-11
|
||
|
||
**核心能力:**
|
||
- ✅ 12个智能体的YAML配置框架
|
||
- ✅ 动态Prompt模板加载(System + User)
|
||
- ✅ 变量替换和条件渲染
|
||
- ✅ 热更新支持
|
||
- ✅ 模型参数配置(temperature, maxTokens, topP)
|
||
|
||
**已开发智能体:**
|
||
1. **选题评价智能体** - 四维度评价框架(创新性、临床价值、科学性、可行性)
|
||
|
||
**配置文件:**
|
||
- `backend/config/agents.yaml` (348行)
|
||
- `backend/prompts/topic_evaluation_system.txt` (143行)
|
||
- `backend/prompts/topic_evaluation_user.txt` (12行)
|
||
|
||
**技术架构:**
|
||
```typescript
|
||
// 智能体服务层
|
||
backend/src/services/agentService.ts
|
||
- loadAgentConfig() // 加载智能体配置
|
||
- getAgentById() // 获取智能体详情
|
||
- renderPrompt() // 渲染Prompt模板
|
||
- 支持变量替换:{{projectBackground}}, {{userInput}}
|
||
- 支持条件渲染:{{#if}}...{{/if}}
|
||
```
|
||
|
||
---
|
||
|
||
#### 1.2 多轮对话系统
|
||
**完成时间:** Day 12-14
|
||
|
||
**核心能力:**
|
||
- ✅ 上下文组装(System + 历史 + 用户输入)
|
||
- ✅ 支持最近100条历史消息
|
||
- ✅ 智能的上下文注入策略
|
||
- ✅ 流式输出(SSE,打字机效果)
|
||
- ✅ 非流式输出(普通模式)
|
||
|
||
**技术实现:**
|
||
```typescript
|
||
// 对话服务层
|
||
backend/src/services/conversationService.ts (381行)
|
||
|
||
// 上下文组装策略
|
||
if (isFirstMessage) {
|
||
// 首次消息:完整模板(项目背景 + 用户问题 + 知识库)
|
||
userPrompt = renderTemplate({
|
||
projectBackground,
|
||
userInput,
|
||
knowledgeBaseContext
|
||
});
|
||
} else {
|
||
// 后续消息:只发送新内容
|
||
userPrompt = knowledgeBaseContext
|
||
? `${userInput}\n\n## 参考文献\n${knowledgeBaseContext}`
|
||
: userInput;
|
||
}
|
||
|
||
// 流式输出
|
||
for await (const chunk of adapter.chatStream(messages)) {
|
||
reply.raw.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/conversations/:id/messages/stream` - 发送消息(流式)
|
||
- `POST /api/v1/conversations/:id/messages` - 发送消息(非流式)
|
||
- `GET /api/v1/conversations/:id` - 获取对话详情
|
||
|
||
---
|
||
|
||
#### 1.3 LLM适配器系统
|
||
**完成时间:** Day 12-13
|
||
|
||
**核心能力:**
|
||
- ✅ 统一的LLM接口抽象(ILLMAdapter)
|
||
- ✅ 3个LLM模型支持:DeepSeek-V3、Qwen3-72B、Qwen-Long
|
||
- ✅ 流式和非流式两种模式
|
||
- ✅ 完整错误处理和Token统计
|
||
- ✅ 工厂模式实现,易于扩展
|
||
|
||
**技术架构:**
|
||
```typescript
|
||
// 适配器接口
|
||
backend/src/adapters/types.ts
|
||
interface ILLMAdapter {
|
||
chat(messages, options): Promise<Response>
|
||
chatStream(messages, options): AsyncGenerator<Chunk>
|
||
}
|
||
|
||
// 具体实现
|
||
backend/src/adapters/
|
||
├── DeepSeekAdapter.ts (150行) - DeepSeek-V3
|
||
├── QwenAdapter.ts (162行) - Qwen3-72B + Qwen-Long
|
||
└── LLMFactory.ts (75行) - 工厂类
|
||
```
|
||
|
||
**模型对比:**
|
||
| 模型 | 定位 | 优势 | Token限制 | 成本 |
|
||
|------|------|------|----------|------|
|
||
| **DeepSeek-V3** | 主力 | 性价比极高 | 64K | ¥1/百万 |
|
||
| **Qwen3-72B** | 备用 | 中文理解好 | 128K | ¥4/百万 |
|
||
| **Qwen-Long** | 全文 | 1M超长上下文 | 1M | ¥5/百万 |
|
||
|
||
---
|
||
|
||
#### 1.4 项目管理系统
|
||
**完成时间:** Day 8-9
|
||
|
||
**核心能力:**
|
||
- ✅ 项目CRUD(创建、读取、更新、删除)
|
||
- ✅ 项目背景管理(动态注入到AI对话)
|
||
- ✅ 软删除机制
|
||
- ✅ 用户项目关联
|
||
|
||
**数据模型:**
|
||
```prisma
|
||
model Project {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
description String? @db.Text // 项目背景
|
||
background String? @db.Text // 详细背景
|
||
researchType String? // 研究类型
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
deletedAt DateTime? // 软删除
|
||
|
||
user User @relation(fields: [userId], references: [id])
|
||
conversations Conversation[]
|
||
|
||
@@index([userId, deletedAt])
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/projects` - 创建项目
|
||
- `GET /api/v1/projects` - 获取项目列表
|
||
- `GET /api/v1/projects/:id` - 获取项目详情
|
||
- `PUT /api/v1/projects/:id` - 更新项目
|
||
- `DELETE /api/v1/projects/:id` - 删除项目
|
||
|
||
---
|
||
|
||
### 2. **个人知识库系统**(里程碑1核心)
|
||
|
||
#### 2.1 知识库管理
|
||
**完成时间:** Day 18-22
|
||
|
||
**核心能力:**
|
||
- ✅ 知识库CRUD
|
||
- ✅ 文档上传(PDF、Word、TXT、Markdown)
|
||
- ✅ 文档状态追踪(uploading → parsing → indexing → completed/error)
|
||
- ✅ 配额管理(每用户3个知识库,每库50个文档)
|
||
- ✅ 文件格式和大小限制(最大10MB)
|
||
|
||
**技术集成:**
|
||
- **Dify平台** - RAG知识库管理
|
||
- **Qdrant向量数据库** - Dify内置
|
||
- **多租户架构** - 每个知识库独立Dataset
|
||
|
||
**数据模型:**
|
||
```prisma
|
||
model KnowledgeBase {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
description String? @db.Text
|
||
difyDatasetId String @unique // 映射到Dify Dataset
|
||
documentCount Int @default(0)
|
||
totalSize BigInt @default(0)
|
||
totalTokens BigInt @default(0) // Phase2新增
|
||
tokenLimit BigInt @default(980000) // Phase2新增
|
||
documentLimit Int @default(50) // Phase2新增
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
user User @relation(fields: [userId], references: [id])
|
||
documents Document[]
|
||
|
||
@@index([userId])
|
||
}
|
||
|
||
model Document {
|
||
id String @id @default(uuid())
|
||
knowledgeBaseId String
|
||
name String
|
||
originalName String
|
||
fileType String
|
||
fileSize BigInt
|
||
difyDocumentId String @unique // 映射到Dify Document
|
||
status String // uploading/parsing/indexing/completed/error
|
||
errorMessage String? @db.Text
|
||
|
||
// Phase2新增:全文存储
|
||
fullText String? @db.Text
|
||
tokenCount Int?
|
||
charCount Int?
|
||
extractionMethod String? // nougat/pymupdf/mammoth
|
||
extractionQuality Float?
|
||
detectedLanguage String? // chinese/english
|
||
|
||
uploadedAt DateTime @default(now())
|
||
processedAt DateTime?
|
||
|
||
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id])
|
||
|
||
@@index([knowledgeBaseId, status])
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/knowledge-bases` - 创建知识库
|
||
- `GET /api/v1/knowledge-bases` - 获取知识库列表
|
||
- `GET /api/v1/knowledge-bases/:id` - 获取详情
|
||
- `PUT /api/v1/knowledge-bases/:id` - 更新知识库
|
||
- `DELETE /api/v1/knowledge-bases/:id` - 删除知识库
|
||
- `POST /api/v1/knowledge-bases/:kbId/documents` - 上传文档
|
||
- `GET /api/v1/knowledge-bases/:kbId/documents` - 获取文档列表
|
||
- `DELETE /api/v1/documents/:id` - 删除文档
|
||
- `POST /api/v1/documents/:id/reprocess` - 重新处理文档
|
||
|
||
---
|
||
|
||
#### 2.2 RAG检索系统(里程碑1.5优化)
|
||
**完成时间:** Day 23-27
|
||
|
||
**核心能力:**
|
||
- ✅ 语义检索(Dify API)
|
||
- ✅ 多知识库联合检索
|
||
- ✅ @知识库功能(前端下拉选择)
|
||
- ✅ 检索结果注入到LLM上下文
|
||
- ✅ **智能引用系统**(100%准确溯源)
|
||
|
||
**优化成果:**
|
||
| 指标 | 优化前 | 优化后 | 提升 |
|
||
|------|--------|--------|------|
|
||
| 检索数量 | 3 chunks | 15 chunks | **5倍** |
|
||
| Chunk大小 | 500 tokens | 1500 tokens | **3倍** |
|
||
| **总覆盖** | **1,500 tokens** | **22,500 tokens** | **15倍** |
|
||
| 覆盖页数 | ~1页 | ~15-20页 | **15-20倍** |
|
||
| 覆盖率 | ~5% | ~40-50% | **8-10倍** |
|
||
|
||
**智能引用系统:**
|
||
```typescript
|
||
// 后端自动收集引用信息
|
||
interface Citation {
|
||
index: number;
|
||
documentName: string;
|
||
segmentIndex: number;
|
||
score: number;
|
||
content: string;
|
||
}
|
||
|
||
// AI回答格式
|
||
根据[来源1]和[来源5]的研究,阿尔兹海默病主要特征包括:
|
||
1. 记忆力减退[来源1][来源3]
|
||
2. 认知功能下降[来源5]
|
||
|
||
---
|
||
📚 **参考文献**
|
||
[1] 📄 **阿尔兹海默综述2023.pdf** - 第3段 (相关度95%)
|
||
"阿尔兹海默病是一种神经退行性疾病..."
|
||
```
|
||
|
||
**前端视觉优化:**
|
||
- `[来源N]`:蓝色高亮badge(#1890ff)
|
||
- 鼠标悬停:背景变深(#bae7ff)
|
||
- 点击跳转:平滑滚动到引用详情
|
||
- 详情闪烁:黄色高亮2秒(#fffbe6)
|
||
|
||
---
|
||
|
||
#### 2.3 全文阅读模式(Phase2)
|
||
**完成时间:** Day 28-32
|
||
|
||
**核心能力:**
|
||
- ✅ **Python微服务**:文档提取服务
|
||
- ✅ **多格式支持**:PDF、Docx、Txt
|
||
- ✅ **智能提取**:Nougat(英文学术) + PyMuPDF(兜底+中文) + Mammoth(Docx)
|
||
- ✅ **语言检测**:自动识别中英文,优化提取策略
|
||
- ✅ **Token管理**:精确计数,双重限制(50文件 + 980K tokens)
|
||
- ✅ **全文存储**:数据库保存完整文本
|
||
- ✅ **智能文档选择**:基于Token容量的智能推荐
|
||
|
||
**技术架构:**
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ Frontend (React) │
|
||
│ - 文档上传 │
|
||
│ - 容量显示(双进度条) │
|
||
│ - 实时进度 │
|
||
└──────────────┬──────────────────────────────┘
|
||
│ REST API
|
||
┌──────────────▼──────────────────────────────┐
|
||
│ Backend (Node.js + Fastify) │
|
||
│ - ExtractionClient │
|
||
│ - TokenService │
|
||
│ - 智能文档选择 │
|
||
└──────────────┬──────────────────────────────┘
|
||
│ HTTP
|
||
┌──────────────▼──────────────────────────────┐
|
||
│ Python Microservice (FastAPI) │
|
||
│ ├── PyMuPDF (快速,中文友好) │
|
||
│ ├── Nougat (学术论文,高质量) │
|
||
│ ├── Mammoth (Docx → Markdown) │
|
||
│ ├── Language Detector │
|
||
│ └── Quality Evaluator │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
**提取策略:**
|
||
```typescript
|
||
// 语言检测 → 选择提取方法
|
||
if (language === 'chinese') {
|
||
// 中文PDF:PyMuPDF(快速)
|
||
text = await pymupdf.extract(pdf);
|
||
} else {
|
||
// 英文PDF:Nougat(高质量) + 降级PyMuPDF
|
||
try {
|
||
text = await nougat.extract(pdf);
|
||
if (quality < 0.7) throw new Error('Quality too low');
|
||
} catch {
|
||
// 自动降级
|
||
text = await pymupdf.extract(pdf);
|
||
}
|
||
}
|
||
```
|
||
|
||
**Python微服务文件结构:**
|
||
```
|
||
extraction_service/
|
||
├── main.py (509行) - FastAPI主服务
|
||
├── services/
|
||
│ ├── pdf_extractor.py (242行) - PDF提取总协调
|
||
│ ├── pdf_processor.py (280行) - PyMuPDF实现
|
||
│ ├── language_detector.py (120行) - 语言检测
|
||
│ ├── nougat_extractor.py (242行) - Nougat实现
|
||
│ ├── docx_extractor.py (253行) - Docx提取
|
||
│ └── txt_extractor.py (316行) - Txt提取(多编码)
|
||
├── requirements.txt
|
||
└── README.md
|
||
```
|
||
|
||
**Backend集成:**
|
||
```typescript
|
||
// ExtractionClient.ts (268行)
|
||
export class ExtractionClient {
|
||
async extractDocument(
|
||
filePath: string,
|
||
fileType: string
|
||
): Promise<ExtractionResult> {
|
||
// 调用Python微服务
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/api/extract/${fileType}`,
|
||
formData
|
||
);
|
||
return response.data;
|
||
}
|
||
}
|
||
|
||
// TokenService.ts (243行)
|
||
export class TokenService {
|
||
calculateTokens(text: string): number {
|
||
const encoder = encoding_for_model("gpt-4");
|
||
const tokens = encoder.encode(text);
|
||
return tokens.length;
|
||
}
|
||
|
||
canUploadDocument(
|
||
kbId: string,
|
||
newDocTokens: number
|
||
): Promise<boolean> {
|
||
// 检查文档数量(≤50)
|
||
// 检查Token容量(≤980K)
|
||
}
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/knowledge-bases/:id/document-selection` - 智能文档选择
|
||
- `GET /api/v1/knowledge-bases/:id/capacity` - 获取容量信息
|
||
|
||
---
|
||
|
||
### 3. **批处理模式**(Phase3)
|
||
|
||
#### 3.1 核心能力
|
||
**完成时间:** Day 29(6小时)
|
||
|
||
**定位:** 任务式交互(非对话),结构化数据提取器
|
||
|
||
**核心功能:**
|
||
- ✅ **预设模板**:临床研究信息提取(8字段)
|
||
- ✅ **自定义模板**:用户提示词 → 文本块显示
|
||
- ✅ **批量处理**:3-50篇文献
|
||
- ✅ **固定3并发**(p-queue)
|
||
- ✅ **失败重试机制**
|
||
- ✅ **Excel导出**(双Sheet设计)
|
||
|
||
**数据模型:**
|
||
```prisma
|
||
model BatchTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
templateType String // preset/custom
|
||
templateId String? // 预设模板ID
|
||
customPrompt String? @db.Text
|
||
|
||
modelType String // deepseek-v3/qwen3/qwen-long
|
||
concurrency Int @default(3)
|
||
|
||
status String // processing/completed/failed
|
||
totalCount Int
|
||
completedCount Int @default(0)
|
||
failedCount Int @default(0)
|
||
|
||
startedAt DateTime?
|
||
completedAt DateTime?
|
||
duration Int? // 秒
|
||
|
||
user User @relation(fields: [userId], references: [id])
|
||
results BatchResult[]
|
||
|
||
@@index([userId, status])
|
||
}
|
||
|
||
model BatchResult {
|
||
id String @id @default(uuid())
|
||
taskId String
|
||
documentId String // 关联Document
|
||
documentName String
|
||
|
||
status String // success/failed
|
||
extractedData Json? // 提取的结构化数据
|
||
rawOutput String? @db.Text
|
||
errorMessage String? @db.Text
|
||
|
||
processingTime Int? // 毫秒
|
||
tokenUsage Int?
|
||
|
||
task BatchTask @relation(fields: [taskId], references: [id])
|
||
|
||
@@index([taskId, status])
|
||
}
|
||
```
|
||
|
||
**预设模板(临床研究信息提取):**
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| research_purpose | text | 研究目的 |
|
||
| research_design | text | 研究设计(RCT/队列研究等) |
|
||
| research_subjects | text | 研究对象(纳入/排除标准) |
|
||
| sample_size | **text** | 样本量(保留原文描述) |
|
||
| intervention_group | text | 干预组 |
|
||
| control_group | text | 对照组 |
|
||
| results_data | longtext | 结果及数据 |
|
||
| oxford_level | text | 牛津评级(1a/1b/2a/2b/3a/3b/4/5) |
|
||
|
||
**技术实现:**
|
||
```typescript
|
||
// batchService.ts (421行)
|
||
export class BatchService {
|
||
async executeBatchTask(
|
||
taskId: string,
|
||
documentIds: string[],
|
||
templateType: 'preset' | 'custom',
|
||
options: BatchOptions
|
||
): Promise<void> {
|
||
// 1. 加载模板或自定义Prompt
|
||
const template = await this.loadTemplate(templateType, options);
|
||
|
||
// 2. 并发执行(固定3并发)
|
||
const queue = new PQueue({ concurrency: 3 });
|
||
const promises = documentIds.map(docId =>
|
||
queue.add(() => this.processDocument(docId, template))
|
||
);
|
||
|
||
// 3. 等待所有任务完成
|
||
const results = await Promise.allSettled(promises);
|
||
|
||
// 4. 统计和保存
|
||
await this.updateTaskStatistics(taskId, results);
|
||
}
|
||
|
||
async processDocument(
|
||
docId: string,
|
||
template: Template
|
||
): Promise<BatchResult> {
|
||
// 1. 获取文档全文
|
||
const document = await this.getDocument(docId);
|
||
|
||
// 2. 构造LLM消息
|
||
const messages = [
|
||
{ role: 'system', content: template.systemPrompt },
|
||
{ role: 'user', content: `${template.userPrompt}\n\n${document.fullText}` }
|
||
];
|
||
|
||
// 3. 调用LLM
|
||
const response = await llm.chat(messages);
|
||
|
||
// 4. 解析JSON(预设模板)或保存文本(自定义)
|
||
const extractedData = template.type === 'preset'
|
||
? this.parseJSON(response.content)
|
||
: response.content;
|
||
|
||
return {
|
||
documentId: docId,
|
||
status: 'success',
|
||
extractedData,
|
||
rawOutput: response.content
|
||
};
|
||
}
|
||
}
|
||
|
||
// jsonParser.ts (145行) - 容错的JSON解析
|
||
export function extractJSON(text: string): object {
|
||
// 支持多种格式
|
||
// 1. 纯JSON:{ "key": "value" }
|
||
// 2. 带前言:这是结果:\n{ ... }
|
||
// 3. 代码块:```json\n{ ... }\n```
|
||
// 4. 带后缀:{ ... }\n\n以上是结果
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/batch/execute` - 执行批处理任务
|
||
- `GET /api/v1/batch/tasks/:taskId` - 获取任务状态
|
||
- `GET /api/v1/batch/tasks/:taskId/results` - 获取任务结果
|
||
- `POST /api/v1/batch/tasks/:taskId/retry-failed` - 重试失败项
|
||
- `GET /api/v1/batch/templates` - 获取所有模板
|
||
|
||
**效率提升:**
|
||
- 手动处理:10篇 × 10分钟 = 100分钟
|
||
- 批处理模式:10篇 × 平均20秒 = ~7分钟
|
||
- **提升约14倍效率** 🚀
|
||
|
||
---
|
||
|
||
### 4. **稿件审查功能**(Day 30独立开发)
|
||
|
||
#### 4.1 核心能力
|
||
**完成时间:** Day 30(1天)
|
||
|
||
**定位:** 独立的稿件智能审查系统
|
||
|
||
**核心功能:**
|
||
- ✅ **双维度评估**:稿约规范性(11项) + 方法学评估(3部分)
|
||
- ✅ **智能分析**:基于真实期刊标准(中华医学超声杂志)
|
||
- ✅ **完整流程**:上传Word → 提取文本 → AI评估 → 生成报告 → 导出PDF
|
||
- ✅ **用户体验**:渐变卡片、拖拽上传、实时进度、颜色编码
|
||
|
||
**评估标准:**
|
||
|
||
**稿约规范性评估(11项):**
|
||
1. 文题(Title)
|
||
2. 作者(Authors)
|
||
3. 中文摘要(Chinese Abstract)
|
||
4. 英文摘要(English Abstract)
|
||
5. 中文关键词(Chinese Keywords)
|
||
6. 英文关键词(English Keywords)
|
||
7. 正文(Main Text)
|
||
8. 参考文献(References)
|
||
9. 图表(Figures and Tables)
|
||
10. 利益冲突(Conflict of Interest)
|
||
11. 伦理审查(Ethics Approval)
|
||
|
||
**方法学评估(3部分):**
|
||
1. 科研设计(Research Design)
|
||
2. 统计方法(Statistical Methods)
|
||
3. 统计分析(Statistical Analysis)
|
||
|
||
**数据模型:**
|
||
```prisma
|
||
model ReviewTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
fileName String
|
||
fileType String
|
||
fileSize BigInt
|
||
|
||
status String // processing/completed/failed
|
||
modelType String // deepseek-v3/qwen3/qwen-long
|
||
|
||
// 评估结果
|
||
editorialScore Float? // 稿约规范性总分
|
||
editorialResult Json? // 详细评估结果
|
||
methodologyScore Float? // 方法学总分
|
||
methodologyResult Json? // 详细评估结果
|
||
|
||
errorMessage String? @db.Text
|
||
processingTime Int? // 毫秒
|
||
|
||
createdAt DateTime @default(now())
|
||
completedAt DateTime?
|
||
|
||
user User @relation(fields: [userId], references: [id])
|
||
|
||
@@index([userId, status])
|
||
}
|
||
```
|
||
|
||
**Prompt设计:**
|
||
```typescript
|
||
// 稿约规范性评估Prompt (210行)
|
||
// prompts/editorial_review_system.txt
|
||
|
||
您是一位专业的医学期刊编辑,您的任务是按照《中华医学超声杂志》的稿约要求,对提交的稿件进行规范性评估。
|
||
|
||
评估维度:
|
||
1. 文题
|
||
- 检查点:准确性、简明性、规范性
|
||
- 评分标准:0-10分
|
||
|
||
2. 作者
|
||
- 检查点:作者信息完整性、排序、单位标注
|
||
- 评分标准:0-10分
|
||
|
||
...(共11个维度)
|
||
|
||
输出格式(JSON):
|
||
{
|
||
"overall_score": 85.5,
|
||
"items": [
|
||
{
|
||
"dimension": "文题",
|
||
"score": 9.0,
|
||
"status": "符合",
|
||
"issues": [],
|
||
"suggestions": []
|
||
},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// 方法学评估Prompt (231行)
|
||
// prompts/methodology_review_system.txt
|
||
|
||
您是一位专业的医学统计学专家,您的任务是评估医学研究稿件的方法学质量。
|
||
|
||
评估维度:
|
||
1. 科研设计
|
||
- 研究类型识别
|
||
- 设计合理性
|
||
- 样本量计算
|
||
|
||
2. 统计方法
|
||
- 方法选择
|
||
- 参数设置
|
||
- 假设检验
|
||
|
||
3. 统计分析
|
||
- 结果呈现
|
||
- 图表规范
|
||
- 结论合理性
|
||
```
|
||
|
||
**技术实现:**
|
||
```typescript
|
||
// reviewService.ts (437行)
|
||
export class ReviewService {
|
||
async reviewManuscript(
|
||
userId: string,
|
||
file: File,
|
||
modelType: ModelType
|
||
): Promise<ReviewTask> {
|
||
// 1. 上传文件并创建任务
|
||
const task = await this.createTask(userId, file);
|
||
|
||
// 2. 提取文档全文(调用Python微服务)
|
||
const fullText = await extractionClient.extractDocument(file);
|
||
|
||
// 3. 稿约规范性评估
|
||
const editorialResult = await this.evaluateEditorial(fullText, modelType);
|
||
|
||
// 4. 方法学评估
|
||
const methodologyResult = await this.evaluateMethodology(fullText, modelType);
|
||
|
||
// 5. 保存结果
|
||
await this.updateTaskResult(task.id, {
|
||
editorialScore: editorialResult.overall_score,
|
||
editorialResult: editorialResult,
|
||
methodologyScore: methodologyResult.overall_score,
|
||
methodologyResult: methodologyResult
|
||
});
|
||
|
||
return task;
|
||
}
|
||
}
|
||
```
|
||
|
||
**API端点:**
|
||
- `POST /api/v1/review/upload` - 上传稿件并开始审查
|
||
- `GET /api/v1/review/tasks/:taskId` - 查询任务状态
|
||
- `GET /api/v1/review/tasks/:taskId/report` - 获取完整报告
|
||
- `GET /api/v1/review/tasks` - 获取任务列表(分页)
|
||
- `DELETE /api/v1/review/tasks/:taskId` - 删除任务
|
||
|
||
**前端组件:**
|
||
```tsx
|
||
// ReviewPage.tsx (625行) - 主页面
|
||
// 包含:上传区 + 进度条 + 报告展示 + PDF导出
|
||
|
||
// ScoreCard.tsx - 分数卡片(颜色编码)
|
||
// EditorialReview.tsx - 稿约规范性评估详情
|
||
// MethodologyReview.tsx - 方法学评估详情
|
||
```
|
||
|
||
---
|
||
|
||
## 🏗️ 技术架构总览
|
||
|
||
### 1. **技术栈**
|
||
|
||
#### 后端技术栈
|
||
```typescript
|
||
核心框架:
|
||
- Node.js 18+
|
||
- TypeScript 5.x
|
||
- Fastify 4.x (高性能HTTP框架)
|
||
|
||
数据层:
|
||
- PostgreSQL 15+ (关系数据库)
|
||
- Prisma 5.x (ORM)
|
||
- Redis (缓存,待集成)
|
||
|
||
AI集成:
|
||
- DeepSeek-V3 (主力LLM,¥1/百万tokens)
|
||
- Qwen3-72B (备用LLM,¥4/百万tokens)
|
||
- Qwen-Long (超长上下文,1M tokens)
|
||
- Dify (RAG平台,向量检索)
|
||
|
||
文件处理:
|
||
- @fastify/multipart (文件上传)
|
||
- @dqbd/tiktoken (Token计数)
|
||
- axios (HTTP客户端)
|
||
|
||
并发控制:
|
||
- p-queue (队列管理)
|
||
|
||
配置管理:
|
||
- js-yaml (YAML解析)
|
||
- dotenv (环境变量)
|
||
```
|
||
|
||
#### 前端技术栈
|
||
```typescript
|
||
核心框架:
|
||
- React 18
|
||
- TypeScript 5.x
|
||
- Vite 5.x (构建工具)
|
||
|
||
UI组件:
|
||
- Ant Design 5.x (主要UI库)
|
||
- TailwindCSS (工具类CSS)
|
||
- React Router 6 (路由)
|
||
|
||
状态管理:
|
||
- Zustand (轻量级状态管理)
|
||
|
||
数据请求:
|
||
- Axios (HTTP客户端)
|
||
- EventSource (SSE流式输出)
|
||
|
||
辅助工具:
|
||
- react-markdown (Markdown渲染)
|
||
- rehype-raw (HTML渲染)
|
||
- html2canvas + jsPDF (PDF导出)
|
||
- xlsx (Excel导出)
|
||
```
|
||
|
||
#### Python微服务
|
||
```python
|
||
核心框架:
|
||
- FastAPI (高性能异步框架)
|
||
- uvicorn (ASGI服务器)
|
||
|
||
PDF处理:
|
||
- PyMuPDF (fitz) - 快速通用
|
||
- pdfplumber - 表格提取
|
||
- nougat-ocr - 学术论文高质量提取
|
||
|
||
Docx处理:
|
||
- mammoth - 转Markdown
|
||
- python-docx - 结构化读取
|
||
|
||
文本处理:
|
||
- chardet - 编码检测
|
||
- langdetect - 语言检测
|
||
|
||
工具:
|
||
- python-multipart - 文件上传
|
||
- python-dotenv - 配置管理
|
||
```
|
||
|
||
---
|
||
|
||
### 2. **数据库设计**
|
||
|
||
#### 核心表结构(13个表)
|
||
|
||
**用户相关(1个表):**
|
||
```prisma
|
||
model User {
|
||
id String @id @default(uuid())
|
||
email String @unique
|
||
password String // bcrypt加密
|
||
name String?
|
||
avatarUrl String?
|
||
role String @default("user")
|
||
status String @default("active")
|
||
kbQuota Int @default(3)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
}
|
||
```
|
||
|
||
**项目管理(1个表):**
|
||
```prisma
|
||
model Project {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
description String? @db.Text
|
||
background String? @db.Text
|
||
researchType String?
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
deletedAt DateTime?
|
||
|
||
@@index([userId, deletedAt])
|
||
}
|
||
```
|
||
|
||
**对话系统(2个表):**
|
||
```prisma
|
||
// 项目对话
|
||
model Conversation {
|
||
id String @id @default(uuid())
|
||
projectId String
|
||
agentId String
|
||
title String?
|
||
metadata Json?
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
deletedAt DateTime?
|
||
}
|
||
|
||
model Message {
|
||
id String @id @default(uuid())
|
||
conversationId String
|
||
role String // user/assistant
|
||
content String @db.Text
|
||
model String? // deepseek-v3/qwen3/qwen-long
|
||
metadata Json? // 知识库引用等
|
||
createdAt DateTime @default(now())
|
||
}
|
||
|
||
// 通用对话(智能问答)
|
||
model GeneralConversation {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
title String?
|
||
metadata Json?
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
deletedAt DateTime?
|
||
}
|
||
|
||
model GeneralMessage {
|
||
id String @id @default(uuid())
|
||
conversationId String
|
||
role String
|
||
content String @db.Text
|
||
model String?
|
||
metadata Json?
|
||
createdAt DateTime @default(now())
|
||
}
|
||
```
|
||
|
||
**知识库系统(2个表):**
|
||
```prisma
|
||
model KnowledgeBase {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
description String? @db.Text
|
||
difyDatasetId String @unique
|
||
documentCount Int @default(0)
|
||
totalSize BigInt @default(0)
|
||
totalTokens BigInt @default(0)
|
||
tokenLimit BigInt @default(980000)
|
||
documentLimit Int @default(50)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@index([userId])
|
||
}
|
||
|
||
model Document {
|
||
id String @id @default(uuid())
|
||
knowledgeBaseId String
|
||
name String
|
||
originalName String
|
||
fileType String
|
||
fileSize BigInt
|
||
difyDocumentId String @unique
|
||
status String
|
||
errorMessage String? @db.Text
|
||
|
||
// 全文存储
|
||
fullText String? @db.Text
|
||
tokenCount Int?
|
||
charCount Int?
|
||
extractionMethod String?
|
||
extractionQuality Float?
|
||
detectedLanguage String?
|
||
|
||
uploadedAt DateTime @default(now())
|
||
processedAt DateTime?
|
||
|
||
@@index([knowledgeBaseId, status])
|
||
}
|
||
```
|
||
|
||
**批处理系统(2个表):**
|
||
```prisma
|
||
model BatchTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
templateType String
|
||
templateId String?
|
||
customPrompt String? @db.Text
|
||
modelType String
|
||
concurrency Int @default(3)
|
||
status String
|
||
totalCount Int
|
||
completedCount Int @default(0)
|
||
failedCount Int @default(0)
|
||
startedAt DateTime?
|
||
completedAt DateTime?
|
||
duration Int?
|
||
|
||
@@index([userId, status])
|
||
}
|
||
|
||
model BatchResult {
|
||
id String @id @default(uuid())
|
||
taskId String
|
||
documentId String
|
||
documentName String
|
||
status String
|
||
extractedData Json?
|
||
rawOutput String? @db.Text
|
||
errorMessage String? @db.Text
|
||
processingTime Int?
|
||
tokenUsage Int?
|
||
|
||
@@index([taskId, status])
|
||
}
|
||
```
|
||
|
||
**稿件审查(1个表):**
|
||
```prisma
|
||
model ReviewTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
fileName String
|
||
fileType String
|
||
fileSize BigInt
|
||
status String
|
||
modelType String
|
||
editorialScore Float?
|
||
editorialResult Json?
|
||
methodologyScore Float?
|
||
methodologyResult Json?
|
||
errorMessage String? @db.Text
|
||
processingTime Int?
|
||
createdAt DateTime @default(now())
|
||
completedAt DateTime?
|
||
|
||
@@index([userId, status])
|
||
}
|
||
```
|
||
|
||
**运营管理(1个表):**
|
||
```prisma
|
||
model AdminLog {
|
||
id String @id @default(uuid())
|
||
adminId String
|
||
action String
|
||
targetType String?
|
||
targetId String?
|
||
details Json?
|
||
ipAddress String?
|
||
userAgent String?
|
||
createdAt DateTime @default(now())
|
||
|
||
@@index([adminId, createdAt])
|
||
@@index([action, createdAt])
|
||
}
|
||
```
|
||
|
||
**总统计:13个表,~80个字段**
|
||
|
||
---
|
||
|
||
### 3. **代码结构**
|
||
|
||
#### 后端代码结构
|
||
```
|
||
backend/
|
||
├── config/
|
||
│ └── agents.yaml (348行) - 智能体配置
|
||
├── prompts/ (441行)
|
||
│ ├── topic_evaluation_system.txt (143行)
|
||
│ ├── topic_evaluation_user.txt (12行)
|
||
│ ├── editorial_review_system.txt (210行)
|
||
│ └── methodology_review_system.txt (231行)
|
||
├── src/
|
||
│ ├── adapters/ (387行) - LLM适配器
|
||
│ │ ├── types.ts (57行)
|
||
│ │ ├── DeepSeekAdapter.ts (150行)
|
||
│ │ ├── QwenAdapter.ts (162行)
|
||
│ │ └── LLMFactory.ts (18行)
|
||
│ ├── clients/ (~550行) - 外部服务客户端
|
||
│ │ ├── DifyClient.ts (282行)
|
||
│ │ └── ExtractionClient.ts (268行)
|
||
│ ├── config/ (56行)
|
||
│ │ └── env.ts - 环境配置
|
||
│ ├── controllers/ (~2,700行) - 控制器
|
||
│ │ ├── projectController.ts
|
||
│ │ ├── agentController.ts (197行)
|
||
│ │ ├── conversationController.ts (247行)
|
||
│ │ ├── chatController.ts
|
||
│ │ ├── knowledgeBaseController.ts
|
||
│ │ ├── documentController.ts
|
||
│ │ ├── batchController.ts (429行)
|
||
│ │ └── reviewController.ts (265行)
|
||
│ ├── services/ (~3,000行) - 业务逻辑
|
||
│ │ ├── projectService.ts
|
||
│ │ ├── agentService.ts (232行)
|
||
│ │ ├── conversationService.ts (381行)
|
||
│ │ ├── knowledgeBaseService.ts
|
||
│ │ ├── documentService.ts
|
||
│ │ ├── batchService.ts (421行)
|
||
│ │ ├── reviewService.ts (437行)
|
||
│ │ └── tokenService.ts (243行)
|
||
│ ├── templates/ (145行)
|
||
│ │ └── clinicalResearch.ts - 批处理预设模板
|
||
│ ├── utils/ (145行)
|
||
│ │ └── jsonParser.ts - 容错JSON解析
|
||
│ ├── routes/ (~250行) - 路由
|
||
│ │ ├── projects.ts
|
||
│ │ ├── agents.ts
|
||
│ │ ├── conversations.ts
|
||
│ │ ├── chatRoutes.ts
|
||
│ │ ├── knowledgeBases.ts
|
||
│ │ ├── batchRoutes.ts
|
||
│ │ └── reviewRoutes.ts
|
||
│ ├── middleware/ (~50行)
|
||
│ │ └── validateProject.ts
|
||
│ └── index.ts (主入口)
|
||
├── prisma/
|
||
│ ├── schema.prisma (~600行)
|
||
│ └── migrations/
|
||
├── package.json
|
||
└── tsconfig.json
|
||
|
||
总计:~12,000行代码
|
||
```
|
||
|
||
#### 前端代码结构
|
||
```
|
||
frontend/
|
||
├── src/
|
||
│ ├── api/ (~1,500行) - API封装
|
||
│ │ ├── projectApi.ts
|
||
│ │ ├── agentApi.ts (76行)
|
||
│ │ ├── conversationApi.ts
|
||
│ │ ├── chatApi.ts
|
||
│ │ ├── knowledgeBaseApi.ts
|
||
│ │ ├── batchApi.ts (147行)
|
||
│ │ ├── reviewApi.ts (319行)
|
||
│ │ └── request.ts (axios配置)
|
||
│ ├── components/ (~5,000行)
|
||
│ │ ├── chat/ (~3,000行)
|
||
│ │ │ ├── MessageList.tsx (含智能引用)
|
||
│ │ │ ├── MessageInput.tsx (含@知识库)
|
||
│ │ │ ├── ModelSelector.tsx
|
||
│ │ │ ├── ModeSelector.tsx
|
||
│ │ │ ├── FullTextMode.tsx
|
||
│ │ │ ├── DeepReadMode.tsx
|
||
│ │ │ ├── BatchMode.tsx
|
||
│ │ │ ├── TaskDefinition.tsx
|
||
│ │ │ ├── DocumentSelection.tsx
|
||
│ │ │ ├── BatchProgress.tsx
|
||
│ │ │ ├── PresetTable.tsx
|
||
│ │ │ ├── CustomTable.tsx
|
||
│ │ │ ├── BatchResults.tsx
|
||
│ │ │ └── CapacityIndicator.tsx
|
||
│ │ ├── knowledge/ (~800行)
|
||
│ │ │ ├── KnowledgeBaseList.tsx
|
||
│ │ │ ├── DocumentList.tsx
|
||
│ │ │ ├── DocumentUpload.tsx
|
||
│ │ │ ├── CreateKBDialog.tsx
|
||
│ │ │ └── EditKBDialog.tsx
|
||
│ │ ├── review/ (~500行)
|
||
│ │ │ ├── ScoreCard.tsx
|
||
│ │ │ ├── EditorialReview.tsx
|
||
│ │ │ └── MethodologyReview.tsx
|
||
│ │ ├── ProjectSelector.tsx
|
||
│ │ ├── CreateProjectDialog.tsx
|
||
│ │ └── EditProjectDialog.tsx
|
||
│ ├── pages/ (~2,500行)
|
||
│ │ ├── HomePage.tsx
|
||
│ │ ├── AgentChatPage.tsx
|
||
│ │ ├── ChatPage.tsx
|
||
│ │ ├── KnowledgePage.tsx
|
||
│ │ ├── ReviewPage.tsx (625行)
|
||
│ │ └── HistoryPage.tsx
|
||
│ ├── stores/ (~400行)
|
||
│ │ ├── useProjectStore.ts
|
||
│ │ └── useKnowledgeBaseStore.ts
|
||
│ ├── hooks/ (~400行)
|
||
│ │ ├── useChatMode.ts
|
||
│ │ ├── useDeepReadState.ts
|
||
│ │ └── useBatchTask.ts (198行)
|
||
│ ├── layouts/ (~200行)
|
||
│ │ └── MainLayout.tsx
|
||
│ ├── types/ (~300行)
|
||
│ │ ├── chat.ts
|
||
│ │ └── index.ts
|
||
│ └── App.tsx
|
||
├── package.json
|
||
└── vite.config.ts
|
||
|
||
总计:~10,000行代码
|
||
```
|
||
|
||
#### Python微服务结构
|
||
```
|
||
extraction_service/
|
||
├── services/
|
||
│ ├── pdf_extractor.py (242行)
|
||
│ ├── pdf_processor.py (280行)
|
||
│ ├── language_detector.py (120行)
|
||
│ ├── nougat_extractor.py (242行)
|
||
│ ├── docx_extractor.py (253行)
|
||
│ └── txt_extractor.py (316行)
|
||
├── main.py (509行)
|
||
├── requirements.txt
|
||
└── README.md
|
||
|
||
总计:~2,100行代码
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 数据流架构
|
||
|
||
### 1. **AI对话流程**
|
||
|
||
```
|
||
用户输入
|
||
↓
|
||
前端 ChatPage/AgentChatPage
|
||
↓ POST /api/v1/conversations/:id/messages/stream
|
||
后端 conversationController
|
||
↓
|
||
conversationService
|
||
├→ agentService.getAgent() - 获取智能体配置
|
||
├→ projectService.getProject() - 获取项目背景
|
||
├→ conversationService.getHistory() - 获取历史对话
|
||
├→ knowledgeBaseService.search() - 知识库检索(可选)
|
||
└→ 组装上下文(System + 历史 + 项目背景 + 知识库 + 用户输入)
|
||
↓
|
||
LLMFactory.getAdapter(modelType)
|
||
↓
|
||
DeepSeekAdapter / QwenAdapter
|
||
↓ HTTP (SSE Stream)
|
||
OpenAI API / DashScope API
|
||
↓ (流式返回)
|
||
后端 conversationService
|
||
├→ 实时写入数据库(messages表)
|
||
└→ SSE流式返回前端
|
||
↓
|
||
前端 MessageList
|
||
└→ 实时渲染(打字机效果)
|
||
```
|
||
|
||
---
|
||
|
||
### 2. **知识库RAG流程**
|
||
|
||
```
|
||
用户上传文档
|
||
↓
|
||
前端 DocumentUpload
|
||
↓ POST /api/v1/knowledge-bases/:id/documents
|
||
后端 documentController
|
||
↓
|
||
documentService.uploadDocument()
|
||
├→ 保存文件到临时目录
|
||
├→ 调用Python微服务提取文本 (Phase2)
|
||
├→ 计算Token数 (Phase2)
|
||
├→ 检查容量限制 (Phase2)
|
||
├→ 上传到Dify (RAG索引)
|
||
├→ 保存全文到数据库 (Phase2)
|
||
└→ 更新知识库统计
|
||
↓
|
||
后台轮询Dify处理状态
|
||
└→ 更新document.status
|
||
|
||
---
|
||
|
||
用户@知识库提问
|
||
↓
|
||
前端 MessageInput (选择知识库)
|
||
↓ POST /api/v1/conversations/:id/messages/stream
|
||
后端 conversationService
|
||
↓
|
||
knowledgeBaseService.search(kbIds, query)
|
||
├→ 对每个知识库调用Dify检索API
|
||
├→ 返回Top 15相关文档片段
|
||
├→ 格式化:【知识库:xxx】\n1. [相关度XX%] 内容...
|
||
└→ 收集引用信息 (Phase 1.5)
|
||
↓
|
||
注入到LLM上下文
|
||
├→ 指导AI使用[来源N]标准编号
|
||
└→ 追加引用清单(HTML格式)
|
||
↓
|
||
前端 MessageList
|
||
├→ 解析引用标记
|
||
├→ 高亮显示[来源N]
|
||
├→ 点击跳转到引用详情
|
||
└→ 详情区域高亮闪烁
|
||
```
|
||
|
||
---
|
||
|
||
### 3. **批处理流程**
|
||
|
||
```
|
||
用户选择文献 + 配置任务
|
||
↓
|
||
前端 BatchMode
|
||
↓ POST /api/v1/batch/execute
|
||
后端 batchController
|
||
↓
|
||
batchService.executeBatchTask()
|
||
├→ 创建BatchTask记录
|
||
├→ 加载预设模板或自定义Prompt
|
||
└→ 异步执行批处理
|
||
↓
|
||
并发队列(p-queue,固定3并发)
|
||
├→ processDocument(doc1)
|
||
├→ processDocument(doc2)
|
||
└→ processDocument(doc3)
|
||
↓ 每个文档处理
|
||
├→ 获取文档全文(database)
|
||
├→ 构造LLM消息(System + User + 文档全文)
|
||
├→ 调用LLM API
|
||
├→ 解析JSON(预设)或保存文本(自定义)
|
||
└→ 保存BatchResult记录
|
||
↓
|
||
后台更新任务统计
|
||
└→ completedCount, failedCount, status
|
||
|
||
---
|
||
|
||
前端轮询任务状态
|
||
↓ GET /api/v1/batch/tasks/:taskId (每5秒)
|
||
后端返回任务进度
|
||
├→ status, totalCount, completedCount, failedCount
|
||
└→ 预估剩余时间
|
||
↓
|
||
任务完成后
|
||
↓ GET /api/v1/batch/tasks/:taskId/results
|
||
后端返回完整结果
|
||
├→ 预设模板:8列表格
|
||
├→ 自定义模板:3列文本块
|
||
└→ 失败项列表
|
||
↓
|
||
前端 BatchResults
|
||
├→ 渲染结果表格
|
||
├→ 导出Excel(双Sheet)
|
||
└→ 重试失败项
|
||
```
|
||
|
||
---
|
||
|
||
## 💾 数据统计
|
||
|
||
### 代码量统计
|
||
|
||
| 模块 | 文件数 | 代码行数 | 占比 |
|
||
|------|-------|---------|------|
|
||
| **后端主代码** | 38 | ~12,000 | 50% |
|
||
| **前端主代码** | 75 | ~10,000 | 42% |
|
||
| **Python微服务** | 8 | ~2,100 | 8% |
|
||
| **总计** | **121** | **~24,100** | **100%** |
|
||
|
||
### 数据库统计
|
||
|
||
| 类别 | 数量 |
|
||
|------|------|
|
||
| **表** | 13 |
|
||
| **字段** | ~80 |
|
||
| **索引** | ~20 |
|
||
| **关系** | 15 |
|
||
|
||
### API端点统计
|
||
|
||
| 模块 | 端点数 |
|
||
|------|-------|
|
||
| 项目管理 | 5 |
|
||
| 智能体管理 | 4 |
|
||
| 对话系统 | 8 |
|
||
| 知识库管理 | 12 |
|
||
| 批处理系统 | 5 |
|
||
| 稿件审查 | 5 |
|
||
| **总计** | **39** |
|
||
|
||
---
|
||
|
||
## 🎯 已验证的技术能力
|
||
|
||
### 1. AI集成能力 ✅
|
||
- ✅ **多模型支持**:DeepSeek-V3、Qwen3-72B、Qwen-Long
|
||
- ✅ **流式输出**:SSE实时传输,打字机效果
|
||
- ✅ **上下文管理**:智能组装,历史对话,项目背景
|
||
- ✅ **错误处理**:完整的重试机制和降级策略
|
||
- ✅ **Token优化**:精确计数,成本控制
|
||
|
||
### 2. RAG能力 ✅
|
||
- ✅ **向量检索**:Dify + Qdrant,语义搜索
|
||
- ✅ **多知识库**:联合检索,结果合并
|
||
- ✅ **智能引用**:100%准确溯源,可点击跳转
|
||
- ✅ **覆盖率优化**:从5%提升到40-50%(15倍提升)
|
||
|
||
### 3. 文档处理能力 ✅
|
||
- ✅ **多格式支持**:PDF、Docx、Txt
|
||
- ✅ **智能提取**:Nougat(学术论文) + PyMuPDF(兜底) + Mammoth(Docx)
|
||
- ✅ **语言检测**:中英文自动识别,优化提取策略
|
||
- ✅ **质量评估**:提取质量评分,自动降级
|
||
- ✅ **大文件处理**:支持50MB+文档
|
||
|
||
### 4. 并发控制能力 ✅
|
||
- ✅ **队列管理**:p-queue,固定3并发
|
||
- ✅ **容错机制**:Promise.allSettled,单个失败不影响其他
|
||
- ✅ **进度追踪**:实时统计,预估剩余时间
|
||
- ✅ **失败重试**:失败项可单独重试
|
||
|
||
### 5. 数据管理能力 ✅
|
||
- ✅ **关系数据库**:PostgreSQL + Prisma ORM
|
||
- ✅ **数据隔离**:用户级、项目级隔离
|
||
- ✅ **软删除**:关键数据可恢复
|
||
- ✅ **事务管理**:ACID保证
|
||
- ✅ **索引优化**:查询性能优化
|
||
|
||
---
|
||
|
||
## 📈 性能指标
|
||
|
||
### 已测试的性能数据
|
||
|
||
| 指标 | 数值 | 说明 |
|
||
|------|------|------|
|
||
| API响应时间 | < 500ms | 普通API端点 |
|
||
| LLM首字响应 | < 3s | DeepSeek-V3 |
|
||
| 流式输出延迟 | < 100ms | SSE chunk延迟 |
|
||
| 文档上传速度 | ~5MB/s | 10MB文档约2秒 |
|
||
| PDF提取速度(PyMuPDF) | ~2页/秒 | 20页PDF约10秒 |
|
||
| PDF提取速度(Nougat) | ~0.5页/秒 | 20页PDF约40秒 |
|
||
| Docx提取速度 | ~1秒/MB | 10MB Docx约10秒 |
|
||
| Token计数速度 | ~10ms/1000字 | Tiktoken |
|
||
| 批处理速度 | ~20秒/文档 | 3并发平均 |
|
||
| RAG检索延迟 | < 1s | Dify检索 |
|
||
|
||
### 成本指标
|
||
|
||
| 项目 | 成本 | 说明 |
|
||
|------|------|------|
|
||
| LLM API成本(DeepSeek-V3) | ¥1/百万tokens | 主力模型 |
|
||
| LLM API成本(Qwen3) | ¥4/百万tokens | 备用模型 |
|
||
| LLM API成本(Qwen-Long) | ¥5/百万tokens | 全文模式 |
|
||
| 单次对话成本 | ¥0.001-0.01 | 500-5000 tokens |
|
||
| 全文精读成本(50篇) | ¥0.5-1 | 100K-200K tokens |
|
||
| 批处理成本(50篇) | ¥0.3-0.5 | 60K-100K tokens |
|
||
| 稿件审查成本 | ¥0.05-0.1 | 10K-20K tokens |
|
||
|
||
---
|
||
|
||
## 🚧 技术债务清单
|
||
|
||
### 高优先级(建议优先处理)
|
||
|
||
1. **日志系统**
|
||
- 现状:大量console.log用于调试
|
||
- 建议:引入日志级别控制(winston/pino)
|
||
- 影响:生产环境日志管理
|
||
|
||
2. **错误码体系**
|
||
- 现状:部分API缺少详细错误信息
|
||
- 建议:统一错误码和错误消息
|
||
- 影响:前端错误处理和用户体验
|
||
|
||
3. **类型定义完善**
|
||
- 现状:部分使用了`any`类型
|
||
- 建议:补充完整的TypeScript类型定义
|
||
- 影响:代码可维护性
|
||
|
||
4. **Redis缓存集成**
|
||
- 现状:已配置但未使用
|
||
- 建议:缓存热点数据(智能体配置、知识库列表)
|
||
- 影响:性能优化
|
||
|
||
### 中优先级(可在里程碑2-3处理)
|
||
|
||
5. **单元测试**
|
||
- 现状:缺少系统性测试
|
||
- 建议:核心业务逻辑添加单元测试
|
||
- 影响:代码质量和重构信心
|
||
|
||
6. **WebSocket实时推送**
|
||
- 现状:批处理进度使用HTTP轮询
|
||
- 建议:改为WebSocket实时推送
|
||
- 影响:用户体验优化
|
||
|
||
7. **文档处理并行化**
|
||
- 现状:文档提取串行处理
|
||
- 建议:并行提取多个文档
|
||
- 影响:批量上传性能
|
||
|
||
8. **API限流**
|
||
- 现状:无限流机制
|
||
- 建议:添加限流中间件
|
||
- 影响:防止API滥用
|
||
|
||
---
|
||
|
||
## 🎉 核心成就
|
||
|
||
### 1. **快速迭代能力**
|
||
- ✅ 1个月内完成5大核心功能模块
|
||
- ✅ 每周都有可见成果
|
||
- ✅ 技术验证全部通过
|
||
|
||
### 2. **AI集成深度**
|
||
- ✅ 3个LLM模型完整集成
|
||
- ✅ 流式输出体验优秀
|
||
- ✅ RAG检索效果显著
|
||
|
||
### 3. **文档处理能力**
|
||
- ✅ Python微服务高质量提取
|
||
- ✅ 多格式全面支持
|
||
- ✅ 智能降级策略可靠
|
||
|
||
### 4. **代码质量**
|
||
- ✅ TypeScript全覆盖
|
||
- ✅ 清晰的三层架构
|
||
- ✅ 良好的模块解耦
|
||
|
||
### 5. **文档完善**
|
||
- ✅ 详细的PRD文档
|
||
- ✅ 完整的技术文档
|
||
- ✅ 丰富的开发日志(60+篇)
|
||
|
||
---
|
||
|
||
## 📝 总结
|
||
|
||
### 现有系统的优势
|
||
|
||
1. **技术架构成熟**
|
||
- 清晰的三层架构(Controller → Service → Database)
|
||
- 良好的模块化设计
|
||
- 完整的LLM适配器抽象
|
||
|
||
2. **功能完整性高**
|
||
- AI对话系统:✅ 完整可用
|
||
- 知识库系统:✅ 完整可用(RAG + 全文)
|
||
- 批处理系统:✅ 完整可用
|
||
- 稿件审查:✅ 完整可用
|
||
|
||
3. **AI能力突出**
|
||
- 多模型支持,灵活切换
|
||
- RAG检索准确,溯源清晰
|
||
- 智能引用100%准确
|
||
|
||
4. **工程质量良好**
|
||
- TypeScript全覆盖
|
||
- Prisma ORM,类型安全
|
||
- 清晰的代码结构
|
||
|
||
### 现有系统的局限
|
||
|
||
1. **架构层面**
|
||
- ❌ 缺少SSA、ST、DC模块(最新需求)
|
||
- ❌ 未考虑私有化部署和单机版
|
||
- ❌ 未考虑微服务架构和K8s
|
||
- ❌ 未考虑模块化售卖
|
||
|
||
2. **技术栈层面**
|
||
- ❌ 缺少R语言集成(SSA需要)
|
||
- ❌ 缺少API网关
|
||
- ❌ 缺少Electron单机版
|
||
|
||
3. **数据库层面**
|
||
- ❌ 单一数据库,未考虑Schema隔离
|
||
- ❌ 未考虑多租户架构
|
||
|
||
4. **部署层面**
|
||
- ❌ 仅支持云端SaaS,未考虑其他3种部署模式
|
||
- ❌ 未考虑容器化部署(K8s)
|
||
|
||
---
|
||
|
||
## 🔮 下一步建议
|
||
|
||
基于现有系统的技术摸底,建议:
|
||
|
||
1. **明确开发阶段**
|
||
- 当前处于"阶段一:模块化单体"
|
||
- 是否立即规划"阶段二:微服务拆分"?
|
||
- 是否立即规划Electron单机版?
|
||
|
||
2. **明确模块优先级**
|
||
- DC模块(数据清洗):核心差异化
|
||
- ASL模块(AI智能文献):已有部分PRD
|
||
- SSA模块(智能统计分析):需要R语言
|
||
- ST模块(统计分析工具):相对简单
|
||
|
||
3. **明确架构演进路径**
|
||
- 是否遵循白皮书的分阶段实施?
|
||
- 是否立即引入K8s和API网关?
|
||
- 是否立即引入R语言和Python微服务?
|
||
|
||
4. **明确文档更新策略**
|
||
- 立即更新哪些P0级文档?
|
||
- 如何整合现有文档和最新需求?
|
||
|
||
---
|
||
|
||
**报告完成日期:** 2025-11-06
|
||
**报告维护者:** 技术团队
|
||
**下一步:** 讨论总体技术架构、文档体系构建、分步骤实施
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|