最近我在折腾 Codex 的 skill,顺手做了一个自己的小工具:hugo-cover-generator。
它做的事情不复杂,就是给 Hugo 博客文章自动生成一张 SVG 封面,然后把文章里的 cover.image、cover.alt 这些 front matter 也一起补好。
本来我只是想解决一个小麻烦。
结果做完之后,反而觉得这次最大的收获,不是“我又做了一个工具”,而是我第一次比较完整地走通了一遍 skill 从想法到落地 的过程。
所以这篇文章不打算只聊“怎么给博客生成封面”。
我更想借这个例子,记录一下这次做 skill 的一些真实体会。标题里的 Hugo 封面生成,只是我拿来练手的那个切入口。
skill 是什么?
说实话,在真正动手之前,我对 skill 的理解挺浅的。
我原来一直以为,所谓 skill,大概就是把提示词写得更长一点、更细一点,让 AI 在某类问题上表现得更稳定一些。
这个理解不能说完全错,但至少这次做完以后,我觉得它还是太表面了。
现在我更愿意把 skill 理解成下面这个东西:
skill 不是提示词加强版,而是把一类重复任务整理成一条稳定工作流。
也就是说,一个真的好用的 skill,起码要回答清楚三件事:
- 它应该在什么场景下被触发;
- 触发之后要遵守哪些固定规则;
- 最后靠什么手段把结果真正落到文件、代码或命令上。
如果只有前两条,那更像“建议”;把第三条也补上,它才更像一种可复用的能力。
选题背景
我这次拿来练手的例子,说起来非常朴素:给 Hugo 博客文章自动生成 cover。
因为我自己的博客,最近写的新文章基本都会配一张统一风格的封面。
这个事情并不难,但就是烦,尤其是重复做的时候特别烦。每次都要手动过一遍:
- 看标题,想办法拆成两行;
- 决定左上角分类标签写什么;
- 再想一句不能太长的副标题;
- 生成一个 SVG 文件;
- 最后回到文章里,把
cover字段补完整。
这种事非常典型:
- 它会反复发生;
- 它的规则比较固定;
- 它又没什么创造性,纯属机械劳动。
所以我后来越想越觉得,这种场景简直就是给 skill 量身定做的。对 skill 新手来说,它还有一个额外好处:题目够小,边界够清晰,结果也很好验证。
做成了,就是生成一张风格统一的封面,并且文章 front matter 被自动补好;没做成,也很容易马上看出来问题在哪。
拆开去做
刚开始时,我差点把所有东西都压到说明文档里,想让 AI 自己根据文章内容临场发挥。
后来很快发现,这样做有两个问题:第一,结果不够稳定;第二,很难复用。
今天这篇文章运气好,明天换一篇文章,风格可能就飘了。
所以后面我把整个 skill 拆成了两层:
SKILL.md负责定义工作流;generate_hugo_cover.py负责执行工作流。
目录层级如下图所示:

如果把这个 skill 的目录结构写出来,大概就是这样:
| |
这几个文件不多,但分工很清楚:
SKILL.md:这是整个 skill 的入口说明。主要负责定义适用场景、调用方式、风格约束,以及单篇/批量模式下的使用方法。简单理解,它决定了 Codex 什么时候该用这个 skill,以及该怎么用。agents/openai.yaml:这个文件更像是给 skill 补了一层交互配置。里面定义了展示名称、简短描述和默认提示词,让这个 skill 在调用时更容易被正确识别,也更方便直接触发。scripts/generate_hugo_cover.py:这是实际干活的核心脚本。它负责读取文章 front matter、推断封面样式、生成 SVG 文件,并把cover.image、cover.alt、cover.relative回写到文章里。
也就是说,这个 skill 虽然目录很小,但其实刚好对应了三件事:怎么介绍自己、怎么被触发、怎么真正执行。
这个分层做完之后,我一下子就觉得顺了。
SKILL.md 解决的是“什么时候用、怎么用”的问题。比如:
- 哪些需求应该触发这个 skill;
- 单篇文章怎么处理,批量文章又怎么处理;
- 什么时候需要手动指定分类标签、标题两行或副标题;
- 封面的视觉语言要遵守哪些约束。
而 Python 脚本解决的是“怎么稳定落地”的问题。比如:
- 读取文章 front matter;
- 拿到标题、分类、标签、摘要;
- 推断要用哪套样式;
- 生成 SVG 文件;
- 把
cover.image、cover.alt、cover.relative回写回去。
这一步对我帮助很大。因为我第一次比较明确地意识到:做 skill,不是把所有东西都塞给 AI 去猜,而是要主动把工作流拆成 AI 擅长的部分和脚本擅长的部分。
示例解释
如果只用一句话来描述,hugo-cover-generator 的目标很简单:
输入一篇 Hugo 文章,输出一张与博客现有风格一致的 SVG 封面,并自动补全文章里的封面配置。
但真正做的时候,我才发现它背后其实藏着不少隐含规则。
风格一致
如果只是让 AI 临时拼一段 SVG,其实很容易就能出结果。但问题在于,那张图未必属于这个博客,可能这篇是这种感觉,下一篇又完全变了。
所以我后面先把几条硬规则固定了下来:
- 尺寸固定为
1600 x 900; - 左上角保留小型分类标签;
- 左侧是两行主标题;
- 标题下有短分隔线和副标题;
- 背景用柔和渐变,右侧有装饰图形。
这一套东西定下来之后,后面的生成空间其实就被收敛得很清楚了。这样做听起来不够“智能”,但实际效果反而稳定得多。
读取上下文
真正影响封面效果的,不只是文章标题。
这次的脚本会一起参考文章里的:
titledescriptionsummarytagscategoriesslug
然后再去决定:
- 分类标签写什么;
- 封面用哪套颜色更合适;
- 标题怎么拆成两行;
- 副标题能不能从
description压缩出来; - 最终文件名和路径应该是什么。
这个过程让我很有感触。很多看起来像“AI 生成内容”的事情,往深了看,其实更像“读取上下文,然后应用规则”。
补全链路
如果这个 skill 只是帮我生成一张 SVG,那当然也有用,但还不够省事。
因为生成完之后,我还是得自己回到文章里,手动补下面这些内容:
| |
所以我后面干脆把 front matter 的回写也做进去了。这样一条命令执行完,封面和文章配置就一起到位了。
我觉得这也是这次做 skill 时很重要的一条经验:不要只自动化最显眼的那一步,而是尽量把整条最烦的链路一起打通。
踩坑记录
标题拆行
封面最容易翻车的地方,其实就是标题。
尤其是中文标题,有的短,有的长,有的中间天然有停顿,有的则一整句连在一起。我最开始想得很简单,觉得直接从中间切开就差不多了。后来发现,这样切出来的效果经常很别扭,语义会断得很难受。
所以后面我又补了一层简单规则,优先去 :、和、的、中 这些更像自然断点的位置附近找拆分点。它不是什么复杂算法,但实际效果已经比“无脑从中间切”好很多了。
这个细节让我意识到一件事:skill 里的很多体验问题,最后往往不是模型能力问题,而是规则设计问题。
风格预设
如果所有文章都用一模一样的颜色和装饰,短时间看还好,文章一多就会有点单调。
所以我后来在脚本里加了几组风格预设,比如偏 Hugo/博客的、偏 Git 的、偏数据库的、偏生活类的。底层版式不变,但颜色和局部装饰稍微有点区别。
这样做的好处挺直接:
- 整个博客仍然是统一的;
- 不同主题又有一点区分度;
- skill 的输出也更像“有规则的变化”,而不是随机发挥。
文档也重要
一开始我更关注脚本,觉得脚本能跑起来,skill 就算差不多完成了。后面才发现,事情根本没这么简单。
因为 AI 什么时候触发这个 skill、读哪些上下文、单篇模式怎么调、批量模式怎么调、哪些参数适合覆盖,这些事情都要靠 SKILL.md 来说清楚。
如果这部分写得不明确,那脚本再好,也可能压根触发不到。
就算触发了,调用姿势也可能不对。
所以现在回头看,我会把 SKILL.md 看成 skill 的“接口说明书”。它不是附属文档,而是这个 skill 能不能被正确使用的关键部分。
三点经验
这次虽然只是一个很小的 skill,但我自己觉得已经足够总结出几条挺实用的方法了。
从小处做
不要一上来就想做一个万能 skill。越抽象的问题,越难做稳定;越具体的问题,越容易沉淀成规则。
“给文章生成封面”这种小事,反而特别适合拿来练手。
先定规则
AI 最容易让人兴奋的地方,就是看起来好像什么都能临场发挥。但真到了需要长期复用的场景,稳定通常比惊艳更重要。
所以我这次的思路就是,先把尺寸、结构、路径、字段这些硬规则定清楚,再把少量可变空间交给 AI 或脚本去判断。
能跑最重要
如果一个 skill 只能告诉我“你应该这么做”,那它当然也有帮助,但帮助有限。
至少对我自己来说,我更想让 skill 帮我省掉实际操作,而不是只提供建议。所以以后如果继续做别的 skill,我大概率还是会优先考虑:能不能把最后一步真的自动做掉。
写在最后
这不是一篇单纯讲 Hugo 封面怎么做的文章,而是一篇我用“博客封面生成”这个具体例子,完成第一次 skill 开发实践的记录。
hugo-cover-generator 只是一个载体,但通过它,我第一次比较具体地想清楚了 skill 的几个关键点:要有清晰场景,要有稳定规则,也要有真正能执行的落地方式。
如果你也和我一样,是个 skill 新手,我会很建议你从自己已经做烦了的重复劳动里找题目。
题目不用大,关键是边界清楚、结果可验证、以后还会反复用到。只要做成第一个,后面很多想法就会自然打开。
而我这次,刚好是从博客封面这件小事开始的。