用 WorkBuddy / Codex + Obsidian 搭建自生长的个人知识库实战
1. 为什么需要一个“自生长”的知识库
传统笔记工具(Notion、语雀、Evernote)的问题在于:你记什么,它就只有什么。所有知识都需要人工录入、人工归类、人工维护链接。当笔记数量突破几千条后,检索靠记忆、维护靠毅力,知识库最终沦为“数字仓库”——存得多、用得上。
“自生长”知识库的核心思路是把知识管理从人工劳动升级为系统能力:
- 自动采集:网页、PDF、音视频转写、RSS 自动落入知识库;
- 自动理解:AI 提取核心概念、生成摘要、打标签、建立链接;
- 自动生长:当你不断写入,系统自动发现“我应该补充什么”“哪些概念正在形成新的主题”;
- 自动检索:用向量语义检索取代关键词匹配。
本教程用三件套实现:
| 工具 | 角色 |
|---|---|
| Obsidian | 本地 Markdown 知识库,数据完全归你所有 |
| WorkBuddy(或 Codex CLI) | AI 智能体,负责解析、总结、结构化、生成新笔记 |
| Obsidian 社区插件 + Python 脚本 | 采集、调度、向量化、自动链接 |
最终效果:你丢给系统一篇文章或随手写下一段灵感,它自动变成结构化、可检索、可生长的新知识。
本文默认你使用 macOS 或 Linux。Windows 用户命令以 WSL2 为准,我会标注差异。
2. OpenCode / Codex:AI 编码智能体的差异与选择
这里的 “Codex” 指 OpenAI 的 Codex 系列(CLI / API),而 WorkBuddy 是类似的终端 AI 编码与自动化助手。它们都能:
- 读取本地文件、执行 shell 命令;
- 根据自然语言指令生成并修改文件;
- 通过 MCP(Model Context Protocol)或自定义工具连接外部服务。
本教程把它当作“知识库大脑”,负责执行我们写好的各类处理函数,比如:
- 输入一篇文章 → 输出结构化 Markdown;
- 输入一批笔记 → 生成 MOC(Map of Content)索引;
- 检索失败时给出联想建议。
选择建议:
- Codex CLI(
@openai/codex):适合有 OpenAI API Key,且乐于把 CLI 接入脚本流水线的场景; - WorkBuddy:适合需要更丰富内置 UI、快捷键和更贴合的本地工作流场景。
无论选哪个,核心原则一致:AI 只负责“认知”工作,文件落盘、调度、版本管理由脚本负责,保证知识库可复现、可回滚。
下面先以 Codex 为例做完整闭环,WorkBuddy 的适配方法在「8. 与 WorkBuddy 结合」中说明。
3. 环境准备:从零搭建基础工作台
3.1 安装 Obsidian 与基础配置
- 从 obsidian.md 下载安装;
- 创建本地 vault,目录建议为
~/knowledge-vault; - 建好以下目录结构(后续脚本依赖它):
mkdir -p ~/knowledge-vault/{00-inbox,10-notes,20-mocs,30-templates,40-archive,90-attachments,_scripts}
目录职责:
| 目录 | 用途 |
|---|---|
00-inbox | 待处理素材,AI 会自动清空并归档 |
10-notes | 正式原子笔记 |
20-mocs | 主题索引(Map of Content) |
30-templates | 笔记模板 |
40-archive | 已加工完的原始素材 |
90-attachments | 图片、PDF 附件 |
_scripts | 所有自动化脚本,不参与知识检索 |
3.2 安装 Codex CLI
# 需要 Node.js 18+
npm install -g @openai/codex
配置 API Key:
export OPENAI_API_KEY="sk-xxxx"
# 建议写入 ~/.zshrc 或 ~/.bashrc 持久化
echo 'export OPENAI_API_KEY="sk-xxxx"' >> ~/.zshrc
source ~/.zshrc
验证:
codex --version
3.3 安装 Python 依赖
本教程的“系统骨架”用 Python 实现,AI 智能体负责其中的认知环节。
python3 -m venv ~/knowledge-vault/_scripts/venv
source ~/knowledge-vault/_scripts/venv/bin/activate
pip install pyyaml python-frontmatter watchdog \
openai chromadb tqdm beautifulsoup4 markdownify
依赖说明:
python-frontmatter:读写 Obsidian 笔记的 YAML frontmatter;watchdog:监听文件变动,实现“落盘即触发”;chromadb:本地向量数据库,零成本语义检索;markdownify/beautifulsoup4:把网页转成干净的 Markdown。
3.4 安装 Obsidian 推荐插件
社区插件从 Obsidian 设置 → 第三方插件中搜索安装:
- Templater:笔记模板与动态变量;
- Dataview:像查数据库一样查笔记;
- QuickAdd:快速捕捉与执行宏;
- Natural Language Dates:自然语言日期,供模板使用;
- Local REST API:让外部脚本通过 HTTP 控制 Obsidian;
- Smart Connections(可选):内置向量检索,可替代自建 Chroma。
这些插件让手写笔记和自动流水线无缝衔接。
4. 设计知识库的笔记规范
自生长的前提是格式统一。这里定义一条“原子笔记”规范,所有 AI 输出都遵守它。
4.1 frontmatter 字段
每篇笔记头部:
---
uuid: 20261022-194500-8f3a
type: note
tags: [knowledge, ai]
source:
type: webpage
url: https://example.com/article
captured: 2026-10-22
aliases: []
related: []
created: 2026-10-22T19:45:00+08:00
---
# 笔记标题
正文内容...
字段含义:
uuid:全局唯一标识,由脚本生成;type:note(原子笔记)/moc(索引)/snippet(代码片段)/reflection(思考);tags:标签列表;source:来源元数据,便于溯源;related:关联笔记 uuid 列表,由 AI 建议、脚本维护。
4.2 创建笔记模板
把以下内容保存为 ~/knowledge-vault/30-templates/note-template.md:
---
uuid: <% tp.user.uuid() %>
type: note
tags: []
source:
type: manual
url: ""
captured: <% tp.file.creation_date("YYYY-MM-DD") %>
aliases: []
related: []
created: <% tp.file.creation_date("YYYY-MM-DDTHH:mm:ssZ") %>
---
# <% tp.file.title %>
## 核心要点
-
## 详情
## 关联
<!-- related-notes -->
在 Templater 插件中把该文件夹设置为模板目录,并创建 User Script uuid.js:
// 30-templates/scripts/uuid.js
async function uuid(tp) {
const crypto = await import("crypto");
return crypto.randomUUID();
}
module.exports = uuid;
5. 核心实战:搭建工作流引擎
我们让 AI 负责认知,脚本负责编排。整个系统分三层:
5.1 配置管理
创建 ~/knowledge-vault/_scripts/config.yaml(新增 AI 配置文件仍属你的本地可编辑内容,前端会按编辑器区块 ID 写入):
vault_root: /Users/yourname/knowledge-vault
openai_api_key_env: OPENAI_API_KEY
model: gpt-4o-mini
chroma_dir: .chroma
inbox: 00-inbox
notes: 10-notes
mocs: 20-mocs
archive: 40-archive
5.2 事件监听与素材捕获
用 watchdog 监听 00-inbox,一旦有文件出现就触发处理。创建 watcher.py:
import time
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from processor import process_inbox_file
class InboxHandler(FileSystemEventHandler):
def on_created(self, event):
if event.is_directory:
return
path = Path(event.src_path)
# 文件可能还没写完,稍等再处理
time.sleep(2)
if path.exists():
process_inbox_file(path)
if __name__ == "__main__":
import yaml
cfg = yaml.safe_load(Path("config.yaml").read_text())
inbox = Path(cfg["vault_root"]) / cfg["inbox"]
observer = Observer()
observer.schedule(InboxHandler(), str(inbox), recursive=False)
observer.start()
print(f"监听中: {inbox}")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
5.3 AI 处理入口:把素材变成原子笔记
创建 processor.py。这里用 OpenAI 官方 Python SDK,通过 codex CLI 批处理也可以,但直接用 SDK 更可控。
import hashlib
import uuid as uuid_lib
from datetime import datetime, timezone
from pathlib import Path
import frontmatter
import yaml
from openai import OpenAI
def load_cfg():
return yaml.safe_load(Path(__file__).parent.joinpath("config.yaml").read_text())
def prompt_for_note(text: str) -> str:
return f"""你是一名知识管理助手。请把下面的原始素材加工成一篇中文 Obsidian
原子笔记。要求:
1. 输出完整的 frontmatter(YAML),字段如下:
uuid: 留空,由系统填充
type: note
tags: 3-6 个英文小写标签
source: 用已知信息填充
aliases: 关键别名
related: 暂时留空
created: 当前时间 ISO8601
2. 正文包含「核心要点」「详情」「关联」三个二级标题。
3. 使用简洁、信息密度高的表达,保留原文关键事实和数据。
4. 只输出 Markdown,不要任何额外解释。
原文如下:
{text[:12000]}
"""
def process_inbox_file(path: Path):
cfg = load_cfg()
vault = Path(cfg["vault_root"])
notes_dir = vault / cfg["notes"]
archive_dir = vault / cfg["archive"]
raw = path.read_text(encoding="utf-8", errors="ignore")
client = OpenAI()
resp = client.chat.completions.create(
model=cfg["model"],
temperature=0.4,
messages=[{"role": "user", "content": prompt_for_note(raw)}],
)
md = resp.choices[0].message.content
# 用当前时间戳生成稳定 uuid
new_uuid = uuid_lib.uuid4().hex
note = frontmatter.loads(md)
note["uuid"] = new_uuid
note["created"] = datetime.now(timezone.utc).isoformat()
file_stem = f"{datetime.now():%Y%m%d-%H%M%S}-{new_uuid[:8]}"
out_path = notes_dir / f"{file_stem}.md"
out_path.write_text(frontmatter.dumps(note), encoding="utf-8")
# 归档原始素材
archive_path = archive_dir / path.name
path.rename(archive_path)
print(f"[OK] {path.name} -> {out_path.name}")
启动监听:
cd ~/knowledge-vault/_scripts
../venv/bin/python watcher.py
现在把任意一篇文章粘成 Markdown 丢进 00-inbox,几秒后它会出现在 10-notes,且被重新组织为原子笔记。
5.4 用 Codex 做“需要推理”的增强
纯 SDK 调用适合批量总结,但有些任务需要多步推理 + 读写文件,比如“把这 10 篇笔记整理成 MOC”。这种场景交给 Codex 更合适。
先创建一个任务目录,Codex 以工作区方式操作:
mkdir -p ~/knowledge-vault/_scripts/codex-jobs
cd ~/knowledge-vault/_scripts/codex-jobs
执行一个交互式会话:
codex "读取 ../10-notes 下最近 10 篇关于 AI 的笔记,生成一篇 MOC 索引,
保存为 ../20-mocs/AI-MOC.md。要求:按主题分小节,每题下用列表链接到原笔记。"
Codex 会自主读取目录、分析内容、生成文件。你可以在会话中继续追加要求,如“再给我总结每篇的核心论点”“检查哪些笔记互相重复”。
把同样逻辑固化成非交互脚本 build_moc.sh:
#!/usr/bin/env bash
# build_moc.sh <topic> <output>
TOPIC="$1"
OUTPUT="$2"
cd ~/knowledge-vault/_scripts/codex-jobs || exit 1
codex --no-interactive \
"读取 ../10-notes 下与“${TOPIC}”相关的笔记,生成中文 MOC 到 ../${OUTPUT}。\
使用与这些笔记一致的 frontmatter,type 为 moc,related 列出被引用笔记的 uuid。"
运行示例:
bash build_moc.sh "向量数据库" "20-mocs/Vector-DB-MOC.md"
6. 语义检索与自动关联:让知识“生长”
没有关联的知识库是孤立的,AI 自动关联是“生长”的关键一步。
6.1 向量入库
创建 indexer.py,把 10-notes 里所有笔记向量化存入 Chroma:
from pathlib import Path
import chromadb
import frontmatter
import yaml
from openai import OpenAI
def index_notes():
cfg = yaml.safe_load(Path("config.yaml").read_text())
vault = Path(cfg["vault_root"])
notes_dir = vault / cfg["notes"]
client = OpenAI()
chroma = chromadb.PersistentClient(path=str(vault / cfg["chroma_dir"]))
collection = chroma.get_or_create_collection("notes")
ids, docs, metas = [], [], []
for md_file in notes_dir.glob("*.md"):
post = frontmatter.loads(md_file.read_text(encoding="utf-8"))
text = post.content.strip()
if not text:
continue
emb = (
client.embeddings.create(model="text-embedding-3-small", input=text)
.data[0]
.embedding
)
ids.append(post.get("uuid", md_file.stem))
docs.append(text)
metas.append(
{
"path": str(md_file.relative_to(vault)),
"tags": ",".join(post.get("tags", [])),
}
)
collection.upsert(ids=ids, documents=docs, embeddings=None, metadatas=metas)
print(f"已索引 {len(ids)} 篇笔记")
if __name__ == "__main__":
index_notes()
为演示清晰,这里一次生成 embedding 再批量入库;笔记量大时可以在
index_notes里改成逐批collection.add处理。
运行:
python indexer.py
6.2 语义检索命令
创建 search.py:
import sys
from pathlib import Path
import chromadb
import yaml
from openai import OpenAI
def search(query: str, top_k: int = 5):
cfg = yaml.safe_load(Path("config.yaml").read_text())
vault = Path(cfg["vault_root"])
client = OpenAI()
chroma = chromadb.PersistentClient(path=str(vault / cfg["chroma_dir"]))
collection = chroma.get_collection("notes")
emb = (
client.embeddings.create(model="text-embedding-3-small", input=query)
.data[0]
.embedding
)
result = collection.query(query_embeddings=[emb], n_results=top_k)
for doc_id, meta, dist in zip(
result["ids"][0], result["metadatas"][0], result["distances"][0]
):
print(f"[{dist:.3f}] {meta['path']} ({meta['tags']})")
if __name__ == "__main__":
search(" ".join(sys.argv[1:]))
试一下:
python search.py "如何本地部署大模型并提供 API"
6.3 自动生成关联链
创建 link_suggest.py,为每篇新笔记找出最相关的 5 篇,再请 AI 判断应该建立哪些关联:
from pathlib import Path
import chromadb
import frontmatter
import yaml
from openai import OpenAI
def suggest_links(note_path: Path, top_k: int = 8):
cfg = yaml.safe_load(Path("config.yaml").read_text())
vault = Path(cfg["vault_root"])
client = OpenAI()
chroma = chromadb.PersistentClient(path=str(vault / cfg["chroma_dir"]))
collection = chroma.get_collection("notes")
post = frontmatter.loads(note_path.read_text(encoding="utf-8"))
text = post.content.strip()
emb = (
client.embeddings.create(model="text-embedding-3-small", input=text)
.data[0]
.embedding
)
result = collection.query(query_embeddings=[emb], n_results=top_k + 1)
candidates = []
for doc_id, meta in zip(result["ids"][0], result["metadatas"][0]):
if doc_id == post.get("uuid"):
continue
candidates.append(f"- {doc_id}: {meta['path']}")
prompt = f"""当前笔记 uuid:{post.get('uuid')}
候选相关笔记:
{chr(10).join(candidates)}
请从中选出 3-5 篇与当前笔记真正相关的,输出它们的 uuid 列表(一行一个)。"""
resp = client.chat.completions.create(
model=cfg["model"],
temperature=0,
messages=[{"role": "user", "content": prompt}],
)
ids = [line.strip() for line in resp.choices[0].message.content.splitlines()]
return ids[:5]
if __name__ == "__main__":
import sys
ids = suggest_links(Path(sys.argv[1]))
print(ids)
把关联写回 frontmatter 的逻辑放在 relate.py:
import sys
from pathlib import Path
import frontmatter
from link_suggest import suggest_links
path = Path(sys.argv[1])
post = frontmatter.loads(path.read_text(encoding="utf-8"))
post["related"] = suggest_links(path)
path.write_text(frontmatter.dumps(post), encoding="utf-8")
print("related 已更新,请手动 review")
关联写入采用“半自动”策略:先写回 frontmatter,用户可以在 Obsidian 里人工确认,避免 AI 过度自信产生错误链接。
把这两步接入 processor.py 的流程末尾,就实现了“新笔记落盘 → 自动找关联”的闭环。
7. 从采集到生长:完整流水线示例
现在把所有环节串成一条“采集 → 结构化 → 关联 → 索引”的流水线。创建 pipeline.py:
import sys
from pathlib import Path
from processor import process_inbox_file
from indexer import index_notes
from relate import relate_note
def run(inbox_file: str):
p = Path(inbox_file)
if not p.exists():
print("文件不存在")
return
# 1. AI 加工成原子笔记
process_inbox_file(p)
# 2. 找到刚归档前的原始文件对应生成的最新笔记
notes = sorted(
Path("10-notes").glob("*.md"), key=lambda x: x.stat().st_mtime, reverse=True
)
newest = notes[0]
# 3. 建议关联并写回
relate_note(newest)
# 4. 重建索引
index_notes()
if __name__ == "__main__":
run(sys.argv[1])
一次性跑通:
python pipeline.py "00-inbox/我的随手笔记.md"
终端输出中的“已索引 N 篇笔记”就是整个流程成功的标志。
8. 与 WorkBuddy 结合:换一个“大脑”同样运行
WorkBuddy 的定位与 Codex 类似,只是交互方式更偏重本地工作区与任务面板。替换成本很低:
- Step 1:把
_scripts作为 WorkBuddy 的工作区打开; - Step 2:把上一节生成 MOC 的提示词复制到 WorkBuddy 的任务输入中;
- Step 3:让 WorkBuddy 调用
python pipeline.py这类命令,而不是要求它自己写全部 Python; - Step 4:在 WorkBuddy 中保存常用的“知识库任务模板”,例如:
任务:整理本周新增笔记
步骤:
1. 读取 10-notes 下本周创建的笔记;
2. 按主题聚类,每组生成一条 MOC 摘要;
3. 对每条新笔记运行 relate_note;
4. 运行 index_notes 重建索引。
关键点:AI 智能体不是要替代流水线,而是成为流水线里最灵活的一个组件。当你需要它“读一批文件、自己决定怎么做、再执行”,就用 Codex 或 WorkBuddy;当你需要高频、稳定、可复现的批处理,就用 Python 脚本 + 定时任务。
9. 让知识库“定时生长”与防退化
9.1 定时任务
用 cron 每天整理一次,并检查断链:
crontab -e
加入:
# 每天 23:30 重建索引
30 23 * * * cd ~/knowledge-vault/_scripts && ./venv/bin/python indexer.py >> logs/index.log 2>&1
# 每周日凌晨 2 点生成 MOC
0 2 * * 0 cd ~/knowledge-vault/_scripts && bash build_moc.sh "每周摘要" "20-mocs/Weekly-MOC.md" >> logs/moc.log 2>&1
9.2 去重检测
自生长系统容易“长歪”——产生大量重复笔记。创建 dedupe_check.py:
from pathlib import Path
import chromadb
import yaml
from openai import OpenAI
def check_duplicates(threshold: float = 0.90):
cfg = yaml.safe_load(Path("config.yaml").read_text())
vault = Path(cfg["vault_root"])
client = OpenAI()
chroma = chromadb.PersistentClient(path=str(vault / cfg["chroma_dir"]))
collection = chroma.get_collection("notes")
result = collection.get(include=["documents", "metadatas"])
seen = []
for i, doc in enumerate(result["documents"]):
emb = (
client.embeddings.create(model="text-embedding-3-small", input=doc)
.data[0]
.embedding
)
similar = collection.query(
query_embeddings=[emb],
n_results=3,
where={"uuid": {"$ne": result["ids"][i]}},
)
for s_id, s_dist in zip(similar["ids"][0], similar["distances"][0]):
if s_dist < (1 - threshold):
seen.append((result["ids"][i], s_id, s_dist))
for a, b, d in seen:
print(f"疑似重复: {a} <-> {b} (dist={d:.3f})")
if __name__ == "__main__":
check_duplicates()
简单起见,这里的重复判定用的是相似度距离;距离小于
1 - threshold时视为可能重复,供人工判断,不自动删除。
9.3 数据备份与版本控制
Obsidian vault 天然适合 Git 管理。在 vault 根目录:
cd ~/knowledge-vault
git init
echo ".obsidian/workspace.json" >> .gitignore
echo ".chroma/" >> .gitignore
git add .
git commit -m "init knowledge vault"
再用 Obsidian 官方 Git 插件定时提交,或走系统 cron 提交。即使 AI 意外写坏某篇笔记,也能从历史中恢复。
10. 常见问题与调优建议
Q1:每次重建索引都要重新 embedding,太慢怎么办?
在 indexer.py 里为每篇笔记记录 mtime 元数据,只对 mtime 变化的文件重新生成 embedding。Chroma 的 collection.get 可取出已有 metadata 做增量判断。
Q2:AI 偶发生成不符合 frontmatter 的笔记。
把输出格式要求写进提示词,并在 processor.py 里用 frontmatter.loads 做校验;解析失败就重试一次,还失败则保留原文到 40-archive 并告警,不污染 10-notes。
Q3:想支持 PDF/图片。
PDF 先本地转纯文本(pdfminer.six 或命令行 pdftotext),图片用 Obsidian 插件或本地 OCR 后送入 process_inbox_file。处理完的二进制文件放 90-attachments,笔记里用 ![[附件名]] 关联。
Q4:本地隐私敏感文档怎么办?
本方案的数据只落在你自己的 vault 和本地 Chroma 里。AI 调用会发送文本,若非常敏感,建议对 processor.py 增加脱敏函数,或改用本地模型(如 Ollama)替换 OpenAI 客户端,只需要改 model 与 base_url。
Q5:WorkBuddy 和 Codex 可以同时用吗?
可以。Codex 用于批处理与流水线,WorkBuddy 用于你坐在电脑前交互式整理,二者操作同一个 vault,注意别同时写同一篇笔记即可。
11. 总结
用 Codex/WorkBuddy + Obsidian,我们搭出的不是一个“会记笔记的软件”,而是一套会自己消化、关联、补充的知识系统:
- 素材丢进
inbox,自动变原子笔记; - 每篇笔记自动找到语义邻居并建立
related关联; - 主题自动聚合成 MOC;
- 定时索引、去重检测、Git 版本管理,防止“长歪”。
启动这套系统只需要三步:
- 建好 vault 目录与模板;
- 跑
watcher.py监听收件箱; - 用
codex或 WorkBuddy 交互式地整理、提问、生成 MOC。
数据在你本地,规则由你定义,AI 只做认知工作。剩下的,就是不断投喂素材、持续校正提示词,让这个知识库越用越懂你。
更多推荐


所有评论(0)