{"meta":{"title":"BYOK （自带密钥）","intro":"BYOK 允许你通过模型提供程序将 Copilot SDK 与自己的 API 密钥一起使用，从而绕过GitHub 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/auth","title":"Authentication"},{"href":"/zh/copilot/how-tos/copilot-sdk/auth/byok","title":"BYOK"}],"documentType":"article"},"body":"# BYOK （自带密钥）\n\nBYOK 允许你通过模型提供程序将 Copilot SDK 与自己的 API 密钥一起使用，从而绕过GitHub Copilot身份验证。 这对于企业部署、自定义模型托管或需要与模型提供商直接计费时非常有用。\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## 支持的服务提供商\n\n| Provider                         | 类型值                                                        | 备注                               |\n| -------------------------------- | ---------------------------------------------------------- | -------------------------------- |\n| OpenAI                           | `\"openai\"`                                                 | OpenAI API 和 OpenAI 兼容的端点        |\n| Microsoft Foundry / Azure OpenAI |                                                            |                                  |\n| `\"openai\"` 或 `\"azure\"`           | 对于 `/openai/v1/`，使用 `\"openai\"`；对于原生 Azure 终结点，使用 `\"azure\"` |                                  |\n| Anthropic                        | `\"anthropic\"`                                              | Claude 模型                        |\n| Ollama                           | `\"openai\"`                                                 | 通过 OpenAI 兼容 API 使用的本地模型         |\n| 微软铸造厂 Local                      | `\"openai\"`                                                 | 通过 OpenAI 兼容的 API 在本地设备上运行 AI 模型 |\n| 其他与 OpenAI 兼容的                   | `\"openai\"`                                                 | vLLM、LiteLLM 等                   |\n\n## 快速入门：Microsoft Foundry\n\nMicrosoft Foundry 是企业常见的 BYOK 部署目标。 下面是一个完整的示例：\n\n<div class=\"ghd-codetabs\">\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\nimport asyncio\nimport os\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\n\nFOUNDRY_MODEL_URL = \"https://<resource-name>.openai.azure.com/openai/v1/\"\n# Set FOUNDRY_API_KEY environment variable\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"gpt-5.2-codex\", provider={\n        \"type\": \"openai\",\n        \"base_url\": FOUNDRY_MODEL_URL,\n        \"wire_api\": \"responses\",  # Use \"completions\" for older models\n        \"api_key\": os.environ[\"FOUNDRY_API_KEY\"],\n    })\n\n    done = asyncio.Event()\n\n    def on_event(event):\n        if event.type.value == \"assistant.message\":\n            print(event.data.content)\n        elif event.type.value == \"session.idle\":\n            done.set()\n\n    session.on(on_event)\n    await session.send(\"What is 2+2?\")\n    await done.wait()\n\n    await session.disconnect()\n    await client.stop()\n\nasyncio.run(main())\n```\n\n</div>\n\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 FOUNDRY_MODEL_URL = \"https://<resource-name>.openai.azure.com/openai/v1/\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"gpt-5.2-codex\",  // Your deployment name\n    provider: {\n        type: \"openai\",\n        baseUrl: FOUNDRY_MODEL_URL,\n        wireApi: \"responses\",  // Use \"completions\" for older models\n        apiKey: process.env.FOUNDRY_API_KEY,\n    },\n});\n\nsession.on(\"assistant.message\", (event) => {\n    console.log(event.data.content);\n});\n\nawait session.sendAndWait({ prompt: \"What is 2+2?\" });\nawait 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    \"fmt\"\n    \"os\"\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        panic(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model: \"gpt-5.2-codex\",  // Your deployment name\n        Provider: &copilot.ProviderConfig{\n            Type:    \"openai\",\n            BaseURL: \"https://<resource-name>.openai.azure.com/openai/v1/\",\n            WireAPI: \"responses\",  // Use \"completions\" for older models\n            APIKey:  os.Getenv(\"FOUNDRY_API_KEY\"),\n        },\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    response, err := session.SendAndWait(ctx, copilot.MessageOptions{\n        Prompt: \"What is 2+2?\",\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    if d, ok := response.Data.(*copilot.AssistantMessageData); ok {\n        fmt.Println(d.Content)\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;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"gpt-5.2-codex\",  // Your deployment name\n    Provider = new ProviderConfig\n    {\n        Type = \"openai\",\n        BaseUrl = \"https://<resource-name>.openai.azure.com/openai/v1/\",\n        WireApi = \"responses\",  // Use \"completions\" for older models\n        ApiKey = Environment.GetEnvironmentVariable(\"FOUNDRY_API_KEY\"),\n    },\n});\n\nvar response = await session.SendAndWaitAsync(new MessageOptions\n{\n    Prompt = \"What is 2+2?\",\n});\nConsole.WriteLine(response?.Data.Content);\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.*;\n\nvar client = new CopilotClient();\nclient.start().get();\n\nvar session = client.createSession(new SessionConfig()\n    .setModel(\"gpt-5.2-codex\")  // Your deployment name\n    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n    .setProvider(new ProviderConfig()\n        .setType(\"openai\")\n        .setBaseUrl(\"https://<resource-name>.openai.azure.com/openai/v1/\")\n        .setWireApi(\"responses\")  // Use \"completions\" for older models\n        .setApiKey(System.getenv(\"FOUNDRY_API_KEY\")))\n).get();\n\nvar response = session.sendAndWait(new MessageOptions()\n    .setPrompt(\"What is 2+2?\")).get();\nSystem.out.println(response.getData().content());\n\nclient.stop().get();\n```\n\n</div>\n\n</div>\n\n## 提供程序配置参考\n\n### ProviderConfig 字段\n\n| 领域                                                                                                                      | 类型  | Description                                             |\n| ----------------------------------------------------------------------------------------------------------------------- | --- | ------------------------------------------------------- |\n| `type`                                                                                                                  |     |                                                         |\n| `\"openai\"`                                                                                                              |     |                                                         |\n| \\|                                                                                                                      |     |                                                         |\n| `\"azure\"`                                                                                                               |     |                                                         |\n| \\|                                                                                                                      |     |                                                         |\n| `\"anthropic\"`                                                                                                           |     |                                                         |\n| 提供程序类型（默认值： `\"openai\"`）                                                                                                 |     |                                                         |\n| `baseUrl` / `base_url`                                                                                                  | 字符串 |                                                         |\n| **必填。** API 端点 URL                                                                                                      |     |                                                         |\n| `apiKey` / `api_key`                                                                                                    | 字符串 | API 密钥（对于像 Ollama 这样的本地提供程序，可选）                         |\n| `bearerToken` / `bearer_token`                                                                                          | 字符串 | 持有者令牌身份验证（优先于 apiKey）                                   |\n| `bearerTokenProvider` / `bearer_token_provider`                                                                         | 回叫  | 按需返回持有者令牌（优先于 `apiKey` 和 `bearerToken`）                 |\n| `wireApi` / `wire_api`                                                                                                  |     |                                                         |\n| `\"completions\"`                                                                                                         |     |                                                         |\n| \\|                                                                                                                      |     |                                                         |\n| `\"responses\"`                                                                                                           |     |                                                         |\n| 选择 `\"completions\"` 以实现广泛的模型兼容性（聊天补全 API）；选择 `\"responses\"` 以实现多轮状态管理、工具命名空间和推理支持（响应 API）。 无论此设置如何，Anthropic模型始终使用消息 API。 |     |                                                         |\n| `azure.apiVersion` / `azure.api_version`                                                                                | 字符串 | Azure API 版本。 设置后，运行时使用带版本的部署路由；省略时，则使用 GA 无版本 `v1` 路由。 |\n\n### 接口 API 格式\n\n此设置 `wireApi` 确定要使用的 OpenAI API 格式：\n\n* **`\"completions\"`**（默认）- Chat Completions API（`/chat/completions`），可广泛兼容各种模型。\n* ```\n            **              `\"responses\"`              ** - 用于多轮状态管理、工具命名空间和推理支持的响应 API。\n  ```\n\n无论此设置为何，Anthropic 模型始终使用 Anthropic Messages API。\n\n### 类型特定的注释\n\n**OpenAI （`type: \"openai\"`）**\n\n* 支持 OpenAI API 以及任何兼容 OpenAI 的端点\n* `baseUrl` 应包含完整路径（例如 `https://api.openai.com/v1`）\n\n**Azure （`type: \"azure\"`）**\n\n* 用于原生 Azure OpenAI 终结点\n* `baseUrl` 应只是主机（例如 `https://my-resource.openai.azure.com`）\n* 请勿在 URL 中包含 `/openai/v1`——SDK 会负责构造路径\n\n**Anthropic（`type: \"anthropic\"`）**\n\n* 用于直接访问 Anthropic API\n* 使用特定于 Claude 的 API 格式\n\n## 示例配置\n\n### OpenAI direct\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https://api.openai.com/v1\",\n    apiKey: process.env.OPENAI_API_KEY,\n}\n```\n\n### Azure OpenAI （本机 Azure 终结点）\n\n在 `type: \"azure\"` 的终结点使用 `*.openai.azure.com`:\n\n```typescript\nprovider: {\n    type: \"azure\",\n    baseUrl: \"https://my-resource.openai.azure.com\",  // Just the host\n    apiKey: process.env.AZURE_OPENAI_KEY,\n    azure: {\n        apiVersion: \"2024-10-21\",\n    },\n}\n```\n\n### Microsoft Foundry (OpenAI 兼容端点)\n\n对于具有 `/openai/v1/` 终结点的 Microsoft Foundry 部署，请使用 `type: \"openai\"`：\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https://<resource-name>.openai.azure.com/openai/v1/\",\n    apiKey: process.env.FOUNDRY_API_KEY,\n    wireApi: \"responses\",  // For GPT-5 series models\n}\n```\n\n### 奥拉马（本地）\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"http://localhost:11434/v1\",\n    // No apiKey needed for local Ollama\n}\n```\n\n### 微软铸造厂 Local\n\n[Microsoft Foundry Local](https://foundrylocal.ai) 允许使用与 OpenAI 兼容的 API 在本地设备上运行 AI 模型。 通过 Foundry Local CLI 安装它，然后将 SDK 指向本地终结点：\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"http://localhost:<PORT>/v1\",\n    // No apiKey needed for local Foundry Local\n}\n```\n\n> \\[!NOTE]\n> Foundry Local 在 **动态端口**上启动 ， 端口未固定。 使用 `foundry service status` 确认该服务当前正在监听的端口，然后在你的 `baseUrl` 中使用该端口。\n\n若要开始使用 Foundry Local：\n\n```bash\n# Windows: Install Foundry Local CLI (requires winget)\nwinget install Microsoft.FoundryLocal\n\n# macOS / Linux: see https://foundrylocal.ai for installation instructions\n# List available models\nfoundry model list\n\n# Run a model (starts the local server automatically)\nfoundry model run phi-4-mini\n\n# Check the port the service is running on\nfoundry service status\n```\n\n### Anthropic\n\n```typescript\nprovider: {\n    type: \"anthropic\",\n    baseUrl: \"https://api.anthropic.com\",\n    apiKey: process.env.ANTHROPIC_API_KEY,\n}\n```\n\n### 持有者令牌身份验证\n\n某些提供程序需要持有者令牌身份验证，而不是 API 密钥。 通过 `bearerToken` 提供静态令牌，或提供一个 `bearerTokenProvider` 回调函数，由 GitHub Copilot SDK 运行时在出站提供程序的请求发出前调用。 它封装的回调库或身份验证库负责管理令牌缓存和刷新。\n\n当应用程序已有令牌时使用 `bearerToken` ：\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https://<resource-name>.openai.azure.com/openai/v1/\",\n    bearerToken: process.env.MY_BEARER_TOKEN,  // Sets Authorization header\n}\n```\n\n> \\[!NOTE]\n> 该 `bearerToken` 选项仅接受 **静态令牌字符串** 。 SDK 不会自动刷新此令牌。 如果令牌过期，则请求将失败，你需要使用新的令牌创建新会话。\n\n使用 `bearerTokenProvider` 按需获取令牌：\n\n<!-- docs-validate: skip -->\n\n```typescript\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https://my-custom-endpoint.example.com/v1\",\n    bearerTokenProvider: async () => {\n        return await acquireBearerToken();\n    },\n}\n```\n\n有关获取和刷新Microsoft Entra持有者令牌的更多详细信息，请参阅 [支持 BYOK（自带密钥）的 Azure 托管标识](/zh/copilot/how-tos/copilot-sdk/setup/azure-managed-identity)。\n\n## 自定义模型列表\n\n使用 BYOK 时，CLI 服务器可能不知道提供程序支持哪些模型。 可以在客户端级别提供自定义 `onListModels` 处理程序，以便 `client.listModels()` 以标准 `ModelInfo` 格式返回提供程序的模型。 这使下游使用者无需查询 CLI 即可发现可用的模型。\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\";\nimport type { ModelInfo } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient({\n    onListModels: () => [\n        {\n            id: \"my-custom-model\",\n            name: \"My Custom Model\",\n            capabilities: {\n                supports: { vision: false, reasoningEffort: false },\n                limits: { max_context_window_tokens: 128000 },\n            },\n        },\n    ],\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 import CopilotClient\nfrom copilot.client import ModelInfo, ModelCapabilities, ModelSupports, ModelLimits\n\nclient = CopilotClient(\n    on_list_models=lambda: [\n        ModelInfo(\n            id=\"my-custom-model\",\n            name=\"My Custom Model\",\n            capabilities=ModelCapabilities(\n                supports=ModelSupports(vision=False, reasoning_effort=False),\n                limits=ModelLimits(max_context_window_tokens=128000),\n            ),\n        )\n    ],\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\npackage main\n\nimport (\n    \"context\"\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\nfunc main() {\n    client := copilot.NewClient(&copilot.ClientOptions{\n        OnListModels: func(ctx context.Context) ([]copilot.ModelInfo, error) {\n            return []copilot.ModelInfo{\n                {\n                    ID:   \"my-custom-model\",\n                    Name: \"My Custom Model\",\n                    Capabilities: copilot.ModelCapabilities{\n                        Supports: copilot.ModelSupports{Vision: false, ReasoningEffort: false},\n                        Limits:   copilot.ModelLimits{MaxContextWindowTokens: copilot.Int(128000)},\n                    },\n                },\n            }, nil\n        },\n    })\n    _ = client\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;\n\nvar client = new CopilotClient(new CopilotClientOptions\n{\n    OnListModels = (ct) => Task.FromResult<IList<ModelInfo>>(new List<ModelInfo>\n    {\n        new()\n        {\n            Id = \"my-custom-model\",\n            Name = \"My Custom Model\",\n            Capabilities = new ModelCapabilities\n            {\n                Supports = new ModelSupports { Vision = false, ReasoningEffort = false },\n                Limits = new ModelLimits { MaxContextWindowTokens = 128000 }\n            }\n        }\n    })\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;\nimport java.util.concurrent.CompletableFuture;\n\nvar client = new CopilotClient(new CopilotClientOptions()\n    .setOnListModels(() -> CompletableFuture.completedFuture(List.of(\n        new ModelInfo()\n            .setId(\"my-custom-model\")\n            .setName(\"My Custom Model\")\n            .setCapabilities(new ModelCapabilities()\n                .setSupports(new ModelSupports().setVision(false).setReasoningEffort(false))\n                .setLimits(new ModelLimits().setMaxContextWindowTokens(128000)))\n    )))\n);\n```\n\n</div>\n\n</div>\n\n结果在首次调用后缓存，就像默认行为一样。 处理程序完全替换 CLI 的 `models.list` RPC 功能，不存在回滚到服务器的情况。\n\n## 局限性\n\n### 功能限制\n\n某些Copilot功能在 BYOK 中的行为可能不同：\n\n* **模型可用性** - 只有提供商支持的模型可用\n* **速率限制** - 受你的服务提供商的速率限制约束，而非 Copilot 的限制\n* **使用情况跟踪** - 使用情况由您的提供方跟踪，而不是 GitHub Copilot\n* **高级请求** - 不会计入 Copilot 高级请求配额\n\n### 提供程序特定的限制\n\n| Provider                                           | 局限性                          |\n| -------------------------------------------------- | ---------------------------- |\n| [Microsoft Foundry Local](https://foundrylocal.ai) | 仅限本地;模型可用性取决于设备硬件;不需要 API 密钥 |\n| Ollama                                             | 无 API 密钥;仅限本地;模型支持各不相同       |\n| OpenAI                                             | 受 OpenAI 速率限制和配额的约束          |\n\n## 故障排除\n\n### “未指定模型”错误\n\n使用 BYOK 时，`model`**参数是必需的**：\n\n```typescript\n// ❌ Error: Model required with custom provider\nconst session = await client.createSession({\n    provider: { type: \"openai\", baseUrl: \"...\" },\n});\n\n// ✅ Correct: Model specified\nconst session = await client.createSession({\n    model: \"gpt-4\",  // Required!\n    provider: { type: \"openai\", baseUrl: \"...\" },\n});\n```\n\n### Azure 终结点类型混淆\n\n对于 Azure OpenAI 端点（`*.openai.azure.com`），请使用正确的类型：\n\n```typescript\n// ❌ Wrong: Using \"openai\" type with native Azure endpoint\nprovider: {\n    type: \"openai\",  // This won't work correctly\n    baseUrl: \"https://my-resource.openai.azure.com\",\n}\n\n// ✅ Correct: Using \"azure\" type\nprovider: {\n    type: \"azure\",\n    baseUrl: \"https://my-resource.openai.azure.com\",\n}\n```\n\n但是，如果您的 Microsoft Foundry 部署提供与 OpenAI 兼容的终结点路径（例如，`/openai/v1/`），请使用 `type: \"openai\"`：\n\n```typescript\n// ✅ Correct: OpenAI-compatible Microsoft Foundry endpoint\nprovider: {\n    type: \"openai\",\n    baseUrl: \"https://your-resource.openai.azure.com/openai/v1/\",\n}\n```\n\n### 连接被拒绝 （Ollama）\n\n确保 Ollama 正在运行并可访问：\n\n```bash\n# Check Ollama is running\ncurl http://localhost:11434/v1/models\n\n# Start Ollama if not running\nollama serve\n```\n\n### 连接被拒绝（Foundry Local）\n\nFoundry Local 使用可在重启之间更改的动态端口。 确认活动端口：\n\n```bash\n# Check the service status and port\nfoundry service status\n```\n\n更新您的 `baseUrl` 以匹配输出中显示的端口。 如果服务未运行，请启动模型以启动它：\n\n```bash\nfoundry model run phi-4-mini\n```\n\n### 身份验证失败\n\n1. 验证 API 密钥是否正确且未过期\n2. 检查 `baseUrl` 是否与您的提供商要求的格式一致\n3. 对于持有者令牌，请确保提供完整令牌（而不仅仅是前缀）\n\n## 后续步骤\n\n* [Authentication](/zh/copilot/how-tos/copilot-sdk/auth) - 了解所有身份验证方法\n* [构建你的第一个由 Copilot 提供支持的应用](/zh/copilot/how-tos/copilot-sdk/getting-started) - 生成第一个Copilot驱动的应用"}