SkillPrompts 拆解:把 Prompt 变成浏览器里的“可复用技能系统”

2 阅读19分钟

SkillPrompts 拆解:把 Prompt 变成浏览器里的“可复用技能系统”

如果你经常在 ChatGPT、Gemini 这类对话式 AI 产品里工作,应该都熟悉一种挫败感:同样一类任务,明明之前写过不错的提示词,过几天又得重新找、重新改、重新贴。

SkillPrompts 解决的,就是这个重复动作。

它不是单纯的提示词收藏夹,也不只是模板仓库。它往前走了一步,把 prompt 做成可调用、可参数化、可跨站点复用的“技能”。当用户在聊天输入框里敲下 /debug/tldr/compare 这类命令时,扩展会像命令面板一样弹出技能列表;当用户提交消息时,它再把这些命令替换成真正的完整提示词。这个交互很像很多开发者熟悉的 slash command,只不过目标对象从 CLI 命令变成了 AI prompt。

如果只看 README,你可能会把它理解成一个浏览器里的 prompt library。但顺着代码往下读,这个项目真正有意思的地方有三层:

  1. 它把 prompt 从文本片段变成了可执行的输入接口。
  2. 它认真处理了跨站点输入框、contenteditable、主题同步和高亮反馈这些实现层的脏活。
  3. 它在产品策略上很克制:仓库内置 169 条提示词,但安装后只预置 16 条默认技能,没有把整套库直接塞给用户。

这篇文章会把 SkillPrompts 从产品思路、交互设计、实现结构、优点与局限几个层面拆开。看完之后,你不但能知道它是什么,也能明白为什么这种 “Prompt → Skill” 的抽象值得借鉴。

一、它到底是什么:提示词系统里的一层调用界面

SkillPrompts 的官方描述很直接:这是一个浏览器扩展,用来在多个 AI 聊天平台之间创建、组织并复用可自定义的 prompt,以提升交互效率。当前 README 明确列出的已支持站点只有两个:

  • https://chatgpt.com
  • https://gemini.google.com

另外,它也兼容 https://chat.openai.com/* 这个旧域名匹配。路线图里还列了 Copilot、Perplexity、Claude、Poe、Kimi、Cursor Agents、v0 等一串平台,但截至 1.0.0,这些都还没有真正落地。

表面看,这件事不算新鲜。做 prompt 管理的工具很多,为什么这个项目值得单独写一篇?

关键在于,它的核心抽象不是“保存一段文本”,而是“定义一个技能,然后在聊天框里调用它”。

这两种理解差别很大。

  • 如果只是保存文本,用户的工作流还是“打开面板 → 找 prompt → 复制 → 粘贴 → 再补变量”。
  • 如果它是技能,用户的工作流会变成“输入 /命令 → 选择 → 填变量 → 发送”。

后者更接近程序员对命令系统的直觉,也更容易形成长期习惯。

所以 SkillPrompts 真正有价值的地方,不在于给你 169 条现成 prompt,而在于把 prompt 变成了一个可以被调用的界面层能力。

二、为什么这个方向成立:Prompt 的问题常常不在写,而在复用

很多人以为 prompt engineering 的核心问题是“怎么把提示词写得更聪明”。但在真实使用里,更常见的问题其实是:

  • 同类任务反复出现;
  • 好 prompt 散落在聊天记录、笔记软件和剪贴板里;
  • 每个平台都要重新粘贴;
  • 一旦 prompt 里带变量,比如语言、年龄层、比较对象、输出格式,就更容易出错。

SkillPrompts 的切入点很实际:它不帮你生成 prompt,它帮你管理 prompt 的使用时机。

这比“做一个会自动生成提示词的 AI”朴素得多,但也更落地。因为绝大多数高频 prompt 任务本来就高度模式化,比如:

  • 让模型解释一个概念;
  • 对比两个方案;
  • 压缩成 TL;DR;
  • 调试代码;
  • 把一段内容改写得更正式;
  • 生成社交媒体帖子。

这些任务并不需要每次都重新发明提示词,真正需要的是一个足够顺手的调用入口。

三、产品层最聪明的地方:用 slash command 当认知桥梁

SkillPrompts 的体验几乎可以用一句话概括:在 AI 输入框里,给 prompt 加上一层命令面板。

当用户在输入区键入 / 时,扩展会拦截这个动作,弹出一个搜索式命令面板。面板里展示的是当前可用技能,每个技能都有:

  • 标签名,比如 /debug/blog/compare
  • 一句描述;
  • 变量数量提示。

这套设计很重要,因为它没有发明一套全新的交互语言,而是借用了用户已经学会的模式:

  • / 代表调用命令;
  • 上下键选择;
  • Enter 确认;
  • Escape 关闭。

用户几乎不需要额外学习。

再细看一点,命令面板还做了两件很值钱的小事。

1. 它把“查找”变成了“筛选”

技能不是按目录翻,而是按搜索直接过滤。你只要记得大概名字或用途,就能很快定位。

2. 它把“调用前确认”嵌进了输入过程

你不是点一下就把整段 prompt 塞进输入框,而是先保留一个类似 /compare option_a="..." option_b="..." criteria="..." 的中间态,再在真正发送时替换成完整文本。

这样做的好处是,用户能先看到自己调用了什么,也能在发送前继续改。

四、SkillPrompts 的核心抽象:Prompt = 模板 + 标签 + 描述 + 变量

从类型定义上看,这个项目对“技能”的定义很朴素。每个 prompt 主要由四个字段构成:

  • id
  • label
  • description
  • template

而内置库里的条目结构也基本一样,只是把 template 命名成了 prompt

这意味着 SkillPrompts 没有把技能系统做复杂。它没有引入分类树、版本管理、复杂依赖或执行链,而是坚持一个很轻的模型:

  • label 决定 slash command 的名字;
  • description 决定列表里的解释文案;
  • template 决定最终注入给模型的真实提示词;
  • {{ variable }} 占位符决定这个技能是否需要参数化。

这个模型足够简单,却已经能覆盖大量常见工作流。

比如,内置的 explain 模板会使用 {{ topic }}{{ age_group }} 两个变量;compare 模板则需要 {{ option_a }}{{ option_b }}{{ criteria }}。这说明作者不是把 prompt 当静态段落处理,而是明确把它看成一次带参数的函数调用。

这也是整个项目最关键的产品判断。

五、一个完整调用过程是怎么跑通的

理解这个项目,最好的方式不是看 UI,而是跟着一次调用过程走一遍。

第一步:扩展注入到支持站点

内容脚本会匹配并注入到 ChatGPT、旧版 ChatGPT 域名以及 Gemini 页面中。也就是说,它不是在自己的独立页面里运行,而是直接附着在目标聊天站点的 DOM 上工作。

这一步决定了它必须处理真实网页环境里的各种不确定性:不同输入组件、不同主题、不同 DOM 更新节奏。

第二步:用户输入 /

当用户在 inputtextareacontenteditable 元素中按下 /,扩展会阻止浏览器默认行为,并记录当前光标位置,然后弹出命令面板。

这听起来简单,做起来并不轻松。因为聊天产品的输入框很多都不是标准文本框,而是富文本编辑器或自定义组件。SkillPrompts 在这里做了不少兼容处理,包括:

  • 记录 selectionStart/selectionEnd
  • contenteditable 使用 RangeSelection
  • 在 Firefox 下单独处理焦点问题;
  • 避免默认菜单和原始按键行为干扰。

所以这不是一个“给 textarea 加个快捷输入”的玩具实现,而是在认真处理现代 Web 输入环境。

第三步:展示技能列表并搜索

命令面板会把已保存技能映射成统一结构,按 label + description 进行过滤,并支持键盘导航。

一个很实用的细节是,面板还会计算每条技能模板里包含多少个变量,然后显示 1 var2 vars 之类的提示。反馈虽然小,但很好用,因为用户可以立刻知道这个命令是不是还需要补参数。

第四步:把 slash command 留在输入框里

用户选中某个技能后,扩展不会立刻把长 prompt 展开,而是先写入类似 /debug/compare 这样的命令文本。

如果模板里有变量,占位命令还会进一步承载参数值。项目甚至会对这些命令片段和变量片段做高亮:

  • 命令本身用 command-insert 高亮;
  • 参数片段用 var-insert 高亮。

这里能看出作者对体验的在意。它不只是让功能能用,还在努力让用户知道,此刻输入框里哪些部分是命令,哪些部分是参数。

第五步:真正发送时再替换成完整 prompt

这个项目最关键的动作发生在提交前。

当用户按下 Enter 发送消息,或者点击站点里的发送按钮时,扩展会扫描当前输入内容,把 /label 命令匹配出来,读取对应模板,提取参数,并用真实值替换掉 {{ variable }} 占位符,最后把结果写回输入控件。

以一个简化例子来说:

/compare option_a="React" option_b="Vue" criteria="ecosystem, learning curve, hiring"

会被展开成一段完整 prompt,大意是:

Compare React and Vue based on these criteria: ecosystem, learning curve, hiring. Provide the results in a Markdown table, then give a final recommendation...

这才是它真正完成价值闭环的地方。

也因为替换发生在“发送前”而不是“选择时”,用户还保留了最后一次编辑命令和参数的机会。这是一个很合理的产品决策。

六、变量系统为什么是这类工具的分水岭

如果没有变量,SkillPrompts 仍然有价值,但它最多只是一个 prompt snippet manager。

有了变量以后,它的性质就变了。

项目里通过 {{ name }} 这种格式识别变量,并在命令展开阶段用正则解析诸如 topic="..." 这样的参数对。模板中的未填变量会被清掉,已提供的变量则会被替换进最终 prompt。

这套能力看似简单,实际意义很大,因为它让“复用”从复制整段文本,升级成复用结构。

举个更贴近实际的例子。

示例 1:解释型技能

模板:

Explain the concept of {{ topic }} as if I am a {{ age_group }} with no prior knowledge.

调用:

/explain topic="TCP handshake" age_group="12-year-old"

这样一来,用户复用的不是一句固定话术,而是一种稳定的表达结构。

示例 2:比较型技能

模板:

Compare {{ option_a }} and {{ option_b }} based on these criteria: {{ criteria }}.

调用:

/compare option_a="Next.js" option_b="Remix" criteria="SSR, routing, deployment"

这类模板在真实工作里特别常见。它们的框架很稳定,变化的只是参数。SkillPrompts 抓住的正是这一点。

七、实现层最值得夸的部分:它认真处理了浏览器里的脏活

很多同类项目,README 看起来很漂亮,一到代码就露馅:只能在某一个站点工作,只支持标准输入框,或者一刷新就失效。

SkillPrompts 还谈不上工业级完善,但从实现可以看出,作者确实踩过坑,也认真填过坑。

1. 同时处理标准输入框和 contenteditable

项目没有偷懒地只支持 textarea。它专门写了逻辑去遍历带 contenteditable 的元素,甚至还递归处理 shadow root 内部节点。

这很关键,因为越来越多 AI 产品的输入区都不是传统表单控件。

2. 使用 MutationObserver 跟踪动态页面

聊天网页是高度动态的。输入区域、发送按钮、主题 class、DOM 结构都可能随时变化。SkillPrompts 在内容脚本里用了多组 MutationObserver

  • 监听文档主题变化;
  • 监听 body 变化,重跑高亮;
  • 监听发送按钮出现与更新。

这说明作者知道,扩展不是一次性把 DOM 改完就结束,而是得在页面不断重绘的环境里长期存活。

3. 高亮方案做了双重兼容

高亮部分优先用 CSS.highlights::highlight(...),失败时再退回到包裹 span 的 fallback 方案。

这是个很成熟的前端思路:

  • 新能力能用就用,效果更干净;
  • 不能用时,保留降级方案;
  • 降级后还会先 unwrap 旧节点,避免高亮嵌套把文本结构搞乱。

这一段代码不算短,但它解决的是一个很实际的问题:用户能不能看出来,命令已经被识别了。

4. 存储层做了迁移与同步

项目现在主要使用 @plasmohq/storage 存储数据,包括:

  • prompts 列表;
  • 扩展开关状态;
  • 使用次数;
  • 主题;
  • 视图模式。

同时,它还兼顾了旧版 localStorage 数据迁移。也就是说,作者没有粗暴地换存储实现,而是把已有数据平滑带了过来。

此外,内容脚本和管理页都通过 storage.watch 监听变化,这让技能库更新后可以尽快反映到 UI 上。

这些都不是 README 会高亮展示的卖点,但恰恰体现了项目是不是做得认真。

八、它为什么只默认种入 16 条技能,而不是全部 169 条

这是我读到代码后最喜欢的一个产品判断。

仓库里的 src/prompts.json 一共内置了 169 条提示词,覆盖写作、调试、社交媒体、职业发展、教育、商业等多个方向。但在安装逻辑里,后台脚本只会把其中 16 条标签加入默认集合,例如:

  • viral-post
  • facebook-post
  • reddit-post
  • linkedin-post
  • debug
  • blog
  • formalizer
  • compare
  • expander
  • shortener
  • simplifier
  • ideas
  • translate-to
  • corrector
  • tldr
  • explain

这背后的思路很清楚:

  • 全量预装会让用户第一次打开时就信息过载;
  • 默认集合应该体现“开箱即用”的高频能力;
  • 更长尾的技能放在库里,由用户按需导入。

管理页里专门有一个 Explore Skills 入口,用来从内置库中搜索并导入新技能。这比一上来就把 169 条全部扔进主列表,更像一个成熟产品。

从设计视角看,这相当于把“技能库”拆成了两层:

  1. 默认工作集;
  2. 可探索的大仓库。

这个结构很值得做类似工具的人参考。

九、管理页其实是另一个重点:它决定了工具能不能长期用下去

很多小工具的问题不是第一次不好用,而是第二十次不好用。

SkillPrompts 的 options 页面之所以重要,是因为它承担了“长期维护技能库”的职责。用户在这里可以:

  • 创建新技能;
  • 编辑已有技能;
  • 删除技能;
  • 查看完整内容;
  • 搜索技能;
  • 在网格和列表视图之间切换;
  • 从内置库导入更多技能;
  • 一键复制模板;
  • 打开或关闭扩展。

这意味着它不是一次性 demo,而是在尝试成为一个真正长期可用的个人 prompt 工具。

尤其值得注意的是两点。

1. 使用次数被当成一等信息

项目维护了 usage 记录,用来追踪技能使用频率。虽然当前版本还没有把它发展成复杂排序系统,但这个方向是对的:真正有价值的技能管理,不是“你收藏了多少条”,而是“你高频用的是哪几条”。

2. UI 语言开始向“技能产品”靠拢

在界面文案里,作者经常使用的是 Skill 而不是 Prompt。比如按钮写的是 Create New SkillExplore Skills

这不是措辞细节,而是在持续强化产品心智:你管理的不是文本,而是一组能力。

十、它的局限也很明显,而且这些局限刚好暴露了下一阶段该往哪走

SkillPrompts 已经很好地证明了方向成立,但如果把它当成一个要继续发展的产品,它的边界也很清楚。

1. 当前支持站点仍然偏少

README 路线图列得很长,但 1.0.0 真正稳定支持的只有 ChatGPT 和 Gemini。对于这类扩展来说,跨站点支持不是锦上添花,而是核心卖点的一部分。

如果后续能把 Claude、Perplexity、Kimi、Cursor Agents 这类环境接进来,它的价值会明显上升。

2. 变量语法仍然比较基础

当前变量系统已经够实用,但还比较轻量。它更像字符串替换,而不是表单 schema。比如:

  • 没有变量类型;
  • 没有默认值;
  • 没有枚举选项;
  • 没有必填校验;
  • 没有更强的模板组合能力。

这不是批评,反而说明它现在还处在一个很健康的“简单但有用”的阶段。但如果项目要继续进化,变量系统大概率会成为最重要的下一跳。

3. 内置 prompt 数量很多,但质量体系还不够透明

169 条内置 prompt 本身很有吸引力,但数量并不自动等于质量。对于用户来说,更关键的问题是:

  • 哪些 prompt 真正高频?
  • 哪些写法更适合不同模型?
  • 哪些是示例,哪些是推荐默认值?
  • 哪些 prompt 已经过验证?

这也是很多 prompt 库都会遇到的问题:收集并不难,策展才难。

4. 缺少团队协作层

当前 SkillPrompts 更像个人生产力工具。它适合个人积累 prompt,但还不适合团队共享、评审、版本化和分发。

如果未来走向团队能力库,它可能需要:

  • 导入导出机制;
  • 云端同步;
  • 团队共享库;
  • prompt 版本历史;
  • 权限和审核流程。

当然,这已经是另一个产品阶段了。

十一、如果你也想做类似项目,SkillPrompts 给出的 4 个启发

读完这个项目,我觉得最值得带走的不是某一段代码,而是四个产品和工程层的判断。

启发 1:不要把 prompt 当内容库,要把它当调用接口

一旦你把 prompt 看成“技能”,就会自然想到命令名、变量、触发时机、执行反馈这些设计问题。产品也会从“存文本”升级成“调能力”。

启发 2:默认库不要贪多,先给用户一个小而稳的工作集

169 条全量内置听起来很丰富,但真正好用的是那 16 条默认技能。第一次体验最怕的不是功能少,而是选择太多。

启发 3:浏览器扩展真正难的不是 UI,而是宿主页面兼容性

如果你要把能力挂到第三方网页里,真正困难的是:

  • 输入框是不是标准控件;
  • DOM 会不会重绘;
  • 站点会不会套 shadow DOM;
  • 发送按钮是不是动态生成;
  • 高亮会不会破坏编辑行为。

SkillPrompts 在这些脏活上投入的精力,恰恰说明它不是停留在概念验证层。

启发 4:好的 AI 工具不一定更“智能”,但一定更顺手

SkillPrompts 并没有额外造一个 AI agent 来替你写 prompt,也没有做复杂编排。它做的事情很朴素:在你原本就会工作的地方,让高频 prompt 更容易被调用。

这类工具的价值,往往就体现在这种“少打几次重复字、少切几次窗口、少找几次旧记录”的小摩擦消失上。

十二、常见误区:看这种项目时,最容易忽略什么

如果你准备借鉴 SkillPrompts 的思路,有几个误区很值得提前避开。

误区 1:把它理解成“又一个 prompt 收藏夹”

如果只是收藏夹,这个项目的很多设计都会显得过度;但如果把它理解成“对话输入框里的技能层”,很多实现就顺了。

误区 2:只抄 UI,不抄触发时机

命令面板很显眼,但真正关键的是“发送前替换”这一步。没有这一步,整个系统就只剩下一个带搜索的复制面板。

误区 3:只支持 textarea,就以为问题解决了

现代 AI Web 应用里,大量输入区都不是标准表单控件。忽略 contenteditable、动态 DOM 和 shadow root,最后工具往往只能在少数页面勉强工作。

误区 4:觉得 prompt 越多越好

内置库的价值不在数量,而在默认工作流是不是干净。SkillPrompts 只默认注入 16 条技能,反而说明作者对首屏复杂度有判断。

十三、我对 SkillPrompts 的总体评价

如果把它当作一个开源浏览器扩展项目来看,SkillPrompts 已经完成了一件很有代表性的事:它把 prompt 从内容资产推进成了交互能力。

它最打动我的地方不是 169 条内置模板,也不是界面本身,而是这套抽象很顺:

  • 用户用 / 调技能;
  • 技能携带变量;
  • 命令在发送前被展开;
  • 技能库在独立管理页里持续维护。

这条链路从认知到实现都比较完整。

它当然还有很多可以继续打磨的地方,比如支持更多平台、更强的变量系统、更清晰的 prompt 质量分层,以及团队协作能力。但作为 1.0.0,它已经把最关键的问题回答清楚了:

Prompt 不一定要被保存成一段文字,它也可以被组织成一个可调用的技能系统。

这就是 SkillPrompts 最值得被学习的地方。

十四、如果把它继续做下去,下一步最值得补什么

如果我是这个项目的下一阶段设计者,我会优先考虑四件事:

  1. 扩展更多宿主站点,尤其是 Claude、Perplexity、Kimi、Cursor Agents;
  2. 给变量增加 schema 能力,比如默认值、必填、枚举和说明;
  3. 引入技能导入导出与分享机制;
  4. 基于 usage 做更聪明的排序、推荐和默认展示。

这四项里,前两项决定“能不能更广更稳地用”,后两项决定“能不能形成真正的技能生态”。

Further Reading

如果你想继续往下看,建议按这个顺序读:

  1. 仓库 README:先建立产品整体认知,了解目标用户、支持平台和安装方式。
  2. src/content.tsx:这是整个项目最关键的实现文件,slash command 的触发、命令高亮、变量替换、提交前展开都在这里。
  3. src/options.tsx:看管理页如何把技能库做成长期可维护的产品界面。
  4. src/background.ts:看默认技能种入策略,以及扩展安装后的初始化动作。
  5. src/prompts.json:看内置技能库的覆盖范围与内容结构。

如果你只想抓住最核心的设计思想,最佳起点是 README + src/content.tsx

参考资料

  • GitHub 仓库首页与 README:Ademking/SkillPrompts
  • src/content.tsx
  • src/options.tsx
  • src/background.ts
  • src/prompts.json
  • package.json
  • GitHub Release v1.0.0