Skip to main content

BYOK (自带密钥)

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

支持的提供程序

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 部署目标。 下面是一个完整的示例:

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())
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();
Go
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)
    }
}
.NET
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);
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();

提供程序配置参考

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

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

Azure OpenAI (本机 Azure 终结点)

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

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"

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
}

奥拉马(本地)

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

微软铸造厂 Local

Microsoft Foundry Local 允许使用与 OpenAI 兼容的 API 在本地设备上运行 AI 模型。 通过 Foundry Local CLI 安装它,然后将 SDK 指向本地终结点:

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

注意

Foundry Local 在 动态端口上启动 , 端口未固定。 使用 foundry service status 确认该服务当前正在监听的端口,然后在你的 baseUrl 中使用该端口。

若要开始使用 Foundry Local:

# 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

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

持有者令牌身份验证

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

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

注意

bearerToken 选项仅接受 静态令牌字符串 。 SDK 不会自动刷新此令牌。 如果令牌过期,则请求将失败,你需要使用新的令牌创建新会话。

自定义模型列表

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

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 },
            },
        },
    ],
});
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),
            ),
        )
    ],
)
Go
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
}
.NET
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 }
            }
        }
    })
});
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)))
    )))
);

结果在首次调用后缓存,就像默认行为一样。 处理程序完全替换 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仅限本地;模型可用性取决于设备硬件;不需要 API 密钥
OpenAI受 OpenAI 速率限制和配额的约束

故障排除

“未指定模型”错误

使用 BYOK 时,model参数是必需的

// ❌ 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),请使用正确的类型:

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",
    },
});
// ❌ 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"

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/",
    },
});
// ✅ Correct: OpenAI-compatible Azure AI Foundry endpoint
provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
}

连接被拒绝 (Ollama)

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

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

# Start Ollama if not running
ollama serve

连接被拒绝(Foundry Local)

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

# Check the service status and port
foundry service status

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

foundry model run phi-4-mini

身份验证失败

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

后续步骤