01它解决什么问题
一句话:把「代码仓库 / 数据集 / 系统」变成一堆普通的 Markdown 文件,让人和 Agent 用完全相同的方式生产、审查、消费它。技能本体不发明格式,而是严格实现上游 GoogleCloudPlatform/open-knowledge-format 的 v0.2 规范。
| 痛点 | OKF 的回答 | 实现锚点 |
|---|---|---|
| 知识只存在于脑子里 / 一次对话里 | 固化成一堆 .md,天然进 git:PR、逐行 diff、blame、评审流程全部免费获得 | 一个概念 = 一个 .md 文件(SPEC §3) |
| Agent 不理解仓库,只能靠现场 grep | frontmatter 放可查询的少数字段,正文放人和 LLM 真正读的散文 / 表格 / 代码 | 结构化与非结构化刻意混合(SPEC §4) |
| 不知道这条知识可不可信、还新不新鲜 | 来源、信任、生命周期都是可查询的一等公民,而不是靠印象 | sources[] / verified / stale_after(SPEC §5) |
| 无法分辨「人写的」还是「Agent 编的」 | Agent 产出一律停在 unverified,人工确认后才能升级 | 只有 human: 前缀能升到 human-reviewed(SPEC §5.3) |
| 平台锁定,换工具就搬不动 | bundle 就是一个普通目录:tar 包 / 静态服务器 / Obsidian / MkDocs 都能直接用 | bundle = directory(SPEC §3) |
| 把整个仓库塞进上下文,成本爆炸 | 自动生成的 index.md 让 Agent 逐层浏览、按需加载 | 渐进披露(SPEC §8) |
1.1为什么是 Markdown,而不是元数据服务
人和 Agent 读同一份
cat 一下就能看;LLM 可以原样塞进上下文。不存在「给人看的界面」和「给机器读的 API」两套真相。
知识运营 = 软件工程
PR 评审、逐行 diff、blame、CI 校验,全部复用现成流程,不需要另建知识管理平台。
零锁定
bundle 就是个目录。tar 包分发、静态服务器托管、用 Obsidian / Notion / MkDocs / Hugo 原生浏览都可以。
渐进披露
index.md 是目录,概念文档是按需加载的单元。Agent 不会一上来就被整个知识库淹没。
- 不伪造权威性:Agent 生成的内容不写
verified,如实保持unverified。 - 编造比缺失更糟:宁缺毋滥,宁可少写一篇,也不写没有源码依据的参数。
- 不重复目录结构:知识库的价值在「非显而易见的事实」,不是把
ls -R翻译成中文。
02OKF v0.2 规范要点
生成方必须遵守的部分。规范全文内置在 references/SPEC.md(1014 行,上游 commit 0b87c52 快照),SKILL.md 只是流程提炼——两者冲突时以 SPEC 为准。
index.md / log.md 是唯二的保留名,二者本身不算「概念」——这一点在渲染阶段会造成一个直观差异(见 6.4)。2.1概念文档:唯一必填字段是 type
只带 type 的概念即完全合规。其余字段分为四个家族,全部可选,但推荐填满前两个家族。
| 家族 | 字段 | 必填 | 说明 |
|---|---|---|---|
| 结构 | type | 必填 | 全局唯一必填项。用自解释英文 token(Module / Component / Playbook / Config / Reference / Concept / State Machine…);消费者对未知 type 按通用概念处理 |
title / description | 推荐 | description 会被 index.md 与搜索摘要原样引用,保持一句话 | |
resource | 推荐 | 指向概念描述的底层资产(源文件路径 / URL);纯抽象概念可省 | |
tags | 可选 | YAML list,用于跨分区归类与前端搜索 | |
| 溯源 | sources[] | 实质必填 | 正文有脚注则必填。每条含 id(脚注 join key)、resource(必填)、title;id 用稳定标识而非位置索引,因为 Agent 会不断重写文档,列表重排会让 sources[0] 静默错配 |
| 信任 | generated | 推荐 | { by, at };by 遵循 actor 约定 |
verified | 不伪造 | Agent 生成且未人工确认时不要写。写了就等于伪造权威性 | |
| 生命周期 | status | 可选 | draft / stable(缺省)/ deprecated;反映现有代码的写 stable,推断/未证实内容写 draft |
stale_after | 可选 | 绝对时刻,now >= stale_after 即过期 |
verified 推导,判定权在前缀:human: 之外的任何 actor 都只能到 machine-confirmed。渲染时这一层会变成节点详情面板上的彩色 badge。2.2链接的两种写法:本技能选了「仓库根基准」
规范允许两种绝对/相对写法。本技能内部约定了一套看似矛盾、实则有明确理由的组合——这是理解后续所有「链接错位」问题的前提:
| 位置 | 本技能的写法 | 为什么 |
|---|---|---|
| 正文里的概念互链 | [事件总线](/okf/core/event-bus.md)仓库根基准,带 /okf/ 前缀 | 编辑器 / 查看器以仓库根解析绝对路径,旧写法 /core/x.md(bundle 根基准)会指向不存在的位置 |
| 正文里的源码脚注 | [^main-src]: /src/main.ts同样是仓库根基准 | 脚注归因行最终渲染成正文文本,路径基准与正文一致才不会点歪 |
frontmatter 的 resource | resource: ../../src/core/Game.ts文档相对,不用 / 开头 | 渲染器对 frontmatter 里 / 开头的值原样放行,会按 bundle 根解析而跳错位置;文档相对写法则由规范化补丁自动处理 |
正文用仓库根(/okf/…),frontmatter 用文档相对(../../…)。两者都符合规范;之所以要分开,是因为渲染器对这两个位置的 / 开头路径处理策略不同——正文会被 rewire 成图内跳转,frontmatter 则原样当链接。
2.3两条容易被忽略的规范精神
断链是合法状态
消费者 MUST NOT 因断链拒绝 bundle——断链可能只是「尚未写出的知识」。这直接决定了本技能的定位:校验脚本是生成方 lint,在发布前把断链当硬失败拦住,而不是伪装成合规检查。
宽容是规范的一部分
type 值不注册、消费者必须容忍未知类型与未知键;缺任何一个可选字段家族都不能被拒绝。所以写知识库时不需要「先对齐 type 词表」,自由扩展是允许的。
03六步生成工作流
SKILL.md 定义的执行路径。第 4 步校验是必做项,第 6 步渲染按需触发。
3.1第 1 步 · 项目侦察:读什么、怎么收敛
- 先读
README.md、构建清单(package.json/pyproject.toml/Package.swift)、CI 配置、关键脚本。 - 列出全部源文件并看规模(
find … -type f+wc -l):≤50 个源文件时全部通读;更大的仓库按模块分层抽样,但每个模块至少精读核心文件。 - 边读边记「非显而易见的事实」——这是知识库价值的全部来源:真实参数(速度 / 时长 / 阈值 / 权重)、设计取舍的注释、实现注记(「原用 Picker 但不生效,换成按钮」)、模块间联动链。
- 反模式:把目录结构翻译成中文、复述类名和方法名。这类内容占篇幅但不增加信息。
3.2第 2 步 · 设计分区
okf/
index.md # okf_version: "0.2"(全 bundle 唯一允许带 frontmatter 的 index)
log.md # ISO 日期分组、newest first
overview/ # 产品全景、架构总览、核心机制(1~3 篇)
<领域分区>/ # 按模块拆:core/ pet/ controllers/ views/ api/ ...
playbooks/ # 构建 / 调试 / 发布的操作手册
references/ # 清单文件、CI、资产等次级材料
每个分区写一个 index.md(无 frontmatter,按分区分组列链接 + 一句话描述)。
SPEC §11 明确:分区 index 缺失不构成拒绝理由。validate_okf.py 也只检查 root index.md 的 okf_version。这条约定存在的唯一目的是保证导航完整性——你若手工维护 bundle,可以不放。
3.3第 3 步 · 生成概念文档
---
type: Module # 必填;自解释英文 token
title: 中文名(或项目语言对应的标题)
description: 一句话概括
resource: ../../Sources/... # 文档相对路径;勿用 / 开头
tags: [a, b]
generated: { by: workbuddy/glm-5.3-flash, at: 2026-09-16T22:05:00+08:00 } # ISO 8601 带 UTC 偏移
sources:
- id: game-src # 正文脚注 [^game-src] 与此 id 逐字对应
resource: ../../src/core/Game.ts
title: src/core/Game.ts
status: stable # 反映现有代码的写 stable;推断/未证实内容写 draft
---
| 正文规则 | 要求 |
|---|---|
| 结构化优先 | 表格列参数、fenced code 列关键代码;保留真实数字(300px/s、25 分钟、30% 概率) |
| 篇幅 | 每篇 40~90 行为宜,聚焦「这个模块是什么、怎么工作、和谁联动」 |
| 互链 | 联动对象用仓库根基准绝对链接:[事件总线](/okf/core/event-bus.md) |
| 归因 | 每处具体论断后标脚注 [^id],文末给脚注定义行,label 必须与 sources[].id 一致 |
| 信任 | 不加 verified 字段——如实保持 unverified |
| 节奏 | 每分区写完立即写该分区 index.md,不要最后补 |
3.4第 4 步 · 校验(硬闸门)
python3 <skill-dir>/scripts/validate_okf.py <project>/okf
退出码非 0 即不通过。断链先修复再复验,直到全绿——出现过「编辑报成功但落盘未生效」,必须跑绿才算完成。校验器细节见 4.1。
3.5第 5 步 · 交付
把 root index.md 作为入口展示给用户(支持文件预览的环境直接开预览,否则给绝对路径),后跟 2~3 篇核心概念(如架构总览、核心状态机),再附 log.md;最终回复给出分区统计表与信任状态说明。
3.6第 6 步 · 渲染交互式知识图谱(可选)
python3 <skill-dir>/scripts/render_viz.py <project>/okf --name "知识图谱"
产出写到 <project>/okf/viz.html:力导向图 + 详情面板 + 反向链接 + 搜索 / 类型过滤,完全离线可用。渲染后建议做多重验证(bodies 无残留相对链接、resource 均为 bundle 根相对形态、脚注路径已改写、无外部 <script src> / <link href>),并把 concepts / edges 数写进最终回复。原理见 4.3。
04脚本内部机制
技能的全部「可执行部分」约 750 行 Python + 一个内置 viewer 副本。下面按真实调用顺序拆开看。
| 文件 | 行数 | 职责 | 依赖 |
|---|---|---|---|
scripts/validate_okf.py | 140 | bundle 一致性校验(生成方 lint) | 仅标准库(有 pyyaml 则增强) |
scripts/render_viz.py | 61 | 命令行壳:解析参数、导入内置 viewer、打印统计 | pyyaml |
scripts/okf_viewer/__init__.py | 24 | 包入口,导出 generate_visualization | pyyaml |
scripts/okf_viewer/document.py | 154 | frontmatter 解析 / 信任层推导 / 时效判定 | pyyaml |
scripts/okf_viewer/generator.py | 368 | 遍历 bundle、链接规范化、组图、吐出自包含 HTML | pyyaml |
scripts/okf_viewer/templates/viz.html | 90 | HTML 骨架,6 个占位符待替换 | — |
scripts/okf_viewer/static/viz.js / viz.css | 333 / 180 | 前端:cytotscape 实例、搜索、过滤、详情、反向链接 | cytoscape + marked |
static/vendor/cytoscape.min.jsstatic/vendor/marked.min.js | — | 内联进产物的第三方库(3.28.1 MIT / 12.0.0 MIT) | — |
4.1校验器 validate_okf.py
定位很关键:SPEC §11 规定消费者不得因断链拒绝 bundle,而本脚本是生成方 lint——在产出流程里把问题拦在发布前,因此断链按硬失败处理。这不是与规范冲突,而是站在规范的另一侧。
[^x]: … 的示例,不去码块就会被当成真正的脚注定义而误报。实测输出(tower-defense bundle,pyyaml 有无两种解释器结果一致)
python3 scripts/validate_okf.py okf
bundle: /private/tmp/tdcase/okf
概念文档 21 篇,内部链接 50 条
✓ 校验通过:frontmatter type / 链接完整性(含锚点)/ 脚注归因 全部一致
exit=0
这不是 bug,是两套口径:
- 21 篇:31 个
.md里,9 个分区index.md+ 1 个log.md属保留名被跳过 → 剩 21 篇概念文档。而渲染器只跳过index.md(不跳log.md),所以图上是 22 个节点(另见 6.4)。 - 50 条内部链接:其中 42 条来自 index 的导航链接(root index 21 条 + 8 个分区 index 21 条),index 不是节点,这些不成边;剩下 8 条恰好是概念文档之间的互链 = 图谱的 8 条边。
校验器会用 try/except ImportError 兜住:没装 pyyaml 时 yaml_ok() 恒返回 True,即跳过 YAML 可解析性深度校验,仍能用正则查 ^type:,保证零依赖可用。渲染器则相反——缺 pyyaml 直接 fail() 退出,因为它真的需要解析 frontmatter。
4.2信任与时效的推导:document.py
渲染时的 badge 不是「读一个字段」,而是从 verified 现场推导出来的。三个函数值得单独看:
信任层
无 verified → unverified;有事件但没有任何 human: 前缀的 actor → machine-confirmed;出现 human:<id> → human-reviewed。判定只看前缀,不看 by 里的其他内容。
单元素宽容
单个 { by, at } mapping 与单元素 list 均合法(SPEC §5.2),消费端一律归一化成 list,避免调用方到处判类型。
时效:宁可不报
now >= stale_after 才算过期。两处保守:值里没有 T(纯日期 2026-12-31)直接不算 —— 它在不同时区是不同的时刻;解析出的 datetime 没有时区信息也不算。都是「不肯猜」的设计。
PyYAML 实现的是 YAML 1.1,其隐式解析器会把 2026-06-30T14:00:00Z 解成 datetime 对象;一旦回写就变成 2026-06-30 14:00:00+00:00——一次 parse → serialize 往返就静默改写了作者写的 frontmatter。内置 viewer 用自定义 _Loader 删除了 tag:yaml.org,2002:timestamp 解析器,让所有值保持字符串,与 YAML 1.2 core schema 对齐。
4.3渲染管线:render_viz.py + 内置 okf_viewer
python -m reference_agent visualize
官方 CLI 的顶层 import 会拉起 google.adk / google-cloud-bigquery 等几个 GB 的重依赖,而渲染链路实际只需要 pyyaml。内置的 okf_viewer 包就是从上游 viewer 提取出的独立副本(Apache 2.0,含链接规范化补丁),直接调用,效果与 CLI 完全一致,且无需 clone 上游仓库。
节点尺寸与配色是怎么定的
| 属性 | 公式 / 取值 | 含义 |
|---|---|---|
| 节点直径 | 30 + min(60, len(body) // 200) | 30~90 px,与正文长度正相关——越大 = 写得越详细 |
| 节点颜色 | 调色板仅定义 3 种 type:BigQuery Dataset #8b5cf6 · BigQuery Table #3b82f6 · Reference #10b981 | 其余一切 type 走默认 #94a3b8 灰。见 6.3 的实测发现 |
| 过期标记 | node[?stale] → 红色虚线边框加粗 | 由 stale_after 推导 |
| 废弃标记 | node[status="deprecated"] → 透明度 0.55 | 保留在图上但视觉降权 |
| 选中态 | 琥珀色 3px 边框(节点 / 边) | 点击节点后从图上定位 |
产物里的前端能力
搜索 title / id / tag
命中之外的节点与边统一加 .dim 降到 15% 透明度,而不是隐藏——上下文始终可见。
按 type 过滤
下拉项由 graph.types 动态生成,与调色板无关,所以灰节点依然可筛。
5 种布局切换
cose(力导向,默认)/ concentric / breadthfirst / circle / grid,外加 Reset view。
详情面板
type chip + id + description + resource 链接 + tags + generated/verified + sources 列表 + marked 渲染的正文。
v0.2 信号 badge
status(stable/draft/deprecated)、trust tier、stale 三项,前端按 CSS 类着色。
Cited by 反向链接
由边表反查生成,点击即跳转该节点。被引用最多的节点 = 架构核心,这是免费的依赖热度图。
前端 rewriteInternalLinks() 只处理 / 开头且以 .md 结尾的 <a href>:目标若在 nodeIndex 里,就把 href 改成 javascript:void(0) 并挂上 showDetail(),实现不刷新页面的图内导航;否则降级为外链(target="_blank" rel="noopener")。这就是为什么正文链接必须被规范化成 bundle 绝对形式——否则一律降级成外链,图就「点不动」。
4.4链接规范化补丁:7 节改动清单
这是本技能相对上游 viewer 的全部本地差异,记录在 references/generator-patch.md(同时是给上游提 PR 的素材)。理解它的价值在于:这些症状在写成「文档相对」或「仓库根基准」链接时必然出现,而不是偶发 bug。
| # | 改动 | 解决的症状 |
|---|---|---|
| 1 | _LINK_RE 升级为带锚点捕获组 | 规范化时 #锚点 被丢掉,跳到文件顶部而非小节 |
| 2 | 新增 _normalize_body_links / _normalize_resource | 正文与 frontmatter 的文档相对路径(../core/x.md、../../src/…)按 bundle 根解析 → 链接整体错位一级 |
| 3 | 在 _walk_concepts 的 Concept 构造处接线(body、resource、sources[].resource) | 规范化函数写了但没接上,等于没改 |
| 4 | _extract_links 支持 / 绝对形式 | 原实现只认文档相对链接,与 SPEC §6.1 推荐的 /x.md 矛盾——官方形态的 bundle 会丢图边 |
| 5 | 新增 _repo_root_abs():/okf/分区/x.md → /分区/x.md | 仓库根基准链接按 bundle 根解析成不存在的 okf/…,边被丢弃、链接降级为外链。带存在性检查,防止分区恰好与 bundle 目录同名时误伤 |
| 6 | 新增 _rewrite_footnote_repo_paths():脚注定义行的仓库根路径改写为 bundle 根相对 | [^main-src]: /src/main.ts 渲染成正文文本后,/ 开头会落到文件系统根(file:///src/main.ts);裸 README.md 则落在 bundle 内不存在的位置 |
| 7 | 第三方库内联(/*__VENDOR_*__*/ 占位符 + </script 转义) | 原模板经 jsdelivr CDN 加载 cytoscape / marked,断网即失效 |
改写只在生成端发生,源 bundle 文档保持仓库根基准写法不动。而且它只匹配脚注定义行 ^(\[\^id\]: )(\S+)$,路径必须「bundle 内不存在、但相对仓库根存在」才改写;两边都不存在就原样保留不瞎猜——宁可能点歪,也不猜一个看似合理的路径。
回归验证方式:官方 bundle(bundles/ga4、bundles/stackoverflow,全用 / 绝对形式)渲染后边数应与仓库里已提交的 viz.html 一致(8 / 54)。补丁对官方 bundle 零影响。
05使用指南
三种用法:让 Agent 走完整工作流、手动跑两个脚本、或把它接进 CI。
5.1安装
# WorkBuddy(用户级技能,全项目可用)
git clone <repo> ~/.workbuddy/skills/okf-knowledge-base
# 其他 Agent 框架:放到你的框架扫描 SKILL.md 的位置即可
技能本体与运行环境无关:一份 SKILL.md 工作流 + 两个独立 Python 脚本。
5.2用法一:对话式(推荐)
| 你说 | 触发的能力 |
|---|---|
| 「按 OKF 标准为本项目生成知识库」 | 六步主干:侦察 → 分区 → 生成 → 校验 → 交付 |
| 「生成 OKF 知识库」「OKF knowledge bundle」 | 同上(技能描述里的触发词) |
| 「顺便出一份知识图谱 / 可视化 / viz」 | 追加第 6 步渲染,产出 okf/viz.html |
5.3用法二:脚本式
# ① 校验(仅标准库,零依赖)
python3 scripts/validate_okf.py <project>/okf
# ② 渲染交互式知识图谱(需要 pyyaml;渲染器已内置,无需 clone 上游)
python3 scripts/render_viz.py <project>/okf --name "知识图谱"
python3 scripts/render_viz.py <project>/okf --out /tmp/kg.html --name "临时图"
| 脚本 | 参数 | 默认 | 说明 |
|---|---|---|---|
validate_okf.py | <bundle-root>(位置参数) | — | 必须是含 index.md 的目录,否则退出码 1 |
render_viz.py | <bundle-dir>(位置参数) | — | 同上 |
--out | <bundle>/viz.html | 输出 HTML 路径 | |
--name | bundle 目录名 | 查看器标题栏显示名 |
$ python3 scripts/render_viz.py okf --name "知识图谱"
✓ 22 concepts / 8 edges / 496898 bytes -> /path/to/okf/viz.html
两个脚本对 pyyaml 的态度不同:校验器没有也能跑(降级为浅校验),渲染器没有直接报错退出(✗ 当前解释器缺少 pyyaml,请先 pip install pyyaml)。如果你机器上默认 python3 没装 pyyaml,只需给渲染那一步换一个解释器即可,不必改任何代码。
5.4用法三:接进 CI
把「知识库是否自洽」变成一次 PR 检查——这是 OKF 相对知识管理平台最大的工程收益:
# .github/workflows/okf.yml(示例)
- run: python3 scripts/validate_okf.py okf
# 退出码非 0 即 CI 失败:断链 / 缺 type / 脚注归因断裂都拦在合并前
5.5frontmatter 填写速查
最小可用 vs 推荐
最小合规:只有 type。
推荐:type + title + description + resource + tags + generated;正文有脚注则 sources[] 实质必填。
两处最容易写反
resource 用文档相对(../../src/x.ts),正文互链用仓库根(/okf/…)。反过来写不会立刻报错,但渲染时会链接错位。
脚注 join key 要用语义 id
用 game-src 而不是 sources[0]——Agent 会不断重写文档,位置索引在列表重排后会静默错配,而 id 不会。
stale_after 要带完整时刻
写 2026-12-31T00:00:00Z;纯日期 2026-12-31 会被刻意忽略(不同时区是不同的时刻,规范不肯猜)。
5.6把信任层用起来:人力确认的完整动作
用户确认某篇内容后,追加一个 verified 即可让它在图谱里从灰转绿:
# okf/core/game.md —— 人工复核后追加这一行
verified: { by: human:wang-junjian, at: 2026-09-17T06:00:00+08:00 }
# 单个 mapping 或单元素 list 都合法;渲染后 badge 变为 human-reviewed
推荐的分工:generated.at 记录「内容什么时候被重新生成」;verified 记录「谁在什么时候确认它仍然正确」。定义过时用 status: deprecated 保留链接与历史,有时效的知识用 stale_after 到时候自动变红。
06实战案例:为「塔塔合成」生成知识库
真实跑通的案例:一款 Vite 5 + 纯 TypeScript(strict)+ HTML5 Canvas 2D 的合成塔防小游戏,零游戏引擎、零音频资源、零运行时依赖。下面所有数字都取自实际产物,不是示意值。
okf/ 直接躺在项目根目录,右侧是 root index.md 的预览效果。左侧树里 8 个分区(config / core / entities / overview / playbooks / references / systems / ui)各带一个 index.md,底部是 log.md 与 viz.html。观察点:它就是普通 markdown 文件——没有任何插件、数据库或私有格式,编辑器自带的预览就能读。6.1输入与产出
| 分区 | 篇数 | 内容 |
|---|---|---|
overview/ | 2 | 产品全景与玩法规则 · 架构总览 |
config/ | 2 | 全局数值配置(平衡调参唯一入口)· 战场地图(MapDef 数据驱动) |
core/ | 3 | Game 主类 · 事件总线(14 个事件清单)· 合成音效 |
entities/ | 4 | 防御塔 · 敌人 · 弹道 · 粒子系统 |
systems/ | 4 | 波次管理 · 经济系统 · 强化修饰器 · 强化池 |
ui/ | 2 | HUD 与卡池栏 · 指针输入 |
playbooks/ | 2 | 构建与运行 · 平衡仿真(无头 AI 自动打 20 波) |
references/ | 2 | 已知注意点与坑位清单 · 持久化键(localStorage) |
| 合计 | 21 篇概念文档(8 种 type:Component 7 · Module 6 · Config 2 · Playbook 2 · Reference 2 · Concept 1 · Content Library 1 · 另 log 落为 Unknown) | |
log.md 里记下了这次生成的「非显而易见事实」清单,可以直接看出知识库的价值密度:mergeRefundAmount 是死代码、强化卡描述与实际乘区不一致、localStorage 实际有 3 个键(AGENTS.md 只记了 2 个)、main.ts / DragHandler.ts 保留过时的「800×600」注释。这类「代码和文档互相说谎」的地方,正是知识库应该重点写的东西。
6.2图上实际有哪 8 条边
| # | 源概念 | → | 目标概念 | 关系含义(由散文表达) |
|---|---|---|---|---|
| 1 | 架构总览 | → | 事件总线 | 架构分层里事件解耦是核心机制 |
| 2 | 产品全景与玩法规则 | → | 战场地图 | 玩法里的三张地图指向 MapDef 配置 |
| 3 | 产品全景与玩法规则 | → | 持久化键 | 进度存档指向 localStorage 键 |
| 4 | 战场地图 | → | 平衡仿真 | 地图机制修饰需要仿真验证难度曲线 |
| 5 | 防御塔 | → | 强化修饰器 | 塔属性计算链读全局 buff 乘区 |
| 6 | 已知注意点 | → | 强化修饰器 | 坑位清单里「描述与实际乘区不一致」在此 |
| 7 | 合成音效 | → | 持久化键 | 静音开关的持久化落点 |
| 8 | 构建与运行 | → | 平衡仿真 | 仿真脚本是构建脚本的一部分 |
render_viz.py 的产物。左侧是力导向图(节点大小 = 正文长度,灰色是默认色,绿色是 type: Reference),右侧是点击节点后的详情面板:type chip、id、status / trust tier badge、Description / Resource / Tags / Generated / Sources 字段区,以及 marked 渲染的正文——正文里能直接看到 [^game-src] 脚注与指向源码的资源链接。整页零外部请求,可以离线打开、也可以直接发给同事。07常见坑速查
前六条来自 SKILL.md 的踩坑记录,后四条是本次源码研读 + 实测补充的。
| # | 现象 | 根因 | 处理 |
|---|---|---|---|
| 1 | 解析 index.md / log.md 时 IndexError | 它们没有 frontmatter,「按 split('---') 取第 2 段」拿不到第二段 | 任何此类逻辑必须先跳过保留文件名 |
| 2 | 链接改完 grep 看着没问题,图谱还是错 | 编辑器报「保存成功」但落盘没生效(历史真实案例) | 以重新读文件为准;校验脚本跑绿才算完成 |
| 3 | resource 指向了不存在的位置 | 路径基准搞错:resource 从文档自身位置起算 | okf/<分区>/x.md 引仓库文件写 ../../…,不是按 bundle 根算 |
| 4 | viz 里链接整体错位一级 | 上游 viewer 以 bundle 根解析一切链接,且只 rewire / 开头的 .md | 内置 okf_viewer 已含规范化补丁,直接用即可;同步上游时按 generator-patch.md 重放 |
| 5 | 校验器报「脚注无对应 sources id」,但正文里那段是示例 | 代码块里的 [^x]: 被当成真脚注定义 | 所有文本扫描都在 strip_code_blocks() 之后做 |
| 6 | 知识库全是「废话」 | 大仓库想全读 → 只能复述目录结构;或凭印象补参数 | 按「每模块精读核心文件」收敛;编造的参数比缺失更糟 |
| 7 | 概念数 21,图上却 22 个节点,types 里冒出 Unknown | _walk_concepts 只跳过 index.md,log.md 被当概念,无 frontmatter → type 落 Unknown | 知情即可(见 6.4);要消掉就在过滤条件里一并跳过 log.md |
| 8 | 仓库根基准链接(/okf/…)全部失效,edges 归零 | _repo_root_abs() 的映射前缀是 /{bundle 目录名}/。实测:把 bundle 复制成 okf_stats_td/ 再渲染,22 个节点只剩 0 条边;目录名恢复为 okf 后立刻回到 8 条 | bundle 目录就叫 okf,且放在仓库根下(补丁 6 以 bundle_root.parent 为仓库根)。改名 / 搬家后必须重跑渲染确认 edges 数 |
| 9 | 代码仓库的图谱全是灰点,看不出模块差异 | 调色板只定义 3 种 BigQuery 场景的 type,其余全走默认灰 | 用 type 下拉或搜索定位;若要按模块着色需自行扩展 _TYPE_PALETTE |
| 10 | 同一路径在 bundle 内和仓库里都存在,渲染却指向了意外的那个 | / 开头链接存在双重解析规则:校验器「bundle 根 → 仓库根」任一存在即通过,渲染器以 bundle 根为准 | 避免在 bundle 内放与仓库同名的路径,从命名上消除歧义 |
整套链接约定(正文 /okf/分区/x.md)只在「bundle 位于仓库根、且目录名恰为 okf」的布局下成立。若把 bundle 放到 docs/okf/ 或改名,仓库根基准的链接不会被映射,必须改用 bundle 根基准写法(/分区/x.md)——那种形式上游原生支持,不需要任何补丁。换句话说:先确定布局,再确定链接写法。
08边界与许可
8.1技能不做什么
- 不实现 Attested Computation。规范 §10 定义了「可证明计算」(runtime / parameters / executor / receipt / attester),但那是数据仓库场景的运行时协议,本技能完全不涉及。若你的场景需要「确认 Agent 跑的是官方批准的计算」,这颗能力目前是空的。
- 不做增量同步。它是一次性的生成工作流;代码变更后要重新跑,靠
generated.at记录新鲜度,而不是自动 diff 更新。 - 不替你确认内容正确性。产出全部停在
unverified,人工复核是独立动作。 - 渲染器的图边只认
.md链接。指向 URL 或非 markdown 资源的链接不进图、只进详情面板的 Sources 区。
8.2依赖与许可
| 组件 | 来源 | 许可 |
|---|---|---|
| SKILL.md 工作流、两个脚本、README | 本仓库自研 | MIT |
references/SPEC.md(OKF v0.2 规范快照,commit 0b87c52) | GoogleCloudPlatform/open-knowledge-format | Apache 2.0(副本见 SPEC-UPSTREAM-LICENSE.md) |
references/usage-guide.zh.md(上游中文指南快照) | 同上 | Apache 2.0;其中讲上游 BigQuery 生产 agent 的 §3 / §4.1–4.2 / §5 A·B / §6 enrich / §8 与本工作流无关 |
scripts/okf_viewer/(渲染包,含链接规范化补丁) | 同上 viewer | Apache 2.0 |
static/vendor/cytoscape.min.js 3.28.1 | cytoscape/cytoscape.js | MIT |
static/vendor/marked.min.js 12.0.0 | markedjs/marked | MIT |
全部上游快照都已内置,无需 clone 上游仓库,也无需联网。上游 viewer 更新时按各文件头部溯源注释与 references/generator-patch.md 重新同步;补丁本身是通用修复(对官方 bundle 零影响、修正规范矛盾),适合整理成 PR 提给上游——合入后即可去掉这处本地差异。
8.3一句话总结
这个技能的本质是一条被约束住的写作纪律:读源码 → 只写有依据的事实 → 每条论断挂上归因 → 用脚本证明没有断链和孤儿脚注 → 诚实标注「没人复核过」。格式与工具都只是为了让这条纪律可检查、可 diff、可离线分发。