首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
用命令行管理个人技能树:从 YAML 数据结构到 CLI 工具实战
📅 2026/10/7 6:52:22
✍️ 爱科研究院
👁 阅读 3,247
最近把自己折腾过的一个小项目重新整理了一遍名字就叫skills。起因很朴素我有段时间觉得自己什么都在学但真到要写简历、做团队技能盘点的时候反而一句话都说不出来。技能点分散在简历、笔记、聊天记录、各个项目的 README 里没有一个地方能说清楚“我目前到底会什么、熟练到什么程度、最近还在不在用”。于是我又犯了程序员的老毛病——不想着去记笔记先写了个工具来管这件事。这篇文章就是完整记录这个叫skills的命令行工具的设计思路、核心实现、开发过程中踩过的坑以及它最终如何融入我的日常工作流。如果你也在琢磨怎么系统化管理自己的技术栈或者想给自己写一个类似的小工具这里面的设计取舍和踩坑过程应该能帮你省不少时间。1. 为什么我会给自己写一个叫 skills 的工具1.1 痛点是“技能数据长在简历里而不是长在系统里”先说说最初的场景。去年我做年中复盘的时候需要把过去半年的技术产出整理成一份文档。我打开简历、翻 Git 提交记录、翻笔记软件、翻团队 Wiki折腾了两个多小时最后产出的技能列表还是靠记忆硬凑的。更难受的是我发现简历上写的“精通 XX”和我内心真实的熟练度根本不是一回事——有些技术我半年没碰了只是因为三年前用过就一直挂在简历上有些技术我每天都在用但我从没认真想过它在我的技能体系里到底处于什么位置。这其实暴露了一个问题技能的“数据”一直被存放在各种不合适的载体里。简历是给别人看的它有美化倾向不适合做真实记录笔记是给自己看的但它只有描述性文字没有结构化的状态管理聊天记录就更不用说了根本称不上数据。所以我的第一个想法是我需要一个专门的地方用结构化的方式管理“我会什么”。我管它叫skills它首先是一个数据文件其次才是一个命令行工具。1.2 为什么不用现成的技能矩阵平台在动手之前我当然先看了一圈现成的方案。Notion 和飞书多维表格可以建技能库在线技能矩阵 SaaS 工具也不少但试下来都有一个共同问题它们把“技能的记录”和“技能的使用场景”隔离得太远。我在终端里写代码、敲命令技能数据却躺在网页里这个距离感会让维护频率直线下降。工具再好如果每次更新要打开浏览器、找到对应的表格、手动改单元格那它很快就会被遗忘。另外很多在线平台对数据的所有权、导入导出的格式都有限制。我是把自己几年积累的技术栈信息放进去如果哪天平台调整收费策略或者关闭服务迁移成本会很高。所以我很明确地定了几个原则本地存储优先纯文本格式优先命令行交互优先。只有做到这三条技能数据才能真正长在我的工作环境里而不是某个第三方平台上。1.3 项目定位写给自己的“技能账本”定下原则之后skills的定位就非常清晰了。它不是简历生成器也不是团队 HR 系统而是一个个人技能账本。它记录三个最核心的问题我学过什么、我现在用到什么程度、我最近还在不在用。为了实现这个定位工具必须足够轻。我没有做 Web 界面没有做数据库甚至没有做服务端就是一个跑在终端里的 CLI。数据文件默认放在~/.config/skills/skills.yaml整体是一个 YAML 文件任何人打开都能看懂也能手动修改。这样做的好处非常明显数据可读、可备份、可进 Git 仓库即使哪天这个工具不再维护我的技能数据也永远是我的随便拿个文本编辑器就能接着记。2. 数据层设计技能树的数据结构才是核心决策2.1 为什么选 YAML 而不是 SQLite 或 JSON很多朋友听说我要写技能管理工具第一反应是“用 SQLite 存啊查询方便”。我理解这个思路但实际做下来发现 SQLite 在这个场景下是过度设计。技能数据的特点是总量小一个人撑死几百条技能记录、结构固定、访问模式简单。它不需要复杂的关联查询不需要并发写入更不需要事务回滚。这种情况下一个结构良好的 YAML 文件比数据库更合适——因为它直接满足了“人可读”这个需求。在 YAML 和 JSON 之间我最终选了 YAML。JSON 当然更通用但 YAML 对“人肉维护”友好太多可以写注释多行字符串不痛苦嵌套结构也不用写一堆花括号。技能数据里不可避免地要写备注、写证据链接YAML 的体验是 JSON 完全比不了的。代价是解析时要小心一些边界情况比如缩进问题、特殊字符转义这个后面踩坑部分会详细说。2.2 分类、层级与字段设计照着“目录树”的思路来技能数据天然是树形的这也是我把核心功能叫做技能树skill tree的原因。最高层是领域category比如后端开发、前端开发、运维与 DevOps、软技能领域下面是具体的技能skill技能再往下是它关联的证据evidence比如参与过的项目、写过的文章、维护过的开源仓库。每个技能条目我设计了这几个字段categories: - name: backend display: 后端开发 skills: - name: golang level: advanced status: active since: 2022-03 last_used: 2025-06-10 evidence: - 交易系统核心服务重构 - 开源项目 x 的主要维护者 tags: [language, backend]这里每个字段都有它的用途level表示熟练度等级status表示当前状态active/stagnant/archivedsince记录从什么时候开始用last_used记录最近一次使用的时间evidence是支撑这个熟练度判断的实际产出tags用于跨领域的检索。这套设计是我试错了好几版之后才稳定下来的它既不过度复杂又能覆盖我 90% 的查询需求。2.3 一个反直觉的决策熟练度不用 1-10 分而是用阶段枚举最早的一版设计里我用的是数字评分1 到 10 打分。用了一段时间发现很别扭今天心情好给 Golang 打 9 分过两天觉得自己也就 7 分的水平数字会因为主观状态剧烈波动。更重要的是数字没有语义9 分和 8 分到底差在哪我自己都说不清楚。后来我换成了 Dreyfus 模型那种阶段式思路简单化成四级basic入门能用、intermediate独立完成常规任务、advanced解决过复杂问题、能带人、expert有体系化的方法论和公认产出。这四级之间是质的差异不是量的差异判断起来没那么纠结。我只需要问自己一个问题这个技能我能不能独立搞定复杂问题并给出让别人信服的方案能就是 advanced不能再高也只能算 intermediate。用枚举之后每次更新熟练度都变成了一次理性的自我评估而不是随手打个分。3. 核心功能拆解从 add 到 tree 的实现细节3.1 命令体系设计子命令优先配置零负担skills的命令设计没有走单命令多参数的老路而是直接用了 Cobra 的子命令体系。原因很简单技能管理这个场景天然就是多动词的添加、删除、查询、统计、导出都是不同的动作硬塞进一个主命令的 flag 里会让命令行变得难记难用。实际的核心命令只有六个命令用途示例skills init初始化配置文件和示例结构skills initskills add添加技能条目skills add golang --category backend --level advancedskills rm删除技能条目skills rm vue --category frontendskills set更新字段熟练度、状态等skills set golang --level intermediateskills query按维度查询skills query --category backend --level advancedskills tree输出完整技能树skills tree --status activeskills export导出为 Markdown 或 JSONskills export --format markdownskills review提示最近未使用的 active 技能skills review --days 30另外还有skills stats做简单的分布统计比如每个领域下 active 技能的数量。这套命令看起来多但实际使用时心智负担很低因为它们就是技能管理的日常动作没有一个是凑数的。3.2 熟练度演化update不是手动打分而是记证据skills set在最早期就是个简单的字段修改命令但用久了发现一个问题我很容易在改熟练度的时候自我欺骗把 intermediate 改到 advanced却说不出来为什么。所以后来我加了一个隐性的规则——如果你要把某个技能升级到advanced或expert必须同时添加一条 evidence。命令设计成skills set golang --level advanced --evidence 主导了交易系统重构线上日志量下降 40%如果--evidence为空工具会拒绝执行升级。这个机制的本质是强迫自己为“熟练度判断”提供依据。它不复杂十几行代码就能实现但它对数据质量的影响极大。从这之后我技能树里的 advanced 以上的条目每一个都有对应的实际产出支撑不再有虚高的数据。skills review则是反向的约束。它扫描所有status: active的技能如果某个技能的last_used距今超过设定天数默认 30 天就列出来问你要不要标记为stagnant。这个功能防止了“我以为我还在用其实已经半年没碰”的情况。每隔一段时间跑一次 review技能树就能自动筛选出值得投入精力保持的技能以及应该诚实面对“已经生疏了”的技能。3.3 tree 渲染在终端里画一棵可读的技能树skills tree是使用频率最高、也是最有成就感的命令。它的输出长这样技能树 ├── 后端开发 │ ├── golang (advanced, active) │ ├── mysql (intermediate, active) │ └── redis (basic, stagnant) ├── 前端开发 │ ├── vue (intermediate, stagnant) │ └── typescript (basic, active) └── 运维与 DevOps ├── docker (intermediate, active) └── kubernetes (basic, active)这个渲染逻辑比想象中要麻烦一点。终端宽度有限技能名、领域名和括号里的状态信息混在一起时很容易出现折行和错位。我没有用现成的树形打印库而是自己处理了树节点的前缀逻辑每一层用├──和└──表示分支缩进用两个空格叶子节点统一用 tabwriter 这类工具做列对齐。为了区分熟练度我给不同 level 加了颜色advanced 用绿色、intermediate 用黄色、basic 用灰色stagnant 的条目会在末尾加一个标记。第一次跑出完整技能树的时候我盯着屏幕看了好一会儿那一刻才真正觉得——这就是我想要的管理面板。4. 开发过程中踩过的三个坑从代码细节到数据结构4.1 Cobra 子命令与普通 flag 解析的“隐式冲突”第一个坑出在命令解析上。Cobra 虽然好用但它的 flag 解析规则和标准库 flag 有一处容易忽略的差异Cobra 的本地 flag 默认只在当前子命令生效持久 flag 才会传给子命令。我在早期版本里把--category同时用在了add、query和set上一开始直接把PersistentFlags()加到了根命令上结果导致所有子命令都必须显式带上这个 flag不传就报错。排查了半天才意识到问题是“定义位置”而不是“代码逻辑”。最后我把全局需要的 flag比如--config指定数据文件路径留在了根命令的PersistentFlags()而--category这样的业务 flag 分散到各个子命令独立定义再用一个initFlags()函数做统一注册。这样既避免了子命令之间的 flag 污染也保持了每个命令的提示信息干净。这个教训用一句话总结就是用 Cobra 时flag 的“作用域”一开始就要想清楚不要图省事全挂到根命令上。4.2 终端中英文混排的对齐问题第二个坑非常典型中文技能名在 tree 渲染时对不齐。最开始实现 tabwriter 对齐时我以为只要按字符数算宽度就够了结果中英文混排的缩进完全乱了。原因在于终端显示的“列宽”是由字节宽度决定的——中文是全角字符占两个英文宽度而 Go 的字符串长度是按字节算的一个中文 UTF-8 字符占 3 个字节。直接用len()计算宽度所有含中文的技能名都会被算短后面项目的对齐就全线崩坏。解决方案是用github.com/mattn/go-runewidth这个库它专门计算字符串的终端显示宽度。每个字符用rune遍历遇到全角字符宽度按 2 算半角按 1 算然后再拿这个宽度去做 padding。修改之后技能树才算真正对齐了。这个坑不好查因为它不报错只是输出看起来乱。如果你以后做任何终端 UI 相关的工具遇到中文对齐问题请第一时间想到 runewidth不要自己造轮子去数字节。4.3 YAML 序列化的字段丢失与默认值陷阱第三个坑藏在 YAML 的序列化行为里。我的技能数据结构中evidence和tags在正常有值的时候没有问题但一旦某个技能的tags为空序列化出来就缺了对应的键。这里涉及 YAML 库我用的gopkg.in/yaml.v3的一个内部细节空切片在序列化时可能被输出为null而不是[]如果字段没有显式设置omitempty之类的 tag就会把空切片序列化成tags: null。更隐蔽的是null在 YAML 里既可以是空值也可以是空映射如果后续解析时类型推断不一致就会产生很难察觉的兼容性问题。我的处理方式是在加载数据后做一个 normalize 步骤遍历所有技能条目把所有为nil的切片字段统一初始化为空切片再写回结构体。同时数据结构里每个字段都显式声明 YAML tag不依赖默认行为。这确保同一个数据文件无论是手工编辑还是工具生成格式都是幂等一致的。数据处理类的工具建议你也在加载后做一次“字段归一化”这比在序列化和反序列化的无数边界里调试要省心得多。5. 完整使用流程从零开始搭建自己的技能管理5.1 初始化与首次录入假设你现在拿到这个工具第一步自然是skills init它会在配置目录下生成一个带示例的skills.yaml。我的建议是不要直接改示例里的数据而是打开这个文件先定义自己的领域分类。领域不宜太细我现在的分类是backend、frontend、devops、mobility、soft五个再细就变成知识点而不是领域了反而失去树形结构的意义。录入具体技能时我有个实用原则先记“正在用”的不要试图把历史上所有用过的东西都补进去。第一次录入的目标是让技能树能真实反映当前状态而不是做一个完整的历史档案。把当前工作中的主力语言、框架、工具链记下来每项填上大概的level和status这个初始版本控制在半个小时以内完成后续再慢慢补。5.2 日常维护把更新技能变成一种轻量习惯工具真正发挥价值靠的是持续维护。我的维护节奏是跟随事件驱动的每次完成一个比较有代表性的任务就顺手更新对应技能的last_used每次意识到某个技能长时间没用了就通过skills review把它标记为stagnant每隔一次大版本迭代我会跑一次skills tree整体看一遍自己的技能分布。这里有一个很重要的使用心得skills的数据准确性比功能丰富度重要得多。哪怕你只是每两个月更新一次last_used也比每天打开工具但数据都是几个月前要好。它本质上是一个自我审视的工具你越诚实它反馈给你的信息越有价值。我自己把skills review加到了每周五的复盘流程里大约每次 10 分钟成了类似 Git 提交那样的例行动作。5.3 导出到简历从技能树直接生成可读片段当初设计导出功能时我考虑的是如何把技能树“用出去”。skills export --format markdown会把技能树转成一段可以直接贴进简历或个人网站的 Markdown 片段### 后端开发 - Golang高级持续使用。主导交易系统重构有开源维护经历。 - MySQL中级持续使用。 - Redis初级较少使用。这个功能虽然简单但非常实用。以前每次更新简历都要重写一遍技能描述现在只需改好skills.yaml导出、粘贴中间省掉了大量重复劳动。它还帮我发现了一个简历的老问题原来我写的“精通”大多数其实只是 intermediate 级别导出功能从源头上杜绝了自我标榜。6. 从个人工具到团队技能地图可行的扩展思路6.1 多机器同步把数据文件交给 Git 管理skills的数据是纯文本 YAML这给它带来了一个天然优势——可以用 Git 做同步。我把~/.config/skills/skills.yaml放到了一个私有仓库里办公电脑和家用电脑之间通过 Git 同步。因为数据结构稳定合并冲突的概率很低真冲突了手动改一下 YAML 也很直观。这个方案比自建同步服务简单一百倍也足够可靠。数据进 Git 之后还能解锁一个隐藏功能历史回溯。用git log可以查看某个技能是什么时候加入的、熟练度从什么时候开始变化。这等于给技能成长记录了带时间线的版本历史比 excel 表格里的“最后修改时间”丰富得多。6.2 团队共享时的格式约定与规范化我后来把skills的数据结构开放给了团队里几个人试用了。这个时候发现个人工具要想在团队里跑起来最容易出问题的地方不是代码而是“格式约定”。不同人记录的技能名写法不统一有人写golang有人写go有人写Go分类也五花八门有人的web领域里包含了后端、前端、UI 设计整体查起来就很混乱。解决办法不是无限兼容而是做一层规范化约束。我给数据文件加了 schema 校验逻辑技能名统一小写连字符风格领域名必须取自预定义的列表熟练度必须是四个枚举值之一。不合法的条目会在读取时报出错误并指出具体位置。实践证明工具强制性约束比文档约定有用得多人的惰性太强了可写可不写的规范最终一定不会被遵守。6.3 Web 展示与自动提醒下一步可以怎么玩最后聊几个我还没做、但已经想清楚方向的扩展。第一个是读入 JSON 或 YAML 后渲染成 Web 技能地图大概就是一个静态页面把技能树按领域和熟练度做成可视化的网格方便分享给同事或者放进个人作品集里。第二个是用 CI 定时跑skills review把长期未使用的高熟练度技能以提醒消息的形式发送到即时通讯群让团队成员能感知各自技能的“保质期”。第三个是给level: expert的技能做关联学习路径比如技能 A 是技能 B 的前置依赖当 B 标记为 stagnant 时自动提示是否需要复习 A。这些扩展的共同点都是基于那个结构化的skills.yaml去生成新的信息。数据结构定好了玩法可以有很多反过来如果一开始就拘泥于特定功能反而很难做出通用性。这也是我对这个项目最满意的一点它最核心的产出不是代码而是一个干净、诚实、可持续维护的数据模型。最后再分享一点个人感受。写完skills之后我最大的变化不是“简历更好写了”这类表面的便利而是我开始更主动地审视自己的技能状态哪些东西在悄悄生锈哪些投入正在产生复利哪些领域其实只是虚张声势的熟悉。工具本身很小几百行代码而已但它帮我把一个模糊的自我认知变成了一个可以定期审视、修正、迭代的数据结构。如果你也想做类似的事情我的建议是别急着写代码先把你想回答的问题列出来然后把数据结构设计好——数据模型想明白了工具只是把它实现出来而已。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/7 6:52:22
Superpowers:开源Web协作开发环境部署与实战
2026/10/7 6:52:22
深入解析MOS管电容特性:米勒电容与开关损耗的工程本质
2026/10/7 6:52:22
Superpowers实战:WebSocket调试、模拟服务器与自动化测试
2026/10/7 7:37:24
超帧与复帧详解:从OTN MFAS到E1/SDH帧同步调测
2026/10/7 7:37:24
Hermes 智能体成长与进化:从闭环学习循环到分层记忆系统的设计实践
2026/10/7 7:37:24
V4L2摄像头采集实战:camera_client工具与MMAP缓冲链路详解
2026/10/7 7:37:24
SpringBoot旅游管理系统毕设实战:源码跑通、环境搭建与二次开发指南
2026/10/7 7:37:24
从零打造ROS2扫地机器人:三条路线、硬件选型与SLAM导航全攻略
2026/10/7 7:32:24
MPP架构核心解析:从并行原理到主流数据库选型实践
2026/10/7 0:01:56
基于sEMG与IMU的手语手势识别:从数据采集到实时部署避坑指南
2026/10/7 0:01:56
装配车间MES落地指南:SimpleMES工单流转、BOM与齐套检查实战
2026/10/7 0:01:56
AI获客怎样减少重复线索?意客AI的原文复用与版本筛选
2026/10/6 15:41:36
Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化
2026/10/6 4:47:52
多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系
2026/10/6 13:15:25
hindsight:面向LLM应用的事后可观测性工程实践
2026/10/6 21:51:29
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/6 22:05:33
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/6 22:06:19
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)