从零到一构建 AI 驱动的个人知识管理系统:一个全栈实战项目
本文记录了我如何用 3 周时间,从 0 到 1 构建一个 AI 驱动的个人知识管理系统(PKM)。涵盖需求分析、技术选型、架构设计、核心功能实现、部署上线全流程。代码开源,可直接复用。
从零到一构建 AI 驱动的个人知识管理系统:一个全栈实战项目
本文记录了我如何用 3 周时间,从 0 到 1 构建一个 AI 驱动的个人知识管理系统(PKM)。涵盖需求分析、技术选型、架构设计、核心功能实现、部署上线全流程。代码开源,可直接复用。
一、为什么需要构建自己的知识管理系统
1.1 知识工作者的痛点
2026 年的今天,我们每天面对的信息量是十年前的数十倍:
- 碎片化严重:微信文章、Twitter 推文、Slack 讨论、会议记录、代码片段... 信息散落在 10+ 个平台
- 检索困难:「我记得看过这篇文章,但就是找不到」—— 这种挫败感每周至少发生 3 次
- 知识孤岛:收藏 = 学会?Notion 里躺着的 500+ 页面,真正被复用的不到 10%
- 缺乏连接:知识点之间是孤立的,无法形成知识网络,难以产生洞察
1.2 现有方案的局限
我尝试过几乎所有主流方案:
| 工具 | 优点 | 缺点 |
|---|---|---|
| Notion | 功能强大、模板丰富 | 检索弱、AI 功能需额外付费、数据在云端 |
| Obsidian | 本地存储、双向链接 | 移动端体验差、AI 插件配置复杂 |
| Logseq | 大纲友好、开源 | 性能问题、生态较小 |
| Heptabase | 视觉化好 | 付费较高、自定义有限 |
| Mem.ai | AI 原生 | 国内访问慢、数据隐私顾虑 |
核心问题:没有一个方案能同时满足「本地优先 + AI 原生 + 完全可控 + 开源免费」。
1.3 我的需求清单
决定自己动手后,我列出了 Must-Have 功能:
- 智能采集:一键保存网页、PDF、微信文章,自动提取正文
- AI 自动标签:上传内容后自动分析主题、生成标签、提取关键词
- 语义检索:支持自然语言提问,如「找一下关于 React 性能优化的文章」
- 知识图谱:可视化展示知识之间的关联
- 本地优先:数据存储在本地,支持端到端加密同步
- 开放 API:可与其他工具集成(如自动同步 GitHub Issues、Twitter 书签)
二、技术选型:2026 年的全栈方案
2.1 整体架构
┌─────────────────────────────────────────────────────────┐
│ Frontend │
│ Next.js 15 + React 19 + TailwindCSS + shadcn/ui │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Backend │
│ Hono (Edge-ready) + TypeScript + Bun Runtime │
└─────────────────────────────────────────────────────────┘
↓
┌───────────────────┴───────────────────┐
↓ ↓
┌───────────────────┐ ┌───────────────────┐
│ PostgreSQL 17 │ │ Qdrant Vector │
│ (主数据存储) │ │ DB (语义检索) │
└───────────────────┘ └───────────────────┘
↓ ↓
┌───────────────────┐ ┌───────────────────┐
│ Local Storage │ │ AI Services │
│ (加密同步) │ │ (Ollama/本地) │
└───────────────────┘ └───────────────────┘
2.2 核心选型决策
前端:Next.js 15 + React 19
为什么不是纯静态?
- 需要 SSR 支持知识图谱的动态渲染
- React 19 的 INLINE_CODE_0 和 Server Components 大幅减少客户端 JS
- Next.js 15 的 Turbopack 开发速度极快(冷启动 <500ms)
UI 组件库:shadcn/ui
- 完全可控的代码(不是黑盒 npm 包)
- 基于 Radix UI,无障碍支持完善
- 与 TailwindCSS 无缝集成
后端:Hono + Bun
为什么不是 Node.js + Express?
| 指标 | Node + Express | Bun + Hono |
|---|---|---|
| 冷启动 | ~800ms | ~50ms |
| 内存占用 | ~150MB | ~40MB |
| TypeScript | 需要 tsc 编译 | 原生支持 |
| API 兼容性 | OpenAPI 需额外配置 | 内置 OpenAPI 生成 |
Hono 的 Edge-ready 特性让未来部署到 Cloudflare Workers 成为可能。
数据库:PostgreSQL 17 + Qdrant
PostgreSQL 17 新特性利用:
- JSONB 索引优化:存储非结构化元数据
- 增量物化视图:知识图谱预计算
- pgvector 扩展:基础向量检索(备用方案)
Qdrant 向量数据库:
- 专为语义检索设计,支持 HNSW 索引
- 内置过滤查询(filter + vector search)
- Rust 编写,性能卓越(单节点 100 万向量 <10ms)
AI 层:本地优先策略
方案对比:
| 方案 | 成本 | 隐私 | 延迟 | 质量 |
|---|---|---|---|---|
| OpenAI API | $0.01/请求 | 数据出境 | ~500ms | ⭐⭐⭐⭐⭐ |
| Claude API | $0.03/请求 | 数据出境 | ~800ms | ⭐⭐⭐⭐⭐ |
| Ollama (本地) | 免费 | 完全本地 | ~2s | ⭐⭐⭐⭐ |
| LM Studio | 免费 | 完全本地 | ~1.5s | ⭐⭐⭐⭐ |
最终选择:Ollama + Qwen2.5-7B-Instruct
- 7B 模型在 M2 Mac 上推理速度 ~20 tokens/s
- 中文能力优秀(阿里出品)
- 支持函数调用(用于自动标签提取)
三、核心功能实现
3.1 智能采集器
目标:一键保存任意网页,自动提取正文和元数据。
// src/services/content-extractor.ts
import { Readability } from '@mozilla/readability';
import { JSDOM } from 'jsdom';
export async function extractContent(url: string) {
const response = await fetch(url, {
headers: { 'User-Agent': 'PKM-Bot/1.0' }
});
const html = await response.text();
const dom = new JSDOM(html, { url });
const reader = new Readability(dom.window.document);
const article = reader.parse();
// AI 自动提取元数据
const metadata = await extractMetadata(article.content, url);
return {
title: article.title,
content: article.content,
textContent: article.textContent,
url,
publishedAt: metadata.publishedAt,
author: metadata.author,
siteName: metadata.siteName,
savedAt: new Date().toISOString()
};
}
async function extractMetadata(content: string, url: string) {
// 调用本地 Ollama 模型
const response = await fetch('http://localhost:11434/api/generate', {
method: 'POST',
body: JSON.stringify({
model: 'qwen2.5:7b',
prompt: `分析以下内容,提取元数据(JSON 格式):
URL: ${url}
内容前 2000 字:${content.slice(0, 2000)}
返回格式:
{
"author": string | null,
"publishedAt": ISO8601 | null,
"siteName": string
}`
})
});
return await response.json();
}
效果:
- 自动识别文章标题、作者、发布时间
- 过滤广告、导航、评论区等噪声
- 支持微信公众号、知乎、Medium 等常见平台
3.2 AI 自动标签系统
核心思路:使用函数调用让 AI 结构化输出标签。
// src/services/auto-tagger.ts
interface TagSuggestion {
primaryTag: string; // 主分类,如 "前端开发"
subTags: string[]; // 子标签,如 ["React", "性能优化"]
entities: string[]; // 提取的实体,如 ["Next.js", "Vercel"]
summary: string; // 一句话摘要
difficulty: 'beginner' | 'intermediate' | 'advanced';
}
export async function generateTags(content: string): Promise<TagSuggestion> {
const prompt = `
你是一个专业的知识管理助手。请分析以下内容,提取结构化标签信息。
内容:
${content.slice(0, 4000)}
请严格按照以下 JSON Schema 返回:
{
"primaryTag": "主分类(从以下选择:前端开发/后端开发/DevOps/AI 技术/产品设计/职业发展)",
"subTags": ["最多 5 个子标签"],
"entities": ["文中提到的技术/工具/人名,最多 10 个"],
"summary": "50 字以内的摘要",
"difficulty": "文章难度级别"
}
`;
const response = await fetch('http://localhost:11434/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'qwen2.5:7b',
prompt,
format: 'json'
})
});
return await response.json();
}
实际效果示例:
输入:一篇关于 React Server Components 的技术文章
输出:
{
"primaryTag": "前端开发",
"subTags": ["React", "Server Components", "Next.js"],
"entities": ["React 19", "Next.js 15", "Vercel", "Dan Abramov"],
"summary": "介绍 React Server Components 的核心概念、使用场景及与 Client Components 的区别",
"difficulty": "intermediate"
}
3.3 语义检索:用自然语言找知识
技术栈:Qdrant + 本地 Embedding 模型
// src/services/semantic-search.ts
import { QdrantClient } from '@qdrant/js-client-rest';
const qdrant = new QdrantClient({
url: 'http://localhost:6333',
});
// 使用本地 Embedding 模型(bge-m3)
async function generateEmbedding(text: string): Promise<number[]> {
const response = await fetch('http://localhost:11434/api/embeddings', {
method: 'POST',
body: JSON.stringify({
model: 'bge-m3',
prompt: text
})
});
const data = await response.json();
return data.embedding;
}
export async function semanticSearch(
query: string,
filters?: { tags?: string[]; dateRange?: [string, string] }
) {
const queryVector = await generateEmbedding(query);
const results = await qdrant.search('knowledge', {
vector: queryVector,
limit: 10,
filter: {
must: [
...(filters?.tags?.map(tag => ({
key: 'tags',
match: { value: tag }
})) || []),
...(filters?.dateRange ? [{
key: 'savedAt',
range: {
gte: filters.dateRange[0],
lte: filters.dateRange[1]
}
}] : [])
]
}
});
return results.map(r => ({
id: r.id,
score: r.score,
...r.payload
}));
}
使用示例:
用户输入:「找一下关于 React 性能优化的文章」
系统执行:
1. 将查询转换为向量
2. 在 Qdrant 中搜索相似内容
3. 返回最相关的 10 篇文章
结果:
1. 《React 性能优化实战:从 3s 到 300ms》(相似度 0.89)
2. 《使用 useMemo 和 useCallback 的正确姿势》(相似度 0.85)
3. 《Next.js 图片优化完整指南》(相似度 0.78)
3.4 知识图谱可视化
技术选型:React Flow + 自定义布局算法
// src/components/KnowledgeGraph.tsx
import ReactFlow, { Node, Edge } from 'reactflow';
import { useForceGraph } from '../hooks/useForceGraph';
interface KnowledgeNode {
id: string;
label: string;
type: 'article' | 'tag' | 'entity';
metadata: {
savedAt: string;
tags: string[];
};
}
export function KnowledgeGraph({ articles }: { articles: Article[] }) {
// 构建节点和边
const { nodes, edges } = useForceGraph(articles);
return (
<div className="h-[600px] border rounded-lg">
<ReactFlow
nodes={nodes}
edges={edges}
fitView
attributionPosition="bottom-left"
nodeTypes={{
article: ArticleNode,
tag: TagNode,
entity: EntityNode
}}
/>
</div>
);
}
// 力导向布局:相关知识点自动聚集
function useForceGraph(articles: Article[]) {
// 使用 d3-force 进行布局计算
// 文章节点根据共同标签/实体产生吸引力
// 标签节点作为枢纽连接相关文章
...
}
可视化效果:
- 文章节点:圆形,大小表示重要性(被引用次数)
- 标签节点:六边形,颜色表示分类
- 实体节点:方形,边框颜色表示类型(工具/框架/人物)
- 连线:表示关联关系,粗细表示关联强度
四、部署与运维
4.1 本地开发环境
# 1. 克隆项目
git clone https://github.com/your-username/ai-pkm.git
cd ai-pkm
# 2. 安装依赖
bun install
# 3. 启动数据库(Docker Compose)
docker compose up -d postgres qdrant
# 4. 启动 AI 服务
ollama pull qwen2.5:7b
ollama pull bge-m3
ollama serve
# 5. 启动开发服务器
bun run dev
# 访问 http://localhost:3000
4.2 生产部署方案
方案 A:VPS 部署(推荐)
# docker-compose.prod.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://...
- QDRANT_URL=http://qdrant:6333
- OLLAMA_URL=http://ollama:11434
depends_on:
- postgres
- qdrant
postgres:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
qdrant:
image: qdrant/qdrant
volumes:
- qdrant_data:/qdrant/storage
ollama:
image: ollama/ollama
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
pgdata:
qdrant_data:
ollama_data:
成本估算(2026 年价格):
| 资源 | 配置 | 月成本 |
|---|---|---|
| VPS | 4 核 8G + 100G SSD | ¥150 |
| GPU(可选) | T4 × 1 | ¥300 |
| 域名 + SSL | - | ¥50 |
| 合计 | - | ¥500/月 |
方案 B:边缘部署(低成本)
- 前端:Vercel(免费)
- 后端 API:Cloudflare Workers($5/月)
- 数据库:Neon PostgreSQL(免费 tier)
- 向量库:Qdrant Cloud($20/月)
- AI:Ollama 本地运行(免费)
合计:$25/月(约 ¥180)
4.3 数据备份策略
#!/bin/bash
# backup.sh - 每日自动备份
# 1. PostgreSQL 备份
pg_dump $DATABASE_URL | gzip > backups/pg-$(date +%Y%m%d).sql.gz
# 2. Qdrant 快照
curl -X POST http://localhost:6333/collections/knowledge/snapshots \
-o backups/qdrant-$(date +%Y%m%d).snapshot
# 3. 加密同步到云存储(可选)
rclone sync backups/ encrypted-remote:/pkm-backups \
--crypt-remote-password=$ENCRYPTION_KEY
# 4. 保留最近 30 天
find backups/ -mtime +30 -delete
五、项目成果与反思
5.1 三周开发时间线
| 周次 | 完成内容 | 工时 |
|---|---|---|
| Week 1 | 需求分析、技术选型、基础架构搭建 | 20h |
| Week 2 | 核心功能开发(采集、标签、检索) | 25h |
| Week 3 | UI 优化、知识图谱、部署上线 | 15h |
| 合计 | - | 60h |
5.2 使用效果(上线 1 个月后)
- 采集文章:127 篇
- 自动标签准确率:~85%(需要手动修正的约 15%)
- 检索满意度:语义检索命中率 ~90%
- 知识复用:通过图谱发现 12 组之前未注意到的关联
5.3 踩过的坑
- 向量维度不匹配:Qdrant 集合创建后无法修改维度,需提前规划
- Ollama 并发限制:默认单请求,需配置 INLINE_CODE_1 参数
- 中文分词问题:初期标签提取把「React Hooks」分成两个标签,后改为实体识别
- 知识图谱性能:文章超过 500 篇后渲染变慢,改为虚拟滚动 + 按需加载
5.4 未来规划
- 移动端 App(React Native)
- 浏览器插件(一键保存 + 高亮批注)
- 多人协作版本(团队知识库)
- 自动化工作流(如:每天自动推送「去年今日」的文章)
六、开源与复用
项目已开源:https://github.com/your-username/ai-pkm
你可以:
- Fork 后自行部署
- 提交 Issue 和 PR
- 基于此项目构建自己的变体
许可证:MIT(完全免费,可商用)
结语
构建这个系统的过程,本身就是一次深度学习。我不仅掌握了 Hono、Qdrant、Ollama 等新技术,更重要的是重新思考了「知识管理」这件事:
工具的价值不在于功能多寡,而在于能否形成「采集 → 整理 → 连接 → 复用」的正向循环。
希望这个项目能给你一些启发。如果你有任何问题或建议,欢迎在 GitHub 上交流。
参考资料: