674 lines
18 KiB
Markdown
674 lines
18 KiB
Markdown
# Karpathy风格 Wiki 自动编译器设计文档
|
||
|
||
> 基于LLM的个人知识库自动构建系统
|
||
|
||
## 一、核心架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 腾讯云 2核2G (编译服务器) │
|
||
│ │
|
||
│ /data/knowledge-base/ │
|
||
│ ├── 00-inbox/ ← 原始资料入口(手动/Web Clipper放入) │
|
||
│ ├── 01-raw/ ← 已整理的原始资料(PDF/网页/图片) │
|
||
│ ├── 02-compiler/ ← 编译器工作目录 │
|
||
│ │ ├── scripts/ ← 编译脚本 │
|
||
│ │ ├── queue/ ← 待处理队列 │
|
||
│ │ └── logs/ ← 处理日志 │
|
||
│ ├── 03-wiki/ ← 生成的Wiki(Obsidian主目录) │
|
||
│ │ ├── Concepts/ ← 概念文章(LLM生成) │
|
||
│ │ ├── Summaries/ ← 资料摘要 │
|
||
│ │ ├── MOCs/ ← 内容地图 │
|
||
│ │ └── Index.md ← 主索引 │
|
||
│ ├── 04-outputs/ ← 查询输出(问答/可视化) │
|
||
│ └── 05-archive/ ← 归档 │
|
||
│ │
|
||
│ 编译服务: │
|
||
│ ├── File Watcher (inotify) ← 监控inbox新文件 │
|
||
│ ├── Compiler Pipeline ← 调用LLM处理 │
|
||
│ └── WebDAV Server ← 供Obsidian同步 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
↑
|
||
WebDAV / HTTPS
|
||
↑
|
||
┌─────────────────────┼─────────────────────┐
|
||
│ │ │
|
||
MacBook 手机/iPad (其他设备)
|
||
(Obsidian IDE) (Obsidian App)
|
||
(也可本地编译)
|
||
```
|
||
|
||
## 二、编译流程设计
|
||
|
||
### 2.1 阶段一:数据摄取(Ingest)
|
||
|
||
**输入**:任意格式的原始资料
|
||
- 网页文章(通过Obsidian Web Clipper)
|
||
- PDF论文
|
||
- 图片/截图
|
||
- GitHub仓库
|
||
- 数据集说明
|
||
|
||
**处理**:
|
||
```bash
|
||
# 1. 文件放入 00-inbox/
|
||
# 2. File Watcher检测到新文件
|
||
# 3. 预处理:
|
||
# - 网页 → Markdown(readability-lxml)
|
||
# - PDF → Markdown(pymupdf4llm)
|
||
# - 图片 → OCR提取文字(可选)
|
||
# 4. 移动到 01-raw/,记录元数据
|
||
```
|
||
|
||
**元数据记录**(JSON sidecar):
|
||
```json
|
||
{
|
||
"source": "https://example.com/article",
|
||
"title": "原始标题",
|
||
"author": "作者",
|
||
"date_ingested": "2025-04-15",
|
||
"file_type": "web_article",
|
||
"word_count": 3500,
|
||
"hash": "sha256:xxx",
|
||
"status": "pending_compilation"
|
||
}
|
||
```
|
||
|
||
### 2.2 阶段二:编译(Compile)
|
||
|
||
**核心编译管道**(每次处理一个文档):
|
||
|
||
```python
|
||
# compiler.py 伪代码
|
||
|
||
def compile_document(raw_file):
|
||
# 1. 读取原始内容
|
||
content = read_raw(raw_file)
|
||
metadata = read_sidecar(raw_file)
|
||
|
||
# 2. LLM生成摘要(500字以内)
|
||
summary = llm_call(
|
||
model="claude-3-5-sonnet",
|
||
prompt=f"""
|
||
请为以下文章生成结构化摘要:
|
||
- 一句话核心观点
|
||
- 3-5个关键要点
|
||
- 重要数据/事实
|
||
- 与其他概念的潜在联系
|
||
|
||
原文:{content[:8000]} # 前8K字符
|
||
"""
|
||
)
|
||
|
||
# 3. LLM提取概念
|
||
concepts = llm_call(
|
||
prompt=f"""
|
||
从以下文章中提取关键概念(实体、理论、方法、工具等)。
|
||
对每个概念给出:名称、定义、重要性(1-5)、相关概念
|
||
|
||
格式:YAML列表
|
||
"""
|
||
)
|
||
|
||
# 4. 生成或更新概念文章
|
||
for concept in concepts:
|
||
concept_file = f"03-wiki/Concepts/{concept.name}.md"
|
||
if exists(concept_file):
|
||
# 更新现有概念(添加新信息)
|
||
update_concept(concept_file, concept, raw_file)
|
||
else:
|
||
# 创建新概念文章
|
||
create_concept(concept_file, concept, raw_file)
|
||
|
||
# 5. 生成资料摘要卡片
|
||
summary_file = f"03-wiki/Summaries/{raw_file.basename}.md"
|
||
create_summary_card(summary_file, summary, concepts, metadata)
|
||
|
||
# 6. 更新主索引
|
||
update_index()
|
||
|
||
# 7. 生成反向链接
|
||
create_backlinks(raw_file, concepts)
|
||
|
||
return {
|
||
"status": "compiled",
|
||
"summary": summary_file,
|
||
"concepts": [c.name for c in concepts],
|
||
"links_created": len(concepts)
|
||
}
|
||
```
|
||
|
||
**概念文章模板**(LLM生成):
|
||
```markdown
|
||
---
|
||
concept: "概念名称"
|
||
aliases: ["别名1", "别名2"]
|
||
importance: 4
|
||
created: 2025-04-15
|
||
last_updated: 2025-04-15
|
||
sources:
|
||
- "[[Summaries/原始文章1]]"
|
||
- "[[Summaries/原始文章2]]"
|
||
related:
|
||
- "[[概念A]]"
|
||
- "[[概念B]]"
|
||
---
|
||
|
||
# 概念名称
|
||
|
||
## 定义
|
||
(LLM生成的简洁定义,50-100字)
|
||
|
||
## 核心要点
|
||
- 要点1
|
||
- 要点2
|
||
- 要点3
|
||
|
||
## 在资料中的出现
|
||
(自动聚合所有提到此概念的原始资料)
|
||
### [[Summaries/原始文章1]]
|
||
> 引用段落...
|
||
> 引用段落...
|
||
|
||
### [[Summaries/原始文章2]]
|
||
> 引用段落...
|
||
|
||
## 相关概念
|
||
- [[概念A]]:关系说明...
|
||
- [[概念B]]:关系说明...
|
||
|
||
## 待探索问题
|
||
(LLM自动生成,供后续查询)
|
||
- 这个概念与X有什么区别?
|
||
- 在Y场景下如何应用?
|
||
```
|
||
|
||
### 2.3 阶段三:MOC生成(Map of Content)
|
||
|
||
**自动生成内容地图**:
|
||
|
||
```python
|
||
def generate_mocs():
|
||
# 1. 分析所有概念的关系
|
||
concepts = load_all_concepts()
|
||
graph = build_concept_graph(concepts)
|
||
|
||
# 2. LLM识别主题集群
|
||
clusters = llm_call(
|
||
prompt=f"""
|
||
以下是我知识库中的所有概念(共{len(concepts)}个)。
|
||
请将它们组织成5-10个主题集群(MOC),每个集群包含:
|
||
- 主题名称
|
||
- 核心概念列表
|
||
- 集群间的联系
|
||
|
||
概念列表:{concepts}
|
||
关系图:{graph}
|
||
"""
|
||
)
|
||
|
||
# 3. 为每个集群生成MOC文件
|
||
for cluster in clusters:
|
||
moc_file = f"03-wiki/MOCs/{cluster.name}.md"
|
||
create_moc(moc_file, cluster)
|
||
|
||
# 4. 更新主索引
|
||
update_master_index(clusters)
|
||
```
|
||
|
||
**MOC文件模板**:
|
||
```markdown
|
||
---
|
||
moc: true
|
||
title: "人工智能研究"
|
||
description: "关于AI核心概念、方法论的集合"
|
||
concepts_count: 42
|
||
last_updated: 2025-04-15
|
||
---
|
||
|
||
# 🗺️ 人工智能研究
|
||
|
||
## 核心概念
|
||
(Dataview查询自动生成)
|
||
```dataview
|
||
LIST
|
||
FROM "Concepts"
|
||
WHERE contains(mocs, "人工智能研究")
|
||
SORT importance DESC
|
||
```
|
||
|
||
## 重要资料
|
||
```dataview
|
||
LIST
|
||
FROM "Summaries"
|
||
WHERE contains(topics, "AI")
|
||
SORT file.mtime DESC
|
||
LIMIT 10
|
||
```
|
||
|
||
## 最新探索
|
||
(手动或自动记录的研究问题)
|
||
- [ ] 大模型微调的最佳实践?
|
||
- [ ] RAG vs 长上下文,何时用哪个?
|
||
|
||
## 关联MOC
|
||
- [[机器学习基础]]
|
||
- [[自然语言处理]]
|
||
```
|
||
|
||
### 2.4 阶段四:问答与输出(Q&A)
|
||
|
||
**基于Wiki的问答机制**:
|
||
|
||
```python
|
||
def query_wiki(question):
|
||
# 1. 确定相关概念
|
||
relevant_concepts = llm_call(
|
||
prompt=f"""
|
||
用户问题:{question}
|
||
|
||
请从以下概念列表中,找出最相关的5-10个概念:
|
||
{all_concepts}
|
||
|
||
返回概念名称列表。
|
||
"""
|
||
)
|
||
|
||
# 2. 读取相关概念文章
|
||
context = ""
|
||
for concept in relevant_concepts:
|
||
context += read_concept_file(concept)
|
||
|
||
# 3. 可选:读取原始资料(如果需要更多细节)
|
||
if need_more_detail(question):
|
||
raw_sources = find_raw_sources(relevant_concepts)
|
||
context += extract_relevant_parts(raw_sources, question)
|
||
|
||
# 4. LLM生成回答
|
||
answer = llm_call(
|
||
prompt=f"""
|
||
基于以下Wiki内容,回答用户问题。
|
||
如果信息不足,请明确说明。
|
||
|
||
上下文:{context[:12000]} # 限制长度
|
||
|
||
问题:{question}
|
||
|
||
要求:
|
||
- 使用中文回答
|
||
- 引用来源概念(如[[概念名称]])
|
||
- 如果涉及多个方面,分点说明
|
||
"""
|
||
)
|
||
|
||
# 5. (可选)生成输出文档
|
||
if user_wants_output:
|
||
output_file = f"04-outputs/QnA-{timestamp}.md"
|
||
create_qna_doc(output_file, question, answer, relevant_concepts)
|
||
|
||
return answer
|
||
```
|
||
|
||
**可视化输出**(可选):
|
||
```python
|
||
def generate_visualization(query_type):
|
||
if query_type == "concept_graph":
|
||
# 生成概念关系图(Mermaid或D3)
|
||
pass
|
||
elif query_type == "timeline":
|
||
# 生成时间线
|
||
pass
|
||
elif query_type == "slides":
|
||
# 生成Marp幻灯片
|
||
pass
|
||
```
|
||
|
||
### 2.5 阶段五:健康检查与增强(Linting)
|
||
|
||
**定期检查任务**(每日/每周):
|
||
|
||
```python
|
||
def health_check():
|
||
# 1. 查找孤立概念(无链接的概念)
|
||
orphans = find_orphan_concepts()
|
||
|
||
# 2. 查找矛盾信息
|
||
contradictions = llm_call(
|
||
prompt="扫描所有概念文章,标记矛盾或过时的信息"
|
||
)
|
||
|
||
# 3. 建议新文章
|
||
gaps = llm_call(
|
||
prompt="基于现有概念,建议缺失的链接文章或MOC"
|
||
)
|
||
|
||
# 4. 生成健康报告
|
||
report = generate_report(orphans, contradictions, gaps)
|
||
save_to("04-outputs/health-reports/weekly.md")
|
||
```
|
||
|
||
## 三、技术实现细节
|
||
|
||
### 3.1 文件监控与触发
|
||
|
||
**使用inotify(Linux)**:
|
||
```python
|
||
# file_watcher.py
|
||
import inotify.adapters
|
||
|
||
def watch_inbox():
|
||
i = inotify.adapters.Inotify()
|
||
i.add_watch('/data/knowledge-base/00-inbox')
|
||
|
||
for event in i.event_gen(yield_nones=False):
|
||
(_, type_names, path, filename) = event
|
||
|
||
if 'IN_CLOSE_WRITE' in type_names:
|
||
# 新文件写入完成,触发编译
|
||
queue_for_compilation(os.path.join(path, filename))
|
||
```
|
||
|
||
**备选:定时扫描**:
|
||
```bash
|
||
# cron任务,每分钟检查
|
||
* * * * * /usr/bin/python3 /data/knowledge-base/compiler/scan_inbox.py
|
||
```
|
||
|
||
### 3.2 队列管理
|
||
|
||
**使用Redis或简单文件队列**:
|
||
```python
|
||
# queue.py - 简化版文件队列
|
||
import json
|
||
import os
|
||
from datetime import datetime
|
||
|
||
QUEUE_DIR = "/data/knowledge-base/02-compiler/queue"
|
||
|
||
def enqueue(file_path, priority=5):
|
||
task = {
|
||
"id": generate_id(),
|
||
"file": file_path,
|
||
"priority": priority, # 1-10, 10最优先
|
||
"status": "pending",
|
||
"created": datetime.now().isoformat(),
|
||
"attempts": 0
|
||
}
|
||
|
||
queue_file = os.path.join(QUEUE_DIR, f"{task['id']}.json")
|
||
with open(queue_file, 'w') as f:
|
||
json.dump(task, f)
|
||
|
||
def dequeue():
|
||
"""按优先级取出任务"""
|
||
tasks = []
|
||
for f in os.listdir(QUEUE_DIR):
|
||
if f.endswith('.json'):
|
||
with open(os.path.join(QUEUE_DIR, f)) as fp:
|
||
task = json.load(fp)
|
||
if task['status'] == 'pending':
|
||
tasks.append(task)
|
||
|
||
# 按优先级排序
|
||
tasks.sort(key=lambda x: x['priority'], reverse=True)
|
||
return tasks[0] if tasks else None
|
||
```
|
||
|
||
### 3.3 LLM调用封装
|
||
|
||
**统一接口,支持多后端**:
|
||
```python
|
||
# llm_client.py
|
||
import os
|
||
from typing import Literal
|
||
|
||
Backend = Literal["claude", "openai", "kimi", "local"]
|
||
|
||
class LLMClient:
|
||
def __init__(self, default_backend: Backend = "claude"):
|
||
self.default = default_backend
|
||
self.api_keys = {
|
||
"claude": os.getenv("ANTHROPIC_API_KEY"),
|
||
"openai": os.getenv("OPENAI_API_KEY"),
|
||
"kimi": os.getenv("MOONSHOT_API_KEY"),
|
||
"local": "http://localhost:11434" # Ollama
|
||
}
|
||
|
||
def call(self, prompt: str, backend: Backend = None, **kwargs):
|
||
backend = backend or self.default
|
||
|
||
if backend == "claude":
|
||
return self._call_claude(prompt, **kwargs)
|
||
elif backend == "openai":
|
||
return self._call_openai(prompt, **kwargs)
|
||
elif backend == "kimi":
|
||
return self._call_kimi(prompt, **kwargs)
|
||
elif backend == "local":
|
||
return self._call_ollama(prompt, **kwargs)
|
||
|
||
def _call_claude(self, prompt, model="claude-3-5-sonnet-20241022", max_tokens=4000):
|
||
import anthropic
|
||
client = anthropic.Anthropic(api_key=self.api_keys["claude"])
|
||
|
||
message = client.messages.create(
|
||
model=model,
|
||
max_tokens=max_tokens,
|
||
messages=[{"role": "user", "content": prompt}]
|
||
)
|
||
return message.content[0].text
|
||
|
||
# ... 其他后端的实现
|
||
```
|
||
|
||
### 3.4 WebDAV配置
|
||
|
||
**使用WsgiDAV**:
|
||
```bash
|
||
# 安装
|
||
pip install wsgidav cheroot
|
||
|
||
# 配置 /etc/wsgidav.yaml
|
||
host: 0.0.0.0
|
||
port: 5232
|
||
root: /data/knowledge-base/03-wiki
|
||
|
||
auth:
|
||
type: htpasswd
|
||
htpasswd_filename: /etc/wsgidav/users.htpasswd
|
||
|
||
# SSL(通过Nginx反向代理)
|
||
```
|
||
|
||
**Nginx反向代理配置**:
|
||
```nginx
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name knowledge.yourdomain.com;
|
||
|
||
ssl_certificate /path/to/cert.pem;
|
||
ssl_certificate_key /path/to/key.pem;
|
||
|
||
# WebDAV
|
||
location / {
|
||
proxy_pass http://localhost:5232;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
|
||
# WebDAV方法
|
||
dav_methods PUT DELETE MKCOL COPY MOVE;
|
||
dav_ext_methods PROPFIND OPTIONS;
|
||
}
|
||
|
||
# API网关(编译器API)
|
||
location /api/ {
|
||
proxy_pass http://localhost:8000;
|
||
proxy_set_header Authorization $http_authorization;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 四、Obsidian配置
|
||
|
||
### 4.1 必需插件
|
||
|
||
1. **Remotely Save** - WebDAV同步
|
||
2. **Dataview** - 查询和索引
|
||
3. **Templater** - 模板自动化
|
||
4. **QuickAdd** - 快速捕获
|
||
5. **Obsidian Web Clipper**(浏览器扩展)- 剪藏网页
|
||
|
||
### 4.2 快捷键配置
|
||
|
||
```json
|
||
{
|
||
"快速捕获到inbox": "Ctrl+Shift+I",
|
||
"触发编译当前文件": "Ctrl+Shift+C",
|
||
"打开概念图谱": "Ctrl+Shift+G",
|
||
"查询Wiki": "Ctrl+Shift+Q"
|
||
}
|
||
```
|
||
|
||
### 4.3 模板示例
|
||
|
||
**新资料模板**(放入00-inbox时自动添加):
|
||
```markdown
|
||
---
|
||
ingest_date: {{date}}
|
||
source: {{source_url}}
|
||
status: pending
|
||
priority: 5
|
||
tags: [raw]
|
||
---
|
||
|
||
# {{title}}
|
||
|
||
[原始链接]({{source_url}})
|
||
|
||
## 内容
|
||
|
||
{{content}}
|
||
|
||
## 待处理
|
||
- [ ] 编译成摘要
|
||
- [ ] 提取概念
|
||
- [ ] 链接到相关MOC
|
||
```
|
||
|
||
## 五、部署清单
|
||
|
||
### 5.1 腾讯云初始化
|
||
|
||
```bash
|
||
# 1. 系统更新
|
||
sudo apt update && sudo apt upgrade -y
|
||
|
||
# 2. 安装依赖
|
||
sudo apt install -y python3 python3-pip nodejs npm redis-server nginx
|
||
|
||
# 3. 安装Python包
|
||
pip3 install anthropic openai pymupdf4llm readability-lxml markdown pyyaml watchdog
|
||
|
||
# 4. 创建目录结构
|
||
sudo mkdir -p /data/knowledge-base/{00-inbox,01-raw,02-compiler,03-wiki,04-outputs,05-archive}
|
||
sudo chown -R $USER:$USER /data/knowledge-base
|
||
|
||
# 5. 配置环境变量
|
||
export ANTHROPIC_API_KEY="your-key"
|
||
export OPENAI_API_KEY="your-key"
|
||
export MOONSHOT_API_KEY="your-key"
|
||
|
||
# 6. 启动服务
|
||
# - WebDAV
|
||
# - File Watcher
|
||
# - Compiler Worker
|
||
```
|
||
|
||
### 5.2 服务脚本
|
||
|
||
**systemd服务:编译器工作器**
|
||
```ini
|
||
# /etc/systemd/system/wiki-compiler.service
|
||
[Unit]
|
||
Description=Wiki Compiler Worker
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=ubuntu
|
||
WorkingDirectory=/data/knowledge-base
|
||
ExecStart=/usr/bin/python3 /data/knowledge-base/compiler/worker.py
|
||
Restart=always
|
||
RestartSec=10
|
||
Environment="ANTHROPIC_API_KEY=xxx"
|
||
Environment="OPENAI_API_KEY=xxx"
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
## 六、使用工作流
|
||
|
||
### 日常流程
|
||
|
||
```
|
||
1. 发现资料
|
||
↓
|
||
2. Web Clipper剪藏 → 自动放入00-inbox/
|
||
↓
|
||
3. File Watcher检测 → 触发编译队列
|
||
↓
|
||
4. Compiler Worker处理:
|
||
- 预处理 → 01-raw/
|
||
- LLM生成摘要 → 03-wiki/Summaries/
|
||
- LLM提取概念 → 03-wiki/Concepts/
|
||
- 更新MOC → 03-wiki/MOCs/
|
||
- 建立反向链接
|
||
↓
|
||
5. Obsidian自动同步(通过WebDAV)
|
||
↓
|
||
6. 在Obsidian中查看生成的Wiki
|
||
```
|
||
|
||
### 查询流程
|
||
|
||
```
|
||
1. 在Obsidian中打开查询面板(或命令行)
|
||
↓
|
||
2. 输入问题
|
||
↓
|
||
3. 系统:
|
||
- 识别相关概念
|
||
- 读取Concepts/和Summaries/
|
||
- 组装上下文
|
||
- 调用LLM生成回答
|
||
↓
|
||
4. 输出:
|
||
- 直接回答(聊天形式)
|
||
- 或生成文档 → 04-outputs/
|
||
- 或生成可视化(图表/幻灯片)
|
||
```
|
||
|
||
## 七、扩展思路
|
||
|
||
### 7.1 未来增强
|
||
|
||
1. **语义搜索**:用向量数据库存储embedding,支持模糊查询
|
||
2. **多模态**:处理图片、音频、视频内容
|
||
3. **协作**:多人共享Wiki,权限管理
|
||
4. **版本控制**:Git集成,追踪概念演变
|
||
5. **AI Agent**:让LLM主动提出问题、建议研究方向
|
||
|
||
### 7.2 与OpenClaw集成
|
||
|
||
可以设计一个OpenClaw Skill:
|
||
- `/wiki ingest <url>` - 让Val帮你剪藏和编译
|
||
- `/wiki query <question>` - 查询你的知识库
|
||
- `/wiki stats` - 查看知识库统计
|
||
|
||
Val可以直接调用腾讯云的编译API,帮你管理个人知识库。
|
||
|
||
---
|
||
|
||
> **核心原则**:LLM维护Wiki,人负责提出问题和判断价值。
|
||
|
||
这是一个活的系统,随着使用它会越来越懂你的知识结构和兴趣方向。 |