用YAML和Python打造个人技能树:从技能盘点开始的高效学习管理

发布时间:2026/10/20 12:50:35
用YAML和Python打造个人技能树:从技能盘点开始的高效学习管理 “skills”这个词看起来特别普通但如果你把它当成一个项目名字来琢磨就会发现里面藏着一个很现实的问题我们每天在学技能却很少有人能说清楚自己到底会什么、学到哪一步了、下一步该学什么。我搭这个小项目的时候就是想把“技能”从一句自我介绍变成一份能长期维护、能统计、能复盘的数据资产。它叫 skills本质不复杂用 YAML 文本记录技能树用 Python 脚本生成报告用 Git 保存每次成长轨迹。你不用把它想成又一个学习类 App它更像一个给技能用的“仓库管理台账”。适合正在自学的人、带团队的开发者也适合想做团队技能盘点的人。这篇文章会从需求拆解讲到具体实现再把我在实际使用中踩过的坑一并倒出来。1. 项目整体设计与需求拆解1.1 为什么需要一份“技能清单”我最早意识到这个问题是前两年和一帮朋友做项目复盘。有人说自己“会 Python”但问他 Python 的异步模型到底怎么回事他只能含糊地说“看过概念”。这不是他能力不行而是绝大多数人对技能的认知都停留在“我接触过”“我好像会”这种模糊状态。技能和钱其实很像。你不记账就永远不知道钱花到哪去了你不给自己的技能做盘点就会陷入“学了三年回头一看简历还是那三板斧”的尴尬。尤其是做技术的人知识更新那么快今天看一门新语言明天学一个框架如果没有一个结构化的清单知识很容易变成一团浆糊。于是 skills 的第一个设计目标就是把隐性技能显性化。它要能回答三个问题。我现在掌握哪些领域的哪些技能每个技能从“听过名字”到“能带人做项目”处在哪个阶段哪些技能之间是前置关系下一步最该学什么想清楚这三个问题技能清单就不再是自嗨而是一张可以做决策的地图。1.2 方案选型为什么不用现成工具而用 YAMLPython做技能管理市面上不是没有工具。Excel 能记录思维导图能展示各种笔记软件也能做表格。但我试过一圈发现都有点别扭。Excel 的问题是太自由。字段一多格式就开始漂移你今天想加一列“最近使用时间”明天想加一列“熟练度分数”最后表格变成了谁都不想打开的重灾区。思维导图好看但它只适合展示结构不适合记录“进度”和“依赖关系”这种动态信息。商业化的技能测评工具更重数据还锁死在平台里想换个展示方式非常麻烦。所以我选择了最“土”也最不容易过时的方案YAML 存数据Python 做处理Git 管历史。这个组合有四个好处。第一YAML 是纯文本任何编辑器都能打开不会因为某个软件停服就报废。第二数据结构可以跟着认知一起迭代今天想加字段改 YAML 就行不用动数据库。第三Python 处理文本的生态太成熟了解析 YAML 只需要一个库生成 Markdown、HTML 都是顺手的事。第四配合 Git每次技能变化都有提交记录哪天想回看自己半年前的技能状态一条命令就能还原。这个选型逻辑放在今天依然成立。工具永远在变化但文本化的数据模型和自动化脚本是能陪你很久的东西。2. 核心细节解析与数据模型设计2.1 技能树的层级结构与字段定义我先把技能树设计成三层领域domain、技能skill、知识点topic。领域是大的方向比如“后端开发”“数据分析”“软技能”。技能是领域下的具体能力比如 Python、SQL、沟通表达。知识点是技能下面的细节比如 Python 下面的装饰器、异步编程、上下文管理器。为什么要分三层因为两层太粗四层又太重。面试的时候你能说“我会 Python”但 Python 很大你要能进一步拆到“我会装饰器”“我理解事件循环”这种粒度才算真正知道自己会什么。知识点这一层恰好是“自我评估”和“实际工作”之间的最小单元。每个技能的字段也应该尽量克制我现在用的核心字段就五个。- name: Python state: proficient level: 4 prereq: [] topics: - name: 装饰器 state: learned note: 能写带参数的装饰器但 functools.wraps 的细节还要再翻 - name: 异步编程 state: learning note: 已理解事件循环实际项目里还没敢用name 不用解释。state 是这个技能当前的整体状态。level 是熟练度等级0 到 5 的整数。prereq 是前置技能列表专门用来表达依赖。topics 是知识点清单每个知识点也带自己的 state还可以加 note 记录一句当时学习的具体心得或迷惑。为什么技能本身要有 state 和 level 两个维度我自己的体会是state 回答“我现在处于什么学习阶段”level 回答“这个技能在我整个能力体系里有多熟练”。两者可以互相印证比如 state 是 mastered 而 level 只有 2那就说明你对自己的“精通”判断失真了。后面统计的时候这两个字段也可以交叉校验。2.2 状态、等级与行为锚定状态定义这件事最初很不以为然觉得不就是“没学、在学、会了”吗实际用起来才发现如果不定义清楚你对自己的评估会随着心情漂移。今天心情好觉得自己精通明天遇到不会的又觉得自己啥都不会。所以我在 YAML 头部放了一段状态定义每个状态都对应到行为而不是形容词。state_meaning: planned: 了解背景尚未动手 learning: 能写示例但不足以独立上项目 learned: 能在项目中独立使用并解决基础问题 proficient: 能评审他人代码能指导新人 mastered: 能输出方法论影响团队或社区这里有个很关键的心得判断状态别问“我感觉自己会多少”要问“我能拿它做成什么事”。举个例子SQL 的窗口函数如果你只能照着教程写出一个 row_number那状态就是 learning如果你能在一张真实业务表里完成分组排名和移动平均并且解释清楚为什么性能比子查询好那才能算 learned 或更高。这样锚定之后状态判断就会稳定很多。level 等级和状态的对应关系我习惯做一个简单的映射planned 对应 0 或 1learning 对应 2learned 对应 3proficient 对应 4mastered 对应 5。这不是强制规则但可以让统计数字更直观。比如一个技能 level 是 3你一眼就知道它具备独立使用能力。2.3 依赖关系让技能树长出学习路径前端有个库后端的任务队列依赖消息队列机器学习依赖 Python 基础和数据清洗能力。这些依赖关系如果只是放在脑子里很容易在学新东西的时候遇到“前置没打通”的挫败感。所以我给技能加了 prereq 字段。- name: FastAPI state: learning level: 2 prereq: - Python - HTTP 基础这样做的直接好处是脚本可以帮你找出“前置未满足”的技能。比如你想把 FastAPI 标记为 learned但它的前置技能 Python 里还有一个关键知识点是 learning 状态那你就知道现在不该硬学 FastAPI而是先回头把那块短板补上。依赖关系的另一边是循环依赖。A 依赖 BB 又依赖 A这在技能体系里是真实存在的比如“Web框架”和“HTTP协议”就容易互相需要。遇到这种情况不用害怕检查脚本里做一次循环检测发现后给一个提示然后你自己选择把其中一个设为主依赖、另一个设为同步学习就行。技能学习本来就不是单线程依赖图有环很正常关键是别让这种环影响你的执行顺序。3. 实操过程与核心环节实现3.1 初始化项目目录新建项目的第一步不是写代码而是把目录结构搭好。我自己用的目录很简单但足够跑起来。mkdir skills cd skills git init mkdir scripts output notes为什么单独搞一个仓库因为技能数据会持续更新很久单独仓库能让 Git 历史非常干净方便回溯。你也可以把整个目录放到一个更大的笔记仓库里但那样提交历史和统计脚本容易混在一起。目录说明skills.yaml主技能清单核心数据。scripts/放解析和生成脚本。output/脚本生成的报告不入库也可以但留着方便看。notes/每次学习后写的几行心得文件名用日期开头。初始化后我习惯先创建一个空 README写清楚这个仓库是干嘛的。这一步不是形式主义而是给你自己一个承诺从今天开始技能要被管理。3.2 编写第一份技能清单第一份 YAML 不需要追求完美我建议只写三个领域、每个领域两三个技能把自己最有把握的部分先填进去。下面是一份可直接复制的简化版。# skills.yaml version: 1 owner: myself updated: 2024-06-01 state_meaning: planned: 了解背景尚未动手 learning: 能写示例但不足以独立上项目 learned: 能在项目中独立使用并解决基础问题 proficient: 能评审他人代码能指导新人 mastered: 能输出方法论影响团队或社区 domains: - name: 后端开发 skills: - name: Python state: proficient level: 4 prereq: [] topics: - name: 装饰器 state: learned note: 能写带参装饰器但 wraps 细节还要加深 - name: 异步编程 state: learning note: 理解事件循环缺真实项目经验 - name: 数据分析 skills: - name: SQL state: proficient level: 4 prereq: [] topics: - name: 窗口函数 state: learned note: rank/row_number 已经常用移动平均还没练透 - name: 执行计划 state: planned note: - name: 软技能 skills: - name: 技术汇报 state: learned level: 3 prereq: - 结构化表达 topics: - name: 电梯汇报法 state: learned note: 能在三分钟内说清背景、方案、结果这里有几个写数据的小技巧。owner字段不只是给人看的。如果你之后把这份 YAML 放在团队里共享脚本可以根据 owner 做分组统计多个人的技能数据放在同一个仓库里也不会乱。每个知识点都要有 note哪怕是空字符串占位。因为当你一个月后回看时没有 note 的知识点大概率已经想不起当初学到什么程度了。哪怕只写“看过文档没动手”也保留了一条有效线索。3.3 用 Python 脚本解析、统计并输出报告数据是死的脚本可以把数据盘活。我写了一个report.py只依赖 PyYAML 一个第三方库职责分成四块读取 YAML、统计状态、生成 Markdown 报告、打印树状结构。#!/usr/bin/env python3 # scripts/report.py import argparse from pathlib import Path import yaml def load(path): with open(path, r, encodingutf-8) as f: return yaml.safe_load(f) def build_stats(domains): states {} total 0 for domain in domains: for skill in domain.get(skills, []): for topic in skill.get(topics, []): total 1 s topic.get(state, planned) states[s] states.get(s, 0) 1 return states, total def build_markdown(data, stats, total): lines [ # Skill Report, , fowner: {data.get(owner, anonymous)}, fupdated: {data.get(updated, -)}, , ## 状态统计, , | state | count |, |-------|-------|, ] for s in sorted(stats, keylambda x: -stats[x]): lines.append(f| {s} | {stats[s]} |) lines.append(f\n**total topics: {total}**\n) for domain in data.get(domains, []): lines.append(f## {domain[name]}) for skill in domain.get(skills, []): lines.append(f### {skill[name]} ({skill.get(state, )}, level {skill.get(level, 0)})) for topic in skill.get(topics, []): lines.append(f- [{topic.get(state, planned)}] {topic[name]}) if skill.get(prereq): lines.append(f - prereq: {, .join(skill[prereq])}) return \n.join(lines) def build_tree(data): lines [] for domain in data.get(domains, []): lines.append(domain[name]) for skill in domain.get(skills, []): lines.append(f {skill[name]} [{skill.get(state, )}/{skill.get(level, 0)}]) for topic in skill.get(topics, []): lines.append(f - {topic[name]} [{topic.get(state, planned)}]) return \n.join(lines) def find_unmet(domains): all_skills set() for domain in domains: for skill in domain.get(skills, []): all_skills.add(skill[name]) unmet [] for domain in domains: for skill in domain.get(skills, []): for prereq in skill.get(prereq, []): if prereq not in all_skills: unmet.append((skill[name], prereq)) return unmet def main(): parser argparse.ArgumentParser(descriptionskills 技能树管理工具) parser.add_argument(--file, defaultskills.yaml) parser.add_argument(--out, defaultoutput/report.md) args parser.parse_args() data load(args.file) domains data.get(domains, []) stats, total build_stats(domains) Path(args.out).parent.mkdir(exist_okTrue) Path(args.out).write_text(build_markdown(data, stats, total), encodingutf-8) print(build_tree(data)) print(ftotal topics: {total}) unmet find_unmet(domains) if unmet: print(unmet prereq:) for skill, prereq in unmet: print(f {skill} - {prereq}) if __name__ __main__: main()代码里有一个很多人容易忽略的安全点读取 YAML 要用yaml.safe_load不是yaml.load。yaml.load在 Python 里默认可以构造任意对象如果文件被别人改写成危险内容执行时就有风险。虽然这是本地私人文件但习惯安全加载很重要。find_unmet函数会扫一遍依赖如果某个技能的 prereq 没有出现在整个技能清单里就说明你列了一个“前置技能”却根本还没建这个技能条目。这多半是漏记了脚本给你提个醒比以后学的时候突然卡住要好。运行方式很简单。python scripts/report.py --file skills.yaml --out output/report.md第一次跑完你会看到类似下面的树状输出。后端开发 Python [proficient/4] - 装饰器 [learned] - 异步编程 [learning] 数据分析 SQL [proficient/4] - 窗口函数 [learned] - 执行计划 [planned] 软技能 技术汇报 [learned/3] - 电梯汇报法 [learned]看到结构的那一刻会比任何“年度总结”都直观原来我在哪些方向上有积累哪些地方只是“听过没练”。3.4 每周复盘让 git 记录你的成长轨迹脚本只是工具真正让项目跑起来的是复盘节奏。我的习惯是每周五下午花十五分钟做一次“技能记账”。先打开skills.yaml把本周新学的知识点补上把已经熟练掌握的知识点从 learning 改成 learned顺手调整 level。然后运行报告脚本最后提交 git。git add skills.yaml output/report.md git commit -m week 2024-22: 完成 SQL 窗口函数练习开始看执行计划这看起来很简单但它解决了一个深层问题学习反馈周期太长人容易失去方向。技能报告就是你的“驾驶仪表盘”每次提交都在告诉自己这周数据更新了方向没有偏。我还习惯在notes/目录里同步写一篇三五行的学习笔记文件名格式是2024-06-01-python-async.md。这篇笔记不追求完整只记录三个东西今天解决了什么问题、卡在哪里、下一步是什么。有了这些碎片以后写月报、写面试项目经验素材都是现成的。4. 常见问题与排查技巧实录4.1 YAML 解析报错八成是缩进和字符问题YAML 看起来简单真写起来很容易翻车。最常见的报错是expected block end这种解析错误原因通常是缩进不一致。我一开始用的是两个空格缩进但某天在某个知识点下面多敲了一个 Tab脚本直接罢工。排查方法很简单先在命令行跑一句快速验证。python -c import yaml; yaml.safe_load(open(skills.yaml))如果不报错说明 YAML 语法没问题再去查脚本逻辑。如果报错优先检查三件事一是不是用了 Tab 混合空格二是不是某个 key 后面忘了冒号三是不是未加引号的字符串里带了:或#。比如知识点 note 里写note: 用了 xxx: 这个方法如果漏掉引号后面的冒号就会被解析成层级直接报错。另外中文和英文冒号不要混用。中文冒号在 YAML 里只是普通字符但如果你用它本来想表示分隔符就会出现“看起来正常其实 key 没生效”的怪问题。这种 bug 特别隐蔽我花了大半个小时才找到。4.2 “全凭感觉”的状态如何校准状态定义写在 YAML 里但实际更新时还是容易凭感觉。我有一次打开清单发现自己把某个技能从 learning 改成了 proficient仔细一想其实只是那周多看了几篇文章并没有实际项目验证。后来我发现校准状态最有效的办法是“用输出倒逼输入”。具体操作是每次打算把状态从 learning 改成 learned 或更高级别时先问自己三个问题能不能不看资料把原理讲给另一个人听能不能独立写一个可运行的最小示例如果相关代码出了问题能不能在半小时内定位到原因如果三个答案都是“能”状态才可能真的往前走。如果有一个“不能”那就继续留在原状态并在 note 里写下还需要补什么。这么做的本质是把技能评估从“自我感动”变成“行为检验”。时间长了你会发现自己对技能的判断明显变准写简历的时候也不再心虚。4.3 坚持不下去先做最小可维护记录我见过不少人照着这个思路搭好项目然后两周就放弃了。原因不是工具不顺手而是把记录这件事搞成了负担。天天更新 YAML、天天跑脚本、天天提交哪来那么多可记录的最终变成为了记而记自然坚持不下去。我的建议是把复盘频率降下来把每次更新的范围缩小。每周一次批量更新就够。平时学到什么新知识只需要在notes/里顺手写一句周末再统一整理进skills.yaml。这样既不会漏掉重要信息也不会被高频维护压垮。另一个缓解坚持困难的办法是给脚本加一个“待办提示”。在 YAML 里给知识点加一个todo字段比如todo: 下次要研究移动平均的窗口边界然后让脚本在输出报告时把 todo 汇总显示。这样每次看报告你都会知道自己接下来还能做什么而不是对着清单发呆。4.4 隐私与多人复用该怎么处理技能清单某种程度上是个人能力画像属于比较敏感的数据。如果把仓库推到远程或者放在团队共享盘里先想清楚哪些信息能公开。我的处理办法是分成两份文件主力技能放在skills.yaml可以共享包含薪资期望、内部项目细节等敏感信息的内容放在private.yaml并且在仓库里加.gitignore忽略掉它。private.yaml notes/private/多人复用的时候每个人在自己的分支上维护自己的 YAML或者按文件名拆分比如skills-zhang.yaml、skills-li.yaml然后用同一个脚本批量汇总。汇总后生成的报告可以用来做团队技能地图项目排期的时候谁适合哪个模块几乎一眼就能看出来。不过有一点要提前约定好所有人的字段结构必须一致。否则有人写了 level有人没写有人用proficient有人用熟练汇总脚本就得写一堆兼容逻辑。团队里推行这种项目先把 YAML 模板固定下来比什么都重要。最后说一点我自己的体会。skills 这个小项目看起来是在管理技能实际上是在管理注意力和方向感。每次更新它我都会被迫想一遍过去这段时间究竟是把时间花在了真正重要的技能上还是在“低水平的重复”里自我安慰。这种复盘带来的价值远超那些数字本身。如果你也想跑起来别想着一次就搭一个完美体系先用最简的 YAML 记下十个自己真正在用的技能跑一次脚本看见输出结果之后你自然会知道下一步该往哪使劲。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询