Scider 技术规格说明书(Beta 阶段更新版)
1. 引言
1.1 文档定位
本文档为 Scider 项目的技术规格说明书,面向开发者与系统架构师,详细描述系统的技术架构、模块设计、数据存储方案、关键技术选型及其演进。本文档基于 Alpha 阶段技术规格进行更新,重点反映 Beta 阶段的新增功能、技术选型变化以及优化策略。
1.2 技术架构总览
Scider 采用前后端分离的 B/S 架构,系统拓扑如下图所示:
┌─────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web App │ │ PWA │ │ 移动端 │ │ 浏览器 │ │
│ │ (Vue 3) │ │(可选) │ │(响应式) │ │扩展(未来)│ │
│ └────┬────┘ └─────────┘ └─────────┘ └─────────┘ │
└───────┼─────────────────────────────────────────────────────┘
│ HTTPS / WebSocket
┌───────┼─────────────────────────────────────────────────────┐
│ ▼ 负载均衡层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Nginx (反向代理 + 静态资源) │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 应用层 (FastAPI) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 认证模块 │ │ 论文模块 │ │ 图谱模块 │ ... │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 异步任务层 (Celery) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │PDF解析 │ │LLM生成 │ │图谱生成 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 数据层 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │Postgres│ │ Redis │ │ 对象 │ │ 向量库 │ │ │
│ │ │ (主库) │ │ (缓存) │ │ 存储 │ │(pgvector)│ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
2. 技术栈总览
2.1 核心技术栈
| 层级 |
技术选型 |
版本 |
用途 |
| 前端 |
Vue 3 |
3.4+ |
渐进式 JavaScript 框架 |
|
TypeScript |
5.0+ |
类型安全 |
|
Element Plus |
2.6+ |
UI 组件库 |
|
D3.js |
7.8+ |
知识图谱可视化(Beta 替换 ECharts) |
|
pdf.js |
4.0+ |
PDF 渲染、标注、搜索 |
|
Vue Test Utils + Vitest |
- |
前端单元测试 |
| 后端 |
Python |
3.12 |
主语言 |
|
FastAPI |
0.110+ |
Web 框架 |
|
SQLAlchemy |
2.0+ |
ORM |
|
Alembic |
1.13+ |
数据库迁移 |
|
Celery |
5.3+ |
异步任务队列 |
|
Redis |
7.0+ |
消息代理 + 缓存 |
| 数据库 |
PostgreSQL |
15+ |
主数据库 |
|
pgvector |
- |
向量检索扩展(RAG) |
| 测试 |
pytest |
8.0+ |
后端单元/集成测试 |
|
pytest-asyncio |
- |
异步测试 |
|
pytest-celery |
- |
Celery 任务测试 |
|
Locust / JMeter |
- |
性能压测 |
|
Playwright |
- |
E2E 测试 |
| 部署 |
Docker |
24+ |
容器化 |
|
Docker Compose |
2.20+ |
编排 |
|
Nginx |
1.24+ |
反向代理 |
2.2 与 Alpha 阶段的主要变更
| 变更项 |
Alpha 阶段 |
Beta 阶段 |
变更原因 |
| 图谱可视化 |
ECharts |
D3.js |
需要支持节点/边的动态编辑、自定义渲染,ECharts 能力受限 |
| PDF 预览 |
vue-pdf-embed |
pdf.js 社区版 |
需要文字搜索、高亮标注、连续滚动等高级功能 |
| 向量检索 |
未涉及 |
pgvector |
支持 RAG 问答的本地向量存储 |
| 富文本编辑 |
无 |
Vue 3 富文本编辑器 |
笔记功能需要 Markdown/LaTeX/图片支持 |
| 首次引导 |
无 |
driver.js / shepherd.js |
降低新用户使用门槛 |
| 性能测试 |
未规划 |
Locust + JMeter |
确保高并发场景下的稳定性 |
| 安全测试 |
基础鉴权 |
越权/XSS/限流测试 |
生产级安全要求 |
3. 前端技术规格
3.1 前端架构
src/
├── api/ # API 请求封装(axios 实例)
├── assets/ # 静态资源
├── components/ # 通用组件
│ ├── PDFViewer/ # PDF 阅读器组件(基于 pdf.js)
│ ├── KnowledgeGraph/# 知识图谱组件(基于 D3.js)
│ ├── RichEditor/ # 富文本编辑器组件
│ └── ...
├── composables/ # 组合式函数
│ ├── useAuth.ts
│ ├── usePdfSearch.ts # PDF 搜索逻辑
│ ├── useChat.ts # AI 问答对话管理
│ └── ...
├── layouts/ # 布局组件
├── router/ # Vue Router 配置
├── stores/ # Pinia 状态管理
│ ├── upload.ts # 上传状态管理
│ ├── user.ts
│ └── ...
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数
└── views/ # 页面视图
├── Login/
├── Library/
├── Graph/
├── PDFReader/ # 新增:PDF 阅读与标注视图
├── Notes/ # 新增:笔记管理视图
└── Profile/ # 新增:个人中心(含 LLM 配置)
3.2 关键技术实现
3.2.1 知识图谱(D3.js)
- 力导向图实现:使用 D3.js 的
forceSimulation 模块,配置力参数(斥力、引力、碰撞检测)。
- 数据更新模式:采用
enter-update-exit 模式动态添加/删除节点和边。
- 性能优化:对于节点数 > 200 的场景,限制仿真迭代次数;使用
requestAnimationFrame 控制渲染帧率。
- 编辑功能:提供工具栏支持添加节点、删除节点/边、编辑节点属性。删除节点时自动删除关联边。
核心代码模式:
function updateGraph(data: GraphData) {
const nodes = svg.selectAll('.node').data(data.nodes, d => d.id);
const links = svg.selectAll('.link').data(data.links, d => `${d.source}-${d.target}`);
// 退出
links.exit().remove();
nodes.exit().remove();
// 更新
const linkEnter = links.enter().append('line').attr('class', 'link');
const nodeEnter = nodes.enter().append('g').attr('class', 'node');
// 合并后重启仿真
simulation.nodes(data.nodes);
simulation.force('link').links(data.links);
simulation.alpha(1).restart();
}
3.2.2 PDF 阅读与标注
- 基础渲染:基于 pdf.js 社区版,启用连续滚动模式(
PDFViewer 配置 viewerContainer 和 scrollMode)。
- 文字搜索:使用
PDFFindController,提取匹配位置并高亮,支持遍历结果。
- 文本高亮:监听
mouseup 事件获取用户选区,计算选区在页面中的归一化坐标(相对于页面视图的百分比),保存至后端。重新加载时渲染高亮层。
- 页码定位:调用
scrollPageIntoView({ pageNumber }) 方法。
- 缩放控制:设置
currentScaleValue = 'auto' 启用自动缩放。
3.2.3 富文本编辑器(笔记)
- 组件选型:使用 Vue 3 生态的富文本编辑器,内置以下扩展:
- Markdown 快捷输入
- LaTeX 数学公式(katex)
- 图片粘贴自动上传(通过
handleImageUpload 回调)
- 图片上传流程:监听从剪贴板粘贴图片事件 → 转换为 Blob → 调用后端图片上传 API → 返回 URL → 插入编辑器。
- 性能:大型笔记采用虚拟滚动(
vue-virtual-scroller)优化长列表。
3.2.4 AI 问答对话界面
- 组合式函数:封装
useChat,管理对话历史、请求状态(loading/error/success)。
- 流式响应:使用 Server-Sent Events (SSE) 或 WebSocket 逐步渲染回答内容。
- 虚拟滚动:消息列表超过 50 条时启用虚拟滚动,避免 DOM 节点过多。
3.2.5 首次引导
- 工具:
driver.js 或 shepherd.js。
- 配置:引导步骤存储在数组中,支持“跳过”和“下一步”。
- 存储:首次访问标记存储在
localStorage 中,完成引导或跳过后更新标记。
3.2.6 撤销功能
- 实现方式:利用 Pinia store 的历史记录模式,在每次修改操作前深拷贝当前状态并推入历史栈,最多保留 20 条记录。
3.3 前端性能指标
| 指标 |
目标值 |
| 首屏加载时间 (LCP) |
< 2.5s |
| 首次输入延迟 (FID) |
< 100ms |
| 图谱拖拽/缩放帧率 |
≥ 30fps(节点数 ≤ 500) |
| PDF 滚动流畅度 |
≥ 30fps(页面 ≤ 200) |
| 笔记列表滚动加载 |
< 200ms(笔记数 ≥ 1000) |
4. 后端技术规格
4.1 后端架构
app/
├── api/ # API 路由层
│ ├── v1/
│ │ ├── auth.py # 认证(登录/注册/重置密码)
│ │ ├── papers.py # 论文管理
│ │ ├── graphs.py # 知识图谱
│ │ ├── notes.py # 笔记管理
│ │ ├── qa.py # AI 问答
│ │ ├── user.py # 用户资料(头像/LLM配置)
│ │ └── ...
├── core/ # 核心模块
│ ├── config.py # 配置管理(Pydantic Settings)
│ ├── security.py # JWT、密码哈希、加密
│ ├── database.py # 数据库连接
│ └── redis_client.py # Redis 连接
├── models/ # SQLAlchemy ORM 模型
├── schemas/ # Pydantic 模型(请求/响应)
├── services/ # 业务逻辑层
│ ├── paper_service.py
│ ├── graph_service.py
│ ├── note_service.py
│ ├── rag_service.py # RAG 检索与生成
│ └── llm_service.py # LLM 调用封装
├── tasks/ # Celery 异步任务
│ ├── pdf_parse.py
│ ├── graph_generate.py
│ └── ...
├── utils/ # 工具函数
│ ├── pdf_extractor.py
│ └── vector_store.py # pgvector 操作
└── tests/ # 测试(pytest)
4.2 核心服务设计
4.2.1 LLM 服务封装
- 目标:统一对接多个 LLM 供应商(OpenAI、本地模型等),支持 API 密钥管理。
- 接口:
LLMService.generate(prompt: str, model: str = None) -> str
- 加密存储:用户配置的 API 密钥使用
cryptography.fernet.Fernet 对称加密后存入数据库。
- Prompt 管理:将 Prompt 模板抽离到配置文件或数据库,支持动态更新和 A/B 测试。
4.2.2 RAG 问答服务
- PDF 场景:
- 上传 PDF 时,后端将全文分块(chunk size = 500 tokens,overlap = 50),调用 Embedding 模型生成向量,存储到 pgvector。
- 用户提问时,将问题向量化,与 PDF 片段进行余弦相似度检索,取 Top‑K(K=5)片段。
- 构建 Prompt(系统指令 + 检索片段 + 用户问题 + 笔记内容),调用 LLM 生成回答。
- 知识图谱场景:
- 根据当前图谱的节点和边数据,提取子图(限制节点数 ≤ 30)。
- 将子图结构化为文本描述(如“节点 A:...,与节点 B 关联,关联类型:...”)。
- 构建 GraphRAG Prompt,调用 LLM 生成回答。
4.2.3 LLM 图谱生成
- 输入:所选文件夹内所有“已确认”论文的四要素(研究背景、方法、创新点、结论)。
- Prompt 设计:要求 LLM 输出 JSON 格式,包含
nodes(id、label、cluster、...)和 links(source、target、type)。其中 cluster 字段用于前端颜色映射。
- 后处理:校验 JSON 结构完整性,补充缺失字段,确保节点 id 唯一。
- 聚类:LLM 根据研究主题/领域自动分配
cluster 值,前端根据 cluster 分配不同颜色。
4.2.4 异步任务管理
- PDF 解析任务:
- 状态流转:
pending → processing → pending_confirm → confirmed
- 使用 Celery 链式任务:
extract_text → call_llm → save_entities
- 失败重试:最多 3 次,指数退避。
- 图谱生成任务:
- 触发时机:用户确认论文后 / 手动点击“生成图谱”
- 异步执行 LLM 调用,完成后前端轮询获取结果。
4.3 数据模型扩展(Beta 新增)
4.3.1 笔记模块
class Note(Base):
id = Column(UUID, primary_key=True)
user_id = Column(UUID, ForeignKey("user.id"))
paper_id = Column(UUID, ForeignKey("paper.id"))
title = Column(String(200))
content = Column(Text) # Markdown 格式
images = Column(JSON) # 存储图片 URL 列表
annotation_position = Column(JSON) # {page: int, x: float, y: float, width: float, height: float}
created_at = Column(DateTime)
updated_at = Column(DateTime)
4.3.2 用户配置模块(LLM 供应商)
class UserLLMConfig(Base):
id = Column(UUID, primary_key=True)
user_id = Column(UUID, ForeignKey("user.id"))
provider = Column(String(50)) # "openai", "azure", "local"
api_key_encrypted = Column(String(500))
base_url = Column(String(200), nullable=True)
default_model = Column(String(50))
is_active = Column(Boolean, default=True)
4.3.3 向量存储(pgvector)
-- 启用 pgvector 扩展
CREATE EXTENSION vector;
-- PDF 片段向量表
CREATE TABLE pdf_chunks (
id UUID PRIMARY KEY,
paper_id UUID REFERENCES paper(id),
chunk_text TEXT,
embedding vector(1536) -- 维度取决于 Embedding 模型
);
-- 创建索引(IVFFlat 或 HNSW)
CREATE INDEX ON pdf_chunks USING ivfflat (embedding vector_cosine_ops);
4.4 API 设计概要
4.4.1 认证相关
| 端点 |
方法 |
描述 |
鉴权 |
/api/v1/auth/register |
POST |
邮箱注册 |
无 |
/api/v1/auth/login |
POST |
登录,返回 JWT |
无 |
/api/v1/auth/refresh |
POST |
刷新 JWT |
Refresh Token |
/api/v1/auth/reset-password |
POST |
发送重置邮件 |
无 |
/api/v1/auth/reset-password/confirm |
POST |
确认重置 |
无 |
4.4.2 论文与 PDF
| 端点 |
方法 |
描述 |
/api/v1/papers/upload |
POST |
上传 PDF,触发解析任务 |
/api/v1/papers/{id}/annotations |
GET |
获取高亮标注数据 |
/api/v1/papers/{id}/annotations |
POST |
保存高亮标注 |
/api/v1/papers/{id}/notes |
GET |
获取笔记列表 |
4.4.3 知识图谱
| 端点 |
方法 |
描述 |
/api/v1/graphs/generate |
POST |
触发 LLM 生成图谱(异步) |
/api/v1/graphs/task/{task_id} |
GET |
查询生成状态 |
/api/v1/graphs/{graph_id} |
PUT |
更新图谱(增删改节点/边) |
/api/v1/graphs/{graph_id}/export |
GET |
导出图谱(JSON/SVG/PNG) |
4.4.4 AI 问答
| 端点 |
方法 |
描述 |
/api/v1/qa/pdf |
POST |
基于当前 PDF 提问(同步/SSE) |
/api/v1/qa/graph |
POST |
基于知识图谱提问 |
/api/v1/qa/chat/history |
GET |
获取对话历史 |
4.4.5 用户配置
| 端点 |
方法 |
描述 |
/api/v1/user/profile |
PUT |
更新头像、昵称 |
/api/v1/user/llm-providers |
GET/POST/PUT/DELETE |
LLM 供应商配置 CRUD |
/api/v1/user/statistics |
GET |
获取使用统计 |
5. 测试策略
5.1 测试层次
| 层次 |
工具 |
覆盖目标 |
执行时机 |
| 单元测试 |
Vitest (前端) / pytest (后端) |
关键组件/函数的逻辑正确性 |
每次提交 |
| 集成测试 |
pytest + httpx (API) |
接口契约、数据库交互、状态流转 |
PR 合并前 |
| E2E 测试 |
Playwright |
核心用户路径(注册→上传→确认→图谱→笔记→问答) |
发布前 |
| 性能测试 |
Locust / JMeter |
100+ 并发下的响应时间、资源占用 |
6.1–6.5 |
| 安全测试 |
自动化脚本 + 手动 |
越权、XSS、CSRF、限流 |
6.11 前 |
| 兼容性测试 |
Playwright + BrowserStack |
跨浏览器、跨操作系统 |
6.11 前 |
5.2 关键测试用例示例
5.2.1 后端 API 集成测试(pytest)
@pytest.mark.asyncio
async def test_password_reset_flow(client):
# 1. 请求重置
resp = await client.post("/api/v1/auth/reset-password", json={"email": "test@example.com"})
assert resp.status_code == 202
# 2. 模拟获取 token(实际从邮件队列)
token = get_token_from_mock_queue()
# 3. 确认重置
resp = await client.post("/api/v1/auth/reset-password/confirm",
json={"token": token, "new_password": "NewPass123"})
assert resp.status_code == 200
5.2.2 知识图谱生成测试
- 拓扑完整性:确保生成的 JSON 无孤立节点、无自环边。
- 聚类有效性:人工抽检或计算聚类相似度指标(如 Silhouette Score)。
- LLM 输出格式:使用 Pydantic 模型校验。
5.2.3 安全测试脚本
# 水平越权测试
def test_horizontal_privilege_escalation():
# 用户 A 的 token
token_a = login("userA@example.com")
# 尝试获取用户 B 的笔记
resp = get_with_token("/api/v1/notes/paper/b_paper_id", token_a)
assert resp.status_code == 403 # 应拒绝
6. 部署与运维
6.1 容器化部署
使用 Docker Compose 编排以下服务:
services:
postgres:
image: pgvector/pgvector:pg15
environment:
POSTGRES_DB: scider
POSTGRES_USER: scider
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
backend:
build: ./backend
depends_on: [postgres, redis]
environment:
DATABASE_URL: postgresql://...
REDIS_URL: redis://redis:6379
celery_worker:
build: ./backend
command: celery -A app.tasks worker -l info
depends_on: [redis, postgres]
frontend:
build: ./frontend
ports:
- "80:80"
nginx:
image: nginx:1.24
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- "443:443"
6.2 一键部署脚本
基于现有 docker-compose 基础设施,编写 deploy.sh:
#!/bin/bash
# 1. 加载环境变量
set -a; source .env.production; set +a
# 2. 数据库迁移
docker-compose run --rm backend alembic upgrade head
# 3. 启动服务
docker-compose up -d
# 4. 健康检查
curl -f http://localhost/api/v1/health || exit 1
回滚脚本:rollback.sh 执行 docker-compose down 并恢复上一个镜像版本。
6.3 监控与日志
- 日志:使用
docker-compose logs 或集成 ELK(可选)。
- 性能监控:Prometheus + Grafana(可选,Beta 阶段暂不做强制)。
7. 安全设计
7.1 身份认证与授权
- JWT Access Token(短期,15min)存储在
localStorage 或 cookie(HttpOnly)。
- Refresh Token(长期,7d)存储在
HttpOnly Cookie 中,防止 XSS。
- API 层使用依赖注入校验当前用户,确保用户只能访问自己的资源。
7.2 数据安全
- 密码:bcrypt 加盐哈希(cost=12)。
- LLM API 密钥:Fernet 对称加密,密钥从环境变量读取。
- 传输安全:生产环境强制 HTTPS。
7.3 输入防御
- XSS:富文本内容在服务端使用
DOMPurify 清洗。
- SQL 注入:SQLAlchemy ORM 参数化查询。
- CSRF:若使用 Cookie 认证,需启用 CSRF Token 机制(Beta 阶段 JWT 方案不涉及)。
7.4 限流策略
| 接口 |
限流规则 |
实现方式 |
/auth/login |
5 次/分钟/IP |
Redis 计数 + FastAPI 中间件 |
/auth/reset-password |
3 次/小时/邮箱 |
Redis 计数 |
/qa/pdf |
10 次/分钟/用户 |
Redis 计数 |
| 论文上传 |
20 篇/小时/用户 |
Redis 计数 |
8. 性能优化策略
8.1 前端优化
- 路由懒加载
- 图片懒加载
- D3 图谱:限制仿真迭代次数,使用
requestAnimationFrame 合并重绘
- PDF 渲染:按需渲染当前视口页面,预加载相邻页面
8.2 后端优化
- 数据库索引:对外键、查询频繁字段建索引
- 缓存:用户基本资料、论文元数据等存入 Redis(TTL 1h)
- LLM 结果缓存:相同输入(论文 DOI + Prompt 版本)缓存 7 天
- 异步任务:PDF 解析使用 Celery,避免阻塞主线程
- 分页:所有列表接口默认
limit=20,支持 offset 游标分页
8.3 大数据量场景
- 图谱节点 > 500:提示用户缩小范围或使用筛选;编辑时仅增量更新。
- 笔记 > 1000:前端虚拟滚动;后端
match_phrase 全文搜索 + 分页。
- PDF > 200 页:首屏仅渲染前 10 页,滚动时动态加载。
9. 技术风险与应对
| 风险 |
应对措施 |
| LLM 调用成本过高 |
使用轻量模型(如 GPT-3.5-turbo)处理简单任务;缓存 + 用户配额 |
| pdf.js 社区版学习曲线 |
封装为独立组件,参考官方示例;预留替换方案(如 react-pdf 但需适配 Vue) |
| D3 性能在大规模图谱下降 |
限制节点数,提供“简化视图”;使用 Web Worker 计算力导向布局 |
| 向量检索精度不足 |
尝试不同 Embedding 模型(text-embedding-3-small / large);调整分块策略 |
| 富文本编辑器兼容性 |
备选方案:降级为纯 Markdown 编辑器 + 独立 LaTeX 渲染 |
10. 版本更新记录
| 版本 |
日期 |
变更内容 |
| Alpha 1.0 |
2025-05-10 |
初始版本,完成基础功能 |
| Beta 1.0 (本文档) |
2025-05-22 |
增加笔记、PDF 标注、AI 问答、图谱编辑、性能/安全测试等模块;技术栈调整 |
AIGC 声明:本文档在 Alpha 阶段技术规格说明书基础上,根据 Beta 阶段任务清单进行更新。新增模块的技术方案、测试策略和部署设计借助 AI 工具(DeepSeek)进行辅助评估与优化。