|
| 1 | +# 云存储链接内置 Skills 配置指南 |
| 2 | + |
| 3 | +本文说明如何通过仓库内 manifest 配置 SkillHub 内置 Skills,以及应用启动时这些 Skills 如何从云存储同步到 `@global` 空间。 |
| 4 | + |
| 5 | +适用场景: |
| 6 | + |
| 7 | +- 希望 SkillHub 新部署实例默认带有一批官方内置 Skills。 |
| 8 | +- 不希望把完整 Skill 包目录长期放在代码仓库和镜像中。 |
| 9 | +- 内置 Skill 包已经上传到官方可控的云存储域名。 |
| 10 | + |
| 11 | +## 1. 方案概览 |
| 12 | + |
| 13 | +内置 Skills 不再以本地目录包的形式直接随仓库维护。当前方案只在仓库中维护一个 manifest 文件,应用启动时根据 manifest 中的云存储 URL 下载 zip 包,并通过 SkillHub 现有发布链路发布到 `@global`。 |
| 14 | + |
| 15 | +流程: |
| 16 | + |
| 17 | +```text |
| 18 | +维护 manifest -> 构建/部署 SkillHub 镜像 -> 应用 ready -> 后台读取 manifest -> 下载云存储 zip 包 -> 校验包内容 -> 发布到 @global -> 对所有用户公开可见 |
| 19 | +``` |
| 20 | + |
| 21 | +核心文件: |
| 22 | + |
| 23 | +```text |
| 24 | +server/skillhub-app/src/main/resources/builtin-skills/manifest.json |
| 25 | +``` |
| 26 | + |
| 27 | +首版 manifest 只需要维护三个字段: |
| 28 | + |
| 29 | +- `slug`:Skill 在 `@global` 下的 slug。 |
| 30 | +- `version`:期望同步的 Skill 版本。 |
| 31 | +- `url`:Skill zip 包的云存储 HTTPS 链接。 |
| 32 | + |
| 33 | +## 2. Manifest 配置 |
| 34 | + |
| 35 | +manifest 文件格式如下: |
| 36 | + |
| 37 | +```json |
| 38 | +{ |
| 39 | + "skills": [ |
| 40 | + { |
| 41 | + "slug": "skillhub-hello", |
| 42 | + "version": "1.0.0", |
| 43 | + "url": "https://bjcdn.openstorage.cn/<path-to-builtin-skill-zip>/skillhub-hello-1.0.0.zip" |
| 44 | + } |
| 45 | + ] |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +可以配置多个 Skills,也可以为同一个 `slug` 配置多个版本: |
| 50 | + |
| 51 | +```json |
| 52 | +{ |
| 53 | + "skills": [ |
| 54 | + { |
| 55 | + "slug": "skillhub-hello", |
| 56 | + "version": "1.0.0", |
| 57 | + "url": "https://bjcdn.openstorage.cn/<path-to-builtin-skill-zip>/skillhub-hello-1.0.0.zip" |
| 58 | + }, |
| 59 | + { |
| 60 | + "slug": "skillhub-hello", |
| 61 | + "version": "1.1.0", |
| 62 | + "url": "https://bjcdn.openstorage.cn/<path-to-builtin-skill-zip>/skillhub-hello-1.1.0.zip" |
| 63 | + }, |
| 64 | + { |
| 65 | + "slug": "skillhub-guide", |
| 66 | + "version": "1.0.0", |
| 67 | + "url": "https://bjcdn.openstorage.cn/<path-to-builtin-skill-zip>/skillhub-guide-1.0.0.zip" |
| 68 | + } |
| 69 | + ] |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +配置要求: |
| 74 | + |
| 75 | +- `skills` 必须是数组。 |
| 76 | +- 每一项必须同时填写 `slug`、`version`、`url`。 |
| 77 | +- `slug` 必须符合 SkillHub slug 规则。 |
| 78 | +- 同一个 `slug + version` 重复出现时,只处理第一条,后续重复项会被跳过。 |
| 79 | +- manifest 最多处理前 100 条 entries。 |
| 80 | +- 同一个 `slug` 的多个版本建议按从旧到新的顺序排列;运行时按 manifest 文件顺序处理,不做自动版本排序。 |
| 81 | + |
| 82 | +## 3. Skill 包要求 |
| 83 | + |
| 84 | +manifest 中的 `url` 必须指向 zip 包。zip 包需要满足 SkillHub Skill 包协议: |
| 85 | + |
| 86 | +- zip 可以在根目录直接包含 `SKILL.md`,也可以包含一个单独的顶层 Skill 目录,并在该目录下包含 `SKILL.md`。 |
| 87 | +- `SKILL.md` frontmatter 中必须包含合法的 `name`、`description`、`version` 等元数据。 |
| 88 | +- `SKILL.md` 中的 `name` 经过 slug 归一化后,必须等于 manifest 中的 `slug`。 |
| 89 | +- `SKILL.md` 中的 `version` 必须等于 manifest 中的 `version`。 |
| 90 | +- 包内容仍会经过 SkillHub 现有发布校验,包括文件数量、文件大小、扩展名、文件类型等规则。 |
| 91 | + |
| 92 | +示例: |
| 93 | + |
| 94 | +```text |
| 95 | +skillhub-hello-1.0.0.zip |
| 96 | +├── SKILL.md |
| 97 | +├── README.md |
| 98 | +└── scripts/ |
| 99 | + └── check.js |
| 100 | +``` |
| 101 | + |
| 102 | +同样支持标准单目录 Skill 包: |
| 103 | + |
| 104 | +```text |
| 105 | +skillhub-hello-1.0.0.zip |
| 106 | +└── skillhub-hello/ |
| 107 | + ├── SKILL.md |
| 108 | + └── README.md |
| 109 | +``` |
| 110 | + |
| 111 | +如果 zip 中存在多个顶层目录,或在多个目录中同时出现 `SKILL.md`,同步器会跳过该项并记录错误,避免误选入口。 |
| 112 | + |
| 113 | +## 4. URL 安全限制 |
| 114 | + |
| 115 | +内置 Skill 同步由后端在启动时主动下载远程文件,因此 URL 有严格限制。 |
| 116 | + |
| 117 | +首版只允许: |
| 118 | + |
| 119 | +- `https://` 协议。 |
| 120 | +- host 为 `bjcdn.openstorage.cn`。 |
| 121 | +- host 为 `bjcdn.openstorage.cn` 的子域名,例如 `assets.bjcdn.openstorage.cn`。 |
| 122 | +- 默认 HTTPS 端口,或显式 `:443`。 |
| 123 | + |
| 124 | +以下 URL 会被跳过: |
| 125 | + |
| 126 | +- `http://...` |
| 127 | +- 非 `bjcdn.openstorage.cn` 及其子域名。 |
| 128 | +- 带 userinfo 的 URL,例如 `https://user:pass@bjcdn.openstorage.cn/file.zip`。 |
| 129 | +- 非 443 端口,例如 `https://bjcdn.openstorage.cn:8443/file.zip`。 |
| 130 | +- `localhost`、IP 地址、IPv6 literal 等 host。 |
| 131 | +- 需要 HTTP redirect 才能拿到文件的链接。 |
| 132 | + |
| 133 | +如果某一项 URL 不符合规则,SkillHub 会记录日志并跳过该项,不会阻塞应用启动。 |
| 134 | + |
| 135 | +## 5. 启动同步流程 |
| 136 | + |
| 137 | +应用 ready 后同步器会在后台执行一次,不阻塞应用 ready。 |
| 138 | + |
| 139 | +详细流程: |
| 140 | + |
| 141 | +1. 检查 `skillhub.builtin-skills.enabled` 是否开启。 |
| 142 | +2. 读取 `classpath:builtin-skills/manifest.json`。 |
| 143 | +3. 查询 `@global` 命名空间是否存在;如果不存在,跳过同步。 |
| 144 | +4. 确保系统发布者 `builtin-skill-publisher` 存在,并且该账号带有系统账号标记。 |
| 145 | +5. 如果该用户 ID 已被非系统账号占用,直接跳过本次内置 Skill 同步,不授予 `@global` 权限。 |
| 146 | +6. 如果系统发布者还不是 `@global` 成员,则创建 `OWNER` 成员记录;已有成员记录不会自动改角色。 |
| 147 | +7. 按 manifest 顺序处理每一个 item。 |
| 148 | +8. 下载前先检查 `@global/{slug}` 和目标版本是否已经存在;如果已经确定应跳过,则不发起远程下载。 |
| 149 | +9. 只有需要发布新 Skill 或新版本时,才下载对应 zip 包。 |
| 150 | +10. 解包并校验 Skill 入口 `SKILL.md`。 |
| 151 | +11. 校验 manifest 中的 `slug`、`version` 与包内元数据一致。 |
| 152 | +12. 发布前再次检查是否已存在同名 Skill 或同版本,处理并发启动场景。 |
| 153 | +13. 需要发布时调用现有 `SkillPublishService.publishFromEntries(...)`。 |
| 154 | +14. 发布完成后,该 Skill 位于 `@global/{slug}`,可见性为 `PUBLIC`。 |
| 155 | + |
| 156 | +同步逻辑不会直接写数据库 seed 数据。它复用现有发布服务,因此会保留现有的包校验、对象存储写入、版本记录、latest version 更新、事件和搜索索引同步。 |
| 157 | + |
| 158 | +## 6. 幂等与冲突处理 |
| 159 | + |
| 160 | +内置 Skill 同步支持重复启动和多次部署。 |
| 161 | + |
| 162 | +幂等键: |
| 163 | + |
| 164 | +```text |
| 165 | +@global/{slug} + version |
| 166 | +``` |
| 167 | + |
| 168 | +行为说明: |
| 169 | + |
| 170 | +| 场景 | 行为 | |
| 171 | +|---|---| |
| 172 | +| `@global/{slug}` 不存在 | 发布 manifest 中的 Skill | |
| 173 | +| `@global/{slug}` 已存在,owner 是 `builtin-skill-publisher`,但目标版本不存在 | 发布新版本 | |
| 174 | +| 同版本已存在且已发布 | 下载前跳过 | |
| 175 | +| 同版本已存在但不是 `PUBLISHED` | 下载前跳过并记录日志 | |
| 176 | +| `@global/{slug}` 已被其他 owner 创建或发布 | 下载前跳过并记录 warning | |
| 177 | + |
| 178 | +这意味着内置同步不会接管用户或管理员已经创建的同 slug Skill;即使该 Skill 仍处于待审、未发布或已拒绝状态,也会跳过对应 manifest item。 |
| 179 | +同版本已存在时,同步器不会重新下载远端 zip,也不会验证远端对象内容是否发生漂移。 |
| 180 | + |
| 181 | +如果多实例同时启动,可能出现多个实例同时尝试发布同一个内置版本。同步器会在发布失败后重新查询目标版本;如果发现同版本已经以相同内容发布成功,则视为并发场景下的正常跳过。 |
| 182 | + |
| 183 | +## 7. 开关配置 |
| 184 | + |
| 185 | +内置 Skill 同步默认开启。 |
| 186 | + |
| 187 | +Spring 配置项: |
| 188 | + |
| 189 | +```yaml |
| 190 | +skillhub: |
| 191 | + builtin-skills: |
| 192 | + enabled: true |
| 193 | +``` |
| 194 | +
|
| 195 | +环境变量: |
| 196 | +
|
| 197 | +```dotenv |
| 198 | +SKILLHUB_BUILTIN_SKILLS_ENABLED=true |
| 199 | +``` |
| 200 | + |
| 201 | +如需禁用启动同步: |
| 202 | + |
| 203 | +```dotenv |
| 204 | +SKILLHUB_BUILTIN_SKILLS_ENABLED=false |
| 205 | +``` |
| 206 | + |
| 207 | +禁用后,应用 ready 后不会读取 manifest,也不会下载或发布任何内置 Skill。 |
| 208 | + |
| 209 | +## 8. 维护流程 |
| 210 | + |
| 211 | +新增一个内置 Skill 的推荐步骤: |
| 212 | + |
| 213 | +1. 准备 Skill 包,并确认 zip 根目录直接包含 `SKILL.md`,或只有一个顶层 Skill 目录且该目录包含 `SKILL.md`。 |
| 214 | +2. 检查 `SKILL.md` 中的 `name` 和 `version`。 |
| 215 | +3. 上传 zip 到 `bjcdn.openstorage.cn` 或其子域名下的官方云存储路径。 |
| 216 | +4. 在 `server/skillhub-app/src/main/resources/builtin-skills/manifest.json` 中新增一项。 |
| 217 | +5. 确保 manifest 中的 `slug` 等于 `SKILL.md name` 归一化后的 slug。 |
| 218 | +6. 确保 manifest 中的 `version` 等于 `SKILL.md version`。 |
| 219 | +7. 本地或测试环境启动 SkillHub,查看后端日志确认同步结果。 |
| 220 | +8. 在 Web UI 或 API 中确认 `@global/{slug}` 已公开可见。 |
| 221 | + |
| 222 | +更新一个已有内置 Skill 的推荐步骤: |
| 223 | + |
| 224 | +1. 不要覆盖已经发布过的旧版本 zip 内容。 |
| 225 | +2. 在 `SKILL.md` 中提升 `version`。 |
| 226 | +3. 重新打包并上传新的 zip 文件。 |
| 227 | +4. 在 manifest 中新增一条同 `slug`、新 `version` 的记录。 |
| 228 | +5. 保留旧版本记录,除非产品明确不再需要该旧版本在新实例中预置。 |
| 229 | + |
| 230 | +不推荐: |
| 231 | + |
| 232 | +- 修改旧版本 zip 内容但保持同一个 `version`。 |
| 233 | +- 把 URL 指向会发生内容变化的临时对象。 |
| 234 | +- 使用需要登录、签名跳转或重定向的下载链接。 |
| 235 | + |
| 236 | +## 9. 日志与排查 |
| 237 | + |
| 238 | +启动时可以通过后端日志观察同步结果。 |
| 239 | + |
| 240 | +常见日志含义: |
| 241 | + |
| 242 | +| 日志含义 | 处理建议 | |
| 243 | +|---|---| |
| 244 | +| manifest not found | 确认 `builtin-skills/manifest.json` 是否被打进 classpath | |
| 245 | +| publisher account id already exists but is not a system account | `builtin-skill-publisher` 已被普通账号占用;需要人工处理账号冲突后再启用内置同步 | |
| 246 | +| slug, version, and url are required | 检查 manifest item 是否缺字段或字段不是字符串 | |
| 247 | +| slug is invalid | 检查 slug 是否符合 SkillHub slug 规则 | |
| 248 | +| URL is not allowed | 检查 URL 是否为 HTTPS、host 是否为 `bjcdn.openstorage.cn` 或其子域名 | |
| 249 | +| package download failed | 检查云存储对象是否存在、是否返回 HTTP 200、是否超时 | |
| 250 | +| package must contain SKILL.md | 检查 zip 是否存在唯一可识别的 `SKILL.md` 入口 | |
| 251 | +| manifest version does not match package version | 检查 manifest `version` 和 `SKILL.md version` 是否一致 | |
| 252 | +| slug already belongs to another user | 说明 `@global/{slug}` 已被非内置发布者创建或发布,内置同步不会覆盖 | |
| 253 | +| published fingerprint differs | 并发发布异常后发现同一内置版本已存在但内容不同,需要人工确认是否发生了版本冲突 | |
| 254 | + |
| 255 | +如果某个 manifest item 失败,后续 item 仍会继续处理,应用可用状态不受影响。 |
| 256 | + |
| 257 | +## 10. 验收检查 |
| 258 | + |
| 259 | +配置或新增内置 Skill 后,建议至少完成以下检查: |
| 260 | + |
| 261 | +- manifest JSON 格式合法。 |
| 262 | +- 每个 item 都包含 `slug`、`version`、`url`。 |
| 263 | +- URL 使用 `https://bjcdn.openstorage.cn/...` 或可信子域名。 |
| 264 | +- zip 根目录直接包含 `SKILL.md`,或只有一个顶层 Skill 目录且该目录包含 `SKILL.md`。 |
| 265 | +- `SKILL.md name` 归一化后的 slug 与 manifest `slug` 一致。 |
| 266 | +- `SKILL.md version` 与 manifest `version` 一致。 |
| 267 | +- 启动日志没有该 item 的 warning 或 error。 |
| 268 | +- Web UI 中可以看到 `@global/{slug}`。 |
| 269 | +- Skill 可被匿名或登录用户按公开 Skill 规则发现。 |
0 commit comments