Karpathy 的 LLM Wiki 到底是什么?完整拆解+实操路径及OKF

4 月 3 日,Andrej Karpathy 在 X 上发了一条长帖,标题就三个词:LLM Knowledge Bases。

这条帖子的数据有点夸张——1500 万浏览,4.8 万转发,8.8 万收藏。两天后他又追加了一篇完整的方法论文档,放在 GitHub Gist 上,评论区也炸了。

我花了一天时间把原帖、Gist 文档、社区讨论全部读了一遍。这不是一个新工具推荐,是一套”用 LLM 管理知识”的方法论。读完之后我有点被刷新——原来 LLM 最该干的事,可能不是帮你写代码,而是帮你”编知识”。

下面把这套东西拆开看看。

一句话说清楚:LLM Wiki 是什么

说白了就是:你把各种原始资料(文章、论文、笔记、图片)丢给 LLM,LLM 帮你把这些资料”编译”成一个结构化的 Markdown wiki——带分类、带摘要、带交叉链接、带索引。

跟 RAG 的区别在哪?RAG 是每次提问都从原始文档里临时检索拼凑答案,知识不会积累。LLM Wiki 是提前把知识”编译”好,存成持久化的 wiki 文件,每次新增资料都会更新已有的页面。知识是会”长”的。

用 Karpathy 自己的类比:Obsidian 是 IDE,LLM 是程序员,wiki 是代码库。你几乎不直接编辑 wiki,那是 LLM 的领地。

三层架构:Raw → Wiki → Schema

Karpathy 在 Gist 文档里把整个系统拆成了三层,每层职责分明:

第一层:Raw Sources(原始资料)

你的资料库。文章、论文、图片、数据文件,什么都往里丢。这一层是不可变的——LLM 只读不写,这是你的信息源头。

实操上,Karpathy 用 Obsidian Web Clipper 浏览器插件把网页文章一键转成 Markdown,再用快捷键把文章里的图片全部下载到本地。这样 LLM 就能直接读图,不用依赖可能失效的外链。

第二层:Wiki(知识库)

LLM 生成和维护的 Markdown 文件集合。包括:摘要页、实体页、概念页、对比分析、综述文章、索引文件。所有页面之间有交叉链接。

关键点:这一层完全由 LLM 拥有。你读,它写。每次新增一个原始资料,LLM 不只是写一篇摘要,它会更新所有相关的实体页、概念页,标注新旧数据的矛盾,维护交叉引用。一个新资料可能触发 10-15 个页面的更新。

第三层:Schema(规则文件)

一个配置文档(比如 Claude Code 的 CLAUDE.md),告诉 LLM wiki 的结构规范、命名约定、工作流程。这是让 LLM 从”通用聊天机器人”变成”专业 wiki 维护员”的关键。你和 LLM 一起迭代这个文件,越用越精确。

三大核心操作:Ingest、Query、Lint

架构搭好之后,日常使用就围绕三个动作展开。

Ingest(摄入)

往 raw 目录丢一个新资料,让 LLM 处理它。LLM 会读原文,写摘要页,更新索引,然后扫一遍 wiki 里所有相关页面做增量更新。

Karpathy 说他更喜欢一次处理一个资料,全程参与——读 LLM 写的摘要,检查更新,引导 LLM 该强调什么。当然你也可以批量丢一堆资料让 LLM 自己处理,看你的风格。

Query(查询)

对着 wiki 提问。LLM 先读索引文件找到相关页面,再深入阅读,最后综合回答。答案可以是 Markdown 文档、对比表格、Marp 幻灯片、matplotlib 图表——取决于你问什么。

这里有个我觉得很聪明的地方:好的回答可以反哺 wiki。你做了一个对比分析,觉得有价值?存回 wiki 变成新页面。你的每次提问都在给知识库”加料”,不会消失在聊天记录里。

Lint(健康检查)

定期让 LLM 给 wiki 做体检:找矛盾的数据、过时的结论、没有入链的孤立页面、被提到但还没有独立页面的概念、可以用网络搜索补充的数据缺口。

Karpathy 说 LLM 很擅长”建议你接下来该研究什么”。想想看,这就是自动化的知识图谱扩展。

索引的秘密:为什么不需要 RAG

很多人第一反应是:wiki 大了之后,LLM 怎么找到相关内容?不需要向量数据库和 RAG 吗?

Karpathy 的回答出乎意料:不需要。至少在他的规模下(约 100 篇文章,40 万字)不需要。

秘密在两个文件:

  • index.md:内容索引。每个 wiki 页面一行,包含链接、一句话摘要、分类标签。LLM 回答问题时先读这个文件,就知道该去看哪些页面。
  • log.md:操作日志。按时间记录每次摄入、查询、检查的操作。格式统一(比如 ## [2026-04-02] ingest | 文章标题),用 grep 就能快速回溯。

这个方案妙在哪?LLM 自己维护索引,索引质量随着 wiki 成长自动提升。不需要额外基础设施,一个目录的 Markdown 文件就够了。

当然,wiki 再大一些可能就需要搜索工具了。Karpathy 推荐了 qmd——一个本地 Markdown 搜索引擎,支持 BM25 和向量混合搜索,有 CLI 和 MCP server 两种接入方式。

真实案例:Farzapedia——2500 条日记变成 400 篇文章

光看方法论可能还是抽象。说个真实的例子。

4 月 4 日,一个叫 Farza(@FarzaTV)的开发者发了一条推文,标题是”This is Farzapedia”。他把 2500 条日记、Apple Notes 笔记和部分 iMessage 对话喂给 LLM,生成了一个关于自己的个人 Wikipedia——400 篇详细文章,覆盖朋友、创业项目、研究方向,甚至他喜欢的动漫对他的影响。所有文章之间都有反向链接。

有意思的是,Farza 说这个 wiki 不是给自己看的——是给他的 AI agent 用的。

他举了一个例子:设计新产品的落地页时,他问 agent:”去看看最近启发我的图片和电影,给我一些文案和视觉方向的建议。”Agent 从 wiki 里翻出了他关于吉卜力纪录片的笔记、他截图过的 YC 公司落地页、还有他几年前保存的 1970 年代 Beatles 周边设计。然后给出了一个融合这些灵感的方案。

Farza 之前用 RAG 做过类似的系统,他的原话是”it was ass”(烂透了)。文件系统结构的 wiki 让 agent 能真正理解和导航知识,比向量检索靠谱得多。

这条推文也火了:123 万浏览,3825 点赞,4710 收藏。

社区实战经验:6 条生产环境教训

Karpathy 的 Gist 评论区也很精彩。一个叫 bluewater8008 的用户分享了他们团队在生产环境跑了几周 LLM Wiki 后的经验,我觉得比原文还实用:

1. 先分类再提取。 不要把所有文档一视同仁。50 页的报告和 2 页的信件需要不同的处理策略。先按类型分类,再用类型专属的提取流程。这能省大量 token,结果也更好。

2. 给索引设 token 预算。 他们用了四级渐进式披露:L0(约 200 token,项目上下文,每次会话都加载)、L1(1-2K,索引文件,会话开始时加载)、L2(2-5K,搜索结果)、L3(5-20K,完整文章)。关键纪律:不读完索引就不读全文。

3. 每种实体类型一个模板。 人物页、事件页、文档摘要页需要不同的字段结构。他们定义了 7 种实体类型,每种有专属的必填字段。LLM 会严格遵守,wiki 的结构一致性就有了保障。

4. 每个任务产出两个输出。 这条最关键。用户问了一个分析问题,LLM 给出答案——这是输出一。输出二是把相关发现更新回 wiki 对应的文章。如果不在 schema 里明确要求这一点,LLM 做完分析就把知识丢在聊天记录里了。

5. 从第一天就设计跨域标签。 如果你的知识可能跨多个项目、客户或研究领域,在 frontmatter 里加 domain 标签。出现在多个领域的共享实体(人物、组织、概念)会成为知识图谱里最有价值的节点。后期补这个很痛苦。

6. 人类负责验证。 LLM 可以在不引用来源的情况下做综合,你不仔细看根本发现不了。在 schema 里强制要求来源引用,定期抽查 wiki 内容——不只是查最终交付物。LLM 是作者,你是主编。

一个有意思的彩蛋:idea file

Karpathy 在追加推文里提到了一个概念,值得单独说一下。

他说这条推文火了之后,他没有选择开源一个具体的代码仓库,而是写了一个”idea file”——就是那个 Gist 文档。他的理由是:在 LLM agent 时代,分享想法比分享代码更有意义。你把 idea file 丢给你的 agent,agent 会根据你的具体需求定制和构建整个系统。

这条追加推文本身也获得了 2709 转发和 4 万收藏。

想想看,这是一种新的知识传播方式:不是给你一个成品让你 fork,而是给你一个想法让你的 AI 帮你从零构建。每个人得到的实现都不一样,核心模式是一致的。

历史回响:80 年前就有人想到了

Karpathy 在 Gist 文档的最后提到了 Vannevar Bush 1945 年发表的文章”As We May Think”和他提出的 Memex 概念。

Bush 当年设想了一种个人知识设备:用户可以存储所有书籍和记录,在任意两个条目之间建立永久链接,形成”思维路径”(trails)。这些路径可以分享给别人,别人可以在自己的 Memex 里继续扩展。

听起来是不是很像 LLM Wiki?关联索引、个人知识库、可分享的知识路径。Bush 在 80 年前就想清楚了。他没解决的问题是:谁来做维护?

LLM 补上了这最后一环。

想试试?快速上手路径

如果你想自己搭一个 LLM Wiki,这是最小可用路径:

  1. 准备工具:安装 Obsidian + Obsidian Web Clipper 浏览器插件。在 Obsidian 设置里把附件目录指定到 raw/assets/,绑一个快捷键用来下载文章图片。
  2. 创建目录结构:
    • raw/ — 放原始资料(用 Web Clipper 剪藏的文章、手动放入的 PDF 和图片)
    • wiki/ — LLM 生成和维护的知识页面
    • wiki/index.md — 内容索引
    • wiki/log.md — 操作日志
    • CLAUDE.md(或对应的 agent 配置文件)— schema 规则
  3. 写 Schema:把 Karpathy 的 Gist 文档(链接见文末)直接丢给你的 LLM agent,让它帮你生成一份适合你领域的 schema。告诉它你的研究方向、你想要的页面类型、你偏好的工作流程。
  4. 开始摄入:丢第一篇资料进 raw/,让 LLM 处理。检查生成的 wiki 页面,调整 schema,再丢第二篇。前 5-10 篇资料是调校期,之后就顺了。
  5. 日常使用:在 Obsidian 里浏览 wiki,在 LLM agent 里提问和摄入新资料。定期跑一次 Lint。

不需要向量数据库,不需要 RAG 框架,不需要部署服务。一个目录的 Markdown 文件加一个 LLM agent,就这样。

反思

读完 Karpathy 的方法论,我一直在想一个问题:这套模式放到企业里会怎样?

现在大多数公司的知识库都是”写了没人维护”的状态。Confluence 里躺着三年前的文档,Notion 里的项目记录半年没更新,新人入职翻半天找不到想要的东西。问题不是没人想维护,是维护成本太高——谁愿意每次开完会还要花半小时更新五个相关文档的交叉引用?

LLM Wiki 模式可能真的能解决这个问题。想象一下:会议纪要、Slack 讨论、客户反馈、项目文档全部作为 raw source 喂进去,LLM 自动维护一个结构化的内部 wiki。新人入职直接对着 wiki 提问,LLM 从索引里找到相关页面综合回答。每次有新的会议纪要进来,相关的项目页、人物页、决策记录都自动更新。

当然,企业场景比个人场景复杂得多。数据安全、权限控制、多人协作的冲突处理,这些 Karpathy 的方案都没涉及。但方向是对的:让 LLM 承担知识库的”记账”工作,人只负责输入和决策。

说几个具体的问题:

  • 规模上限不明确。 Karpathy 自己的 wiki 大概 100 篇文章、40 万字。再大一个量级会怎样?索引文件还够用吗?LLM 的上下文窗口能不能覆盖?他没说。
  • 对 LLM 能力有要求。 这套方法论默认你用的是顶级模型(Claude、GPT-4 级别)。小模型跑 Ingest 和 Lint 效果可能打折扣。
  • 冷启动需要耐心。 前 5-10 篇资料的摄入过程需要你深度参与,调校 schema 和 wiki 结构。不是”丢进去就能用”的东西。
  • 验证成本容易被低估。 bluewater8008 的第 6 条经验说得对:LLM 会在不引用来源的情况下做综合。如果你用这个系统做严肃研究或商业决策,抽查验证的时间要算进去。

一句话总结

如果你经常需要在某个领域持续积累和检索知识,Karpathy 的 LLM Wiki 模式值得一试。它不是一个工具,是一种思路——把 LLM 从”问答机器”变成”知识编译器”。

Obsidian + 任意 LLM agent + 一个目录的 Markdown 文件,门槛不高,上限很高。

作者:NikoAI编程
链接:https://juejin.cn/post/7625301482213130291

okf

目录

  1. OKF 概述
  2. 核心术语
  3. Bundle 目录结构规范
  4. Concept 文档编写规范
  5. 交叉链接规则
  6. Index 与 Log 文件
  7. 引用规范
  8. 一致性校验
  9. Reference Agent 自动化生成流程
  10. 可视化生成流程
  11. 完整操作流程示例(GA4 实例)
  12. 三大实例 Bundle 结构对比
  13. 周边工具链
  14. 最佳实践与注意事项

1. OKF 概述

Open Knowledge Format (OKF) 是一种开放的、厂商中立的格式,用于将知识——即围绕数据和系统的元数据、上下文和精选洞察——表示为带 YAML frontmatter 的纯 Markdown 文件。

设计理念

特性说明
人类与 Agent 可读无需 SDK 或查询语言,工程师可 cat 概念文档,LLM 可直接将其载入上下文
版本可控Bundle 存放在 Git 中,PR、diff、blame、review 工作流开箱即用
便携无锁定Bundle 是一个目录,可打包为 tarball、托管在任何仓库、从任何文件系统挂载
结构化与非结构化混合frontmatter 提供可查询字段,markdown body 提供人类和 LLM 实际阅读的叙述
最小化约束仅标准化少量必填字段,允许生产者自由扩展
渐进式披露自动生成的 index.md 让 Agent 或人类逐层导航层级结构
图状而非树状概念间通过 markdown 链接相互引用,表达比目录父子更丰富的关系

目标

  1. 定义一个通用格式,富化 Agent (Enrichment Agent) 可以写入
  2. 指导消费 Agent (Consumption Agent) 如何读取和遍历
  3. 促进跨系统和组织的知识交换
  4. 标准化少量必填字段

非目标

  • 不定义固定的概念类型分类法
  • 不规定存储、服务或查询基础设施
  • 不替代领域特定 schema (Avro, Protobuf, OpenAPI 等) — OKF *引用*它们,不取代

2. 核心术语

术语定义
Knowledge Bundle自包含的、分层级的知识文档集合,是分发的单位
ConceptBundle 中的一个知识单元,表示为一个 markdown 文档。可描述有形资产(表、API)或抽象概念(指标、流程)
Concept ID概念文件在 Bundle 中的路径,去掉 .md 后缀。例如 tables/users.md 的 ID 为 tables/users
Frontmatter文件顶部由 — 分隔的 YAML 元数据块
Bodyfrontmatter 之后的所有内容
Link从一个概念到另一个概念的标准 markdown 链接
Citation从概念到外部来源的链接,支持 body 中的声明

3. Bundle 目录结构规范

3.1 基本结构

path/to/bundle/
├── index.md                      # 可选。目录列表,用于渐进式披露
├── log.md                        # 可选。更新历史
├── <concept>.md                  # Bundle 根目录下的概念
└── <subdirectory>/               # 子目录将概念分组
    ├── index.md
    ├── <concept>.md
    └── <subdirectory>/
        └── …

3.2 保留文件名

文件名用途规则
index.md目录列表(见 §6)MUST NOT 用作概念文档
log.md更新历史(见 §7)MUST NOT 用作概念文档

所有其他 .md 文件都是概念文档。

3.3 分发形式

  • Git 仓库(推荐 — 提供历史、归属、diff)
  • tarball 或 zip 归档
  • 更大仓库中的一个子目录

3.4 实际实例结构

以 GA4 Bundle 为例,实际产出的目录结构为:

bundles/ga4/
├── index.md                              ← 根索引
├── datasets/
│   ├── index.md                          ← 数据集目录索引
│   └── ga4_obfuscated_sample_ecommerce.md  ← 数据集概念文档
├── tables/
│   ├── index.md                          ← 表目录索引
│   └── events_.md                        ← 表概念文档(含完整 schema)
├── references/
│   ├── index.md                          ← 引用目录索引
│   ├── joins/
│   │   ├── index.md
│   │   └── events___ads_clickstats.md    ← Join 引用文档
│   └── metrics/
│       ├── index.md
│       ├── event_count.md                ← 指标引用文档
│       ├── user_count.md
│       ├── day_count.md
│       ├── new_user_count.md
│       ├── avg_pageviews.md
│       ├── avg_transactions_per_purchaser.md
│       ├── avg_spend_per_purchase_session_by_user.md
│       └── overall_avg_spend_per_purchase_session.md
└── viz.html                              ← 可视化 HTML(可选)

4. Concept 文档编写规范

每个概念是一个 UTF-8 Markdown 文件,由两部分组成:

  1. YAML frontmatter 块 — 以 --- 开头和结尾
  2. Markdown body — 自由格式内容

4.1 Frontmatter 字段

---
type: <Type name>                  # 必填 (REQUIRED)
title: <Optional display name>     # 推荐
description: <Optional one-line summary>  # 推荐
resource: <Optional canonical URI>       # 推荐
tags: [<tag>, <tag>, …]            # 可选
timestamp: <ISO 8601 datetime>     # 可选,最后修改时间
# … 其他生产者自定义键值对
---

必填字段

字段说明示例值
type标识概念类型的短字符串,消费者用于路由、过滤和展示BigQuery Table, BigQuery Dataset, Reference, Metric, Playbook

Type 值不在中心注册。生产者应选择描述性、自解释的值;消费者必须优雅地容忍未知类型。

推荐字段(按优先级排序)

优先级字段说明
1title人类可读显示名。省略时消费者可从文件名推导
2description单句概括概念。用于 index.md 生成器、搜索摘要和预览
3resource唯一标识概念所描述底层资产的 URI。描述抽象概念时省略
4tagsYAML 列表,用于交叉分类
5timestampISO 8601 最后修改时间

扩展字段

生产者可包含任何额外键。消费者应保留未知键,不应拒绝包含未识别字段的文档。

注意:Reference Agent 实现中 (document.py),必填键为 type, title, description, timestamp 四项。frontmatter 键的推荐顺序为:type → resource → title → description → tags → timestamp。

4.2 Body 规范

Body 是标准 Markdown。生产者应优先使用结构化 Markdown — 标题、列表、表格、围栏代码块 — 而非自由散文,因为结构有助于人类阅读和 Agent 检索。

约定章节标题

标题用途
# Schema资产列/字段的结构化描述
# Examples具体使用示例,通常为围栏代码块
# Citations支持 body 中声明的外部来源(见 §7)

Reference Agent 生成表文档时遵循以下 body 顺序:

  1. 短散文描述(1-3 段)— 描述概念是什么、代表什么、通常如何使用
  2. # Schema — 扁平化、可读的字段摘要。对嵌套 RECORD 字段,缩进或表格格式化其子字段
  3. # Common query patterns — 1-3 个短 SQL 片段,用 `__CODE_BLOCK_4__yaml --- type: BigQuery Table resource: https://bigquery.googleapis.com/v2/projects/bigquery-public-data/datasets/ga4_obfuscated_sample_ecommerce/tables/events_* title: Events table (Google Analytics BigQuery Export) description: Contains Google Analytics event export data from thega4_obfuscated_sample_ecommerce` dataset. tags:
  • events
  • Google Analytics
  • BigQuery
  • ecommerce
  • schema
  • basic queries
  • advanced queries timestamp: ‘2026-05-28T22:53:05+00:00’ —
Body 包含 `# Overview`、`# Metrics`(链接到指标引用)、`# Schema`(详细字段描述,包括 `event`、`user`、`device`、`geo`、`items` 等 RECORD)、`# Joins`(链接到 join 引用)、`# Citations`。

### 4.4 实例:未绑定资源的概念

以指标引用 `references/metrics/user_count.md` 为例:

```yaml
---
type: Reference
resource: https://developers.google.com/analytics/bigquery/web-ecommerce-demo-dataset
title: User Count
description: Total number of unique users.
tags:
- metric
timestamp: '2026-05-28T22:50:09+00:00'
---

Total number of unique users.

```sql
COUNT(DISTINCT user_pseudo_id)

Citations

### 4.5 实例:Join 引用概念

以 `references/joins/events___ads_clickstats.md` 为例:

```yaml
---
type: Reference
resource: https://developers.google.com/analytics/bigquery/basic-queries
title: Join Google Analytics Events to Google Ads Clicks
description: Join Google Analytics event data with Google Ads click data.
tags:
- join
- Google Ads
timestamp: '2026-05-28T22:51:46+00:00'
---

Join Google Analytics event data with Google Ads click data.

__CODE_BLOCK_8__

# Citations
- https://developers.google.com/analytics/bigquery/basic-queries

5. 交叉链接规则

概念间可使用标准 markdown 链接相互引用。支持两种形式:

5.1 绝对链接(Bundle 相对)

以 / 开头,相对于 Bundle 根目录解释。

See the [customers table](/tables/customers.md) for the join key.
__CODE_BLOCK_10__markdown
See the [neighboring concept](./other.md).

从 tables/events_.md 链接到其他概念的示例:

链接目标类型示例路径
同级表[users](users.md)
父数据集[dataset](../datasets/ga4_obfuscated_sample_ecommerce.md)
引用文档[Event Count](../references/metrics/event_count.md)

5.3 链接语义

  • 从概念 A 到概念 B 的链接断言一种关系。具体关系类型由周围散文传达,而非链接本身
  • 构建图视图的消费者通常将所有链接视为无类型关系的有向边
  • 消费者必须容忍断链 — 目标不存在的链接不是格式错误,可能表示尚未编写的知识

5.4 Reference Agent 链接规则

  1. 仅使用文件相对路径。绝不以 / 开头(在 GitHub 渲染中会失效)
  2. 仅链接到 list_concepts() 返回的 ID。不得发明链接目标
  3. 每个章节每个概念提及一个链接足够。不要过度链接
  4. 不要从标题、围栏代码块或 schema 字段名列表中链接
  5. 不要将当前文档链接到自身

6. Index 与 Log 文件

6.1 Index 文件 (index.md)

index.md 可出现在任何目录(包括 Bundle 根)。它枚举目录内容以支持渐进式披露。

格式规范

  • 不含 frontmatter(唯一例外:Bundle 根 index.md 可包含 okf_version 字段)
  • Body 使用一个或多个章节,每个章节在标题下分组概念:
# Section / Group Heading

* [Title 1](relative-url-1) - short description of item 1
* [Title 2](relative-url-2) - short description of item 2

# Another Section

* [Subdirectory](subdir/) - short description of the subdirectory

自动生成

Reference Agent 的 regenerate_indexes() 函数自动生成 index.md:

  1. 遍历 Bundle 中所有 .md 文件,收集需要索引的目录
  2. 按层级深度从深到浅处理(先处理子目录,再处理父目录)
  3. 对每个目录,按 type 分组概念,按 title 字母排序
  4. 条目包含从 frontmatter 提取的 description
  5. 对子目录,使用 LLM 合成一句话描述(当子目录有多个条目时)

实例

GA4 Bundle 根 index.md:

# Subdirectories

* [datasets](datasets/index.md) - A sample of obfuscated Google Analytics BigQuery event export data...
* [references](references/index.md) - This directory contains specifications for data joins...
* [tables](tables/index.md) - Contains Google Analytics event export data...
__CODE_BLOCK_13__markdown
# BigQuery Table

* [Events table (Google Analytics BigQuery Export)](events_.md) - Contains Google Analytics event export data...
__CODE_BLOCK_14__markdown
# Directory Update Log

## 2026-05-22
* **Update**: Added new BigQuery table reference for [Customer Metrics](/tables/customer-metrics.md).
* **Creation**: Established the [Dataplex Playbook](/playbooks/dataplex.md).

## 2026-05-15
* **Initialization**: Created foundational directory structure.
  • 日期标题必须使用 ISO 8601 YYYY-MM-DD 格式
  • 日志条目为散文;加粗的前导词(**Update**, **Creation**, **Deprecation** 等)是约定,非要求

7. 引用规范

当概念 body 中的声明来源于外部材料时,这些来源应在文档底部的 # Citations 标题下列出,编号排列:

# Citations

[1] [BigQuery public dataset announcement](https://cloud.google.com/blog/products/data-analytics/...)
[2] [Internal data quality runbook](https://wiki.acme.internal/data/quality)
__CODE_BLOCK_16__markdown
# Citations
- https://developers.google.com/analytics/bigquery/web-ecommerce-demo-dataset
- https://support.google.com/analytics/answer/7029846
- https://developers.google.com/analytics/bigquery/basic-queries
- https://developers.google.com/analytics/bigquery/advanced-queries

注意:Reference Agent 使用无编号的 - 列表格式而非 [1] 编号格式,这是生产者的选择变体。


8. 一致性校验

一个 Bundle 符合 OKF v0.1 当且仅当:

  1. ✅ 树中每个非保留 .md 文件包含可解析的 YAML frontmatter 块
  2. ✅ 每个 frontmatter 块包含非空 type 字段
  3. ✅ 每个保留文件名(index.md, log.md)在存在时遵循 §6 和 §7 的结构

消费者容忍规则

消费者应将所有其他约束视为软指导。特别是,消费者不得因以下原因拒绝 Bundle:

  • ❌ 缺少可选 frontmatter 字段
  • ❌ 未知 type 值
  • ❌ 未知额外 frontmatter 键
  • ❌ 断链
  • ❌ 缺少 index.md 文件

Reference Agent 校验实现

document.py 中的 OKFDocument.validate() 方法检查必填键:

REQUIRED_FRONTMATTER_KEYS = ("type", "title", "description", "timestamp")

def validate(self) -> None:
    missing = [k for k in REQUIRED_FRONTMATTER_KEYS if not self.frontmatter.get(k)]
    if missing:
        raise OKFDocumentError(f"Missing required frontmatter keys: {', '.join(missing)}")

write_concept_doc 工具在写入前调用 validate(),拒绝无效 frontmatter 的写入。同时在 web pass 中实施增强守卫:拒绝会缩减现有 BigQuery Table 文档 # Schema 字段集或 # Citations 条目数的写入。


9. Reference Agent 自动化生成流程

Reference Agent 是 OKF 的概念验证生产者,基于 Google ADK 构建。它通过两个阶段 (pass) 自动从数据源和 Web 文档生成 OKF Bundle。

9.1 架构概览

┌─────────────────────────────────────────────────────────────────┐
│                     Reference Agent                             │
│                                                                 │
│  ┌─────────────┐    ┌──────────────┐    ┌────────────────────┐ │
│  │  BQ Agent   │    │  Web Agent   │    │  Visualize         │ │
│  │  (Pass 1)   │    │  (Pass 2)    │    │  (Subcommand)      │ │
│  └──────┬──────┘    └──────┬───────┘    └─────────┬──────────┘ │
│         │                  │                      │            │
│         ▼                  ▼                      ▼            │
│  ┌─────────────┐    ┌──────────────┐    ┌────────────────────┐ │
│  │ Source Tools │    │  Web Tools   │    │  Viewer Generator  │ │
│  │ - list       │    │  - fetch_url │    │  - Cytoscape.js    │ │
│  │ - read_raw   │    │  - 爬虫预算  │    │  - marked.js       │ │
│  │ - sample     │    │  - 深度限制  │    │  - 自包含 HTML     │ │
│  └──────┬──────┘    └──────┬───────┘    └────────────────────┘ │
│         │                  │                      │            │
│         ▼                  ▼                      ▼            │
│  ┌─────────────┐    ┌──────────────┐    ┌────────────────────┐ │
│  │ Bundle Tools │    │ Bundle Tools │    │  Bundle 目录       │ │
│  │ - read_doc   │    │ - read_doc   │    │  → viz.html        │ │
│  │ - write_doc  │    │ - write_doc  │    │                    │ │
│  └─────────────┘    └──────────────┘    └────────────────────┘ │
│         │                  │                      │            │
│         └────────┬─────────┘                      │            │
│                  ▼                                ▼            │
│         ┌──────────────┐                 ┌──────────────┐     │
│         │ regenerate_  │                 │ generate_    │     │
│         │ indexes()    │                 │ visualization│     │
│         └──────────────┘                 └──────────────┘     │
└─────────────────────────────────────────────────────────────────┘
__CODE_BLOCK_19__
┌──────────────────────────────────────────────────────────────┐
│  BQ Agent 单概念富化工作流                                     │
│                                                              │
│  1. read_existing_doc(concept_id)                            │
│     → 检查是否已有文档,有则在此基础上改进而非重写             │
│                                                              │
│  2. read_concept_raw(concept_id)                             │
│     → 获取结构化元数据(schema、分区、聚类、行数、时间戳)     │
│                                                              │
│  3. sample_rows(concept_id, n=3)  [可选]                     │
│     → 元数据稀疏时拉取少量数据样本辅助描述                    │
│                                                              │
│  4. list_concepts()                                          │
│     → 了解 Bundle 中存在哪些其他概念,用于编织交叉链接         │
│                                                              │
│  5. write_concept_doc(concept_id, frontmatter, body)         │
│     → 组合并写入 OKF 文档(仅调用一次)                       │
└──────────────────────────────────────────────────────────────┘
__CODE_BLOCK_20__
┌──────────────────────────────────────────────────────────────┐
│  Web Agent 爬虫工作流                                         │
│                                                              │
│  1. list_concepts()                                          │
│     → 了解 Bundle 已有哪些概念                                │
│                                                              │
│  2. 对每个种子 URL 调用 fetch_url(url)                        │
│     → 返回页面 markdown 内容 + 出站链接列表                    │
│                                                              │
│  3. 从出站链接中选取少量看起来像权威文档的链接                  │
│     → 跳过导航、页脚、登录页、关于我们、营销页等                │
│     → 对选中链接递归调用 fetch_url                             │
│                                                              │
│  4. 对每个抓取的页面,决定以下之一:                           │
│     a) 增强现有概念 — read_existing_doc → write_concept_doc  │
│     b) 创建新引用概念 — 仅当同时满足四个条件(见下文)          │
│     c) 跳过                                                  │
│                                                              │
│  5. 停止条件:                                                │
│     - fetch_url 返回 "max_pages reached"(预算耗尽)           │
│     - 已覆盖种子站点相关材料,继续抓取收益递减                  │
└──────────────────────────────────────────────────────────────┘

创建新引用概念的四个条件(必须全部满足):

  1. 主题形状:定义了可被现有概念文档按名称引用的内容(业务实体、指标、枚举/状态码、字段/参数词汇表、定价说明、单位/时区/标识符约定)
  2. 非 Bundle 级元信息:不是概述、介绍、快速入门、教程、发布说明、变更日志、路线图、FAQ 或产品落地页
  3. 引用测试:能在现有概念文档中合理写出 See the [X reference](/references/x.md) for ... 的句子
  4. 复用测试:至少两个现有概念会受益于引用它,或一个概念需要它作为其自身文档放不下的承重背景

安全限制(在 fetch_url 工具中强制执行):

限制说明默认值
max_pages硬性抓取页面上限100
allowed_hosts仅允许种子 URL 的主机名(可额外添加)种子主机名
max_depth距种子 URL 的跳数上限2
allowed_path_prefixesURL 路径前缀白名单无限制
denied_path_substringsURL 路径子串黑名单无

增强守卫:Web Pass 不允许缩减已有 BQ Pass 生成的 BigQuery Table 文档的 # Schema 字段集或 # Citations 条目数。如果新文档缺失字段,写入将被拒绝。

9.4 CLI 命令

enrich 子命令

.venv/bin/python -m reference_agent enrich \
    --source bq \
    --dataset <project>.<dataset> \
    --web-seed-file <path/to/seeds.txt> \
    --out ./bundles/<name>
__CODE_BLOCK_22__bash
.venv/bin/python -m reference_agent visualize --bundle ./bundles/<name>
参数默认值说明
–bundle(必填)Bundle 根目录
–out<bundle>/viz.html输出 HTML 路径
–nameBundle 目录名查看器头部显示名

10.2 生成逻辑 (generator.py)

1. _walk_concepts(bundle_root)
   → 遍历所有 .md 文件(跳过 index.md)
   → 解析 frontmatter 和 body
   → 用 _extract_links() 提取 body 中的相对链接
   → 构建 Concept 对象列表

2. _build_graph(concepts)
   → 节点:每个概念一个节点(id, label, type, color, size)
   → 边:从 body 链接提取的有向边(去重、去自环、仅保留存在的目标)
   → 颜色映射:BigQuery Dataset=#8b5cf6, BigQuery Table=#3b82f6, Reference=#10b981

3. generate_visualization()
   → 加载 HTML 模板 (viz.html)
   → 将 Bundle 序列化为 JSON 嵌入 HTML
   → 使用 Cytoscape.js (图) + marked.js (Markdown 渲染)
   → 写入单个自包含 HTML 文件

10.3 可视化特性

  • 力导向图:Bundle 中所有概念为节点,按类型着色,有向边由 markdown 交叉链接绘制
  • 详情面板:选中概念显示其 frontmatter(description、resource、tags)和渲染的 markdown body,内部链接重写为查看器内导航
  • “被引用”反向链接列表:从链接图的反向计算
  • 搜索框(匹配标题、概念 ID 和标签)、类型过滤器、可切换图布局(cose / concentric / breadth-first / circle / grid)

11. 完整操作流程示例(GA4 实例)

以 GA4 Google Merchandise Store 数据集为例,完整展示从安装到产出的端到端流程。

Step 1: 环境安装

# 从仓库根目录
python3.13 -m venv .venv
.venv/bin/pip install --index-url https://pypi.org/simple/ -e .[dev]
__CODE_BLOCK_25__bash
# BigQuery 访问
gcloud auth application-default login
gcloud config set project <your-billing-project>

# Gemini 凭据(二选一)
# 方式 A: AI Studio API Key
export GEMINI_API_KEY=<key>

# 方式 B: Vertex AI
export GOOGLE_GENAI_USE_VERTEXAI=true
export GOOGLE_CLOUD_PROJECT=<id>
export GOOGLE_CLOUD_LOCATION=<region>
__CODE_BLOCK_26__
# Seed URLs for the GA4 Google Merchandise Store anchor dataset
# 每行一个 URL,# 开头为注释

# GA4 BigQuery Export — top-level overview and index
https://support.google.com/analytics/answer/7029846

# GA4 BigQuery Export — schema reference (events, items, params)
https://support.google.com/analytics/answer/7029846?hl=en

# GA4 BigQuery cookbook (example queries by use case)
...
__CODE_BLOCK_27__bash
.venv/bin/python -m reference_agent enrich \
    --source bq \
    --dataset bigquery-public-data.ga4_obfuscated_sample_ecommerce \
    --web-seed-file samples/ga4_merch_store/seeds.txt \
    --out ./bundles/ga4

Step 5: Agent 内部执行流程

┌─────────────────────────────────────────────────────────────────────┐
│  阶段 1: BQ Pass                                                     │
│                                                                     │
│  ① BigQuerySource.list_concepts()                                   │
│     → 发现概念:                                                     │
│       - datasets/ga4_obfuscated_sample_ecommerce (BigQuery Dataset)│
│       - tables/events_ (BigQuery Table, 分片表, wildcard=True)      │
│                                                                     │
│  ② 对每个概念运行 BQ Agent:                                         │
│     datasets/ga4_obfuscated_sample_ecommerce:                       │
│       → read_concept_raw → 获取 dataset 元数据                      │
│       → list_concepts → 了解有 tables/events_ 可链接                │
│       → write_concept_doc → 写入 datasets/ga4_obfuscated_sample_   │
│         ecommerce.md (含 Overview, Sample Query, Citations)          │
│                                                                     │
│     tables/events_:                                                 │
│       → read_concept_raw → 获取表 schema (含嵌套 RECORD)            │
│       → sample_rows(n=3) → 拉取样本行                               │
│       → list_concepts → 了解有 datasets/ 和可链接的概念             │
│       → write_concept_doc → 写入 tables/events_.md                  │
│         (含 Overview, Metrics 链接, Schema, Joins 链接, Citations)  │
│                                                                     │
│  ③ regenerate_indexes() → 自动生成各层 index.md                     │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│  阶段 2: Web Pass                                                    │
│                                                                     │
│  ① list_concepts() → 了解已有 datasets/ 和 tables/ 概念             │
│                                                                     │
│  ② 抓取种子 URL (developers.google.com / support.google.com):       │
│     → fetch_url → 获取页面 markdown + 出站链接                      │
│                                                                     │
│  ③ 跟踪权威文档链接 (max_depth=2):                                  │
│     → schema reference 页 → 增强 tables/events_.md 的 Schema 部分   │
│     → cookbook 页 → 为指标定义创建引用文档:                         │
│       references/metrics/event_count.md                             │
│       references/metrics/user_count.md                              │
│       references/metrics/day_count.md                               │
│       references/metrics/new_user_count.md                          │
│       references/metrics/avg_pageviews.md                           │
│       references/metrics/avg_transactions_per_purchaser.md          │
│       references/metrics/avg_spend_per_purchase_session_by_user.md  │
│       references/metrics/overall_avg_spend_per_purchase_session.md  │
│     → basic-queries 页 → 创建 join 引用文档:                        │
│       references/joins/events___ads_clickstats.md                   │
│     → 在 tables/events_.md 中添加到引用的交叉链接                    │
│                                                                     │
│  ④ regenerate_indexes() → 更新所有 index.md                         │
└─────────────────────────────────────────────────────────────────────┘

Step 6: 生成可视化

.venv/bin/python -m reference_agent visualize --bundle ./bundles/ga4
# → 产出 bundles/ga4/viz.html

Step 7: 最终产出

bundles/ga4/
├── index.md                                    ← 根索引 (自动生成)
├── viz.html                                    ← 交互式可视化 (自动生成)
├── datasets/
│   ├── index.md
│   └── ga4_obfuscated_sample_ecommerce.md      ← BQ Pass 产出
├── tables/
│   ├── index.md
│   └── events_.md                              ← BQ Pass 产出 + Web Pass 增强
└── references/                                 ← Web Pass 产出
    ├── index.md
    ├── joins/
    │   ├── index.md
    │   └── events___ads_clickstats.md
    └── metrics/
        ├── index.md
        ├── event_count.md
        ├── user_count.md
        ├── day_count.md
        ├── new_user_count.md
        ├── avg_pageviews.md
        ├── avg_transactions_per_purchaser.md
        ├── avg_spend_per_purchase_session_by_user.md
        └── overall_avg_spend_per_purchase_session.md

Step 8: 迭代与验证

# 仅迭代单个概念
.venv/bin/python -m reference_agent enrich \
    --source bq \
    --dataset bigquery-public-data.ga4_obfuscated_sample_ecommerce \
    --concept tables/events_ \
    --no-web \
    --out ./bundles/ga4

# 运行测试
.venv/bin/pytest

12. 三大实例 Bundle 结构对比

维度GA4Stack OverflowBitcoin (crypto_bitcoin)
数据源bigquery-public-data.ga4_obfuscated_sample_ecommercebigquery-public-data.stackoverflowbigquery-public-data.crypto_bitcoin
表数量1 (分片表 events_*)16 (独立表)4 (blocks, transactions, inputs, outputs)
表特征单一宽表,大量嵌套 RECORD多个独立实体表紧密关联的事实表,外键关系
引用文档8 metrics + 1 join28 个引用(枚举、类型、状态码等)无引用文档
种子 URLGA4 BigQuery Export 官方文档Stack Exchange Data Dump schema 文档bitcoin-etl GitHub + Google Cloud 博客
Web Pass 行为单概念增强 + 指标/join 创建多概念增强(单页面描述多个表)跨表外键关系在 prose 中体现
数据量级中等大(stackoverflow 表数百 GB)大(transactions 数百 GB)
引用类型Metric, Join枚举类型、状态码、审核类型等—
适用场景展示单一宽表的完整 schema 文档化展示多表交叉增强展示紧密关联表的跨表关系

13. 周边工具链

13.1 Metadata as Code (toolbox/mdcode/)

提供源代码工件式的元数据管理能力:

  • YAML + Markdown 表示元数据,与资源层级镜像的目录结构
  • 双向同步:本地工作区 ↔ Knowledge Catalog 服务
  • 分发形式:TypeScript/Python 库、CLI 工具 (kcmd)、MCP 服务器
  • 支持 BigQuery Dataset、EntryGroup 等资源类型

目录布局

path/to/root/
├── catalog.yaml                # 清单和配置指令
└── catalog/                    # 元数据快照
    └── <dir1>/
        └── <entry-id1>.yaml    # Entry
        └── <dir2>/
            ├── <entry-id2>.yaml      # 带 sidecar markdown 的 Entry
            └── <entry-id2>.aspect.md # sidecar 文件
__CODE_BLOCK_33__
输入文本
    │
    ├─ 第一行是否为 "---"? ──否──→ 返回空 frontmatter + 全文为 body
    │
    是
    │
    ├─ 查找闭合 "---" ──未找到──→ 抛出 OKFDocumentError("未终止的 YAML frontmatter")
    │
    找到
    │
    ├─ yaml.safe_load(frontmatter 文本)
    │   └─ 解析失败 → 抛出 OKFDocumentError("无效 YAML")
    │   └─ 非 dict → 抛出 OKFDocumentError("frontmatter 必须是 YAML 映射")
    │
    └─ 返回 OKFDocument(frontmatter=解析结果, body=闭合之后的文本)

序列化流程 (OKFDocument.serialize())

OKFDocument 对象
    │
    ├─ yaml.safe_dump(frontmatter, sort_keys=False, allow_unicode=True)
    │
    ├─ 确保 body 以 "\n" 结尾
    │
    └─ 输出: "---\n{fm_text}\n---\n\n{body}"

附录 B: 概念 ID 路径映射

概念 ID 与文件系统路径之间的双向映射 (paths.py):

操作示例
Concept ID → 文件路径tables/events_ → bundle_root/tables/events_.md
文件路径 → Concept IDbundle_root/tables/events_.md → (“tables”, “events_”)
字符串 → Concept ID“tables/events_” → (“tables”, “events_”)

路径段验证正则:[A-Za-z0-9_][A-Za-z0-9_.\-]*(字母数字开头,允许下划线、点、连字符)


附录 C: 完整依赖清单

# pyproject.toml
google-adk>=2.0           # Google ADK 框架
google-cloud-bigquery>=3.20  # BigQuery 客户端
pyyaml>=6.0               # YAML 解析
pydantic>=2.0             # 数据验证
markdownify>=0.11          # HTML → Markdown 转换(Web 抓取)
pytest>=7.0               # 测试(dev)
__CODE_BLOCK_36__
# 运行时凭据
GEMINI_API_KEY            # AI Studio 方式
# 或
GOOGLE_GENAI_USE_VERTEXAI=true
GOOGLE_CLOUD_PROJECT=<id>
GOOGLE_CLOUD_LOCATION=<region>
# 以及
gcloud auth application-default login  # BigQuery ADC

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注