把零散的资料,变成真正的理解。
一个面向个人学习的知识库、RAG 问答与 AI 主动练习平台。
English · 从零文档 · MIT License · GitHub
LearnHub 是一个可运行、可阅读、可扩展的全栈学习项目:你可以上传资料、建立个人知识库、通过 RAG 与资料对话,再把理解沉淀为可回看、可筛选、可练习的题库。它首先是一套从零搭建的工程学习实践,其次才是一个可继续迭代的产品原型。
| 从资料到掌握 | 从源码到系统 |
|---|---|
| 上传资料 → 异步解析 → 向量检索 → SSE 流式问答 → AI 生成题目 → 主动回忆与反馈 | Java 21、Spring Boot、Spring AI、MyBatis、Redis、RabbitMQ、MinIO、Qdrant、MySQL、TypeScript、Vite |
以下截图来自本仓库的本地联调环境,仅用于展示界面与功能;项目当前没有部署公共在线演示站。请按下方“本地运行”启动自己的环境。
![]() |
![]() |
| 总览 知识空间、最近活动与额度一屏掌握 |
知识库 按主题整理资料,作为 RAG 与练习的上下文 |
![]() |
![]() |
| 已有题库 筛选、回看、批量练习历史生成的题目 |
生成新题 选择知识库、题型、数量和可选主题后生成 |
练习反馈:提交答案后查看正误、标准答案与解析。
- 个人知识库:创建、编辑、删除知识库;将多个资料按主题组织起来。
- 文档生命周期:上传 PDF、Word、Markdown、TXT 等资料;查看解析任务并管理绑定关系。
- RAG 问答:从私有资料中检索上下文,以 SSE 实时返回答案和引用片段。
- SSE 加固:前端兼容 HTTP JSON 错误、HTTP SSE 错误、
event:error、多行data、末段无空行、空响应和连接中断。 - AI 主动学习:已有题库与“生成新题”分为清晰入口,避免生成浮层长期占据页面。
- 题库复习:按单选 / 多选筛选、分页回看、批量选择、连续练习、查看解析与错题记录。
- 额度与订单:额度扣减、模拟订单、幂等支付回调与 AI 调用成本控制。
- 工程基础设施:MySQL、Redis、RabbitMQ、MinIO、Qdrant 通过 Docker Compose 提供本地依赖。
flowchart LR
A[上传资料] --> B[异步解析 / 切分]
B --> C[Embedding / Qdrant]
C --> D[RAG 检索问答]
D --> E[生成单选 / 多选题]
E --> F[题库回看与筛选]
F --> G[主动作答]
G --> H[答案、解析与错题]
H --> D
flowchart TB
U[浏览器]
FE[frontend\nTypeScript + Vite]
API[Spring Boot API]
DB[(MySQL)]
REDIS[(Redis)]
MQ[RabbitMQ]
MINIO[(MinIO)]
QDRANT[(Qdrant)]
MODEL[OpenAI-compatible\nChat / Embedding Provider]
U --> FE
FE -->|REST / JSON| API
FE -->|POST + text/event-stream| API
API --> DB
API --> REDIS
API --> MQ
API --> MINIO
API --> QDRANT
API --> MODEL
MQ -->|异步文档解析| MINIO
MQ -->|切分与向量化| QDRANT
LearnHubBackend/docs/ 是本项目的重要组成部分,不是简单的接口说明。它是一套按阶段编排的“从零搭建与学习记录”,保留设计取舍、实现过程、测试要点和复盘内容;适合边读边实现,而不是只复制最终代码。
- 文档导航:
docs/README.md - 后端完整学习文档:
LearnHubBackend/docs/ - 项目阶段计划:
LEARNHUB_PLAN.md
| 阶段 | 学习主题 | 文档入口 |
|---|---|---|
| Week 01 / Part 01 | Maven、Spring Boot、MVC、统一响应、OpenAPI、Docker 基础 | week-01 · part-01 |
| Part 02 | MySQL、Flyway、注册登录、密码安全、JWT、RBAC、登录限制 | part-02 |
| Part 03 | MyBatis-Plus、XML Mapper、MinIO、知识库与文档生命周期 | part-03 |
| Part 04 | RabbitMQ、异步解析、重试、死信与恢复 | part-04 |
| Part 05 | Spring AI、文档切分、Embedding、向量检索、RAG、SSE | part-05 |
| Part 06 | Redis、缓存、限流、额度、订单与幂等 | part-06 |
| Part 07 | Study 题库领域、测试、并发、性能、部署思路 | part-07 |
| Part 08 | 配置治理、缓存一致性、SSE 加固、发布整理 | part-08 |
这是一个单仓库 monorepo:前后端共用同一个 Git 根目录与 GitHub 项目,因而两端的完整提交历史均可见。
LearnHub/
├─ LearnHubBackend/ # Java 21 + Spring Boot 多模块后端
│ ├─ learnhub-application/ # 启动模块、配置、Swagger / OpenAPI
│ ├─ learnhub-common/ # ApiResponse、异常码、公共分页
│ ├─ learnhub-user/ # 注册、登录、JWT、RBAC
│ ├─ learnhub-knowledge/ # 知识库、文件、解析任务、MinIO
│ ├─ learnhub-ai/ # RAG、Spring AI、SSE、AI 出题
│ ├─ learnhub-study/ # 题库、答题、错题、复习
│ ├─ learnhub-credit/ # 额度、订单、幂等支付回调
│ ├─ learnhub-infrastructure/ # Redis、RabbitMQ、MinIO 等基础设施
│ ├─ compose.yaml # 本地依赖服务
│ └─ docs/ # 从零学习与实现文档(核心)
├─ frontend/ # TypeScript + Vite 前端工作台
│ ├─ public/ # LearnHub Logo、favicon 等品牌资产
│ ├─ src/api.ts # REST 封装与 SSE 解析器
│ ├─ src/main.ts # 页面、路由状态与交互逻辑
│ └─ src/style.css # 暖白纸张感视觉系统
├─ docs/ # 根目录文档导航与真实界面截图
├─ README.md # 中文主文档
├─ README_en.md # English documentation
├─ LEARNHUB_PLAN.md # 分阶段学习与开发计划
└─ LICENSE # MIT License
| 层级 | 技术 |
|---|---|
| 语言与构建 | Java 21、Maven 多模块、TypeScript、Vite 8 |
| Web 与安全 | Spring Boot 3.5.16、Spring MVC、Bean Validation、Spring Security 6、JWT、RBAC |
| 数据访问 | MySQL 8.4、Flyway、MyBatis-Plus 3.5.17、MyBatis XML |
| 缓存与并发 | Redis 7.4、Redisson、登录失败计数、AI 限流 |
| 异步与对象存储 | RabbitMQ 4.1、重试 / 死信、MinIO |
| AI 与检索 | Spring AI 1.1.8、ChatClient、Embedding、Qdrant 1.14.1、RAG、SSE |
| API 与可观测性 | springdoc OpenAPI、Swagger UI、Actuator、SLF4J、滚动日志 |
| 前端交互 | 原生 DOM 渲染、Hash 路由、Fetch、ReadableStream、响应式 CSS |
仓库根目录现在提供完整的容器化运行方案,可一次启动前端、后端、MySQL、Redis、RabbitMQ、MinIO 和 Qdrant:
Copy-Item .env.example .env
# 编辑 .env,替换密码、JWT_SECRET 和 API_KEY
docker compose up -d --build启动完成后访问:
LearnHub: http://127.0.0.1:8088
Swagger UI: http://127.0.0.1:8088/swagger-ui/index.html
Health: http://127.0.0.1:8088/actuator/health
完整说明、更新、日志、数据卷和单机服务器建议见 docs/docker-deployment.md。
面试演示时,准备好根目录 .env 后可以直接双击 start-demo.cmd;它会检查 Docker、启动服务、等待健康检查通过并打开 http://127.0.0.1:8088。
Docker 启动不要求宿主机安装 Java、Maven、Node.js 或数据库。项目尚未附带公网域名和 HTTPS;公开部署时应额外配置反向代理、证书、备份与 Secret 管理。
本仓库目前没有公共部署地址。下列地址仅适用于你在本机启动服务之后,不是在线演示链接。
cd D:\LearnHub\LearnHubBackend
Copy-Item .env.example .env
# 根据自己的本机环境填写 .env;不要提交真实密钥
docker compose up -d依赖服务:MySQL(3306)、Redis(6379)、RabbitMQ(5672 / 管理端 15672)、MinIO(9000 / 控制台 9001)、Qdrant(6333 / 6334)。
推荐通过 IntelliJ IDEA 运行:
com.github.comui520.learnhub.LearnHubApplication
或在后端目录执行:
mvn -pl learnhub-application -am spring-boot:run启动后,可在浏览器访问以下本地地址:
API: http://localhost:8080
Swagger UI: http://localhost:8080/swagger-ui/index.html
Health check: http://localhost:8080/actuator/health
cd D:\LearnHub\frontend
npm install
npm run dev -- --host 127.0.0.1前端开发地址:
http://127.0.0.1:5173/
Vite 会把 /api、/v3、/swagger-ui、/actuator 代理到本机后端 8080。前端页面已使用 frontend/public/favicon.ico、SVG favicon 和 LearnHub Logo。
cd D:\LearnHub\frontend
npm run build项目提供了一套可重复执行的 k6 测试脚本,位于 perf/k6/,执行说明见 perf/README.md,完整报告见 docs/performance/baseline.md。
以下结果来自 2026 年 9 月 19 日 的 Windows + Docker Desktop / WSL2 环境。压测入口为 Docker 网络中的
frontend服务,包含 Nginx 和 Spring Boot,不包含宿主机端口转发耗时。它们是本地工程基线,不是公网生产容量承诺。
| 场景 | 并发 / 时长 | 请求数 | 吞吐量 | 错误率 | p50 | p95 | p99 |
|---|---|---|---|---|---|---|---|
| Health | 5 VU / 10s | 20,184 | 2,018.09 req/s | 0% | 1.87 ms | 4.32 ms | 7.47 ms |
| Credit balance | 5 VU / 10s | 17,045* | 1,659.31 req/s* | 0% | 2.27 ms | 5.41 ms | 8.46 ms |
| Study library page | 5 VU / 10s | 9,149* | 906.91 req/s* | 0% | 4.22 ms | 9.66 ms | 15.06 ms |
| Auth login | 2 VU / 20 次 | 20 | 29.32 req/s | 0% | 66.84 ms | 72.33 ms | 72.58 ms |
| Read journey(7 个读取接口 / 迭代) | 5 VU / 5s | 6,672 | 1,313.15 req/s | 0% | 3.23 ms | 7.18 ms | 10.01 ms |
* Credit / Study 脚本的请求总数包含 1 次 setup 登录请求。
| 场景 | 测试规模 | 结果 | 延迟 / 结论 |
|---|---|---|---|
| 文档上传 | 1 个小 Markdown | HTTP 200,测试文档随后删除 | p95 79.87 ms |
| 文档异步解析 | 8 个用户、8 份测试文档 | 8 个解析任务全部成功 | 异步任务状态均为 SUCCESS |
| AI 生成单选题 | 1 道 | HTTP 200,题目 ID 为 6 并成功落库 | p95 5.94 s |
| 支付回调幂等 | 同一订单 5 次回调 | 全部 HTTP 200,数据库仅 1 条 GRANT 流水 |
p95 63.64 ms |
| 模型 / 场景 | 并发 | 结果 | 指标 |
|---|---|---|---|
Qwen/Qwen3.5-4B |
1 次 | 超时 | 超过 60 秒未完成,停止继续测试 |
deepseek-ai/DeepSeek-V4-Flash |
1 次 | 成功,HTTP 200,SSE 完整 | p95 11.67 s,错误率 0% |
| DeepSeek,同一用户 | 3 VU / 20s | 10 次成功,约 5,011 次被限流 | 验证 5 次 / 10 秒 / 用户 限流 |
| DeepSeek,多用户 | 8 VU / 60s | 98 次成功,5,664 次被限流或拒绝 | 成功 Chat p95 12.54 s,最大耗时 56.62 s |
多用户测试准备了 8 个独立账号、8 个独立知识库和 8 份已经完成向量化的测试文档。每个账号充值 20 个模拟 credits,总额度从 160 降至 62,正好对应 98 次成功 Chat 扣减。
失败请求主要是每个用户的限流响应,没有继续消耗额度;成功进入模型的 Chat 请求错误率为 0%。这说明 SSE 链路和多用户知识库隔离正常,同时也说明当前瓶颈主要是模型响应时间和用户级限流,而不是基础 CRUD 或 Nginx。
测试结束时记录到的一次资源快照如下。它不是峰值监控,只用于展示本地运行成本:
| 容器 | CPU | 内存 |
|---|---|---|
| backend | 14.55% | 682.1 MiB |
| frontend | 0.00% | 18.15 MiB |
| mysql | 0.69% | 446.6 MiB |
| redis | 1.01% | 6.9 MiB |
| rabbitmq | 0.26% | 109.9 MiB |
| minio | 1.94% | 234.7 MiB |
| qdrant | 0.39% | 97.7 MiB |
首次 Chat SSE 测试时发现:请求已经进入 Controller,但 Spring MVC 异步 dispatch 阶段 JWT SecurityContext 丢失,导致:
AuthorizationDeniedException
upstream prematurely closed connection
unexpected EOF
最终在 JwtAuthenticationFilter 中允许异步 dispatch 重新解析 Bearer Token,修复后 Chat SSE 恢复正常。这次问题定位和修复本身也是本项目压测的重要产出,而不是只记录几个延迟数字。
注意:Chat 在建立流之前会先扣 1 credit,因此上游模型超时也可能产生额度消耗。当前充值只是模拟订单和回调,不涉及真实支付;具体策略见完整性能报告。
普通 REST 接口使用统一包装:
{
"code": "COMMON_0000",
"message": "SUCCESS",
"httpStatus": 200,
"data": {},
"timestamp": "..."
}AI Chat 使用 POST 和 text/event-stream,事件示例:
event: references
data: [{"fileName":"notes.md","chunkIndex":2}]
event: content
data: 这是回答的一部分
event: error
data: {"code":"...","message":"..."}
题库分页请求示例:
POST /api/v1/study/question/{knowledgeBaseId}/page
Content-Type: application/json
Authorization: Bearer <JWT>{
"knowledgeBaseId": 1,
"page": 1,
"size": 12,
"questionType": "SINGLE_CHOICE"
}- 启动基础设施、后端和前端;
- 注册或登录一个本地账号;
- 创建知识库并上传资料;
- 等待文档解析完成后,在 Chat 中确认引用和流式回答;
- 在“AI 学习”中生成单选或多选题;
- 回到“已有题库”,筛选、查看并提交答案;
- 通过 Swagger UI 查看完整接口定义;
- 执行
npm run build,确保前端生产构建通过。
本项目使用 MIT License。MIT 是宽松许可证:在保留版权与许可声明的前提下,任何人都可以将本项目用于个人、教育、商业或其他用途,也可以使用、复制、修改、合并、发布、分发、再授权或销售其副本。
项目按“现状”提供,不附带任何明示或默示担保。详见 LICENSE。
如果这个项目对你的学习或实践有帮助,欢迎 Star、Fork、修改并用于自己的项目。
Read this README in English




