Nano Studio: 打造现代化的 AI 知识管理平台
引言
在信息爆炸的时代,如何高效地管理和利用知识成为了一个重要课题。Nano Studio 是我开发的一个基于 AI 的知识管理平台,它不仅能够帮助用户整理和存储各种形式的知识(PDF 文档、网页内容、文本笔记),还能通过 RAG(检索增强生成)技术实现智能问答,自动生成思维导图和重点摘要。
本文将深入介绍 Nano Studio 的技术架构、核心功能、技术选型以及开发过程中的经验和思考。
项目概览
🎯 项目定位
Nano Studio 是一个完整的全栈应用,包含:
- 现代化前端:基于 Vue 3 + TypeScript + Arco Design
- 双后端架构 :
- 开发环境:Express.js + Prisma
- 生产环境:Cloudflare Workers + Hono + Drizzle ORM
- AI 增强功能:RAG 智能问答、自动笔记生成、思维导图
✨ 核心特性
1. 📚 Notebook LM - 智能知识管理系统
-
多源知识导入
- PDF 文档自动解析和文本提取
- 网页内容一键抓取(集成 Jina Reader API)
- 纯文本知识源添加
-
RAG 智能对话
- 基于 Qdrant 向量数据库的语义检索
- 支持多轮对话上下文
- 流式输出,实时显示回答
-
AI 笔记生成
- 自动生成思维导图(Mermaid 渲染)
- 智能总结重点简报
- Markdown 格式笔记
2. 🔍 Code Archaeologist - 代码分析工具
- 项目结构可视化
- 代码依赖关系分析
- 自动生成 API 文档
- 智能代码搜索
3. 🎮 Cyber - 禅意工具箱
系统隐藏彩蛋,欢迎小伙伴们发现唔~
- 电子木鱼
- 求签功能
- 2048 游戏
- 深呼吸练习
4. 👤 完整的用户系统
- 个人中心管理
- 每日签到系统
- OpenAI API 配置
- 多模型支持
技术架构
🏗️ 整体架构图
┌─────────────────────────────────────────────────────┐
│ Nano Studio │
│ │
│ ┌──────────────┐ │
│ │ Frontend │ (Vue 3 + TypeScript) │
│ │ │ │
│ └──────┬───────┘ │
│ │ │
│ │ API 调用 │
│ │ │
│ ┌────┴────────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌──────────────┐ │
│ │ nano-back- │ │ backend │ │
│ │ cloudfare │ │ (Express.js) │ │
│ │ (Workers) │ │ │ │
│ │ 🌐 生产环境 │ │ 💻 开发环境 │ │
│ └─────────────────┘ └──────────────┘ │
│ │
│ Database: MySQL + Hyperdrive/Direct │
│ Storage: MinIO (S3-compatible) │
│ Vector: Qdrant │
│ │
└─────────────────────────────────────────────────────┘
🤔 为什么选择双后端架构?
这是 Nano Studio 最具特色的设计决策之一。我同时维护了两个功能完全相同的后端:
💻 开发环境:Express.js + Prisma
优势:
- ✅ 完整的本地调试支持
- ✅ 支持断点调试、热重载
- ✅ 直连数据库,开发效率高
- ✅ 可部署到私有服务器
技术栈:
- Express.js 4.18+ - 成熟的 Node.js Web 框架
- Prisma 5.22+ - 下一代 TypeScript ORM
- MySQL 8.0+ - 关系型数据库
- bcrypt + JWT - 安全认证
🌐 生产环境:Cloudflare Workers + Hono
优势:
- ⚡ 全球边缘网络,低延迟访问
- 💰 无服务器架构,按需计费
- 🔒 Hyperdrive 数据库连接池优化
- 🚀 自动扩展,无需运维
技术栈:
- Hono 4.6+ - 超高性能 Web 框架
- Drizzle ORM 0.45+ - 轻量级 ORM
- Cloudflare Workers - 边缘计算平台
对比分析
| 特性 | Express.js (开发) | Cloudflare Workers (生产) |
|---|---|---|
| 本地调试 | ✅ 完整支持 | ⚠️ 受限 |
| 部署成本 | 💰 需要服务器 | 🆓 按需计费 |
| 全球延迟 | 📍 单点部署 | 🌐 边缘网络 |
| 冷启动 | ✅ 无 | ⚠️ 有(毫秒级) |
| 数据控制 | ✅ 完全自主 | ⚠️ 依赖平台 |
设计理念:
- 开发效率优先:Cloudflare Workers 虽然性能优异,但本地调试受限,使用 Express.js 可以提供完整的开发体验
- 灵活部署:生产环境使用边缘计算,私有部署使用 Express.js
- 技术解耦:两个后端保持 API 接口一致,可独立升级优化
前端技术实现
🎨 技术栈
- Vue 3.5+ - Composition API +
<script setup> - TypeScript - 完整的类型安全
- Arco Design Vue - 字节跳动的企业级 UI 组件库
- Pinia - Vue 官方状态管理
- Vite - 极速开发体验
📁 项目结构
frontend/src/
├── api/ # API 调用层
│ ├── auth.ts # 认证 API
│ ├── session.ts # 会话 API
│ ├── source.ts # 知识源 API
│ └── chat.ts # 聊天 API
├── components/ # 全局组件
├── store/ # Pinia 状态管理
│ ├── notebookStore.ts # 笔记本状态
│ └── settingsStore.ts # 设置状态
├── utils/ # 工具函数
│ ├── pdf.ts # PDF 处理
│ ├── apiClient.ts # HTTP 客户端
│ └── modelApi.ts # 模型 API
└── views/ # 页面视图
├── LoginPage/ # 登录页
├── notebook/ # 笔记本界面
├── codeAns/ # 代码分析
├── cyber/ # 彩蛋功能
└── ProfileCenter/ # 个人中心
🔑 核心功能实现
1. PDF 文档处理
使用 PDF.js 5.4+ 实现客户端 PDF 解析:
typescript
// utils/pdf.ts
import * as pdfjsLib from 'pdfjs-dist';
export async function extractTextFromPDF(file: File): Promise<string> {
const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
let fullText = '';
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
const pageText = textContent.items
.map((item: any) => item.str)
.join(' ');
fullText += pageText + '\\n';
}
return fullText;
}
2. 流式 AI 对话
使用 Server-Sent Events (SSE) 实现实时流式输出:
typescript
// api/chat.ts
export async function* streamChat(
sessionId: number,
message: string
): AsyncGenerator<string> {
const response = await fetch('/api/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': \`Bearer \${token}\`
},
body: JSON.stringify({ sessionId, message })
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
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 = line.slice(6);
if (data !== '[DONE]') {
yield JSON.parse(data).content;
}
}
}
}
}
3. 思维导图渲染
使用 Mermaid 渲染 AI 生成的思维导图:
vue
<template>
<div ref="mermaidContainer" class="mermaid-diagram">
{{ mermaidCode }}
</div>
</template>
<script setup lang="ts">
import mermaid from 'mermaid';
mermaid.initialize({
startOnLoad: true,
theme: 'default'
});
const renderMermaid = async () => {
const { svg } = await mermaid.render(
'mermaid-diagram',
props.mermaidCode
);
mermaidContainer.value.innerHTML = svg;
};
</script>
后端技术实现
📊 数据库设计
核心数据模型
prisma
// Prisma Schema
model User {
id Int @id @default(autoincrement())
email String @unique
username String
password String // bcrypt 加密
sessions Session[]
sources Source[]
settings UserSettings?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Session {
id Int @id @default(autoincrement())
title String
userId Int
user User @relation(fields: [userId], references: [id])
sources Source[] // 多个知识源
notes Note[] // AI 生成的笔记
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Source {
id Int @id @default(autoincrement())
name String
type String // 'pdf' | 'website' | 'text'
content String @db.Text
objectKey String? // MinIO 对象键
ragStatus String // 'pending' | 'processing' | 'completed'
sessionId Int
session Session @relation(fields: [sessionId], references: [id])
userId Int
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}
model Note {
id Int @id @default(autoincrement())
type String // 'mindmap' | 'summary'
content String @db.Text
sessionId Int
session Session @relation(fields: [sessionId], references: [id])
createdAt DateTime @default(now())
}
🔌 核心 API 设计
1. 认证系统
typescript
// Express.js 版本
router.post('/api/auth/register', async (req, res) => {
const { email, username, password } = req.body;
// 密码加密
const hashedPassword = await bcrypt.hash(password, 10);
// 创建用户
const user = await prisma.user.create({
data: {
email,
username,
password: hashedPassword
}
});
// 生成 JWT
const token = jwt.sign(
{ userId: user.id },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({ token, user: { id: user.id, email, username } });
});
2. RAG 智能问答流程
关键步骤:
- 文档上传 → MinIO 存储
- 文本提取 → 分块(Chunking)
- 向量化 → Qdrant 存储
- 用户提问 → 向量检索相关文档
- 上下文增强 → LLM 生成回答
typescript
// services/llm.service.ts
export async function ragCompletion(
sessionId: number,
userMessage: string,
c: Context
) {
// 1. 获取会话的所有知识源
const sources = await db.query.sources.findMany({
where: eq(schema.sources.sessionId, sessionId)
});
// 2. 向量检索相关内容
const relevantChunks = await qdrantService.search(
userMessage,
sources.map(s => s.id)
);
// 3. 构建上下文
const context = relevantChunks
.map(chunk => chunk.text)
.join('\\n\\n');
// 4. 调用 LLM
const response = await fetch(apiBaseUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': \`Bearer \${apiKey}\`
},
body: JSON.stringify({
model: 'gpt-4',
messages: [
{
role: 'system',
content: \`你是一个智能助手。以下是相关文档内容:\\n\${context}\`
},
{ role: 'user', content: userMessage }
],
stream: true
})
});
// 5. 流式返回
return response.body;
}
3. 文件上传(预签名 URL)
typescript
// services/minio.service.ts
import * as Minio from 'minio';
export async function generatePresignedUploadUrl(
filename: string,
userId: number
) {
const minioClient = new Minio.Client({
endPoint: env.MINIO_ENDPOINT,
port: parseInt(env.MINIO_PORT),
useSSL: env.MINIO_USE_SSL === 'true',
accessKey: env.MINIO_ACCESS_KEY,
secretKey: env.MINIO_SECRET_KEY
});
// 生成唯一对象键
const objectKey = \`\${userId}/\${Date.now()}-\${filename}\`;
// 生成预签名 URL(15分钟有效期)
const uploadUrl = await minioClient.presignedPutObject(
env.MINIO_BUCKET,
objectKey,
15 * 60
);
return { uploadUrl, objectKey };
}
🌐 Cloudflare Workers 特殊处理
Hyperdrive 数据库连接
typescript
// src/db/index.ts
import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';
import * as schema from './schema';
export function createDb(env: Env) {
// 创建 mysql2 连接池
const pool = mysql.createPool({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
disableEval: true, // Required for Workers
});
// 创建 Drizzle 实例
const db = drizzle(pool, { schema, mode: 'default' });
// 手动附加 schema 以便通过 db.schema 访问
return Object.assign(db, { schema });
}
}
技术亮点与创新
1. ⚡ 性能优化
- 前端打包优化:使用 Vite 的代码分割,首屏加载时间 < 2s
- 边缘计算:Cloudflare Workers 全球 200+ 节点,平均延迟 < 50ms
- 数据库连接池:Hyperdrive 减少 Workers 冷启动时的连接开销
- 流式传输:SSE 实现流式 AI 回答,提升用户体验
2. 🔒 安全设计
- 密码加密:bcrypt 加盐哈希
- JWT 认证:无状态认证,支持分布式部署
- 预签名 URL:客户端直传 MinIO,减轻服务器压力
- CORS 配置:严格的跨域策略
3. 📦 开发体验
- TypeScript 全栈:前后端类型共享
- 自动导入:unplugin-auto-import 自动导入 API
- 热重载:前端 Vite HMR + 后端 Nodemon
- Prisma Studio:可视化数据库管理
开发经验与挑战
💡 挑战 1:PDF 文本提取精度
问题: PDF.js 提取的文本格式混乱,影响 RAG 效果
解决方案:
- 自定义文本后处理算法
- 去除多余空格和换行
- 保留段落结构
- 使用更大的文本块(chunk size = 1000 tokens)
💡 挑战 2:Cloudflare Workers 冷启动
问题: 数据库连接在冷启动时耗时 1-2 秒
解决方案:
- 使用 Hyperdrive:连接池 + 连接缓存
- 从 Prisma 迁移到 Drizzle ORM:更轻量级
- 优化:冷启动时间从 ~2s 降至 ~200ms
💡 挑战 3:向量检索准确性
问题: 有时检索到不相关的文档片段
解决方案:
- 调整 Embedding 模型(使用 text-embedding-3-small)
- 优化分块策略(重叠分块,overlap = 100 tokens)
- 设置相似度阈值(score > 0.7)
- 结合关键词搜索
未来规划
📅 短期计划(1-3个月)
- 多模态支持:图片、音频文件的知识源
- 协作功能:多人共享笔记本
- 导出功能:导出为 Markdown、PDF
- 移动端适配:响应式设计优化
🚀 长期规划(3-6个月)
- Chrome 插件:一键保存网页到知识库
- 知识图谱:可视化知识之间的关联
- 智能推荐:基于阅读历史推荐相关内容
- 本地部署方案:Docker Compose 一键部署
技术栈总结
前端
- Vue 3.5 + TypeScript
- Arco Design Vue
- Pinia + Vue Router
- PDF.js + Mermaid
- Vite
后端(开发)
- Express.js 4.18
- Prisma ORM
- MySQL 8.0
- bcrypt + JWT
后端(生产)
- Hono 4.6
- Drizzle ORM
- Cloudflare Workers
- Hyperdrive
基础设施
- MinIO(对象存储)
- Qdrant(向量数据库)
- MySQL(关系数据库)
结语
Nano Studio 是我在探索现代 Web 开发和 AI 应用结合的一次实践。通过这个项目,我深刻体会到:
-
架构设计的重要性:双后端策略虽然增加了维护成本,但在开发效率和生产性能之间取得了良好平衡
-
技术选型的权衡:没有完美的技术栈,只有最适合场景的选择
-
用户体验优先:流式输出、思维导图等功能极大提升了产品的可用性
-
持续迭代:项目仍在不断演进,每次迭代都会带来新的思考
如果你对这个项目感兴趣,欢迎访问 GitHub 仓库 查看源码,也欢迎提出建议和贡献代码!
项目信息
技术栈标签
Vue3
TypeScript
CloudflareWorkers
Hono
ExpressJS
Prisma
DrizzleORM
RAG
AI
知识管理