Skip to main content

自定义技能

技能是用于扩展 Copilot 功能的可复用提示模块。 从目录中加载技能,为特定域或工作流提供Copilot专用功能。

概述

技能是一个具有名称的目录,其中包含一个 SKILL.md 文件——这是一份向 Copilot 提供指令的 Markdown 文档。 加载后,技能的内容将注入到会话上下文中。

技能允许您:

  • 将域专业知识打包到可重用模块中
  • 跨项目共享特定行为
  • 整理复杂的代理配置
  • 每个会话启用/禁用功能

加载技能

创建会话时,指定包含技能的目录:

TypeScript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    skillDirectories: [
        "./skills/code-review",
        "./skills/documentation",
    ],
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

// Copilot now has access to skills in those directories
await session.sendAndWait({ prompt: "Review this code for security issues" });
Python
from copilot import CopilotClient, PermissionDecisionApproveOnce

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(
        on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
        model="gpt-4.1",
        skill_directories=[
            "./skills/code-review",
            "./skills/documentation",
        ],
    )

    # Copilot now has access to skills in those directories
    await session.send_and_wait("Review this code for security issues")

    await client.stop()
Go
package main

import (
    "context"
    "log"
    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model: "gpt-4.1",
        SkillDirectories: []string{
            "./skills/code-review",
            "./skills/documentation",
        },
        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    // Copilot now has access to skills in those directories
    _, err = session.SendAndWait(ctx, copilot.MessageOptions{
        Prompt: "Review this code for security issues",
    })
    if err != nil {
        log.Fatal(err)
    }
}
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    SkillDirectories = new List<string>
    {
        "./skills/code-review",
        "./skills/documentation",
    },
    OnPermissionRequest = (req, inv) =>
        Task.FromResult(PermissionDecision.ApproveOnce()),
});

// Copilot now has access to skills in those directories
await session.SendAndWaitAsync(new MessageOptions
{
    Prompt = "Review this code for security issues"
});
Java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;
import java.util.List;

try (var client = new CopilotClient()) {
    client.start().get();

    var session = client.createSession(
        new SessionConfig()
            .setModel("gpt-4.1")
            .setSkillDirectories(List.of(
                "./skills/code-review",
                "./skills/documentation"
            ))
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();

    // Copilot now has access to skills in those directories
    session.sendAndWait(new MessageOptions()
        .setPrompt("Review this code for security issues")
    ).get();
}

禁用技能

禁用特定技能,同时使其他人保持活动状态:

TypeScript
const session = await client.createSession({
    skillDirectories: ["./skills"],
    disabledSkills: ["experimental-feature", "deprecated-tool"],
});
Python
from copilot.session import PermissionHandler

session = await client.create_session(
    on_permission_request=PermissionHandler.approve_all,
    skill_directories=["./skills"],
    disabled_skills=["experimental-feature", "deprecated-tool"],
)
Go
package main

import (
    "context"
    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)

    session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
        SkillDirectories: []string{"./skills"},
        DisabledSkills:   []string{"experimental-feature", "deprecated-tool"},
        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })
    _ = session
}
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
    SkillDirectories: []string{"./skills"},
    DisabledSkills:   []string{"experimental-feature", "deprecated-tool"},
})
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;

public static class SkillsExample
{
    public static async Task Main()
    {
        await using var client = new CopilotClient();

        var session = await client.CreateSessionAsync(new SessionConfig
        {
            SkillDirectories = new List<string> { "./skills" },
            DisabledSkills = new List<string> { "experimental-feature", "deprecated-tool" },
            OnPermissionRequest = (req, inv) =>
                Task.FromResult(PermissionDecision.ApproveOnce()),
        });
    }
}
var session = await client.CreateSessionAsync(new SessionConfig
{
    SkillDirectories = new List<string> { "./skills" },
    DisabledSkills = new List<string> { "experimental-feature", "deprecated-tool" },
});
Java
import com.github.copilot.rpc.*;
import java.util.List;

var session = client.createSession(
    new SessionConfig()
        .setSkillDirectories(List.of("./skills"))
        .setDisabledSkills(List.of("experimental-feature", "deprecated-tool"))
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();

技能目录结构

每个技能都是一个包含 SKILL.md 文件的命名子目录:

skills/
├── code-review/
│   └── SKILL.md
└── documentation/
    └── SKILL.md

选项 skillDirectories 指向父目录(例如 ./skills)。 CLI 可发现即时子目录中的所有 SKILL.md 文件。

SKILL.md 格式

SKILL.md文件是一个具有可选 YAML 头部信息的 Markdown 文件:

---
name: code-review
description: Specialized code review capabilities
---

# Code Review Guidelines

When reviewing code, always check for:

1. **Security vulnerabilities** - SQL injection, XSS, etc.
2. **Performance issues** - N+1 queries, memory leaks
3. **Code style** - Consistent formatting, naming conventions
4. **Test coverage** - Are critical paths tested?

Provide specific line-number references and suggested fixes.

"前置信息字段:"

  • name:技能的标识符(与 disabledSkills 一起使用,用于选择性地禁用该技能)。 如果省略,则使用目录名称。
  • description:简要说明技能的作用。

Markdown 正文包含加载技能时注入到会话上下文的说明。

配置选项

SessionConfig 技能字段

语言领域类型Description
Node.jsskillDirectoriesstring[]要从中加载技能的目录
Node.jsdisabledSkillsstring[]禁用技能
Pythonskill_directorieslist[str]要从中加载技能的目录
Pythondisabled_skillslist[str]禁用技能
GoSkillDirectories[]string要从中加载技能的目录
GoDisabledSkills[]string禁用技能
.NETSkillDirectoriesList<string>要从中加载技能的目录
.NETDisabledSkillsList<string>禁用技能

最佳做法

  1. 按域组织 - 将相关技能组合在一起(例如, skills/security/``skills/testing/

  2. 使用前置元数据 - 在 YAML 前置元数据中包含 namedescription,以提高清晰度

  3. 文档依赖项 - 记下技能所需的任何工具或 MCP 服务器

  4. 单独测试技能 - 在将技能组合起来之前,先确认各项技能可正常运行

  5. 使用相对路径 - 使技能在环境中可移植

与其他功能结合使用

技能 + 自定义代理

代理 skills 字段中列出的技能 是预先加载的—其完整内容在启动时注入到代理的上下文中,因此代理可以立即访问技能说明,而无需调用技能工具。 技能名称从会话级 skillDirectories 中解析。

const session = await client.createSession({
    skillDirectories: ["./skills/security"],
    customAgents: [{
        name: "security-auditor",
        description: "Security-focused code reviewer",
        prompt: "Focus on OWASP Top 10 vulnerabilities",
        skills: ["security-scan", "dependency-check"],
    }],
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

注意

技能为可选启用项——省略 skills 时,不会注入任何技能内容。 子代理不从父级继承技能;必须为每个代理显式列出它们。

技能 + MCP 服务器

技能可以补充 MCP 服务器功能:

const session = await client.createSession({
    skillDirectories: ["./skills/database"],
    mcpServers: {
        postgres: {
            type: "local",
            command: "npx",
            args: ["-y", "@modelcontextprotocol/server-postgres"],
            tools: ["*"],
        },
    },
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

故障排除

技能未加载

  1. 检查路径是否存在 - 验证技能目录路径是否正确,并且包含包含 SKILL.md 文件的子目录
  2. 检查权限 - 确保 SDK 可以读取目录
  3. 检查 SKILL.md 格式 - 验证 markdown 格式正确,并且任何 YAML frontmatter 都使用有效的语法
  4. 启用调试日志 - 将 logLevel: "debug" 设为开启以查看技能加载日志

技能冲突

如果多个技能提供冲突的说明:

  • 使用 disabledSkills 来排除冲突技能
  • 重新组织技能目录以避免重叠

另见