{"meta":{"title":"自定义技能","intro":"技能是用于扩展 Copilot 功能的可复用提示模块。 从目录中加载技能，为特定域或工作流提供Copilot专用功能。","product":"GitHub Copilot","breadcrumbs":[{"href":"/zh/copilot","title":"GitHub Copilot"},{"href":"/zh/copilot/how-tos","title":"操作方法"},{"href":"/zh/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/zh/copilot/how-tos/copilot-sdk/features","title":"功能"},{"href":"/zh/copilot/how-tos/copilot-sdk/features/skills","title":"技能"}],"documentType":"article"},"body":"# 自定义技能\n\n技能是用于扩展 Copilot 功能的可复用提示模块。 从目录中加载技能，为特定域或工作流提供Copilot专用功能。\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## 概述\n\n技能是一个具有名称的目录，其中包含一个 `SKILL.md` 文件——这是一份向 Copilot 提供指令的 Markdown 文档。 加载后，技能的内容将注入到会话上下文中。\n\n技能允许您：\n\n* 将域专业知识打包到可重用模块中\n* 跨项目共享特定行为\n* 整理复杂的代理配置\n* 每个会话启用/禁用功能\n\n## 加载技能\n\n创建会话时，指定包含技能的目录：\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"gpt-5.4\",\n    skillDirectories: [\n        \"./skills/code-review\",\n        \"./skills/documentation\",\n    ],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n\n// Copilot now has access to skills in those directories\nawait session.sendAndWait({ prompt: \"Review this code for security issues\" });\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient, PermissionDecisionApproveOnce\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(\n        on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),\n        model=\"gpt-5.4\",\n        skill_directories=[\n            \"./skills/code-review\",\n            \"./skills/documentation\",\n        ],\n    )\n\n    # Copilot now has access to skills in those directories\n    await session.send_and_wait(\"Review this code for security issues\")\n\n    await client.stop()\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    copilot \"github.com/github/copilot-sdk/go\"\n    \"github.com/github/copilot-sdk/go/rpc\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model: \"gpt-5.4\",\n        SkillDirectories: []string{\n            \"./skills/code-review\",\n            \"./skills/documentation\",\n        },\n        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {\n            return &rpc.PermissionDecisionApproveOnce{}, nil\n        },\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Copilot now has access to skills in those directories\n    _, err = session.SendAndWait(ctx, copilot.MessageOptions{\n        Prompt: \"Review this code for security issues\",\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing GitHub.Copilot;\nusing GitHub.Copilot.Rpc;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"gpt-5.4\",\n    SkillDirectories = new List<string>\n    {\n        \"./skills/code-review\",\n        \"./skills/documentation\",\n    },\n    OnPermissionRequest = (req, inv) =>\n        Task.FromResult(PermissionDecision.ApproveOnce()),\n});\n\n// Copilot now has access to skills in those directories\nawait session.SendAndWaitAsync(new MessageOptions\n{\n    Prompt = \"Review this code for security issues\"\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\ntry (var client = new CopilotClient()) {\n    client.start().get();\n\n    var session = client.createSession(\n        new SessionConfig()\n            .setModel(\"gpt-5.4\")\n            .setSkillDirectories(List.of(\n                \"./skills/code-review\",\n                \"./skills/documentation\"\n            ))\n            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n    ).get();\n\n    // Copilot now has access to skills in those directories\n    session.sendAndWait(new MessageOptions()\n        .setPrompt(\"Review this code for security issues\")\n    ).get();\n}\n```\n\n</div>\n\n</div>\n\n## 禁用技能\n\n禁用特定技能，同时使其他人保持活动状态：\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills\"],\n    disabledSkills: [\"experimental-feature\", \"deprecated-tool\"],\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot.session import PermissionHandler\n\nsession = await client.create_session(\n    on_permission_request=PermissionHandler.approve_all,\n    skill_directories=[\"./skills\"],\n    disabled_skills=[\"experimental-feature\", \"deprecated-tool\"],\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{\n    SkillDirectories: []string{\"./skills\"},\n    DisabledSkills:   []string{\"experimental-feature\", \"deprecated-tool\"},\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    SkillDirectories = new List<string> { \"./skills\" },\n    DisabledSkills = new List<string> { \"experimental-feature\", \"deprecated-tool\" },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setSkillDirectories(List.of(\"./skills\"))\n        .setDisabledSkills(List.of(\"experimental-feature\", \"deprecated-tool\"))\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n).get();\n```\n\n</div>\n\n</div>\n\n## 技能目录结构\n\n每个技能都是一个包含 `SKILL.md` 文件的命名子目录：\n\n```text\nskills/\n├── code-review/\n│   └── SKILL.md\n└── documentation/\n    └── SKILL.md\n```\n\n选项 `skillDirectories` 指向父目录（例如 `./skills`）。 CLI 可发现即时子目录中的所有 `SKILL.md` 文件。\n\n### SKILL.md 格式\n\n`SKILL.md`文件是一个具有可选 YAML 头部信息的 Markdown 文件：\n\n```markdown\n---\nname: code-review\ndescription: Specialized code review capabilities\n---\n\n# Code Review Guidelines\n\nWhen reviewing code, always check for:\n\n1. **Security vulnerabilities** - SQL injection, XSS, etc.\n2. **Performance issues** - N+1 queries, memory leaks\n3. **Code style** - Consistent formatting, naming conventions\n4. **Test coverage** - Are critical paths tested?\n\nProvide specific line-number references and suggested fixes.\n```\n\n\"前置信息字段：\"\n\n* **`name`**：技能的标识符（与 `disabledSkills` 一起使用，用于选择性地禁用该技能）。 如果省略，则使用目录名称。\n* **`description`**：简要说明技能的作用。\n\nMarkdown 正文包含加载技能时注入到会话上下文的说明。\n\n## 配置选项\n\n### SessionConfig 技能字段\n\n| 语言      | 领域                  | 类型             | Description |\n| ------- | ------------------- | -------------- | ----------- |\n| Node.js | `skillDirectories`  | `string[]`     | 要从中加载技能的目录  |\n| Node.js | `disabledSkills`    | `string[]`     | 禁用技能        |\n| Python  | `skill_directories` | `list[str]`    | 要从中加载技能的目录  |\n| Python  | `disabled_skills`   | `list[str]`    | 禁用技能        |\n| Go      | `SkillDirectories`  | `[]string`     | 要从中加载技能的目录  |\n| Go      | `DisabledSkills`    | `[]string`     | 禁用技能        |\n| .NET    | `SkillDirectories`  | `List<string>` | 要从中加载技能的目录  |\n| .NET    | `DisabledSkills`    | `List<string>` | 禁用技能        |\n\n## 最佳做法\n\n1. **按域组织** - 将相关技能组合在一起（例如， `skills/security/``skills/testing/`）\n\n2. **使用前置元数据** - 在 YAML 前置元数据中包含 `name` 和 `description`，以提高清晰度\n\n3. **文档依赖项** - 记下技能所需的任何工具或 MCP 服务器\n\n4. **单独测试技能** - 在将技能组合起来之前，先确认各项技能可正常运行\n\n5. **使用相对路径** - 使技能在环境中可移植\n\n## 与其他功能结合使用\n\n### 技能 + 自定义代理\n\n代理 `skills` 字段中列出的技能 **是预先加载**的—其完整内容在启动时注入到代理的上下文中，因此代理可以立即访问技能说明，而无需调用技能工具。 技能名称从会话级 `skillDirectories` 中解析。\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills/security\"],\n    customAgents: [{\n        name: \"security-auditor\",\n        description: \"Security-focused code reviewer\",\n        prompt: \"Focus on OWASP Top 10 vulnerabilities\",\n        skills: [\"security-scan\", \"dependency-check\"],\n    }],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\n> \\[!NOTE]\n> 技能为可选启用项——省略 `skills` 时，不会注入任何技能内容。 子代理不从父级继承技能;必须为每个代理显式列出它们。\n\n### 技能 + MCP 服务器\n\n技能可以补充 MCP 服务器功能：\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills/database\"],\n    mcpServers: {\n        postgres: {\n            type: \"local\",\n            command: \"npx\",\n            args: [\"-y\", \"@modelcontextprotocol/server-postgres\"],\n            tools: [\"*\"],\n        },\n    },\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\n## 故障排除\n\n### 技能未加载\n\n1. **检查路径是否存在** - 验证技能目录路径是否正确，并且包含包含 `SKILL.md` 文件的子目录\n2. **检查权限** - 确保 SDK 可以读取目录\n3. **检查 SKILL.md 格式** - 验证 markdown 格式正确，并且任何 YAML frontmatter 都使用有效的语法\n4. **启用调试日志** - 将 `logLevel: \"debug\"` 设为开启以查看技能加载日志\n\n### 技能冲突\n\n如果多个技能提供冲突的说明：\n\n* 使用 `disabledSkills` 来排除冲突技能\n* 重新组织技能目录以避免重叠\n\n## 另见\n\n* [构建你的第一个由 Copilot 提供支持的应用](/zh/copilot/how-tos/copilot-sdk/getting-started#create-custom-agents) - 定义专用 AI 角色\n* [构建你的第一个由 Copilot 提供支持的应用](/zh/copilot/how-tos/copilot-sdk/getting-started#step-4-add-a-custom-tool) - 生成自己的工具\n* [将 MCP 服务器与 GitHub Copilot SDK 配合使用](/zh/copilot/how-tos/copilot-sdk/features/mcp) - 连接外部工具提供方"}