os-taxonomy
少壮不努力,老大徒伤悲。——《汉乐府・长歌行》
把「孩子学会了什么」画成一张会生长的地图
一张会呼吸的星图
想象这样一个画面:整个小学阶段所有能被称为「一个知识点」的东西,被拆成一千多颗小星星,铺在一块黑色的画布上。星星按学科上色,高度代表年龄——越小的孩子站得越低,越大的孩子站得越高;星与星之间有线,线不是装饰,是「必须先懂这个,才能懂那个」。
这不是比喻,这是一份开源数据集自带的视觉说明。它叫 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——恒星的视亮度
一个是四五岁孩子在语言里摸索的第一次完整表达,一个是天文学里关于恒星看起来有多亮的认知门槛。它们被放在同一套结构里,用同一组字段描述。
每个微主题包含六类信息:
- 一句人话的描述——这个概念到底在说什么,用平实的语言讲清。
- 掌握证据——不是「学会了」这种模糊判断,而是可以观察到的具体表现。
- 类型——conceptual、procedural、representational、language、meta 五类之一。概念性的、程序性的、表征性的、语言性的、元认知性的,五种不同的「懂」。
- 学科 + 领域——它属于哪一科,以及科内的哪个领域。
- 大致年龄区间——这个概念通常在什么年纪出现。
- 课标出处——它从哪些标准里被蒸馏出来。
这里面最见功力的是第二项,「掌握证据」。文档给出的示例是这样一个微主题: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 | { |
id 是稳定标识,前缀 mt_,依赖表和邻居引用都靠它对齐。这一点看着平常,其实是整份数据能不能被长期依赖的分水岭——名字会改,描述会改,ID 不能改。
一条依赖:
1 | { "topicId": "mt__00ZSLnB7p", "prerequisiteId": "mt_VBl1T1sFCM", "strength": "hard", |
两行,三个字段,加一句理由。整张图的 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 | import topics from './data/topics.json' with { type: 'json' }; |
几行代码,就把「搭句子」这个主题的所有直接前序,换成了人能读的名字。
再往上一层,把教学指引接进来:
1 | import research from './data/teaching-research.json' with { type: 'json' }; |
这段代码本身就是一份文档。它取的例子恰好是一个查不到的主题——English 还不在研究覆盖范围里,于是注释里直接写着 undefined,把原因交代清楚。示例没有绕开这个空洞,而是把它留在原地。
愿意在示例里展示失败路径的数据集,通常对自己的边界心里有数。
结构、研究覆盖、证据链接、校验和,都能验:
1 | node scripts/validate.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 里。
最后
回到那张星图。
一千五百多颗星,三千多条线,八个学科,每个概念都带着一句人话的解释、一组能看见的证据、一段能问出口的检测语,以及它从哪一份课标里来。有些概念后面还接着教学研究,告诉你可能怎么教、孩子可能怎么错、错了以后下一步往哪走。
把这些东西放在一起,它做的事其实很朴素:把「学会」这个模糊的词,拆成了一张可以走、可以查、可以辩论的地图。
地图不是路。但有了地图,至少不会有人在河边站了很久,还以为自己只是不够聪明。
