# BYOK （自带密钥）

BYOK 允许你通过模型提供程序将 Copilot SDK 与自己的 API 密钥一起使用，从而绕过GitHub Copilot身份验证。 这对于企业部署、自定义模型托管或需要与模型提供商直接计费时非常有用。

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## 支持的提供程序

| Provider                       | 类型值           | 备注                               |
| ------------------------------ | ------------- | -------------------------------- |
| OpenAI                         | `"openai"`    | OpenAI API 和 OpenAI 兼容的端点        |
| Azure OpenAI/ Azure AI Foundry | `"azure"`     | Azure托管的模型                       |
| Anthropic                      | `"anthropic"` | Claude 模型                        |
| Ollama                         | `"openai"`    | 通过 OpenAI 兼容 API 使用的本地模型         |
| 微软铸造厂 Local                    | `"openai"`    | 通过 OpenAI 兼容的 API 在本地设备上运行 AI 模型 |
| 其他与 OpenAI 兼容的                 | `"openai"`    | vLLM、LiteLLM 等                   |

## 快速入门：Azure AI Foundry

Azure AI Foundry（前 Azure OpenAI）是企业常见的 BYOK 部署目标。 下面是一个完整的示例：

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
import asyncio
import os
from copilot import CopilotClient
from copilot.session import PermissionHandler

FOUNDRY_MODEL_URL = "https://your-resource.openai.azure.com/openai/v1/"
# Set FOUNDRY_API_KEY environment variable

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

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5.2-codex", provider={
        "type": "openai",
        "base_url": FOUNDRY_MODEL_URL,
        "wire_api": "responses",  # Use "completions" for older models
        "api_key": os.environ["FOUNDRY_API_KEY"],
    })

    done = asyncio.Event()

    def on_event(event):
        if event.type.value == "assistant.message":
            print(event.data.content)
        elif event.type.value == "session.idle":
            done.set()

    session.on(on_event)
    await session.send("What is 2+2?")
    await done.wait()

    await session.disconnect()
    await client.stop()

asyncio.run(main())
```

</div>

<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

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

const FOUNDRY_MODEL_URL = "https://your-resource.openai.azure.com/openai/v1/";

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-5.2-codex",  // Your deployment name
    provider: {
        type: "openai",
        baseUrl: FOUNDRY_MODEL_URL,
        wireApi: "responses",  // Use "completions" for older models
        apiKey: process.env.FOUNDRY_API_KEY,
    },
});

session.on("assistant.message", (event) => {
    console.log(event.data.content);
});

await session.sendAndWait({ prompt: "What is 2+2?" });
await client.stop();
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
package main

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

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

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model: "gpt-5.2-codex",  // Your deployment name
        Provider: &copilot.ProviderConfig{
            Type:    "openai",
            BaseURL: "https://your-resource.openai.azure.com/openai/v1/",
            WireAPI: "responses",  // Use "completions" for older models
            APIKey:  os.Getenv("FOUNDRY_API_KEY"),
        },
    })
    if err != nil {
        panic(err)
    }

    response, err := session.SendAndWait(ctx, copilot.MessageOptions{
        Prompt: "What is 2+2?",
    })
    if err != nil {
        panic(err)
    }

    if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
        fmt.Println(d.Content)
    }
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5.2-codex",  // Your deployment name
    Provider = new ProviderConfig
    {
        Type = "openai",
        BaseUrl = "https://your-resource.openai.azure.com/openai/v1/",
        WireApi = "responses",  // Use "completions" for older models
        ApiKey = Environment.GetEnvironmentVariable("FOUNDRY_API_KEY"),
    },
});

var response = await session.SendAndWaitAsync(new MessageOptions
{
    Prompt = "What is 2+2?",
});
Console.WriteLine(response?.Data.Content);
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

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

var session = client.createSession(new SessionConfig()
    .setModel("gpt-5.2-codex")  // Your deployment name
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    .setProvider(new ProviderConfig()
        .setType("openai")
        .setBaseUrl("https://your-resource.openai.azure.com/openai/v1/")
        .setWireApi("responses")  // Use "completions" for older models
        .setApiKey(System.getenv("FOUNDRY_API_KEY")))
).get();

var response = session.sendAndWait(new MessageOptions()
    .setPrompt("What is 2+2?")).get();
System.out.println(response.getData().content());

client.stop().get();
```

</div>

</div>

## 提供程序配置参考

### ProviderConfig 字段

| 领域                                                                                                                                           | 类型  | Description                      |
| -------------------------------------------------------------------------------------------------------------------------------------------- | --- | -------------------------------- |
| `type`                                                                                                                                       |     |                                  |
| `"openai"`                                                                                                                                   |     |                                  |
| \|                                                                                                                                           |     |                                  |
| `"azure"`                                                                                                                                    |     |                                  |
| \|                                                                                                                                           |     |                                  |
| `"anthropic"`                                                                                                                                |     |                                  |
| 提供程序类型（默认值： `"openai"`）                                                                                                                      |     |                                  |
| `baseUrl` / `base_url`                                                                                                                       | 字符串 |                                  |
| **必填。** API 端点 URL                                                                                                                           |     |                                  |
| `apiKey` / `api_key`                                                                                                                         | 字符串 | API 密钥（对于像 Ollama 这样的本地提供程序，可选）  |
| `bearerToken` / `bearer_token`                                                                                                               | 字符串 | 持有者令牌身份验证（优先于 apiKey）            |
| `wireApi` / `wire_api`                                                                                                                       |     |                                  |
| `"completions"`                                                                                                                              |     |                                  |
| \|                                                                                                                                           |     |                                  |
| `"responses"`                                                                                                                                |     |                                  |
| 选择 `"completions"` 以获得广泛的模型兼容性（Chat Completions API）；选择 `"responses"` 以获得多轮对话状态管理、工具命名空间和推理支持（Responses API）。 无论此设置如何，Anthropic模型始终使用消息 API。 |     |                                  |
| `azure.apiVersion` / `azure.api_version`                                                                                                     | 字符串 | Azure API 版本（默认值：`"2024-10-21"`） |

### 线路 API 格式

此设置 `wireApi` 确定要使用的 OpenAI API 格式：

* **`"completions"`**（默认）- Chat Completions API（`/chat/completions`），可广泛兼容各种模型。
* **`"responses"`** - 用于多轮状态管理、工具命名空间和推理支持的 Responses API。

无论此设置为何，Anthropic 模型始终使用 Anthropic Messages API。

### 类型特定的注释

**OpenAI （`type: "openai"`）**

* 支持 OpenAI API 以及任何兼容 OpenAI 的端点
* `baseUrl` 应包含完整路径（例如 `https://api.openai.com/v1`）

**Azure （`type: "azure"`）**

* 用于原生 Azure OpenAI 终结点
* `baseUrl` 应只是主机（例如 `https://my-resource.openai.azure.com`）
* 请勿在 URL 中包含 `/openai/v1`——SDK 会负责构造路径

**Anthropic（`type: "anthropic"`）**

* 用于直接访问 Anthropic API
* 使用特定于 Claude 的 API 格式

## 示例配置

### OpenAI direct

```typescript
provider: {
    type: "openai",
    baseUrl: "https://api.openai.com/v1",
    apiKey: process.env.OPENAI_API_KEY,
}
```

### Azure OpenAI （本机 Azure 终结点）

在 `type: "azure"` 的终结点使用 `*.openai.azure.com`:

```typescript
provider: {
    type: "azure",
    baseUrl: "https://my-resource.openai.azure.com",  // Just the host
    apiKey: process.env.AZURE_OPENAI_KEY,
    azure: {
        apiVersion: "2024-10-21",
    },
}
```

### Azure AI Foundry （OpenAI 兼容终结点）

对于具有 `/openai/v1/` 终结点的 Azure AI Foundry 部署，请使用 `type: "openai"`：

```typescript
provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
    apiKey: process.env.FOUNDRY_API_KEY,
    wireApi: "responses",  // For GPT-5 series models
}
```

### 奥拉马（本地）

```typescript
provider: {
    type: "openai",
    baseUrl: "http://localhost:11434/v1",
    // No apiKey needed for local Ollama
}
```

### 微软铸造厂 Local

[Microsoft Foundry Local](https://foundrylocal.ai) 允许使用与 OpenAI 兼容的 API 在本地设备上运行 AI 模型。 通过 Foundry Local CLI 安装它，然后将 SDK 指向本地终结点：

```typescript
provider: {
    type: "openai",
    baseUrl: "http://localhost:<PORT>/v1",
    // No apiKey needed for local Foundry Local
}
```

> \[!NOTE]
> Foundry Local 在 **动态端口**上启动 ， 端口未固定。 使用 `foundry service status` 确认该服务当前正在监听的端口，然后在你的 `baseUrl` 中使用该端口。

若要开始使用 Foundry Local：

```bash
# Windows: Install Foundry Local CLI (requires winget)
winget install Microsoft.FoundryLocal

# macOS / Linux: see https://foundrylocal.ai for installation instructions
# List available models
foundry model list

# Run a model (starts the local server automatically)
foundry model run phi-4-mini

# Check the port the service is running on
foundry service status
```

### Anthropic

```typescript
provider: {
    type: "anthropic",
    baseUrl: "https://api.anthropic.com",
    apiKey: process.env.ANTHROPIC_API_KEY,
}
```

### 持有者令牌身份验证

某些提供程序需要持有者令牌身份验证，而不是 API 密钥：

```typescript
provider: {
    type: "openai",
    baseUrl: "https://my-custom-endpoint.example.com/v1",
    bearerToken: process.env.MY_BEARER_TOKEN,  // Sets Authorization header
}
```

> \[!NOTE]
> 该 `bearerToken` 选项仅接受 **静态令牌字符串** 。 SDK 不会自动刷新此令牌。 如果令牌过期，则请求将失败，你需要使用新的令牌创建新会话。

## 自定义模型列表

使用 BYOK 时，CLI 服务器可能不知道提供程序支持哪些模型。 可以在客户端级别提供自定义 `onListModels` 处理程序，以便 `client.listModels()` 以标准 `ModelInfo` 格式返回提供程序的模型。 这使下游使用者无需查询 CLI 即可发现可用的模型。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient } from "@github/copilot-sdk";
import type { ModelInfo } from "@github/copilot-sdk";

const client = new CopilotClient({
    onListModels: () => [
        {
            id: "my-custom-model",
            name: "My Custom Model",
            capabilities: {
                supports: { vision: false, reasoningEffort: false },
                limits: { max_context_window_tokens: 128000 },
            },
        },
    ],
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient
from copilot.client import ModelInfo, ModelCapabilities, ModelSupports, ModelLimits

client = CopilotClient(
    on_list_models=lambda: [
        ModelInfo(
            id="my-custom-model",
            name="My Custom Model",
            capabilities=ModelCapabilities(
                supports=ModelSupports(vision=False, reasoning_effort=False),
                limits=ModelLimits(max_context_window_tokens=128000),
            ),
        )
    ],
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
package main

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

func main() {
    client := copilot.NewClient(&copilot.ClientOptions{
        OnListModels: func(ctx context.Context) ([]copilot.ModelInfo, error) {
            return []copilot.ModelInfo{
                {
                    ID:   "my-custom-model",
                    Name: "My Custom Model",
                    Capabilities: copilot.ModelCapabilities{
                        Supports: copilot.ModelSupports{Vision: false, ReasoningEffort: false},
                        Limits:   copilot.ModelLimits{MaxContextWindowTokens: 128000},
                    },
                },
            }, nil
        },
    })
    _ = client
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

var client = new CopilotClient(new CopilotClientOptions
{
    OnListModels = (ct) => Task.FromResult<IList<ModelInfo>>(new List<ModelInfo>
    {
        new()
        {
            Id = "my-custom-model",
            Name = "My Custom Model",
            Capabilities = new ModelCapabilities
            {
                Supports = new ModelSupports { Vision = false, ReasoningEffort = false },
                Limits = new ModelLimits { MaxContextWindowTokens = 128000 }
            }
        }
    })
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;

var client = new CopilotClient(new CopilotClientOptions()
    .setOnListModels(() -> CompletableFuture.completedFuture(List.of(
        new ModelInfo()
            .setId("my-custom-model")
            .setName("My Custom Model")
            .setCapabilities(new ModelCapabilities()
                .setSupports(new ModelSupports().setVision(false).setReasoningEffort(false))
                .setLimits(new ModelLimits().setMaxContextWindowTokens(128000)))
    )))
);
```

</div>

</div>

结果在首次调用后缓存，就像默认行为一样。 处理程序完全替换 CLI 的 `models.list` RPC 功能，不存在回滚到服务器的情况。

## 局限性

使用 BYOK 时，请注意以下限制：

### 标识限制

BYOK 身份验证 **仅使用静态凭据**。

必须使用自己管理的 API 密钥或静态持有者令牌。

### 功能限制

某些Copilot功能在 BYOK 中的行为可能不同：

* **模型可用性** - 只有提供商支持的模型可用
* **速率限制** - 受你的服务提供商的速率限制约束，而非 Copilot 的限制
* **使用情况跟踪** - 使用情况由您的提供方跟踪，而不是 GitHub Copilot
* **高级请求** - 不会计入 Copilot 高级请求配额

### 提供程序特定的限制

| Provider                                           | 局限性                          |
| -------------------------------------------------- | ---------------------------- |
| Azure AI Foundry                                   | 无Entra ID身份验证;必须使用 API 密钥    |
| Ollama                                             | 无 API 密钥;仅限本地;模型支持各不相同       |
| [Microsoft Foundry Local](https://foundrylocal.ai) | 仅限本地;模型可用性取决于设备硬件;不需要 API 密钥 |
| OpenAI                                             | 受 OpenAI 速率限制和配额的约束          |

## 故障排除

### “未指定模型”错误

使用 BYOK 时，`model`**参数是必需的**：

```typescript
// ❌ Error: Model required with custom provider
const session = await client.createSession({
    provider: { type: "openai", baseUrl: "..." },
});

// ✅ Correct: Model specified
const session = await client.createSession({
    model: "gpt-4",  // Required!
    provider: { type: "openai", baseUrl: "..." },
});
```

### Azure 终结点类型混淆

对于 Azure OpenAI 端点（`*.openai.azure.com`），请使用正确的类型：

<!-- docs-validate: hidden -->

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

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    provider: {
        type: "azure",
        baseUrl: "https://my-resource.openai.azure.com",
    },
});
```

<!-- /docs-validate: hidden -->

```typescript
// ❌ Wrong: Using "openai" type with native Azure endpoint
provider: {
    type: "openai",  // This won't work correctly
    baseUrl: "https://my-resource.openai.azure.com",
}

// ✅ Correct: Using "azure" type
provider: {
    type: "azure",
    baseUrl: "https://my-resource.openai.azure.com",
}
```

但是，如果Azure AI Foundry部署提供与 OpenAI 兼容的终结点路径（例如 `/openai/v1/`），请使用 `type: "openai"`：

<!-- docs-validate: hidden -->

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

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    provider: {
        type: "openai",
        baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
    },
});
```

<!-- /docs-validate: hidden -->

```typescript
// ✅ Correct: OpenAI-compatible Azure AI Foundry endpoint
provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
}
```

### 连接被拒绝 （Ollama）

确保 Ollama 正在运行并可访问：

```bash
# Check Ollama is running
curl http://localhost:11434/v1/models

# Start Ollama if not running
ollama serve
```

### 连接被拒绝（Foundry Local）

Foundry Local 使用可在重启之间更改的动态端口。 确认活动端口：

```bash
# Check the service status and port
foundry service status
```

更新您的 `baseUrl` 以匹配输出中显示的端口。 如果服务未运行，请启动模型以启动它：

```bash
foundry model run phi-4-mini
```

### 身份验证失败

1. 验证 API 密钥是否正确且未过期
2. 检查 `baseUrl` 是否与您的提供商要求的格式一致
3. 对于持有者令牌，请确保提供完整令牌（而不仅仅是前缀）

## 后续步骤

* [Authentication](/zh/copilot/how-tos/copilot-sdk/auth) - 了解所有身份验证方法
* [构建你的第一个由 Copilot 提供支持的应用](/zh/copilot/how-tos/copilot-sdk/getting-started) - 生成第一个Copilot驱动的应用