OpenCode Skills 文档

OpenCode Skills 文档

目录

  1. [什么是 Skill](#什么是 Skill "#%E4%BB%80%E4%B9%88%E6%98%AF-skill")
  2. [SKILL.md 文件格式](#SKILL.md 文件格式 "#skillmd-%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F")
  3. 发现路径与配置
  4. [与 MCP、Subagent 的区别](#与 MCP、Subagent 的区别 "#%E4%B8%8E-mcpsubagent-%E7%9A%84%E5%8C%BA%E5%88%AB")
  5. [如何注入到 LLM](#如何注入到 LLM "#%E5%A6%82%E4%BD%95%E6%B3%A8%E5%85%A5%E5%88%B0-llm")
  6. 渐进式加载策略
  7. [如何自定义 Skill](#如何自定义 Skill "#%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89-skill")
  8. [远程 Skill 托管](#远程 Skill 托管 "#%E8%BF%9C%E7%A8%8B-skill-%E6%89%98%E7%AE%A1")

什么是 Skill

Skill 是一种按需加载的 Markdown 指令文件,用于给 AI 注入专项知识或操作规范。

每个 Skill 本质上是一个 SKILL.md 文件,包含:

  • YAML frontmatter:声明 skill 的名称和用途
  • Markdown 正文:具体的指令、规则、示例、最佳实践

AI 通过 skill 工具按需加载 skill 内容,不需要的 skill 不占用上下文。

典型用途:

  • 项目编码规范(命名、文件结构、禁止模式)
  • 框架使用指南(如何正确使用 Effect、React、Prisma)
  • 工作流程规范(提交前检查清单、测试策略)
  • 领域知识(业务术语定义、架构约束)

SKILL.md 文件格式

yaml 复制代码
---
name: my-skill
description: 简短描述这个 skill 的用途(AI 根据此决定是否加载)
---

# 正文内容

这里写具体的指令、规则、示例等。

## 章节一

...

## 章节二

...

Frontmatter 字段:

字段 类型 必填 说明
name string skill 的唯一标识符,用于 skill 工具调用
description string 单行描述,显示在 AI 的工具描述和系统提示中

真实示例.opencode/skills/effect/SKILL.md):

yaml 复制代码
---
name: effect
description: Guidelines for writing idiomatic Effect-TS code in this project
---

## Effect Coding Guidelines

- Always use `Effect.gen` for sequential async operations
- Prefer `pipe` over method chaining for readability
- Use `Schema` for all data validation
- Never use `Effect.runSync` in production code

## Error Handling

...

发现路径与配置

OpenCode 按以下顺序扫描 skill 文件:

内置路径(自动扫描)

优先级 路径 用途
1 ~/.claude/skills/ Claude 全局 skills
2 ~/.agents/skills/ 通用 agent skills
3 <项目根>/.opencode/skills/ 项目级 skills
4 opencode.jsonskills.paths 指定的路径 自定义路径
5 opencode.jsonskills.urls 指定的远程 URL 远程 skills

每个目录下的每个子目录若含 SKILL.md 文件,即视为一个 skill。

目录结构示例:

objectivec 复制代码
.opencode/
└── skills/
    ├── effect/
    │   └── SKILL.md          ← skill: effect
    ├── testing/
    │   ├── SKILL.md          ← skill: testing
    │   └── examples.md       ← 伴随文件(可在 SKILL.md 中引用)
    └── commit-style/
        └── SKILL.md          ← skill: commit-style

配置文件(opencode.json

json 复制代码
{
  "skills": {
    "paths": [
      "~/my-shared-skills",
      "/team/shared/opencode-skills"
    ],
    "urls": [
      "https://example.com/opencode-skills"
    ]
  }
}
字段 类型 说明
skills.paths string[] 额外扫描的本地目录(支持 ~ 展开)
skills.urls string[] 远程 skill 包的 URL(见[远程托管](#字段 类型 说明 skills.paths string[] 额外扫描的本地目录(支持 ~ 展开) skills.urls string[] 远程 skill 包的 URL(见远程托管) "#%E8%BF%9C%E7%A8%8B-skill-%E6%89%98%E7%AE%A1"))

与 MCP、Subagent 的区别

维度 Skill MCP Tool Subagent
本质 Markdown 指令文件 可执行工具(函数) 独立 AI 进程
作用 注入知识/规范到 AI 扩展 AI 的操作能力 将子任务委托给另一个 AI
运行时 无副作用,仅读取文本 调用外部进程/API 启动新的 AI 对话
上下文共享 在当前对话中内联 工具结果返回当前对话 独立上下文,结果汇报
定义方式 SKILL.md 文件 服务器进程 + JSON Schema 代码调用 AI API
加载时机 按需(AI 主动调用 skill 工具) 启动时注册到 LLM 任务执行时动态创建
适合场景 编码规范、领域知识、操作指南 文件读写、代码执行、API 调用 并行任务、隔离复杂子任务

简单理解:

  • Skill = 给 AI 读的"说明书",告诉它"应该怎么做"
  • MCP Tool = 给 AI 用的"工具箱",让它能"做某件事"
  • Subagent = 给 AI 雇的"助手",让它"帮你做某件事"

如何注入到 LLM

Skills 采用两阶段注入机制,兼顾信息可见性和上下文效率。

阶段一:系统提示列表(每次请求都包含)

每次 LLM 调用时,系统提示中自动插入所有可用 skill 的概览:

xml 复制代码
<skills>
  <skill>
    <name>effect</name>
    <description>Guidelines for writing idiomatic Effect-TS code in this project</description>
  </skill>
  <skill>
    <name>testing</name>
    <description>Testing strategy and patterns for this codebase</description>
  </skill>
  <skill>
    <name>commit-style</name>
    <description>Commit message format and branch naming conventions</description>
  </skill>
</skills>

AI 看到这个列表后,知道有哪些 skill 可用,并根据任务判断是否需要加载。

同时,skill 工具的描述中也嵌入了可用 skill 列表(简短格式),供 AI 调用时参考:

kotlin 复制代码
Load the content of a skill.

Available skills:
- effect: Guidelines for writing idiomatic Effect-TS code in this project
- testing: Testing strategy and patterns for this codebase
- commit-style: Commit message format and branch naming conventions

阶段二:按需加载(AI 主动调用 skill 工具)

当 AI 判断某个 skill 与当前任务相关时,调用 skill 工具:

json 复制代码
{
  "tool": "skill",
  "input": { "name": "effect" }
}

工具返回完整内容:

xml 复制代码
<skill_content name="effect">
  ## Effect Coding Guidelines

  - Always use `Effect.gen` for sequential async operations
  ...

  <files>
    <file>packages/core/src/effect-utils.ts</file>
    <file>packages/core/src/schema.ts</file>
  </files>
</skill_content>

返回内容包含:

  • skill 正文:完整的 Markdown 指令
  • 相关文件列表(最多 10 个):通过 ripgrep 在项目中搜索与 skill 同名的文件,帮助 AI 快速定位相关代码

完整流程示意

markdown 复制代码
会话开始
    │
    ▼
系统提示构建
    ├─ ...其他系统提示内容...
    └─ <skills> 列表(所有已发现的 skill 名称+描述)
    
    │
    ▼
LLM 收到请求
    ├─ 看到 <skills> 列表,了解有哪些 skill
    └─ 根据任务决定是否调用 skill 工具

    │(AI 决定加载某个 skill)
    ▼
AI 调用: skill("effect")
    │
    ▼
OpenCode 读取 SKILL.md
    ├─ 解析 frontmatter
    ├─ 返回完整 Markdown 内容
    └─ 附加相关文件列表(ripgrep 搜索)

    │
    ▼
AI 将 skill 内容纳入上下文
    └─ 按 skill 指令执行后续任务

渐进式加载策略

渐进式加载(Progressive Loading)描述的是 AI 在完成一个任务时从粗到细、按需展开的资源获取方式。它不是一次性把所有相关信息塞入上下文,而是从极低代价的元信息开始,随着任务推进逐步加载更具体的内容。

三个层次

objectivec 复制代码
层次 1:描述(系统提示中的 skill 列表)
         ↓  AI 判断与当前任务相关
层次 2:规则(SKILL.md 正文 + 文件列表)
         ↓  AI 判断需要了解具体实现
层次 3:代码(SKILL.md 中列出的资源文件)
层次 内容 上下文代价 何时触发
描述 skill 名称 + 一句话说明 极低(每个 skill ~20 tokens) 每次请求自动包含
规则 SKILL.md 完整正文 + 相关文件列表 中(几百到几千 tokens) AI 调用 skill 工具时
代码 文件列表中的实际源码文件 高(按文件大小) AI 主动读取文件时

核心思想:只有真正需要某个层次的信息时,才付出对应的上下文代价。

复杂示例:实现一个新的业务 Service

项目背景:

arduino 复制代码
.opencode/skills/backend/
├── SKILL.md                          ← 规则:Service 编写规范
├── service-template.ts               ← 资源:Service 模板
├── error-codes.md                    ← 资源:错误码定义表
└── existing-service-example.ts       ← 资源:现有 Service 示例

任务: "帮我实现 OrderService,支持创建订单和查询订单详情"


第 1 步:层次 1 --- AI 看到描述,决定加载

系统提示中包含:

xml 复制代码
<skills>
  <skill>
    <name>backend</name>
    <description>Service layer patterns, dependency injection rules, and error handling conventions</description>
  </skill>
  ...
</skills>

AI 识别到任务需要编写 Service,决定加载 backend skill。此时上下文中只有一句话描述,代价极低。


第 2 步:层次 2 --- AI 加载 SKILL.md,获得规则 + 文件列表

AI 调用:

json 复制代码
{ "tool": "skill", "input": { "name": "backend" } }

返回:

ruby 复制代码
<skill_content name="backend">
  ## Service 编写规范

  ### 结构要求
  - 每个 Service 必须通过 `Effect.Service` 定义,不能用普通 class
  - 依赖其他 Service 通过构造参数注入,禁止在方法内直接 import
  - 所有公开方法返回 `Effect<Result, AppError>`,不允许 throw

  ### 错误处理
  - 业务错误使用 `error-codes.md` 中定义的错误码
  - 数据库错误统一包装为 `DatabaseError`,不能透传 Prisma 错误

  ### 命名约定
  - 文件名:`<domain>.service.ts`
  - 查询方法:`find*`(单个)、`list*`(列表)
  - 写入方法:`create*`、`update*`、`delete*`

  <files>
    <file>.opencode/skills/backend/service-template.ts</file>
    <file>.opencode/skills/backend/error-codes.md</file>
    <file>.opencode/skills/backend/existing-service-example.ts</file>
    <file>packages/api/src/services/user.service.ts</file>
    <file>packages/api/src/services/product.service.ts</file>
  </files>
</skill_content>

AI 现在知道:

  1. Service 的结构规范(Effect.Service、依赖注入、返回类型)
  2. 错误处理约定
  3. 有哪些资源文件可以参考

但此时还没有读取任何资源文件,代价只有 SKILL.md 正文的 tokens。


第 3 步:层次 3 --- AI 按需读取资源文件

AI 根据任务复杂度和 SKILL.md 中的提示,决定读取哪些文件:

读取 1:模板文件(最优先,直接给出骨架)

arduino 复制代码
AI 读取: .opencode/skills/backend/service-template.ts
scala 复制代码
// service-template.ts
import { Effect, Layer } from "effect"
import { PrismaService } from "./prisma.service"

export class TemplateService extends Effect.Service<TemplateService>()(
  "TemplateService",
  {
    effect: Effect.gen(function* () {
      const prisma = yield* PrismaService

      return {
        findById: (id: string) =>
          Effect.tryPromise({
            try: () => prisma.client.template.findUniqueOrThrow({ where: { id } }),
            catch: (e) => new DatabaseError({ cause: e }),
          }),
      }
    }),
  }
) {}

export const TemplateServiceLive = TemplateService.Default

AI 获得了具体的代码骨架,知道如何套用到 OrderService

读取 2:错误码表(写错误处理时需要)

bash 复制代码
AI 读取: .opencode/skills/backend/error-codes.md
lua 复制代码
| 错误码 | 类名 | 含义 |
|--------|------|------|
| ORDER_NOT_FOUND | OrderNotFoundError | 订单不存在 |
| ORDER_ALREADY_PAID | OrderAlreadyPaidError | 订单已支付 |
| INSUFFICIENT_STOCK | InsufficientStockError | 库存不足 |

读取 3:现有 Service 示例(理解项目惯用法)

如果模板已经足够清晰,AI 可以跳过 这一步,不读取 existing-service-example.tsuser.service.ts,节省上下文。


最终上下文消耗对比:

ini 复制代码
全量预加载(假设):
  5 个技能 × 平均 2000 tokens = 10,000 tokens(大量无关内容)

渐进式加载(实际):
  层次 1:80 tokens    (5 个 skill 的描述)
  层次 2:800 tokens   (backend SKILL.md 正文)
  层次 3:600 tokens   (service-template.ts + error-codes.md)
  ─────────────────────
  合计:约 1,480 tokens(节省约 85%)

资源文件的两个来源

skill 工具返回的文件列表来自两处,AI 会根据相关性选择性读取:

来源 示例 特点
skill 目录中的伴随文件 service-template.tserror-codes.md 由 skill 作者精心准备,直接相关
项目中同名搜索结果 user.service.tsproduct.service.ts ripgrep 搜索 skill 名称找到的真实代码

伴随文件是"教材"(规范示例),项目文件是"参考实现"(已有代码的惯用法)。两者结合让 AI 既了解规范又了解当前项目的实际写法。

如何在 SKILL.md 中引导渐进式加载

SKILL.md 正文中主动告诉 AI 什么时候该读哪个文件,可以使加载行为更可预测:

yaml 复制代码
---
name: backend
description: Service layer patterns, dependency injection rules, and error handling conventions
---

## 使用指引

**新建 Service 时:** 先读 `service-template.ts` 获取骨架,再根据需要查阅 `error-codes.md`

**排查错误时:** 直接查阅 `error-codes.md` 中的错误码定义

**不确定惯用法时:** 参考 `existing-service-example.ts` 或项目中现有的 `*.service.ts`

## 规则

...

这样 AI 在读完 SKILL.md 后,能精准判断下一步应该读哪个文件,而不是盲目读取所有列出的文件。


如何自定义 Skill

步骤一:创建目录结构

perl 复制代码
# 项目级 skill(推荐)
mkdir -p .opencode/skills/my-skill

# 或全局 skill(所有项目可用)
mkdir -p ~/.claude/skills/my-skill

步骤二:编写 SKILL.md

yaml 复制代码
---
name: my-skill
description: 描述这个 skill 的用途(简洁,一句话)
---

# My Skill

## 规则

1. 规则一:...
2. 规则二:...

## 禁止事项

- 不要做 X
- 避免 Y 模式

## 示例

...

编写建议:

  • description 要精准,AI 靠它决定是否加载 skill
  • 正文使用清晰的 Markdown 结构,便于 AI 理解
  • 可以包含代码示例、对比示例(好/坏)
  • 保持专注,一个 skill 解决一类问题

步骤三:添加伴随文件(可选)

可在同一目录放置辅助文件(模板、示例等),AI 调用 skill 时会在文件列表中看到它们:

arduino 复制代码
.opencode/skills/my-skill/
    ├── SKILL.md          ← 主文件(必须)
    ├── template.ts       ← 模板文件
    └── examples.md       ← 详细示例

步骤四:验证

重启 OpenCode 后,在对话中测试:

perl 复制代码
请使用 my-skill skill 帮我...

或直接询问 AI 有哪些可用的 skill。


远程 Skill 托管

可以将 skills 托管在 HTTP 服务器上,供团队共享。

服务器目录结构

objectivec 复制代码
https://example.com/opencode-skills/
    ├── index.json              ← 索引文件(必须)
    ├── effect/
    │   └── SKILL.md
    └── testing/
        └── SKILL.md

index.json 格式

json 复制代码
{
  "skills": [
    {
      "name": "effect",
      "files": ["effect/SKILL.md"]
    },
    {
      "name": "testing",
      "files": ["testing/SKILL.md", "testing/examples.md"]
    }
  ]
}
字段 类型 说明
skills array skill 列表
skills[].name string skill 名称(对应目录名)
skills[].files string[] 该 skill 包含的文件路径(相对于 URL 根)

配置使用

json 复制代码
{
  "skills": {
    "urls": ["https://example.com/opencode-skills"]
  }
}

缓存机制: 远程 skill 下载后缓存到 ~/.cache/opencode/skills/,避免每次重复下载。


源码位置参考

功能 文件
Skill 服务(发现、加载、fmt) packages/opencode/src/skill/index.ts
远程 skill 下载 packages/opencode/src/skill/discovery.ts
skill 工具定义 packages/opencode/src/tool/skill.ts
工具描述(含 skill 列表) packages/opencode/src/tool/skill.txt
系统提示注入 packages/opencode/src/session/system.ts
配置 schema packages/opencode/src/config/skills.ts
工具注册(enriched description) packages/opencode/src/tool/registry.ts
相关推荐
无限进步_1 小时前
二叉搜索树完全解析:从概念到实现与应用场景
c语言·开发语言·数据结构·c++·算法·github·visual studio
05候补工程师2 小时前
深度解构 ROS 2:如何手动调通 Nav2 A* 路径规划引擎
linux·人工智能·经验分享·算法·机器人
上弦月-编程2 小时前
【C语言逻辑题】谋杀案凶手是谁?——经典矛盾推理题详解
算法
天若有情6732 小时前
逆向玩家狂喜!用C++野生写法一键破解线性加密(不规范但巨好用)
开发语言·c++·算法
风筝在晴天搁浅3 小时前
剑指Offer 60.n个骰子的点数
算法
ProgramHelpOa3 小时前
Optiver 2026 OA 全面复盘|26NG / Intern 最新高频题型整理
人工智能·算法·机器学习
feifeigo1233 小时前
基于无迹变换的电网概率潮流分析 MATLAB 实现
开发语言·算法·matlab
Java成神之路-3 小时前
【算法刷题笔记】全题型导航目录
笔记·算法
爱写代码的倒霉蛋3 小时前
2022年天梯赛L1-8真题解析(哈希+排序)
数据结构·算法