「写一篇文档,让它生长。」—— 当 LLM 成为知识库的编译器,本地约定升级为云端服务。
2026 年 4 月,Andrej Karpathy 发布了一个被称为 "LLM Wiki"(或 "LLM Knowledge Bases")的模式。它不是一个软件,而是一套关于人类与 LLM Agent 如何分工维护知识的约定。本文先讲清楚这套理念,再以我们自己的一个云端实现(llm-wiki,部署在多租户 SaaS 平台 2Ryun 上)为主线,展示把「本地 markdown 文件夹」升级成「云端多租户知识库服务」时,工程上会遇到什么、又是怎么解决的。
01 引言:卡帕西的 LLM Wiki 理念
Karpathy 的核心比喻一句话概括:「Obsidian 是 IDE,LLM 是程序员,wiki 是代码库。」
传统上我们让 LLM 帮忙「检索」知识——问一个问题,现场从一堆文档里捞相关的片段拼答案(也就是 RAG)。Karpathy 认为这等于每次运行程序都重新读一遍源码。他说:你不会在每次运行程序前重读所有代码,而是编译一次,把成本摊到整个生命周期。知识也应该如此:在入库时就把杂乱材料「编译」成一份结构化、互相链接的 wiki,之后随取随用,而不是每次查询都从头现算。
这套模式有三层结构、三个操作:
| 层 | 内容 | 谁写 |
|---|---|---|
| /raw | 不可变的原始文档、文章、论文 | 人类(只读,Agent 绝不修改) |
| /wiki | LLM 维护的 markdown 页面:实体页、概念页、综合页 | 只有 Agent 写 |
| schema | 用自然语言约定结构、规范、工作流 | 人类设计 |
两个辅助文件让系统可检查:index.md(所有页面的一句话目录,Agent 先读它)、log.md(只追加的摄入/查询/检查流水账)。
三个操作
- Ingest(摄入):读一个新源 → 建摘要页 → 更新 index → 顺手更新 10-15 个相关页 → 自动生成交叉引用。
- Query(查询):回答问题的结果回填成新页面——每个问题都在让系统长大,复利增长。
- Lint(体检):周期性检查矛盾、过期声明、孤儿页、缺口。
Karpathy 明确把思想渊源追溯到 Vannevar Bush 1945 年的《As We May Think》和Memex——那台设想中的「知识机器」。Memex 之所以失败,是因为人工交叉引用不可持续;而 LLM Wiki 把维护成本降到近乎为零,让 Memex 在 80 年后第一次变得可行。
这套理念很美,但它有两个隐含前提:单机、单用户。当一个产品要做成云端多租户服务时,本地约定里的每一件事都要重新设计。本文要讲的,正是把「LLM 当编译器」这件事服务化的工程实践。
02 系统总览:从本地约定到云服务
我们的 llm-wiki 是 2Ryun 平台的一个插件式能力。2Ryun 是一个文档管理 + 知识库 + 建站的全栈 SaaS:前端 Nuxt,后端 Express + Mongoose,AI 层是一个 LangGraph 编排的 DeerFlow 服务。llm-wiki 的知识提取全部走 DeerFlow。
把卡帕西的本地约定翻译成云端服务,一一对应:
| 卡帕西本地约定 | 云端服务化 |
|---|---|
| /raw 原始文档 | 主平台的文档库(不可变来源) |
| /wiki markdown 页面 | wiki_entries 集合(结构化的条目,带溯源和置信度) |
| schema / agents.md | 提取与组织的 skill prompt(结构、分类、质量规则的唯一来源) |
| index.md 目录 | 语义检索(嵌入 + 余弦相似度) |
| log.md 流水账 | operation_log(每次 create/merge/link/stale 都留痕) |
| Ingest / Query / Lint | llm-wiki-extract / 语义搜索 / llm-wiki-organize |
本地约定靠人「手动把新文章丢进 /raw 然后让 Agent 跑一遍」;云端靠变更时自动触发——文档一保存,后端就异步通知 wiki-service 提取。这就是「把维护成本降到零」在服务端的落地:不是人记得去 ingest,而是系统自己感知。
03 提取管线:LLM 如何「编译」文档
3.1 触发:变更即提取
文档在编辑器里保存后,主后端调用 wiki-service 的 notify-update。提取是异步的——写文档的请求绝不阻塞在 LLM 调用上,用户保存完立刻返回,知识在后台「生长」。每条提取还有去重语义:skip_if_extracted 会跳过已处理的文档,幂等。
3.2 DeerFlow:三个 skill 对应三种操作
wiki-service 自己不碰 LLM,它通过 HTTP 调用 DeerFlow 的无状态 run 接口,由 DeerFlow(LangGraph 编排)去执行 LLM。一共三个 skill,恰好覆盖卡帕西的三个操作:
llm-wiki-extract → Ingest:从文档内容提取条目 llm-wiki-organize → Lint:合并、关联、聚簇、标记过期、生成洞察 llm-wiki-maintain → 新证据出现时增量更新既有条目
这种「编排层 + 无状态接口」的解耦很关键:wiki-service 不关心 LLM 是哪个模型、有没有流式、prompt 怎么拼,它只发内容、收结构化 JSON。换模型、换 skill 都不影响存储层。
3.3 提取 prompt:内容的「可信」是设计出来的
提取不是「把文档丢给 LLM 让它总结」,而是带着严格约束的结构化提取。看 _build_extract_prompt 的核心约定:
For each entity (concept, person, project, event, location, organization, technology, etc.) found, output: - title: Concise descriptive title - content: Well-structured markdown — ONLY use info explicitly stated in the document - summary: One-sentence description - category: concept|person|project|event|location|organization|technology|tool|... - confidence_tier: extracted|inferred|ambiguous - confidence_score: 0.9+ for explicit, 0.7-0.8 for implied, 0.5-0.6 for tentative - text_spans: exact text snippet(s) from the document that this entry is based on - tags: 2-5 keywords - related_titles: titles of existing entries this relates to (if provided) - related_labels: VERY SHORT label (≤15 chars) describing HOW they relate CRITICAL — Content Rules: - The 'content' field must ONLY contain facts, descriptions, and claims - that APPEAR IN THE DOCUMENT - Do NOT inject your own knowledge, definitions, background, or examples - If the doc mentions '冠脉搭桥' without explaining it, do NOT add an explanation
这里藏着整个知识库可信度的三根支柱:
内容只来自原文 + text_spans 溯源
每条内容都被约束为「文档里明确写了的」,并给出原文片段作为证据。用 prompt 约束 + 溯源字段把 LLM 幻觉污染挡在源头。
置信度分档
confidence_tier 区分三种知识:extracted(0.9+)、inferred(0.7-0.8)、ambiguous(0.5-0.6)。本地靠人肉判断,云端内化成条目的一等字段。
Enrichments 与 content 分离
LLM 在文档之外的知识放进独立的 enrichments 数组,作为待审补充,不写进内容本体。这是「LLM 编译」和「LLM 创作」的清晰分界。
这三根支柱本质上是把卡帕西 schema(agents.md 里的约定)固化成了 prompt 里的硬规则 + 数据模型里的字段。Schema 从一份人类可读的约定,变成了提取管线里强制执行的结构。
04 组织与关联:让知识长出结构
光有提取,得到的是一堆平铺的条目。知识库的「意义」在于关系——这正是 Karpathy 说的交叉引用,也是 Memex 当年死在手工作坊里的地方。本项目把「交叉引用」也交给了 LLM 和向量。
4.1 organize:去重、聚簇、过期
llm-wiki-organize 一次运行做四件事:
- 重复合并:canonical selection → 智能合并(merge_entries 保留信息不丢失)。
- 聚簇:社区发现产出 wiki_clusters,每个簇有中心条目和成员列表。
- 过期标记:检测陈旧条目,打 stale 标。
- 洞察生成:在簇/根级别提炼模式、主题、gap——insights。
organize 同样支持 organize-by-root:按文档树范围做,并把 root_id 写回条目。
4.2 三类边:system / llm / semantic
条目之间的关系来自三个来源,前端图谱用不同颜色/线型区分:
- system:同文档、父子、同根、同看板——来自文档本身的结构,无需 LLM。
- llm:提取时 LLM 给出的语义关系(related_titles + related_labels,如 extends、contradicts、depends_on……),标签 ≤15 字。
- semantic:嵌入向量的相似度自动连边。
这套「来源可溯的三类边」比本地约定的手写 [[链接]] 走得更远:云端靠结构化的关系元数据,图谱能直接渲染、筛选、按类型着色。
4.3 图谱
graph_builder 把 entries + links + clusters 组装成前端可直接消费的 GraphData(nodes / edges / clusters / insights)。每个节点带 category、confidence_tier、confidence_score、stale;每条边带 link_source、link_type、strength。前端实现了 2D 力导向 + 3D 球形视图(d3-force-3d + three.js)。
05 检索:语义搜索
卡帕西的本地方案里,Agent 先读 index.md 找到相关页面。云端的规模不允许「把目录塞进上下文」,本项目用嵌入做语义检索:
async def search_entries(self, user_id, query, max_results=10):
# 优先语义:query 向量化,与有条目的向量做余弦相似度
query_vec = await compute_embedding(query)
if query_vec:
results = await self._semantic_search(user_id, query_vec, max_results)
if results:
return results
# 兜底:关键词全文检索
return await self._keyword_search(user_id, query, max_results)
嵌入默认走 Qwen text-embedding-v3(OpenAI 兼容接口),在嵌入服务不可用时降级为「关键词重叠向量」再退到全文搜索——逐级降级,语义优先,可用性兜底。这正是 index.md 的规模化替代:索引不再是一份人类可读的目录,而是每个条目生成时就写好的向量。
卡帕西的 Query 会「回填」——每个问题都会长成新页面,系统复利增长。本项目的检索目前是只读的:搜索命中、但不把「这个问题 + 答案」沉淀回知识库。这是理念与实现之间最明显的一条差距,也是未来「maintain」之外值得补的一环。
06 前端与质量护栏
前端是一个插件(@dave/llm-wiki),挂在 2Ryun 的插件系统上。它不是一个孤立的页面,而是和文档编辑器深度集成:
- WikiSidebar:文档侧栏展示提取状态,可一键初始化、重提取。
- WikiMain:知识库主界面,Google 风格搜索 + 条目/图谱两个 tab。
- WikiEntryCard:条目详情,展示置信度徽标、分类、标签、来源、关联、待审 enrichments。
- WikiGraph:2D/3D 知识图谱,按类型/度数/置信度着色,聚焦时邻居高亮。
- InsightsPanel / PendingEnrichmentsList:洞察列表 + AI 补充的人工审核队列。
质量护栏贯穿全链路:置信度徽标让「这条是原文说的还是模型推的」一眼可见;text_spans 让每条内容都能点回原文;source_gap 类 enrichments 主动标注「这条没有出处」;而 AI 的补充一律进待审,不自动写进内容。这些护栏合起来,回答了知识库产品最关键的问题:「这里面的东西,我凭什么信?」
07 理念验证与反思
把卡帕西的三操作对照本项目,大部分对得上:
| 卡帕西操作 | 本项目实现 |
|---|---|
| Ingest(摄入新源→建页→交叉引用) | notify-update 自动触发 + llm-wiki-extract |
| Lint(矛盾/过期/孤儿/缺口) | llm-wiki-organize(聚簇/去重/过期/洞察) |
| Query(检索 + 回填) | 语义检索(缺回填,见上文) |
| /raw 不可变 | 文档库 + text_spans 溯源 |
| log.md | operation_log |
云端化解决了什么:把「维护成本接近零」从人的自觉变成了系统的自动——文档一保存就提取、图谱实时可看、多租户数据天然隔离(所有查询都带 user_id)、嵌入索引入库即生成。
牺牲了什么:卡帕西模式最迷人的地方是产物是纯 markdown——人可以直接读、直接改、直接 diff。云端落地后,知识变成数据库里的条目 + 嵌入向量,人失去了对「编译结果」的直接可编辑性;可控性转移到了「提取 prompt 写得好不好」。这恰好印证了批评者说的「Schema 是瓶颈」——在本项目里,瓶颈就是那三份 skill prompt 和它们产出的 JSON schema。
局限(与 Karpathy 的批评者共识)
错误复利
提取阶段的一个错误「事实」,会被 organize、洞察、图谱放大,而检查它的同样是那个会犯错的 LLM。缓解是置信度分档和 enrichments 待审,但没有根治。
规模
仍是「提取一批文档→管理条目」的模型,不是卡帕西设想的长期积累复利的生长体。真正到百万级,图谱和检索需要新工程(节点预算、布局后端化、WASM 物理等)。
「编译」不等于理解
维护良好的知识库 ≠ 使用者真懂这些知识。把整理工作外包给 LLM 的人,可能收获一个自己没消化过的 wiki。
08 结语
Karpathy 的 LLM Wiki 把「知识维护」从一种劳动变成了一种约定:人做策展(决定读什么、问什么),LLM 做编译(建页、交叉引用、体检),产物是可读、可溯源、复利增长的知识体。本文的 llm-wiki 把这套约定搬上了云端:用自动触发取代手动 ingest,用结构化条目 + 溯源 + 置信度取代自由 markdown,用嵌入检索取代 index.md,用图谱取代手写链接。
两条主线交织出的启示是:理念是「编译一次」,工程是「让编译可信」。卡帕西给了方向,而把方向做成一个别人敢用的产品,靠的是 prompt 里的硬约束、数据模型里的置信度、以及「内容忠于源、补充单独隔离」这条把 LLM 当编译器而不是作者的纪律。
Andrej Karpathy「LLM Knowledge Bases」
本项目代码位于 packages/extensions/wiki-service/(提取/组织/检索/图谱)
与 packages/frontend/plugins/@dave/llm-wiki/(前端插件)