少壮不努力,老大徒伤悲。——《汉乐府・长歌行》

把「孩子学会了什么」画成一张会生长的地图

一张会呼吸的星图

想象这样一个画面:整个小学阶段所有能被称为「一个知识点」的东西,被拆成一千多颗小星星,铺在一块黑色的画布上。星星按学科上色,高度代表年龄——越小的孩子站得越低,越大的孩子站得越高;星与星之间有线,线不是装饰,是「必须先懂这个,才能懂那个」。

这不是比喻,这是一份开源数据集自带的视觉说明。它叫 Marble Skill Taxonomy,一个开放的、结构化的分类体系,描述的是孩子们在小学阶段究竟学到了什么。它把这些内容拆成细颗粒的「微主题」,串成一张前序依赖图,再对齐到各国的国家课程标准。

更关键的是它的姿态:不是一个被锁在产品里的黑箱,而是一份可以直接下载、直接解析、直接拿去做东西的纯数据。

项目地址:https://github.com/withmarbleapp/os-taxonomy

先说结论式的自我介绍

这份数据的自我定位很短,但每个词都有分量:开放的、结构化的、「孩子学什么」的分类体系,覆盖小学阶段,拆成微主题,接上依赖图,对齐课标。

它出现的原因也很直接:市面上大多数课程数据,要么是一张扁平的课标清单,要么被牢牢锁在某个产品内部,只能看、不能算、更不能改。这份数据集想做的,是把「学习」本身变成一个可计算的连通图。

一句话概括它的差异:别人给的是一份目录,它给的是一张路网。

四个数字,先把骨架立住

维度 数值
版本 v1
微主题 1,591
前序依赖边 3,225
学科 8

1,591 个节点,3,225 条边,8 个学科。平均下来每个节点身上挂着两条左右的依赖关系——这个密度说明它不是稀疏地摆几个概念,而是真的把知识之间「谁先谁后」的纹理织了出来。

八个学科的分布也很有意思:

学科 微主题数
Science 547
Mathematics 504
English 286
History 90
Personal & Social Development 88
Life Skills 37
Computing 21
Learning to Learn 18

把这一列数字加起来:547 + 504 + 286 + 90 + 88 + 37 + 21 + 18 = 1,591,正好等于总数。也就是说,这八个学科是穷尽且不重叠的划分,没有漏掉的边角料。

值得一提的是,这份清单里不只有数学和科学。History、Personal & Social Development、Life Skills、Computing、Learning to Learn 都在——「学会怎么学习」本身被当成一个学科,给了 18 个微主题。这个选择挺诚实地承认了一件事:小孩子在学校里学到的东西,从来不只在课本上。

微主题:把「学会」切成一口一块

一千多个微主题是什么概念?文档里举了两个例子,一个软、一个硬:

  • Building sentences——把句子搭起来
  • Apparent brightness of stars——恒星的视亮度

一个是四五岁孩子在语言里摸索的第一次完整表达,一个是天文学里关于恒星看起来有多亮的认知门槛。它们被放在同一套结构里,用同一组字段描述。

每个微主题包含六类信息:

  1. 一句人话的描述——这个概念到底在说什么,用平实的语言讲清。
  2. 掌握证据——不是「学会了」这种模糊判断,而是可以观察到的具体表现。
  3. 类型——conceptual、procedural、representational、language、meta 五类之一。概念性的、程序性的、表征性的、语言性的、元认知性的,五种不同的「懂」。
  4. 学科 + 领域——它属于哪一科,以及科内的哪个领域。
  5. 大致年龄区间——这个概念通常在什么年纪出现。
  6. 课标出处——它从哪些标准里被蒸馏出来。

这里面最见功力的是第二项,「掌握证据」。文档给出的示例是这样一个微主题:Building sentences,四到六岁,领域是 Grammar & Punctuation,证据写成两条——能分辨完整句子和句子碎片;能造出一个带主语和动词的完整句。

你看,这就不是「理解句子」这种无法验证的表述了。它把「懂」翻译成了两个能当场看见的动作。分类体系最怕的就是含糊,而含糊恰恰是从「掌握」这个词开始的。这份数据在这一步上选择了具体。

它还附了一个 assessmentPrompt,一段自然语言的检测问法,大意是:如果孩子说出「The dog」这样的片段,孩子自己能不能说出这不是一个完整的句子。这段文字里带一个 {{name}} 占位符,代表孩子的名字——用之前替换掉或者删掉。

这个细节很轻,但透露出设计者的取向:这份数据是准备被真正拿去跟孩子对话的,不是只放在论文里被引用的。

依赖边:知识不是清单,是河道

3,225 条边,构成了一个有向无环图。每条边的语义只有一个方向:主题 X 依赖于前序 Y。

它不是「相关」,不是「同类」,而是硬邦邦的先后。而且每条边都带两个额外属性:

  • 强度:hard 或 soft。有些依赖是缺了就过不去的门槛,有些只是顺畅与否的差别。
  • 理由:一句话说明为什么。文档给的例子是——「必须先理解振动产生声音,才能发现音量变化的规律」。

一句话的理由,看起来是最不值钱的字段,其实是最值钱的。因为它把「为什么这条线存在」这个判断暴露在阳光下,可以被质疑、被反驳、被修正。一张只有连线没有理由的图,你只能信或者不信;一张每条线都写着理由的图,你可以跟它辩论。

README 还顺手提了一个使用视角的转换:把边反过来读,topicId 依赖 prerequisiteId 就变成了「prerequisiteId 解锁了 topicId」。同一个数据结构,正向是学习者要补的债,反向是教学者能给的钥匙。

这也是那张星图真正好玩的地方:点住任何一个概念,可以一路往回追,把它之前必须掌握的东西全部拉出来。对家长来说,这是一条「我孩子卡在这里,那前面是哪一步没踩稳」的追溯路径;对做教育产品的人来说,这是一套现成的技能树。

课标对齐:每颗星都有来处

一份分类体系最容易被追问的问题是:这些概念是你自己编的吗?

这里的回答是,每个微主题都链回它被蒸馏出来的课程标准。文档点名了几个课程体系:NGSS、Common Core、英国国家课程标准,以及更多。这些标准不内嵌在主题里,而是单独存放在 curriculum-standards.json,按课程体系分组;主题里的 standards 字段存的是键,格式是 <curriculum-slug>:<code>。

这个设计很务实。标准会改版,课程体系会更新,把标准和主题分成两张表、用键连接,改一层不会震塌另一层。而主题里那个示例的 standards 数组长这样:ccss-ela:L.K.1f 和 uk-nc-2013:Eng.App2.Y1.Sent.1——同一个「搭句子」,同时挂在美式共同核心和英国国家课程两套体系上。

交叉对齐的价值就在这儿:它不是某国课标的电子版,而是一层中间语言。不同国家的标准在这层语言里说的是同一件事。

教学研究:从「学什么」走到「怎么教」

如果只有节点和边,这份数据回答的是「学什么」和「先学什么」。但它还带了第三层——1,051 条教学研究记录,覆盖当前的 Science 和 Mathematics 主题,内容包括教学方法、具体的学习活动、反馈方式、评估指导,以及关联的来源。

这里的数字咬得很紧:Science 547 加 Mathematics 504,正好 1,051,与记录数完全对上;1,591 减去 1,051,剩下 540 个主题在本版本里没有研究内容。

而这份数据对「没有」这件事的处理方式,比「有」更值得看。

它没有假装全覆盖。coverage.missingTopicIds 明确列出哪些主题缺研究,每个学科的记录数也一并给出。文档还专门补了一句:缺失并不构成对「这个主题能不能教」的判断。

这句话很重要。一份数据集愿意承认自己的边界,比它宣称自己完整要可信得多。

领域速写:写给家长的那段话

在节点、边、研究之外,还有一类很不一样的内容:176 段写给家长看的一段话,按「学科 + 领域 + 年龄段」组织,用平实的语言概括这个领域在这个阶段大概是什么样。

1,591 个微主题是给工程师和课程设计者用的,颗粒度细到可以计算;176 段领域速写是给家长用的,颗粒度粗到可以读完。同一份数据里同时容纳两种密度,说明它想服务的对象不止一类人。

这也是这份数据集少见的地方:它不假设读者一定是开发者。

仓库长什么样

数据全部放在 data/ 下,UTF-8 编码的 JSON。schema/ 里是 JSON Schema,data/manifest.json 里是各项计数和 SHA-256 校验和。

文件 装的是什么
data/topics.json 微主题,也就是图的节点
data/dependencies.json 前序依赖,也就是图的边,语义是 topicId 依赖 prerequisiteId
data/curriculum-standards.json 原始课程标准,按课程体系分组
data/clusters.json 面向家长的领域摘要
data/teaching-research.json 按 topicId 连接的教学研究,带明确的覆盖说明与出版说明,约 24 MB
data/manifest.json 计数、分学科明细、逐文件校验和

一个很清醒的工程决定是:只有数据,没有运行时,没有依赖。没有 SDK 要装,没有服务要起,没有版本要锁。把 JSON 读进来,就可以开始算。

一颗节点、一条边,长什么样

一个微主题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"id": "mt_N8CpN1EJrP",
"type": "CONCEPTUAL",
"subject": "English",
"domain": "Grammar & Punctuation",
"name": "Building sentences",
"description": "Understand that words combine to make sentences — a sentence expresses a complete thought…",
"ageRangeStart": 4,
"ageRangeEnd": 6,
"centrality": 0.257,
"evidence": [
"Distinguish between complete sentences and fragments",
"Compose a complete sentence with a subject and verb"
],
"assessmentPrompt": "If {{name}} says something like \"The dog\", can they tell you that's not a complete sentence…?",
"standards": ["ccss-ela:L.K.1f", "uk-nc-2013:Eng.App2.Y1.Sent.1"]
}

id 是稳定标识,前缀 mt_,依赖表和邻居引用都靠它对齐。这一点看着平常,其实是整份数据能不能被长期依赖的分水岭——名字会改,描述会改,ID 不能改。

一条依赖:

1
2
{ "topicId": "mt__00ZSLnB7p", "prerequisiteId": "mt_VBl1T1sFCM", "strength": "hard",
"reason": "Must understand vibrations make sound before finding volume patterns" }

两行,三个字段,加一句理由。整张图的 3,225 条边,全是这个形状。

教学研究那一层,讲究到什么程度

这一层值得单独拉出来讲,因为它展示了「诚实」在数据工程里可以做到多细。

覆盖是显式的。 文件带 schemaVersion: 1 和分类体系版本 v1,每条 records[] 通过 topicId 与 topics.json 连接。哪些主题有研究、哪些没有,写在数据里,不靠读者猜。

字段分工清楚。 一条记录包含:

字段 含义
pedagogy 原始教学摘要:教学实践、表征方式、常见误解
learn 可移植的学习指引,schemaVersion: 2,含摘要、活动、教育约束与审阅说明
learn.activities[] 学习者动作、预期洞察、反馈、理由,以及支撑的来源论断。不含产品物料类型,也不含适配度排序
assess 原始诊断任务、作答层级、错误模式与下一步教学动作;在公开接口里可为空
sources 论断、具名来源、可选链接,以及原作者的核验标记
confidence 原始撰写时的置信度,不是一个独立的质量评分
provenance 原始撰写模型与来源记录时间戳;更新时间戳也反映了学习指引的重写
publicationNotes 因「只保留课标编号」的出版策略而被省略文本的路径与课标代码

作者身份是坦白的。 这些记录由智能体撰写。学习指引为可移植性重写过,由一个独立的事实批评者核查,再由第二个智能体抽样复查。大部分原始教学与评估内容被保留下来,其中可能有被更新后的指引所限定的说法;#30 之后的图表相关对齐修补,记录在受影响的学习指引审阅说明里,读的时候要连同约束和审阅说明一起读。

核验状态没有被美化。 本版本没有重新抓取或重新核验来源。历史上的 verified: true 和 confidence: "high",不是新的证据评级。活动是有研究依据的提案,不是经过实证验证的干预。

这些话放在任何一份数据集里都算得上逆耳,但它们是这份数据最可信的部分。它明确告诉你:这里的每一条建议,边界在哪里。

引用是精确对齐的。 sourceClaims 与 sources[].claim 在出版变换之后完全一致。一个来源可能支撑的是一条普遍原理或一次课标对齐,这并不意味着所提议的活动被测试过;有些活动没有直接关联的来源论断。

受限文本做了机械替换。 部分原始研究引用了有使用限制的课程标准。匹配到的段落被替换为行内课标引用,引用论断内部也一并替换;所有被变换的路径都列在 publicationNotes 里。文档把这步的性质说得很清楚:一次保守的机械省略,不是完整的权利清理。

拆分是可追溯的。 一次编号为 #30 的改动把图表相关内容拆开之后,mt_bESTSBB0wK 管饼图,mt_H6LlpWgEYS 管更早的折线图解题,mt_HlNSurPVDp 单独持有「作图与读图」的记录。新记录改编自既有的图表研究,不是一次新的文献综述,所有复用的来源核验标记都是 false。它的评估要求交出一张完整构造出来的图;后续的分组图表评估,则把「选错图型」的错误导向数据呈现,把「扇形角度算错」的错误导向饼图。

绑定是字节级的。 这份研究文件通过 topicFileSha256 与 topics.json 的精确字节绑定。只要主题文件变了,就要重新生成研究投影——哪怕主题 ID 一个都没动。

最后这一条是整套设计里最硬的一颗螺丝。ID 稳定不代表内容稳定,描述改一个字,研究记录与该主题的对应关系就可能悄悄错位。用哈希把两份文件钉在一起,是为了让这种错位没法发生在无人察觉的地方。

上手:读进来就能算

纯数据的好处是,第一行代码几乎就是最后一行。

1
2
3
4
5
6
7
import topics from './data/topics.json' with { type: 'json' };
import deps from './data/dependencies.json' with { type: 'json' };

const byId = new Map(topics.topics.map(t => [t.id, t]));
const prereqs = deps.dependencies
.filter(d => d.topicId === 'mt_N8CpN1EJrP')
.map(d => byId.get(d.prerequisiteId).name);

几行代码,就把「搭句子」这个主题的所有直接前序,换成了人能读的名字。

再往上一层,把教学指引接进来:

1
2
3
4
5
import research from './data/teaching-research.json' with { type: 'json' };

const guidanceByTopic = new Map(research.records.map(r => [r.topicId, r]));
const guidance = guidanceByTopic.get('mt_N8CpN1EJrP'); // undefined: English is not covered yet
const activities = guidance?.learn.activities ?? [];

这段代码本身就是一份文档。它取的例子恰好是一个查不到的主题——English 还不在研究覆盖范围里,于是注释里直接写着 undefined,把原因交代清楚。示例没有绕开这个空洞,而是把它留在原地。

愿意在示例里展示失败路径的数据集,通常对自己的边界心里有数。

结构、研究覆盖、证据链接、校验和,都能验:

1
2
node scripts/validate.mjs
node --test scripts/teaching-research.test.mjs

许可:两层授权,和一条关于商用的解释

这份数据是多层授权的,README 用了一句很直白的提醒:用之前、转发之前,先读这一段。

层 内容 许可
数据库 集合、结构、ID、主题与主题、主题与课标之间的关系 ODbL 1.0——研究与商用都免费,需要署名,需要同样方式共享
Marble 撰写的文本 主题的 description、name、evidence、assessmentPrompt,依赖的 reason,领域摘要,以及原创的教学研究文字 CC BY-SA 4.0——同样的精神:署名 + 同样方式共享
curriculum-standards.json 从第三方框架中提取 不属于 Marble 可再授权的范围,每个来源各归其上游许可

最容易被误读的是 ODbL 那一栏。「同样方式共享」听起来像是要求你把整个产品开源,但 README 专门解释了这个区别:

ODbL 区分衍生数据库和产出作品。扩展或修改这套分类体系本身,那是一份衍生数据库,必须继续开放;把它用在一个产品、模型或应用里面,那是产出作品,仍然归你。所以完全可以在这份数据上做一个商业产品,而不必开源自己的产品——你欠的只是把对分类体系本身的改进回馈出来。

这个区分不是文字游戏,它是开放数据能不能真正被产业用起来的关键阀门。阀门关得太死,只有学术圈会用;完全不设阀门,数据会被搬走后再也不回来。ODbL 这条线画在了中间。

署名需要包含四样东西:数据集名称与版本 Marble Skill Taxonomy v1、版权方 Generative Spark, Inc. 也就是 Marble、数据库层采用 ODbL 1.0、内容层采用 CC BY-SA 4.0。

如果你用到了课标,还要一并附上 PROVENANCE.md 里的上游声明。正式引用格式在 CITATION.cff 里。

刻意不放进来的东西

一份数据集的品味,往往体现在它拒绝放进去什么。

这一版明确排除了两类内容:

语义向量。 它是派生的、可以重算的,所以不放进仓库。这个决定省掉了一堆派生产物,也省掉了「你算的向量和我算的不一样」这类没完没了的兼容问题。想要就自己算,反正原料都在。

任何与单个孩子相关的数据。 这一类是「永不发布」,不是「暂不发布」。一份关于儿童学习的数据集,这条线不用讨论。

变更历史在 CHANGELOG.md 里。

最后

回到那张星图。

一千五百多颗星,三千多条线,八个学科,每个概念都带着一句人话的解释、一组能看见的证据、一段能问出口的检测语,以及它从哪一份课标里来。有些概念后面还接着教学研究,告诉你可能怎么教、孩子可能怎么错、错了以后下一步往哪走。

把这些东西放在一起,它做的事其实很朴素:把「学会」这个模糊的词,拆成了一张可以走、可以查、可以辩论的地图。

地图不是路。但有了地图,至少不会有人在河边站了很久,还以为自己只是不够聪明。