1. 为什么会想写一个技能管理工具1.1 一次复盘让我发现自己的技能底牌是模糊的事情的起因大概是半年前的一次季度复盘。当时我在梳理自己这一年到底积累了哪些能力脑子里的第一反应是我好像什么都会一点又好像什么都不够硬。这种模糊感在面试、转岗、规划学习方向时尤其致命——你说你熟悉容器化但让你把Kubernetes的调度原理讲清楚你能讲几分钟你说你了解前端工程化那Webpack的构建链路你调过几条我试过用表格记技能试过在备忘录里列清单试过在网盘里存各种课程证书。结果都一样记的时候热血澎湃过两周就荒废因为那个清单没有结构、没有量化、没有行动指引。说白了它只是一份自我感觉良好名单不是能支撑决策的技能底牌。所以就有了skills这个项目。它不是笔记软件的插件也不是那种大而全的人才测评系统而是一个跑在终端里的、用Python写的个人技能管理工具。它解决的核心问题有三个让你随时看清自己的技能结构、让你诚实评估熟练度、让差距自动变成可执行的学习计划。这个工具我断断续续写了三个月中间推翻过两版数据结构现在每天至少用一次。这篇文章把我完整的建模思路、代码设计、踩坑经历整理出来给同样想看清自己手里到底有什么牌的朋友一条可以直接照做的路径。1.2 市面现成方案的痛点要么太重要么太假在动手写之前我先研究过现成的技能管理方案大致分两类。第一类是轻量清单类——比如Excel表格、Notion数据库、各种TODO应用里的技能标签。它们的问题是数据完全靠手填没有任何评估引导今天心情好给自己打个5分明天焦虑了又改成3分评分标准来回漂移。而且维度单一只有技能名分数没有技能之间的层级关系、没有证据记录、没有时间维度根本支撑不了我现在该学什么这个核心问题。第二类是正规测评类——比如企业级的人才盘点系统、胜任力模型平台。这类东西设计严谨岗位模型、行为锚点、雷达图都很完善但个人用起来太笨重。你需要先搭建岗位能力模型再邀请同事给你做360评估再等系统生成一份四十页的报告。跑完流程至少要一周对于个人开发者或者独立从业者来说这个成本根本不可接受。我真正想要的是一个介于两者之间的东西轻量得像记事本但内部数据结构要足够严谨能支撑差距分析和学习规划评估标准要有稳定锚点不至于今天和明天打分口径不一样最好还能留证据——每个分数背后都有一个具体产出物支撑而不是纯感觉。市面上没有这样的工具那就自己造一个这就是skills项目的起点。1.3 设计原则不做App不做云同步先做本地CLI我给自己定了三条设计边界防止项目失控。第一不做图形界面。技能管理是高频短时的行为每天打开终端敲一条命令比打开App点击七八次更快而且CLI天然就是结构化数据的入口。Rich库可以把终端输出做得足够漂亮根本不需要前端。第二不上云、不搞多人协作。这个工具的核心用户就是我自己如果用云端同步就要考虑账号、数据库、服务器复杂度至少翻三倍。数据就存在本地目录下的YAML和SQLite文件里用Git管理版本天然免费且可控。第三优先保证输入体验。很多个人工具的失败在于录入太痛苦所以我花了大量精力在skills check这个交互命令上——它要像答辩一样逐项引导你打分而不是甩给你一张空白表让你自己填。后面我会具体讲这个设计。2. 技能树的建模思路从清单到三层结构2.1 第一版教训扁平清单根本不可维护我先说一段黑历史。skills的第一个版本数据结构极其简单就是一个技能名对应一个分数skills: - name: Python level: 4 - name: Docker level: 3 - name: Kubernetes level: 2 - name: 正则表达式 level: 4用了一周就发现问题了。首先是粒度混乱Python这个技能太宽泛我可能异步编程很熟但对类型系统一窍不通一个4分根本表达不了这种差异。其次是没法做差距分析——我想规划三个月后能独立带队做项目,但Python从4分涨到5分这件事和我真实的能力短板比如系统设计之间没有任何可操作的连接。最要命的是这种扁平结构会不断膨胀今天加一个Redis明天加一个Nginx后天再看这个列表根本不知道先从哪一行开始看。那次重构给我一个重要教训技能数据如果没有层级关系和统一粒度分数成长线就只是一串自我安慰的数字。2.2 领域/能力组/单技能三层模型我把技能树改成了三层结构。顶层是领域代表一个你在职场或作品中会被人问到的能力方向比如后端开发前端工程团队协作写作表达。中间层是能力组把领域下的技能按目标逻辑分组。比如后端开发下面有语言基础工程化实践高并发设计数据存储。底层是单技能它必须满足一个条件能在两周到一个月内通过学习或实践产生可感知的进步。用这个模型前面那条完全没法用的清单就变成了这样domain: 后端开发 groups: - name: 语言基础 skills: - name: Python类型注解 - name: asyncio并发模型 - name: Python C扩展接口 - name: 数据存储 skills: - name: MySQL索引优化 - name: Redis持久化策略 - name: 消息队列选型关键是第三层单技能的粒度。拿Python类型注解举例它可以在一个月内通过写一个包含Protocol、TypeVar、overload的小项目来验证进步但Python不行因为你没法定义练到什么程度算进步。2.3 YAML定义技能树字段设计与扩展性考虑我最终采用的YAML schema在原有三层基础上加了几个关键字段。一个完整的技能条目长这样- name: MySQL索引优化 anchor: index-optimization group: 数据存储 domain: 后端开发 description: | 理解B树结构与索引失效场景 能针对慢SQL进行explain分析与索引重构 level: 3 evidence: - 2025-03 某订单查询接口从800ms优化到50ms - 2025-04 Node客户列表分页深翻页问题修复 next_action: 研究覆盖索引在排序场景中的应用字段设计时我反复斟酌过的有四个anchor是技能在系统内的稳定ID。技能名可以改但锚点不能变这样历史数据才能关联上。description不是摆设。它用一两句话限定这个技能的边界防止我以为的打分标准和实际的能力定义之间产生漂移。level是当前熟练度取值来自Dreyfus五级模型这个我后面专门讲。evidence是证据列表每一条都要能说清楚做了什么、产出什么、解决什么。如果你从这个清单里看不到一个叫Python的技能别奇怪这是三层模型刻意为之的。真正在面试中帮到你的是asyncio并发模型设计过一个限流中间件这种含金量的颗粒度。3. 核心功能拆解与CLI设计3.1 命令设计理念查询和修改彻底分开skills的CLI从一开始就遵循一个原则读操作和写操作分离。我见过很多工具为了减少命令数量让skills list既能查列表又能改分数最后界面一堆flag心智负担极重。我的做法是两套命令空间动作类型命令作用查询skills list查看技能清单支持按领域/能力组/熟练度筛选查询skills tree输出整棵技能树的结构查询skills report生成Markdown格式的分析报告修改skills entry add新增一个技能修改skills check引导式评估更新熟练度修改skills evidence给指定技能追加证据分析skills plan基于缺口自动生成学习计划每个命令都只做一件事参数最少化。比如skills list的过滤能做到skills list --domain 后端开发 --min-level 4这种程度但绝不提供顺带改分数之类的隐藏功能。3.2skills list让技能树在终端里一目了然这个命令是日常使用频率最高的。我依赖Rich库实现了一个带颜色的树形输出顶部显示领域下面缩进显示能力组最底层是技能名、熟练度色块和最近证据时间。# 简化版核心输出逻辑片段 from rich.tree import Tree from rich.table import Table from rich.console import Console console Console() def render_skill_tree(tree_data): root Tree( 我的技能树) for domain, groups in tree_data.items(): domain_node root.add(f[bold]{domain}[/bold]) for group_name, skills in groups.items(): group_node domain_node.add(f[cyan]{group_name}[/cyan]) for skill in skills: level_mark █ * skill[level] ░ * (5 - skill[level]) group_node.add(f{skill[name]} [green]{level_mark}[/green]) console.print(root)输出效果大致类似这样 我的技能树 └── 后端开发 ├── 数据存储 │ ├── MySQL索引优化 [█████░░░░░] │ ├── Redis持久化策略 [███░░░░░░░] │ └── 消息队列选型 [██░░░░░░░░]熟练度用5格色块表达扫一眼就能看出哪块比较薄弱。这个命令解决的核心问题是每当你迷茫我接下来该干嘛的时候技能树的视觉短板会直接告诉你答案。3.3skills check答辩式打分治标也治本如果只给一个懒人接口那必然是skills check。执行后它会逐个取出尚未达到满分5级的技能用交互问答的形式引导评估 开始新一轮技能评估当前需要评估 12 项技能 [3/12] MySQL索引优化当前等级3 最近一次实际应用的产出物是什么请输入关键词或留空 回答某订单接口慢SQL优化 根据以下5级描述诚实评估当前熟练度 [1级] 能在他人口述指导下完成固定操作 [2级] 能独立解决常见问题但某些边界场景需查阅资料 [3级] 能系统性解决问题并理解底层原理 [4级] 能指导他人并沉淀方法论 [5级] 能创造新方法并影响团队技术方向 你的选择1-5这里最关键的设计是强制你先回忆最近一次实践证据再打分。没有证据就不准打分。这一步把凭感觉打分硬生生扭成了凭事实打分是避免自我欺骗的核心机制。我建议这个环节保持每题必答的强制力虽然多花十几秒但打分质量的提升非常明显。后面我会用数据说明自我评估偏差到底有多常见。3.4skills plan差距分析生成三个月学习计划skills check完成更新后skills plan就有了数据基础。它做三件事找出目标等级与实际等级差距2的技能标记为短板。根据技能所属能力组和领域判断优先级——同组多个短板优先处理核心领域优先于边缘领域。按可投入时间默认每天1小时拆分出每周行动项并写入一个Markdown学习计划。def generate_plan(skill_profile, target_levels, hours_per_week7): gaps [] for skill in skill_profile: target target_levels.get(skill[name], 4) if target - skill[level] 2: gaps.append({ skill: skill[name], gap: target - skill[level], domain: skill[domain], }) # 按领域聚合、间隔排序输出行动计划 gaps.sort(keylambda x: x[domain]) return render_plan_markdown(gaps, hours_per_week)生成的学习计划不追求精准到天而是给一个本周聚焦清单。比如这周要做的三件事里第一件永远是给差距最大的技能补一个实战项目而不是看视频课——因为只有实战能同时拉升技能等级和补充证据列表。4. 数据存储与评估模型Dreyfus五级怎么落地4.1 为什么选YAMLSQLite双轨存储skills的数据存储从第一版开始就确立了一个铁律人类可读为主机器可查为辅。所有技能树的定义、描述、证据都放在一个skills.yaml文件里。原因很简单YAML我可以用任何编辑器打开、修改、复制、放到Git里做diff没有任何黑盒。对于个人工具来说可解释性比性能重要一万倍。但纯YAML也有两个问题一是grep跨文件查询能力弱当技能数量超过100个时想快速查有哪些技能低于3级且最近没有证据就很别扭二是没有时间维度历史变更记录难以追踪。所以我在YAML之上加了一层SQLite作为只读索引库。写操作仍然先写YAML然后触发一次skills index同步将解析结果导入SQLite。查询走SQL修改走YAML两边各司其职。同步逻辑是手动调用的不是文件监听。个人工具没必要搞常驻进程一个命令搞定反而更可控。建议每周末跑一次索引同步这样报告的统计口径是稳定的。4.2 Dreyfus五级配套行为锚点避免评分漂移提到熟练度模型很多人第一反应是1到5分打个分不就行了。但前面提过没有锚点的评分必然漂移——今天心血来潮给自己打4分过几天冷静下来又改成2分数据完全失去可比性。所以我把Dreyfus技能获得模型稍微改造了一下每一个等级都绑定了具体行为描述。等级行为锚点典型特征1级 新手能在他人的逐步指导下完成操作需要看着教程操作遇到报错会卡住2级 进阶能独立完成常规任务但边界场景需查资料不再需要手把手但遇到非典型情况会慌3级 胜任能系统性解决一类问题并理解底层原理不只看怎么用还能解释为什么这样设计4级 精通能指导他人、沉淀方法论、复盘复用能把自己的经验结构化传递给团队5级 专家能创造新方法并影响领域方向别人遇到疑难杂症会主动来问甚至团队的技术规范会参考你的方案这个锚点表被直接编译在skills check的交互逻辑里每次打分前都会展示一次。你可能觉得这样有点啰嗦但正是这种反复强化才把我的打分口径从我觉得还行校准到了对照行为我确实只到3级。这里有一个非常明显的例子我在消息队列选型这项技能上曾经一年内给自己打过2分、4分、3分三个版本。直到加了锚点之后才发现我实际能做的只是在两种常见队列间做比较和选择完全谈不上理解底层协议和一致性模型最终稳定在2级。锚点最大的价值不是让你加分而是让你诚实地给自己扣分。4.3 记录证据而不只是分数evidence字段的意义我在skills.yaml的schema里给每个技能留了一个evidence列表这句话现在看可能是全项目最关键的决策。证据不是荣誉列表而是最近一次实际应用的客观记录。我的填写规则是每次为一个技能打分/更新分数时必须有至少一条证据并且证据要能回答三个问题——我在什么场景用过、我做了什么、产出或结果是什么。比如- name: MySQL索引优化 level: 3 evidence: - 2025-03 某订单查询接口慢SQL定位与复合索引重构耗时从800ms降到50ms - 2025-04 分页深翻页场景下改用搜索方案解决offset过大性能问题这两条证据一摆出来任何看到这份数据的人都能立刻理解这个3级是实打实的。证据还有一个隐蔽的价值当你想要进步到下一级时你会自然地去寻找还缺一个什么样的项目来证明我到了4级这就把一个抽象的熟练度目标变成了一个具体的实操待办。5. 可视化报告把技能底牌摊开给自己看5.1 终端里的技能热度图0到5分的色块映射光有树形列表还是不够直观。技能树告诉你有短板但你想知道整个能力结构的健康状况是什么样热度图更合适。skills heatmap命令输出一个按领域分组的矩阵行是单个技能列是周序号格子颜色从红色到绿色表示该周该技能是否有实践/学习记录以及熟练度变化。这个图在终端里就是一块用█字符拼成的色块墙我能很直观地看到过去六周里哪些技能区域一直没被触碰。def render_heatmap(records, weeks6): # records: [{ week, skill, delta_level, has_practice }] from rich.console import Console console Console() header 技能名称 .join([fW{weeks - i} for i in range(weeks)]) console.print(header) for skill in skill_list: cells [] for w in weeks: record records.get((skill, w)) if record and record[has_practice]: cells.append(█) # 用真色块 else: cells.append(░) console.print(f{skill:12} .join(cells))这功能一周跑一次就够了。它的核心洞察和代码量关系不大但极其好用当你严重偏科时热度图上某个领域会连续几周全灰这个视觉冲击比任何总结表格都强烈。5.2 导出Markdown周报给未来的自己看热度图偏向即时感知周报则偏向历史留痕。skills report会把当前技能快照和改动记录渲染成一份Markdown文档我在每周日晚上生成一份放Git仓库里的reports/目录。Week report的内容包括本周新增技能数与总技能数当前每个领域的平均熟练度、最大短板本周实际完成的实践项目清单来自evidence下周推荐聚焦的3个技能我写这份周报时给自己定了一个要求不要在周报里写空泛的自我鼓励。比如下周要加油这种话一句都不许有只允许列出数据和具体行动项。写满三个月后回头翻你能清晰地看到一条技能成长的轨迹——哪周连续断档哪个技能突然起跳都历历在目。5.3 技能组合雷达图的取舍SVG方案多数技能管理工具会画一个雷达图展示多维度能力均衡性。我在skills里试过两个方案最后都砍掉了。第一个方案是在终端里用ASCII字符画雷达图效果惨不忍睹坐标轴稍微多点就混成一团。第二个方案是生成SVG图片。技术上完全可行——生成一个report.svg文件浏览器打开就行。但我发现雷达图对我的决策帮助极其有限雷达图的优点是展示多个维度间的均衡但我的技能树有十几个领域雷达图画出来就是一团颜色鲜艳的变形虫哪个环节凹了远不如前文的树形图直观。砍掉后我把精力集中在WEEK-LEVEL的环比数据上。也就是说与其看静态的均衡性不如看动态的变化趋势。新增了一个skills trend --domain 后端开发命令输出最近八周该领域所有技能等级的折线趋势。这个更实用因为它直接告诉你你的某一个行动项到底有没有拉高技能等级。6. 踩坑与升级真实使用三个月后我改了什么6.1 踩坑一打分上瘾反而助长了自我欺骗第一个月出现了最讽刺的问题我每天跑十几次skills check刷新的不是技能而是分数条。有一阵每次更新完看分数上涨都会感到一阵满足结果月底复盘时发现好几项技能的evidence列表还是空的分数却涨了一级。这个坑伤害很大。等于说工具不仅没有帮我认清自己反而成了自我安慰的玩具。修复方式不复杂我加了一个冷静期规则——任何技能两天内只能打一次分而且更新时必须先填证据。同时在check交互里增加了一个二次确认当本次打分高于上次必须再回答一次你最近的证据是什么。这个改动让打分频次立刻降了下来但证据质量和自评准确度都上去了。6.2 踩坑二技能粒度太粗让计划无法落地第二版技能树虽然比扁平清单好很多但第三层仍然太粗。我最初把Kubernetes当一个技能然后不管怎么努力等级都很难越过3级。后来意识到Kubernetes本身就是二三十个技能的组合——Deployment滚动更新、Service网络、存储卷、RBAC权限、Operator开发每一样都可以作为独立的第三层技能。调细粒度是项体力活但收益极大。切分之后每一项都变得可以定义进步比如RBAC权限模型可以在两周内通过做一个多租户应用加强而Kubernetes本身很难在一个月内感知到提升。我的判断标准是如果一个技能的progress描述需要绕过三层那么粒度就得拆如果一个技能的计划描述里出现了了解熟悉这种模糊动词那一定还没拆到底。6.3 踩坑三只记录不回顾数据沦为僵尸第三个月我发现一个危险信号我的技能数据在持续增长但我再也不看历史数据了。YAML文件越来越长weekly report堆了一堆没人翻。数据一旦停止被使用它就从管理工具变成了数字藏品。我被迫引入一个回顾仪式每周日的那次skills report加上一次原生SQL查询专门找出过去两周都没有任何evidence更新的技能SELECT s.name, s.level, MAX(e.evidence_date) AS last_evidence FROM skills s LEFT JOIN evidence e ON s.anchor e.anchor GROUP BY s.anchor HAVING last_evidence date(now, -14 days) ORDER BY last_evidence ASC;然后逐条问自己这个技能是故意搁置的还是被遗忘的前者允许后者要么补上实践要么干脆从树里降级。这一招挽救了整个工具——数据流重新转动起来不再是记完就死。6.4 最终保留的工作流每周15分钟闭环经过三个月的迭代我淘汰了大部分复杂功能只保留了最小可行闭环。现在每周只花大约15分钟在skills上周一跑一次skills check针对上周计划里的3个重点技能打分更新证据。周日跑skills report结合trend看本周变化然后跑skills plan制定下周聚焦清单。这15分钟的价值不只是记录更重要的是形成了一个实践—打分—规划—实践的闭环。打分迫使你面对事实计划迫使你选择方向证据迫使你真正动手。最后说一点个人体会写完这个项目我自己最大的改变倒不是学会了多少新技能——技能树只是度量工具种树还得靠实操。真正的改变是我不再逃避评估这件事了。以前想到盘点技能就觉得麻烦、心虚现在每天打开终端跑一条命令数据全在那儿短板暴露得清清楚楚反而没那么焦虑了。如果你想复刻这个项目我建议你别照抄我的YAML和命令设计而是先想清楚你最需要回答的问题是什么——是想转行想晋升还是单纯想找到下个月学什么你的问题决定了你的模型。skills的价值不在于它本身有多完美而在于它逼着你把模糊的我感觉我还可以翻译成可定位、可验证的一行行技能记录。最后再分享一个操作层面小技巧在skills.yaml所在目录建一个Git仓库每周末提交一次。三个月后回看提交历史里的skills.yamldiff那种看到自己能力结构一点点重构的感觉会比任何打卡App的连续天数都更真实。
阅读完成 · 觉得有帮助?