# BYOK(사용자 고유의 키 가져오기)

BYOK를 사용하면 GitHub Copilot 인증을 우회하여 모델 공급자의 고유한 API 키와 함께 Copilot SDK를 사용할 수 있습니다. 엔터프라이즈 배포, 사용자 지정 모델 호스팅 또는 모델 공급자에게 직접 청구하려는 경우에 유용합니다.

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

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

## 지원되는 공급자

| Provider                      | 타입 값          | Notes                                 |
| ----------------------------- | ------------- | ------------------------------------- |
| OpenAI                        | `"openai"`    | OpenAI API 및 OpenAI 호환 엔드포인트          |
| Azure OpenAI/Azure AI Foundry | `"azure"`     | Azure 호스트된 모델                         |
| Anthropic                     | `"anthropic"` | 클로드 모델                                |
| Ollama                        | `"openai"`    | OpenAI 호환 API를 통한 로컬 모델               |
| Microsoft Foundry 로컬          | `"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 필드

| Field                                                                                                                                                | Type   | Description                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ---------------------------------- |
| `type`                                                                                                                                               |        |                                    |
| `"openai"`                                                                                                                                           |        |                                    |
| \|                                                                                                                                                   |        |                                    |
| `"azure"`                                                                                                                                            |        |                                    |
| \|                                                                                                                                                   |        |                                    |
| `"anthropic"`                                                                                                                                        |        |                                    |
| 공급자 유형(기본값: `"openai"`)                                                                                                                              |        |                                    |
| `baseUrl` / `base_url`                                                                                                                               | string |                                    |
| **필수입니다**. API 엔드포인트 URL                                                                                                                             |        |                                    |
| `apiKey` / `api_key`                                                                                                                                 | string | API 키(Ollama와 같은 로컬 공급자의 경우 선택 사항) |
| `bearerToken` / `bearer_token`                                                                                                                       | string | 전달자 토큰 인증(apiKey보다 우선)             |
| `wireApi` / `wire_api`                                                                                                                               |        |                                    |
| `"completions"`                                                                                                                                      |        |                                    |
| \|                                                                                                                                                   |        |                                    |
| `"responses"`                                                                                                                                        |        |                                    |
| 광범위한 모델 호환성(채팅 완료 API)을 선택하고, 다중 턴 상태 관리, 도구 이름 간격 및 추론 지원(응답 API)을 선택합니다 `"completions"``"responses"` . Anthropic 모델은 이 설정에 관계없이 항상 메시지 API를 사용합니다. |        |                                    |
| `azure.apiVersion` / `azure.api_version`                                                                                                             | string | Azure API 버전(기본값: `"2024-10-21"`)  |

### Wire API 형식

이 설정은 `wireApi` 사용할 OpenAI API 형식을 결정합니다.

* **`"completions"`** (기본값) - 광범위한 모델 호환성을 위한 채팅 완료 API(`/chat/completions`)입니다.
* **`"responses"`** - 다중 턴 상태 관리, 도구 이름 간격 및 추론 지원을 위한 응답 API입니다.

Anthropic 모델은 이 설정에 관계없이 항상 Anthropic 메시지 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 액세스
* 클로드별 API 형식 사용

## 구성 예

### OpenAI 직통

```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 호환 엔드포인트)

Azure AI Foundry 배포의 `/openai/v1/` 엔드포인트를 사용하려면 `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
}
```

### Ollama (로컬)

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

### Microsoft Foundry 로컬

[Microsoft Foundry Local](https://foundrylocal.ai)을 사용하면 OpenAI 호환 API를 사용하여 자체 디바이스에서 로컬로 AI 모델을 실행할 수 있습니다. Foundry 로컬 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 서버는 공급자가 지원하는 모델을 모를 수 있습니다. 공급자의 모델을 표준 `ModelInfo` 형식으로 반환할 수 있도록 `client.listModels()` 클라이언트 수준에서 사용자 지정 `onListModels` 처리기를 제공할 수 있습니다. 이를 통해 다운스트림 소비자는 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를 사용하는 경우 다음과 같은 제한 사항에 유의하세요.

### ID 제한 사항

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 속도 제한 및 할당량 적용                              |

## Troubleshooting

### "모델을 지정하지 않음" 오류

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. 전달자 토큰의 경우 전체 토큰이 제공되었는지 확인합니다(접두사뿐만 아니라).

## 다음 단계

* [인증](/ko/copilot/how-tos/copilot-sdk/auth) - 모든 인증 방법에 대해 알아보기
* [첫 번째 Copilot 기반 앱 빌드](/ko/copilot/how-tos/copilot-sdk/getting-started) - 첫 번째 Copilot 지원 앱 빌드