1. 当“skills”成为一个项目标题:我看到的不是空壳,而是最诚实的起点
第一次看到“skills”这个项目标题时,我的反应和大多数人一样——这也太宽泛了。没有正文,没有关键词,没有摘要描述,连一个限定词都没有。放在任何一个项目列表里,它都像是一个占位符,一个还没来得及想好名字就匆匆提交的半成品。但恰恰是这种“什么都没有”的状态,让我觉得值得认真聊一聊。
因为在实际工作中,我见过太多类似的情况。一个开发者新建了一个仓库,名字就叫“skills”,然后对着空白的README发呆。他不是不知道自己要做什么,而是想做的事情太多,反而不知道从哪里开始描述。这种状态本身就是一个信号:他意识到自己需要一套系统化的能力管理方案,但还没想清楚这套方案的具体形态。
“skills”这个词在当下的语境里,已经远远超出了“技能”这个单一翻译的范畴。它可以是个人能力矩阵的梳理工具,可以是团队技能图谱的可视化方案,可以是一个技能评估与追踪的系统,也可以是一个帮助开发者规划学习路径的辅助工具。标题的开放性反而给了我们最大的讨论空间——我们可以从任何一个合理的角度切入,去拆解一个“skills”项目应该具备的核心要素。
这篇文章适合几类人看:如果你手里正好有一个类似命名的项目,不知道该怎么往下推进;如果你在团队里负责技术能力建设,想找一个系统化的管理思路;或者你只是一个对个人成长有要求的从业者,想看看别人是怎么把“技能”这件事从模糊的感觉变成可操作的系统。不管你是哪种情况,接下来的内容都会给你一些可以直接参考的东西。
我打算从五个层面来拆解这个项目:先搞清楚“skills”作为一个项目到底要解决什么问题,再聊数据模型怎么设计,然后是核心功能的实现思路,接着是实际落地时容易踩的坑,最后分享一些让项目真正产生价值的运营经验。每个部分我都会给出具体的方案和代码示例,你可以直接拿去改改用。
2. 先想清楚“skills”项目到底要解决谁的什么问题
2.1 三种典型场景下的需求差异
一个没有正文描述的项目,最危险的做法就是直接开始写代码。我见过太多人拿到一个模糊的需求就开始搭架子,结果写到一半发现方向错了,推倒重来的成本高得让人想放弃。所以在动手之前,我们必须先把“skills”这个项目可能服务的场景想清楚。
第一种场景是个人能力管理。一个开发者想系统地记录自己掌握的技术栈、熟练程度、学习时间线,以及下一步的学习计划。这种场景下,项目的核心是“自我追踪”,数据是私有的,功能重点是录入便捷、可视化清晰、能生成成长曲线。用户可能每天花两分钟更新一下状态,周末花十分钟回顾一下进展。
第二种场景是团队技能盘点。一个技术团队的负责人需要知道团队里每个人会什么、不会什么、谁可以补位、哪些技能存在单点依赖。这种场景下,项目的核心是“全局视图”,数据是共享的,功能重点是权限管理、技能矩阵展示、缺口分析。负责人可能每个月做一次盘点,每次盘点后要输出一份报告给上级。
第三种场景是学习路径规划。一个刚入行的新人想知道从当前水平到目标岗位之间还差哪些技能,以及按什么顺序去补齐。这种场景下,项目的核心是“路径推荐”,数据是半公开的,功能重点是技能图谱、依赖关系、资源关联。用户可能每周调整一次计划,每次调整后要看到明确的下一步行动。
这三种场景的需求差异非常大,但它们的底层逻辑是相通的:都需要一个结构化的方式来描述“技能”,都需要一个可量化的方式来评估“水平”,都需要一个可视化的方式来呈现“全貌”。如果我们能在数据模型层面把这三件事抽象好,上层的功能就可以按需组合。
2.2 为什么大多数技能管理项目最后都变成了“僵尸项目”
我观察过一个现象:很多人在年初兴致勃勃地建了一个技能管理表格或者小工具,到了三月份就再也没打开过。这不是因为懒,而是因为设计上出了问题。最常见的原因有三个。
第一个原因是录入成本太高。每次更新都要填一堆字段,选一堆标签,写一段描述。用户坚持了两周就烦了,因为收益看不见,成本却每天都在发生。好的设计应该是“默认值合理、增量更新、一键操作”。比如熟练度用滑块而不是下拉菜单,学习记录用一句话而不是结构化表单。
第二个原因是反馈周期太长。技能提升是一个缓慢的过程,如果项目不能提供即时的正向反馈,用户很快就会失去动力。解决方案是引入“微成就”机制:每完成一个小目标就点亮一个节点,每连续记录一周就生成一张趋势图,每掌握一个新技能就解锁一个徽章。这些机制听起来简单,但效果非常好。
第三个原因是缺乏外部连接。一个人的技能管理是孤独的,如果能看到同行在学什么、团队在缺什么、市场在要什么,动力会强很多。所以项目在设计之初就要考虑“可分享”和“可对比”的能力,哪怕只是生成一张可以导出的技能卡片。
注意:不要一上来就做社交功能。先让单机版跑通,让用户自己觉得有用,再考虑连接的事。我见过太多项目死在“先做社区”上。
2.3 最小可行产品的边界在哪里
基于上面的分析,一个“skills”项目的最小可行产品应该包含三个核心能力:技能录入、水平评估、视图展示。其他的都可以往后放。
技能录入要支持快速添加和批量导入。快速添加是指用户输入一个技能名称就能创建,系统自动补全分类和标签。批量导入是指支持从文本、表格、甚至简历中解析技能列表。水平评估要有一个简单直观的标尺,比如1到5级,每一级有明确的行为描述,而不是让用户凭感觉打分。视图展示至少要提供列表视图和雷达图视图,列表用于日常查看,雷达图用于整体感知。
这三个能力做扎实了,项目就有了存在的价值。后面再加学习计划、资源推荐、团队对比、趋势分析,都是锦上添花。但如果这三个能力没做好,加再多功能也是空中楼阁。
3. 数据模型设计:把“技能”这件事拆到不能再拆
3.1 技能本体的结构化描述
在数据库里,“技能”不能只是一个字符串。它需要被拆解成多个维度,才能支撑后续的评估、分析和推荐。我通常会把技能本体拆成以下几个字段。
基础信息包括技能名称、别名、分类、标签。名称是唯一标识,别名用于处理同义词,比如“JS”和“JavaScript”应该指向同一个技能。分类用于粗粒度分组,比如前端、后端、数据库、运维。标签用于细粒度筛选,比如“框架”、“语言”、“工具”。
元信息包括难度等级、学习周期、依赖关系。难度等级可以用1到5表示,学习周期用小时或周表示,依赖关系用关联表存储。这些信息不需要用户手动填写,可以从公开数据中预置,用户只需要确认或微调。
状态信息包括当前水平、目标水平、最后更新时间、学习状态。当前水平和目标水平用同一个标尺,最后更新时间用于提醒和统计,学习状态可以是“未开始”、“进行中”、“已掌握”、“已放弃”。
CREATE TABLE skills ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(100) NOT NULL UNIQUE, aliases TEXT, category VARCHAR(50), tags TEXT, difficulty INTEGER DEFAULT 3, estimated_hours INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE user_skills ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, skill_id INTEGER NOT NULL, current_level INTEGER DEFAULT 0, target_level INTEGER DEFAULT 3, status VARCHAR(20) DEFAULT 'not_started', last_updated DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (skill_id) REFERENCES skills(id), UNIQUE(user_id, skill_id) );这个设计的关键在于把“技能是什么”和“用户对技能的掌握情况”分开存储。前者是全局共享的,后者是用户私有的。这样设计的好处是,当多个用户都关注同一个技能时,技能本体的信息只需要维护一份,而每个人的掌握情况互不干扰。
3.2 水平评估的标尺怎么定才合理
水平评估是技能管理项目里最容易做歪的地方。很多人直接用一个1到10的滑块让用户自己拖,结果就是每个人对“5分”的理解都不一样,数据完全没法横向对比。我的做法是给每一级都写清楚行为描述,让用户对号入座。
以“数据库设计”这个技能为例,1级是“了解基本概念,能看懂ER图”,2级是“能设计简单的单表结构,会写基本的增删改查”,3级是“能设计多表关联,理解范式,会做基本的索引优化”,4级是“能设计高并发场景下的分库分表方案,熟悉多种数据库的适用场景”,5级是“能主导数据库架构设计,解决过复杂的性能问题,有方法论沉淀”。
这样的描述让评估变得客观很多。用户不需要纠结“我到底算几分”,只需要看自己能做到哪一级。而且这种描述本身就有指导意义,用户看到下一级的要求,就知道自己该往哪个方向努力。
提示:行为描述要具体、可验证、不含糊。避免使用“熟练掌握”、“深入了解”这类主观词汇,用“能做什么”来代替“懂多少”。
3.3 技能之间的依赖关系怎么建模
技能不是孤立的。学React之前最好先会JavaScript,学Kubernetes之前最好先懂Docker。如果项目能把这些依赖关系建模,就可以做路径推荐和缺口分析。
依赖关系用一张关联表来存储,包含前置技能、后置技能、依赖强度三个字段。依赖强度可以用1到3表示,1是“建议先学”,2是“最好先学”,3是“必须先学”。有了这张表,我们就可以做拓扑排序,生成合理的学习路径。
CREATE TABLE skill_dependencies ( id INTEGER PRIMARY KEY AUTOINCREMENT, prerequisite_skill_id INTEGER NOT NULL, dependent_skill_id INTEGER NOT NULL, strength INTEGER DEFAULT 1, FOREIGN KEY (prerequisite_skill_id) REFERENCES skills(id), FOREIGN KEY (dependent_skill_id) REFERENCES skills(id), UNIQUE(prerequisite_skill_id, dependent_skill_id) );依赖关系的初始化可以手动录入,也可以从公开的技能图谱中导入。我建议先手动录入核心的几十条关系,覆盖主要的技术栈,剩下的让用户自己补充。用户补充的数据可以标记为“社区贡献”,经过一定数量的验证后再转为“官方数据”。
3.4 学习记录的存储与查询优化
学习记录是用户最频繁写入的数据。每次用户更新技能水平、添加学习笔记、完成一个学习任务,都会产生一条记录。如果设计不当,这张表会迅速膨胀,查询性能会急剧下降。
我的做法是把学习记录分成两类:状态变更记录和内容记录。状态变更记录只存技能ID、旧水平、新水平、时间戳,数据量小但查询频繁。内容记录存笔记、心得、资源链接,数据量大但查询较少。两张表分开存储,分别优化。
CREATE TABLE skill_level_changes ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, skill_id INTEGER NOT NULL, old_level INTEGER, new_level INTEGER, changed_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE skill_notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, skill_id INTEGER NOT NULL, content TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_level_changes_user_time ON skill_level_changes(user_id, changed_at); CREATE INDEX idx_notes_user_skill ON skill_notes(user_id, skill_id);索引的设计要匹配查询模式。如果最常用的查询是“某个用户最近一个月的水平变化”,那么(user_id, changed_at)的联合索引就是必须的。如果最常用的查询是“某个技能下所有用户的笔记”,那么(skill_id, created_at)的索引更合适。不要盲目加索引,每个索引都会增加写入成本。
4. 核心功能实现:从录入到可视化的完整链路
4.1 快速录入的交互设计与实现
录入是用户接触项目的第一个环节,体验好坏直接决定了用户会不会继续用下去。我的设计原则是:能点选的不打字,能自动的不手动,能批量不单个。
具体来说,用户进入录入页面时,首先看到的是一个搜索框。输入技能名称的前几个字符,系统就从预置的技能库中匹配候选。如果匹配到了,用户点击即可添加,系统自动填充分类、标签、难度等信息。如果没有匹配到,用户可以选择“创建新技能”,只需要填写名称和分类,其他信息可以后续补充。
批量录入支持三种方式:粘贴文本、上传表格、导入简历。粘贴文本是最常用的,用户把一段包含技能关键词的文字贴进来,系统用正则和词典匹配出技能列表,让用户确认。上传表格要求用户按照模板填写,适合有现成数据的情况。导入简历是进阶功能,需要解析PDF或Word,实现成本较高,可以放在后期。
def parse_skills_from_text(text, skill_dict): found = [] for skill_name, skill_info in skill_dict.items(): if skill_name.lower() in text.lower(): found.append(skill_info) for alias in skill_info.get('aliases', []): if alias.lower() in text.lower(): found.append(skill_info) break return list({s['id']: s for s in found}.values())这个匹配逻辑看起来简单,但实际用起来效果不错。关键是要维护一个高质量的技能词典,包含常见的别名和缩写。词典可以定期从公开数据源更新,也可以让用户贡献。
4.2 水平评估的引导式流程
前面说了水平评估要用行为描述来锚定,但用户不一定有耐心逐条阅读。所以评估流程需要设计得轻量且有引导性。
我的做法是分三步走。第一步,用户选择一个大致的水平区间,比如“入门”、“熟练”、“精通”。这一步很快,几秒钟就能完成。第二步,系统展示该区间对应的行为描述,让用户确认或微调。比如用户选了“熟练”,系统展示3级和4级的描述,问“你更接近哪一个”。第三步,用户可以选择性地添加证据,比如项目经历、作品链接、证书等。这一步是可选的,不强制。
整个流程控制在两分钟以内。如果用户中途退出,系统保存草稿,下次继续。评估完成后,系统生成一个“技能卡片”,包含技能名称、当前水平、目标水平、下一步建议。这张卡片可以导出为图片,方便用户分享或存档。
4.3 雷达图与技能矩阵的渲染方案
可视化是技能管理项目的灵魂。用户需要一眼看到自己的整体分布,才能做出合理的规划。最常用的两种视图是雷达图和技能矩阵。
雷达图适合展示单个用户在多个维度上的分布。比如把技能按分类聚合,每个分类取平均分,画成一个六边形或八边形的雷达图。实现上可以用ECharts或Chart.js,数据格式是一个包含分类名称和分值的数组。
const radarOption = { radar: { indicator: [ { name: '前端', max: 5 }, { name: '后端', max: 5 }, { name: '数据库', max: 5 }, { name: '运维', max: 5 }, { name: '算法', max: 5 }, { name: '架构', max: 5 } ] }, series: [{ type: 'radar', data: [{ value: [4, 3, 3, 2, 2, 1], name: '当前水平' }, { value: [5, 4, 4, 3, 3, 3], name: '目标水平' }] }] };技能矩阵适合展示团队或群体的分布。行是人员,列是技能,单元格的颜色深浅表示水平高低。这种视图可以快速识别出“谁强在哪儿”和“哪儿有缺口”。实现上可以用HTML表格加CSS渐变,也可以用D3.js做更复杂的交互。
注意:雷达图的数据聚合方式会影响观感。如果某个分类下技能数量很少,平均分容易失真。建议在图上标注每个分类包含的技能数量,让用户知道数据的置信度。
4.4 学习路径推荐的算法思路
学习路径推荐是“skills”项目从工具升级为助手的关键功能。它的核心逻辑是:根据用户当前的水平分布和目标技能,结合技能依赖关系,生成一条合理的学习顺序。
算法可以分三步。第一步,找出目标技能的所有前置依赖,形成一个依赖图。第二步,检查用户在这些前置技能上的当前水平,标记出已经满足的和需要补课的。第三步,对需要补课的技能做拓扑排序,同时考虑难度递进和用户兴趣,生成最终路径。
def generate_learning_path(user_skills, target_skill_id, dependencies): # 构建依赖图 graph = {} for dep in dependencies: graph.setdefault(dep['dependent_skill_id'], []).append(dep['prerequisite_skill_id']) # 找出所有需要的前置技能 needed = set() stack = [target_skill_id] while stack: current = stack.pop() for prereq in graph.get(current, []): if prereq not in needed: needed.add(prereq) stack.append(prereq) # 过滤掉已经掌握的 to_learn = [s for s in needed if user_skills.get(s, 0) < 3] # 拓扑排序 sorted_skills = topological_sort(to_learn, graph) return sorted_skills这个算法的输出是一个有序的技能列表,用户按顺序学习即可。实际产品中还可以加入时间估算、资源推荐、进度追踪等增强功能,但核心逻辑就是上面这些。
5. 落地时最容易踩的五个坑
5.1 技能分类的粒度失控
刚开始做的时候,很容易陷入“分类越细越好”的误区。前端下面分框架、库、工具、语言、标准,框架下面又分UI框架、状态管理、路由、构建工具。分到第四层的时候,用户已经不知道该怎么选了。
我的经验是分类层级不要超过两层,第一层是领域(前端、后端、数据、运维、安全),第二层是类型(语言、框架、工具、概念)。再细的维度用标签来表达,标签可以多选,不强制分类。这样既保持了结构的清晰,又保留了灵活性。
5.2 水平评估的主观性偏差
即使用行为描述来锚定,用户仍然会高估或低估自己。高估的人觉得自己“用过”就是“掌握”,低估的人觉得自己“没深入”就是“不会”。这种偏差在团队盘点时尤其明显,会导致技能矩阵失真。
缓解的办法有两个。一是引入“证据”机制,用户声称达到某个水平时,可以附上项目链接、代码仓库、证书等佐证。二是引入“校准”机制,定期让用户做一个小测试,用测试结果来校准自我评估。测试不需要很复杂,几道选择题就能起到很好的校准作用。
5.3 数据导入导出的格式兼容
用户的数据往往散落在各处:Excel表格、Notion页面、GitHub仓库、简历文档。如果项目不能方便地导入这些数据,用户就要手动录入,成本极高。导出也一样,用户需要把数据带到别的地方用,如果只能看不能导,价值就大打折扣。
我的做法是至少支持CSV和JSON两种格式的导入导出。CSV适合表格数据,JSON适合结构化数据。导入时提供模板下载,导出时提供字段说明。如果精力允许,再支持从常见工具的API直接同步,比如从代码托管平台拉取仓库语言分布,从笔记工具拉取标签列表。
5.4 多用户场景下的权限设计
从个人版扩展到团队版时,权限设计是最容易出问题的地方。谁能看到谁的技能数据?谁能修改团队的目标?谁能导出全量报告?这些问题如果不在早期想清楚,后期改起来非常痛苦。
我的建议是采用基于角色的访问控制,至少定义三种角色:管理员、成员、访客。管理员可以管理团队配置和所有成员数据,成员可以管理自己的数据并查看团队聚合视图,访客只能查看公开的聚合视图。权限检查要在API层统一实现,不要散落在各个业务逻辑里。
5.5 长期不用导致的“数据腐烂”
技能数据是有时效性的。一个人两年前掌握的技能,现在可能已经生疏了。如果项目不能反映这种变化,数据就会“腐烂”,用户会逐渐失去信任。
解决方案是引入“新鲜度”概念。每个技能的水平都有一个“最后确认时间”,超过一定时间没有更新,系统自动降低置信度,或者在视图上用灰色标注。用户可以定期做“回顾”,确认哪些技能仍然熟练,哪些需要重新学习。这个机制不需要很复杂,但能显著提升数据的可信度。
6. 让项目真正活起来的运营思路
6.1 从“记录工具”到“成长伙伴”的定位转变
我见过很多技能管理项目,功能做得不错,但用户用了一段时间就放弃了。根本原因是定位错了:它们把自己定位成“记录工具”,而用户需要的是“成长伙伴”。记录是被动的,成长是主动的。
怎么转变?关键是提供“下一步行动”的建议。用户打开项目,不应该只看到一堆数据和图表,而应该看到“你今天可以做什么”。比如“你的React水平停留在3级已经两个月了,要不要试试这个实战项目?”“你的团队在Kubernetes上只有一个人达到4级,存在单点风险,建议安排一次内部分享。”
这些建议不需要很复杂,基于简单的规则就能生成。但它们能让用户感受到项目的价值,而不只是一个冷冰冰的数据库。
6.2 用“微成就”机制对抗半途而废
技能提升的反馈周期太长了,这是用户放弃的主要原因。微成就机制的核心是把大目标拆成小里程碑,每完成一个就给予即时反馈。
具体可以这样设计:连续记录7天,解锁“坚持一周”徽章;某个技能从1级升到2级,解锁“入门”徽章;完成一条学习路径的所有前置技能,解锁“通关”徽章;团队整体水平提升10%,解锁“团队进步”徽章。徽章本身没有实际价值,但它提供了即时的正向反馈,让用户有动力继续。
提示:徽章的获取条件要透明,让用户知道怎么做才能解锁。隐藏成就虽然有趣,但容易让人困惑。
6.3 团队场景下的“技能缺口”分析
团队版最有价值的功能不是展示谁会什么,而是分析“缺什么”。一个团队如果所有人在某个关键技能上都只有1到2级,那就是一个明显的风险点。如果某个技能只有一个人达到4级以上,那就是一个单点依赖。
缺口分析的报告应该包含三个部分:当前团队的整体水平分布、与目标水平的差距、风险提示和建议。报告可以按月生成,自动发送给团队负责人。负责人拿到报告后,可以有针对性地安排培训、招聘或内部分享。
6.4 数据驱动的个人成长复盘
个人用户最需要的是“复盘”功能。每个月或每个季度,系统自动生成一份成长报告,包含:这个周期内水平提升的技能、新学习的技能、停滞不前的技能、下一步建议。
这份报告的价值在于它把零散的记录变成了有意义的叙事。用户看到的不再是“我在某月某日把React从2级改成了3级”,而是“这个季度你在前端领域取得了明显进步,但在数据库方面没有变化,建议下个季度重点关注”。
我在实际使用类似工具时的体会是,复盘报告的质量决定了用户会不会长期留下来。如果报告只是数据的堆砌,用户看一次就不看了。如果报告能给出有洞察力的分析和可操作的建议,用户会主动期待下一份报告。
6.5 开放数据与社区共建的边界
技能词典和依赖关系如果只靠项目维护者录入,覆盖面和更新速度都有限。开放给社区共建是一个自然的选择,但要注意质量控制。
我的做法是分两级:官方数据和社区数据。官方数据经过审核,质量高,优先展示。社区数据由用户贡献,标记来源,经过一定数量的用户确认后可以升级为官方数据。贡献者可以获得徽章或积分,形成正向激励。
但要注意,开放数据不等于开放编辑。核心的技能分类和依赖关系仍然需要一定的审核机制,否则很容易被恶意修改或误操作破坏。审核可以自动化加人工结合,简单的修改自动通过,复杂的修改进入审核队列。
7. 一些零散但实用的经验
关于技术选型,如果让我重新做一个“skills”项目,我会选择SQLite作为默认存储,PostgreSQL作为团队版的存储。SQLite足够轻量,单文件,零配置,适合个人用户。PostgreSQL在并发和复杂查询上更强,适合团队场景。前端用React或Vue都可以,关键是图表库要选好,ECharts在雷达图和矩阵图上的表现比Chart.js更成熟。
关于性能优化,最需要注意的是技能列表的加载速度。当技能数量超过500个时,一次性加载所有数据会导致页面卡顿。解决方案是分页加载加虚拟滚动,首屏只加载可视区域的数据,滚动时动态加载。搜索功能要用防抖,避免每次输入都触发查询。
关于数据备份,个人用户最容易忽略这件事。我建议项目内置自动备份功能,每天把数据导出到一个本地文件,保留最近30天的备份。团队版则应该支持定时备份到对象存储,并且提供一键恢复的功能。
关于移动端适配,技能录入和查看是高频操作,用户很可能在手机上完成。所以响应式设计不是可选项,而是必选项。雷达图在手机上要能缩放和旋转,技能矩阵要能横向滚动,录入表单要能单手操作。
关于国际化,如果项目有可能被不同语言的用户使用,最好从一开始就把文案抽离成语言包。技能名称本身可能是英文的,但界面文案、提示信息、报告模板都需要翻译。这件事越早做成本越低。
最后分享一个我踩过的坑:不要试图一次性把所有功能都做完。我见过一个团队花了六个月做了一个功能极其丰富的技能管理系统,结果上线后发现用户只用其中三个功能。后来他们砍掉了80%的功能,反而用户满意度提升了。技能管理这件事,简单直接比大而全重要得多。先让核心流程跑通,让用户用起来,然后再根据反馈逐步添加功能。这才是“skills”这个项目从空标题变成有价值产品的正确路径。