{"meta":{"title":"사용량 및 청구 메트릭","intro":"이 가이드에서는 Copilot SDK 애플리케이션에서 토큰 수, 컨텍스트 창 사용률, AI 크레딧 비용 및 계정 할당량을 읽는 방법을 보여 줍니다. TypeScript, Python, Go, .NET, Java 및 Rust에 대한 예제가 표시됩니다.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ko/copilot","title":"GitHub Copilot"},{"href":"/ko/copilot/how-tos","title":"방법"},{"href":"/ko/copilot/how-tos/copilot-sdk","title":"코필로트 SDK"},{"href":"/ko/copilot/how-tos/copilot-sdk/features","title":"기능"},{"href":"/ko/copilot/how-tos/copilot-sdk/features/usage-and-billing","title":"사용량 및 청구"}],"documentType":"article"},"body":"# 사용량 및 청구 메트릭\n\n이 가이드에서는 Copilot SDK 애플리케이션에서 토큰 수, 컨텍스트 창 사용률, AI 크레딧 비용 및 계정 할당량을 읽는 방법을 보여 줍니다. TypeScript, Python, Go, .NET, Java 및 Rust에 대한 예제가 표시됩니다.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n> \\[!TIP]\n> 각 예제는 여러 언어에서 기능적으로 동일합니다. TypeScript 코드 조각은 기본적으로 확장됩니다. 축소 가능한 블록에서 언어를 선택하여 해당 SDK에서 동일한 논리를 확인합니다.\n\n## Overview\n\nSDK는 두 가지 보완 메커니즘을 통해 사용량 현황 데이터를 표시합니다.\n\n* **세션 이벤트**: 런타임이 턴이 실행될 때 내보내는 임시 이벤트입니다. 실시간 API 호출별 데이터에 대해 이러한 데이터를 구독합니다.\n* **RPC 메서드**: 요청 시 수행된 요청/응답 호출입니다. 누적 합계를 스냅샷하거나 계정 수준 할당량을 조회하는 데 사용합니다.\n\n아래 표는 각 신호를 노출하는 API에 매핑합니다.\n\n| 신호                       | API                            | Scope | Type |\n| ------------------------ | ------------------------------ | ----- | ---- |\n| 호출별 토큰 수                 |                                |       |      |\n| `assistant.usage` 이벤트    | 세션                             | Event |      |\n| 컨텍스트 창 사용률               |                                |       |      |\n| `session.usage_info` 이벤트 | 세션                             | Event |      |\n| 컨텍스트 윈도우 세부 내역(요청 시)     | `session.metadata.contextInfo` | 세션    | RPC  |\n| 누적 AI 크레딧 및 토큰 합계        | `session.usage.getMetrics`     | 세션    | RPC  |\n| 모델별 AI 크레딧 가격 책정         | `models.list`                  | 서버    | RPC  |\n| 계정 할당량 및 프리미엄 상호 작용      | `account.getQuota`             | 서버    | RPC  |\n\n> \\[!NOTE]\n> `session.usage.getMetrics`, `session.metadata.contextInfo`및 `session.metadata.recomputeContextTokens` 생성된 RPC 화면에서 실험적으로 표시됩니다. .NET에서는 `GHCP001` 실험적 진단을 발생시키며, 이는 `#pragma warning disable GHCP001` 또는 프로젝트 수준의 `<NoWarn>GHCP001</NoWarn>`로 억제합니다. 애플리케이션이 의존하는 경우 SDK와 Copilot CLI 런타임을 모두 고정합니다.\n\n아래 필드 테이블은 이 페이지의 예제에 사용된 필드만 나열합니다. 항상 최신의 전체 필드 참조는 생성된 SDK 형식과 [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events)이며 모든 종속성 범프에 대한 CLI 스키마에서 다시 생성됩니다. 이를 진리의 근원으로 취급하고 이 페이지를 작업 지향 가이드로 취급합니다.\n\n## 호출별 토큰 수\n\n`assistant.usage` 이벤트는 한 턴에서 각 모델 API 호출마다 한 번씩 발생합니다(하위 에이전트가 수행한 호출 포함). 해당 호출 1회분의 토큰 수와 요금 배수를 포함합니다.\n\n아래 예제에서는 이러한 필드를 사용합니다. 캐시, 추론, 대기 시간 및 추적 필드를 비롯한 전체 목록은 [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events#assistantusage) 을 참조하세요.\n\n| Field          | Type     | Description           |\n| -------------- | -------- | --------------------- |\n| `model`        | `string` | 이 호출의 모델 식별자          |\n| `inputTokens`  | `number` | 사용된 입력 토큰             |\n| `outputTokens` | `number` | 생성된 출력 토큰             |\n| `cost`         | `number` | 이 호출에 적용되는 프리미엄 요청 배수 |\n\n> \\[!TIP]\n> `assistant.usage` 가 임시이므로 라이브로 배달되지만 세션을 다시 시작할 때 재생되지 않습니다. 사후에 누적 총계를 확인하려면 `session.usage.getMetrics`를 호출하세요(자세한 내용은 [누적 AI 크레딧 및 토큰 총계](#accumulated-ai-credit-and-token-totals) 참조).\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\nsession.on(\"assistant.usage\", (event) => {\n    const { model, inputTokens, outputTokens, cost } = event.data;\n    console.log(\n        `${model}: in=${inputTokens ?? 0} out=${outputTokens ?? 0} cost=${cost ?? 0}`,\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\ndef on_usage(event):\n    if event.type == SessionEventType.ASSISTANT_USAGE:\n        data = event.data\n        print(f\"{data.model}: in={data.input_tokens or 0} out={data.output_tokens or 0} cost={data.cost or 0}\")\n\nsession.on(on_usage)\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.On(func(event copilot.SessionEvent) {\n    d, ok := event.Data.(*copilot.AssistantUsageData)\n    if !ok {\n        return\n    }\n    in, out, cost := int64(0), int64(0), float64(0)\n    if d.InputTokens != nil {\n        in = *d.InputTokens\n    }\n    if d.OutputTokens != nil {\n        out = *d.OutputTokens\n    }\n    if d.Cost != nil {\n        cost = *d.Cost\n    }\n    fmt.Printf(\"%s: in=%d out=%d cost=%g\\n\", d.Model, in, out, cost)\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\nsession.On<AssistantUsageEvent>(evt =>\n{\n    var data = evt.Data;\n    Console.WriteLine(\n        $\"{data.Model}: in={data.InputTokens ?? 0} out={data.OutputTokens ?? 0} cost={data.Cost ?? 0}\");\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\nsession.on(AssistantUsageEvent.class, event -> {\n    var data = event.getData();\n    long in = data.inputTokens() != null ? data.inputTokens() : 0;\n    long out = data.outputTokens() != null ? data.outputTokens() : 0;\n    double cost = data.cost() != null ? data.cost() : 0.0;\n    System.out.printf(\"%s: in=%d out=%d cost=%s%n\", data.model(), in, out, cost);\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nuse github_copilot_sdk::session_events::AssistantUsageData;\n\nlet mut events = session.subscribe();\nwhile let Ok(event) = events.recv().await {\n    if event.event_type == \"assistant.usage\" {\n        if let Some(data) = event.typed_data::<AssistantUsageData>() {\n            println!(\n                \"{}: in={} out={} cost={}\",\n                data.model,\n                data.input_tokens.unwrap_or(0),\n                data.output_tokens.unwrap_or(0),\n                data.cost.unwrap_or(0.0),\n            );\n        }\n    }\n}\n```\n\n</div>\n\n</div>\n\n## 컨텍스트 창 사용률\n\n토큰 개수는 각 호출이 사용된 내용을 알려줍니다. 컨텍스트 창 사용률은 자동 압축이 시작되기 전에 진행률 표시줄을 표시하거나 사용자에게 경고하는 데 유용한 모델의 프롬프트 창이 현재 얼마나 가득 찼는지를 알려줍니다.\n\n### 실시간 업데이트 제공 `session.usage_info`\n\n런타임은 컨텍스트 창 크기가 `session.usage_info` 변경 될 때마다 이벤트를 내보낸다. 예제에서는 `currentTokens` 및 `tokenLimit`을 사용합니다. 전체 페이로드는 [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events#sessionusage_info)에서 확인하세요.\n\n| Field           | Type     | Description          |\n| --------------- | -------- | -------------------- |\n| `currentTokens` | `number` | 현재 컨텍스트 창에 있는 토큰     |\n| `tokenLimit`    | `number` | 모델의 컨텍스트 창에 대한 최대 토큰 |\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\nsession.on(\"session.usage_info\", (event) => {\n    const { currentTokens, tokenLimit } = event.data;\n    const pct = Math.round((currentTokens / tokenLimit) * 100);\n    console.log(`Context: ${currentTokens}/${tokenLimit} (${pct}%)`);\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\ndef on_usage_info(event):\n    if event.type == SessionEventType.SESSION_USAGE_INFO:\n        data = event.data\n        pct = round(data.current_tokens / data.token_limit * 100)\n        print(f\"Context: {data.current_tokens}/{data.token_limit} ({pct}%)\")\n\nsession.on(on_usage_info)\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.On(func(event copilot.SessionEvent) {\n    d, ok := event.Data.(*copilot.SessionUsageInfoData)\n    if !ok {\n        return\n    }\n    pct := int(float64(d.CurrentTokens) / float64(d.TokenLimit) * 100)\n    fmt.Printf(\"Context: %d/%d (%d%%)\\n\", d.CurrentTokens, d.TokenLimit, pct)\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\nsession.On<SessionUsageInfoEvent>(evt =>\n{\n    var pct = (int)Math.Round((double)evt.Data.CurrentTokens / evt.Data.TokenLimit * 100);\n    Console.WriteLine($\"Context: {evt.Data.CurrentTokens}/{evt.Data.TokenLimit} ({pct}%)\");\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\nsession.on(SessionUsageInfoEvent.class, event -> {\n    var data = event.getData();\n    long pct = Math.round((double) data.currentTokens() / data.tokenLimit() * 100);\n    System.out.printf(\"Context: %d/%d (%d%%)%n\", data.currentTokens(), data.tokenLimit(), pct);\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nuse github_copilot_sdk::session_events::SessionUsageInfoData;\n\nlet mut events = session.subscribe();\nwhile let Ok(event) = events.recv().await {\n    if event.event_type == \"session.usage_info\" {\n        if let Some(data) = event.typed_data::<SessionUsageInfoData>() {\n            let pct = (data.current_tokens as f64 / data.token_limit as f64 * 100.0) as i64;\n            println!(\"Context: {}/{} ({}%)\", data.current_tokens, data.token_limit, pct);\n        }\n    }\n}\n```\n\n</div>\n\n</div>\n\n### 주문형 분석 `session.metadata.contextInfo`\n\n이벤트는 컨텍스트가 변경되는 경우에만 발생합니다. 언제든지 현재 내역을 읽으려면(예: 세션을 재개한 직후) `session.metadata.contextInfo`를 호출하세요.\n`0` 런타임 기본값을 사용하도록 전달 `promptTokenLimit` 합니다. 값을 알 수 없는 경우 전달 `0``outputTokenLimit` 합니다.\n\n결과는 `contextInfo``null` 세션이 초기화될 때까지입니다(시스템 프롬프트 및 도구 메타데이터가 캐시됨). 합계를 , ,  및 로 나눕니다.\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 { contextInfo } = await session.rpc.metadata.contextInfo({\n    promptTokenLimit: 0,\n    outputTokenLimit: 0,\n});\n\nif (contextInfo) {\n    console.log(\n        `Total ${contextInfo.totalTokens}/${contextInfo.promptTokenLimit} ` +\n            `(system=${contextInfo.systemTokens}, conversation=${contextInfo.conversationTokens})`,\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\nresult = await session.rpc.metadata.context_info(\n    MetadataContextInfoRequest(prompt_token_limit=0, output_token_limit=0)\n)\ninfo = result.context_info\n\nif info is not None:\n    print(\n        f\"Total {info.total_tokens}/{info.prompt_token_limit} \"\n        f\"(system={info.system_tokens}, conversation={info.conversation_tokens})\"\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\nresult, _ := session.RPC.Metadata.ContextInfo(ctx, &rpc.MetadataContextInfoRequest{\n    PromptTokenLimit: 0,\n    OutputTokenLimit: 0,\n})\n\nif info := result.ContextInfo; info != nil {\n    fmt.Printf(\"Total %d/%d (system=%d, conversation=%d)\\n\",\n        info.TotalTokens, info.PromptTokenLimit, info.SystemTokens, info.ConversationTokens)\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 result = await session.Rpc.Metadata.ContextInfoAsync(promptTokenLimit: 0, outputTokenLimit: 0);\nvar info = result.ContextInfo;\n\nif (info is not null)\n{\n    Console.WriteLine(\n        $\"Total {info.TotalTokens}/{info.PromptTokenLimit} \" +\n        $\"(system={info.SystemTokens}, conversation={info.ConversationTokens})\");\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\nvar result = session.getRpc().metadata\n    .contextInfo(new SessionMetadataContextInfoParams(null, 0L, 0L, null))\n    .join();\nvar info = result.contextInfo();\n\nif (info != null) {\n    System.out.printf(\"Total %d/%d (system=%d, conversation=%d)%n\",\n        info.totalTokens(), info.promptTokenLimit(), info.systemTokens(), info.conversationTokens());\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nuse github_copilot_sdk::rpc::MetadataContextInfoRequest;\n\nlet result = session\n    .rpc()\n    .metadata()\n    .context_info(MetadataContextInfoRequest {\n        prompt_token_limit: 0,\n        output_token_limit: 0,\n        selected_model: None,\n    })\n    .await?;\n\nif let Some(info) = result.context_info {\n    println!(\n        \"Total {}/{} (system={}, conversation={})\",\n        info.total_tokens, info.prompt_token_limit, info.system_tokens, info.conversation_tokens,\n    );\n}\n```\n\n</div>\n\n</div>\n\n## 누적 AI 크레딧 및 토큰 합계\n\n`session.usage.getMetrics` 는 단일 호출에서 전체 세션의 실행 합계를 반환합니다. 이는 모든 API 호출(주 에이전트 및 하위 에이전트)을 집계하기 때문에 AI 크레딧 비용을 읽는 가장 깨끗한 방법입니다.\n\n이 예제에서는 아래 필드를 사용합니다. 생성된 `UsageGetMetricsResult` 형식이 전체 참조입니다.\n\n| Field                     | Type                          | Description                                                              |\n| ------------------------- | ----------------------------- | ------------------------------------------------------------------------ |\n| `totalNanoAiu`            | `number`                      | 세션 차원의 AI 크레딧 비용(nano-AI 단위)                                             |\n| `totalPremiumRequestCost` | `number`                      | 승수 적용 후 전체 모델에 걸친 프리미엄 요청 비용                                             |\n| `modelMetrics`            | `Record<string, ModelMetric>` | 모델별 분석; 각 항목에는 `usage.inputTokens`, `usage.outputTokens`및 `totalNanoAiu` |\n\n> \\[!NOTE]\n> 비용은 **nano-AI 단위** 로 보고됩니다(필드 이름은 `totalNanoAiu`지정됨). AI 크레딧으로의 정확한 변환과 프리미엄 요청 계정의 정확한 의미는 SDK가 아닌 GitHub Copilot 청구에 의해 정의됩니다. [GitHub Copilot 청구 설명서를](/ko/copilot/concepts/billing) 진실의 근원으로 취급하고 사용자에게 통화와 유사한 값을 표시하기 전에 확인합니다. 예제는 SI `1e9` 접두사에 따라 편의를 위해 나눕니다`nano`. 이 예제가 현재 청구와 일치하는지 확인한 후 이를 사용합니다.\n> `modelMetrics` 및 `tokenDetails` 맵의 키는 SDK 형식 시스템이 유효성을 검사하지 않는 런타임 문자열(모델 ID 및 토큰 유형 이름)입니다.\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 metrics = await session.rpc.usage.getMetrics();\n\nconst aiCredits = (metrics.totalNanoAiu ?? 0) / 1e9;\nconsole.log(`AI credits used: ${aiCredits.toFixed(6)}`);\nconsole.log(`Premium requests: ${metrics.totalPremiumRequestCost}`);\n\nfor (const [model, m] of Object.entries(metrics.modelMetrics)) {\n    if (!m) continue;\n    console.log(\n        `${model}: in=${m.usage.inputTokens} out=${m.usage.outputTokens} ` +\n            `nanoAiu=${m.totalNanoAiu ?? 0}`,\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\nmetrics = await session.rpc.usage.get_metrics()\n\nai_credits = (metrics.total_nano_aiu or 0) / 1e9\nprint(f\"AI credits used: {ai_credits:.6f}\")\nprint(f\"Premium requests: {metrics.total_premium_request_cost}\")\n\nfor model, m in metrics.model_metrics.items():\n    print(f\"{model}: in={m.usage.input_tokens} out={m.usage.output_tokens} nanoAiu={m.total_nano_aiu or 0}\")\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\nmetrics, _ := session.RPC.Usage.GetMetrics(ctx)\n\naiCredits := float64(0)\nif metrics.TotalNanoAiu != nil {\n    aiCredits = *metrics.TotalNanoAiu / 1e9\n}\nfmt.Printf(\"AI credits used: %.6f\\n\", aiCredits)\nfmt.Printf(\"Premium requests: %v\\n\", metrics.TotalPremiumRequestCost)\n\nfor model, m := range metrics.ModelMetrics {\n    nanoAiu := float64(0)\n    if m.TotalNanoAiu != nil {\n        nanoAiu = *m.TotalNanoAiu\n    }\n    fmt.Printf(\"%s: in=%d out=%d nanoAiu=%v\\n\", model, m.Usage.InputTokens, m.Usage.OutputTokens, nanoAiu)\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 metrics = await session.Rpc.Usage.GetMetricsAsync();\n\nvar aiCredits = (metrics.TotalNanoAiu ?? 0) / 1e9;\nConsole.WriteLine($\"AI credits used: {aiCredits:F6}\");\nConsole.WriteLine($\"Premium requests: {metrics.TotalPremiumRequestCost}\");\n\nforeach (var (model, m) in metrics.ModelMetrics)\n{\n    Console.WriteLine(\n        $\"{model}: in={m.Usage.InputTokens} out={m.Usage.OutputTokens} nanoAiu={m.TotalNanoAiu ?? 0}\");\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\nvar metrics = session.getRpc().usage.getMetrics().join();\n\ndouble aiCredits = metrics.totalNanoAiu() != null ? metrics.totalNanoAiu() / 1e9 : 0;\nSystem.out.printf(\"AI credits used: %.6f%n\", aiCredits);\nSystem.out.printf(\"Premium requests: %s%n\", metrics.totalPremiumRequestCost());\n\nmetrics.modelMetrics().forEach((model, m) -> {\n    double nanoAiu = m.totalNanoAiu() != null ? m.totalNanoAiu() : 0;\n    System.out.printf(\"%s: in=%d out=%d nanoAiu=%s%n\",\n        model, m.usage().inputTokens(), m.usage().outputTokens(), nanoAiu);\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nlet metrics = session.rpc().usage().get_metrics().await?;\n\nlet ai_credits = metrics.total_nano_aiu.unwrap_or(0.0) / 1e9;\nprintln!(\"AI credits used: {ai_credits:.6}\");\nprintln!(\"Premium requests: {}\", metrics.total_premium_request_cost);\n\nfor (model, m) in &metrics.model_metrics {\n    let nano_aiu = m.total_nano_aiu.unwrap_or(0.0);\n    println!(\n        \"{model}: in={} out={} nanoAiu={nano_aiu}\",\n        m.usage.input_tokens, m.usage.output_tokens,\n    );\n}\n```\n\n</div>\n\n</div>\n\n## 모델별 AI 크레딧 가격 책정\n\n턴을 실행하기 전에 비용을 예측하려면 각 모델의 토큰 가격을 읽어보 `models.list`십시오. 클라이언트에서 서버 범위 호출이므로 세션이 필요하지 않습니다. 가격은 토큰의 청구 일괄 처리당 AI 크레딧으로 표현됩니다. 생성된 `ModelBillingTokenPrices` 형식은 `cachePrice`를 포함한 모든 필드를 나열합니다.\n\n| Field                             | Type     | Description            |\n| --------------------------------- | -------- | ---------------------- |\n| `billing.multiplier`              | `number` | 기본 요금 대비 프리미엄 요청 비용 배수 |\n| `billing.tokenPrices.inputPrice`  | `number` | 입력 토큰 일괄 처리당 AI 크레딧 비용 |\n| `billing.tokenPrices.outputPrice` | `number` | 출력 토큰 일괄 처리당 AI 크레딧 비용 |\n| `billing.tokenPrices.batchSize`   | `number` | 청구 일괄 처리당 토큰 수         |\n\n> \\[!NOTE]\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 { models } = await client.rpc.models.list({});\n\nfor (const model of models) {\n    const prices = model.billing?.tokenPrices;\n    if (!prices) continue;\n    console.log(\n        `${model.id}: input=${prices.inputPrice} output=${prices.outputPrice} ` +\n            `per ${prices.batchSize} tokens (x${model.billing?.multiplier ?? 1})`,\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\nresult = await client.rpc.models.list(ModelsListRequest())\n\nfor model in result.models:\n    prices = model.billing.token_prices if model.billing else None\n    if prices is None:\n        continue\n    multiplier = model.billing.multiplier if model.billing else 1\n    print(\n        f\"{model.id}: input={prices.input_price} output={prices.output_price} \"\n        f\"per {prices.batch_size} tokens (x{multiplier})\"\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\nlist, _ := client.RPC.Models.List(ctx, &rpc.ModelsListRequest{})\n\nfor _, model := range list.Models {\n    if model.Billing == nil || model.Billing.TokenPrices == nil {\n        continue\n    }\n    prices := model.Billing.TokenPrices\n    multiplier := 1.0\n    if model.Billing.Multiplier != nil {\n        multiplier = *model.Billing.Multiplier\n    }\n    in, out := 0.0, 0.0\n    if prices.InputPrice != nil {\n        in = *prices.InputPrice\n    }\n    if prices.OutputPrice != nil {\n        out = *prices.OutputPrice\n    }\n    batch := int64(0)\n    if prices.BatchSize != nil {\n        batch = *prices.BatchSize\n    }\n    fmt.Printf(\"%s: input=%v output=%v per %d tokens (x%v)\\n\", model.ID, in, out, batch, multiplier)\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 list = await client.Rpc.Models.ListAsync();\n\nforeach (var model in list.Models)\n{\n    var prices = model.Billing?.TokenPrices;\n    if (prices is null) continue;\n    Console.WriteLine(\n        $\"{model.Id}: input={prices.InputPrice} output={prices.OutputPrice} \" +\n        $\"per {prices.BatchSize} tokens (x{model.Billing?.Multiplier ?? 1})\");\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\nvar list = client.getRpc().models.list().join();\n\nfor (var model : list.models()) {\n    var billing = model.billing();\n    if (billing == null || billing.tokenPrices() == null) {\n        continue;\n    }\n    var prices = billing.tokenPrices();\n    double multiplier = billing.multiplier() != null ? billing.multiplier() : 1;\n    System.out.printf(\"%s: input=%s output=%s per %d tokens (x%s)%n\",\n        model.id(), prices.inputPrice(), prices.outputPrice(), prices.batchSize(), multiplier);\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nlet list = client.rpc().models().list().await?;\n\nfor model in &list.models {\n    let Some(billing) = &model.billing else { continue };\n    let Some(prices) = &billing.token_prices else { continue };\n    let multiplier = billing.multiplier.unwrap_or(1.0);\n    println!(\n        \"{}: input={} output={} per {} tokens (x{multiplier})\",\n        model.id,\n        prices.input_price.unwrap_or(0.0),\n        prices.output_price.unwrap_or(0.0),\n        prices.batch_size.unwrap_or(0),\n    );\n}\n```\n\n</div>\n\n</div>\n\n## 계정 할당량 및 프리미엄 상호 작용\n\n`account.getQuota`인증된 사용자의 남은 Copilot 권한을 보고합니다. 결과의 `quotaSnapshots` 맵은 할당량 유형을 키로 사용하며, 일반적으로 `premium_interactions`, `chat`, `completions`입니다. 이를 사용하여 사용자에게 월별 수당이 얼마나 남아 있는지 표시하거나 제한에 도달하기 전에 작업을 게이트하는 데 사용합니다.\n\n이 예제에서는 아래 필드를 사용합니다. 생성된 `AccountQuotaSnapshot` 형식이 전체 참조입니다.\n`quotaSnapshots` 키는 SDK 타입 시스템에서 유효성을 검사하지 않는 런타임 문자열이므로 조회 시 검사를 수행하세요.\n\n| Field                 | Type     | Description               |\n| --------------------- | -------- | ------------------------- |\n| `entitlementRequests` | `number` | 자격에 포함된 요청 또는 `-1` 무제한 요청 |\n| `usedRequests`        | `number` | 이 기간 동안 사용된 요청            |\n| `remainingPercentage` | `number` | 남은 자격의 백분율                |\n| `resetDate`           | `string` | 할당량이 다시 설정되는 ISO 8601 날짜  |\n\n> \\[!TIP]\n> 연결의 전역 인증 컨텍스트(예: 다중 테넌트 백 엔드)가 아닌 특정 사용자에 대한 할당량을 읽으려면 해당 사용자의 GitHub 토큰을 전달합니다`getQuota`.\n> [다중 테넌트 및 서버 배포](/ko/copilot/how-tos/copilot-sdk/setup/multi-tenancy)을(를) 참조하세요.\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 { quotaSnapshots } = await client.rpc.account.getQuota({});\nconst premium = quotaSnapshots[\"premium_interactions\"];\n\nif (premium) {\n    console.log(\n        `Premium interactions: ${premium.usedRequests}/${premium.entitlementRequests} ` +\n            `(${premium.remainingPercentage.toFixed(1)}% left, resets ${premium.resetDate ?? \"n/a\"})`,\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\nresult = await client.rpc.account.get_quota(AccountGetQuotaRequest())\npremium = result.quota_snapshots.get(\"premium_interactions\")\n\nif premium is not None:\n    print(\n        f\"Premium interactions: {premium.used_requests}/{premium.entitlement_requests} \"\n        f\"({premium.remaining_percentage:.1f}% left, resets {premium.reset_date or 'n/a'})\"\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\nresult, _ := client.RPC.Account.GetQuota(ctx, &rpc.AccountGetQuotaRequest{})\n\nif premium, ok := result.QuotaSnapshots[\"premium_interactions\"]; ok {\n    resets := \"n/a\"\n    if premium.ResetDate != nil {\n        resets = premium.ResetDate.Format(time.RFC3339)\n    }\n    fmt.Printf(\"Premium interactions: %d/%d (%.1f%% left, resets %s)\\n\",\n        premium.UsedRequests, premium.EntitlementRequests, premium.RemainingPercentage, resets)\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 result = await client.Rpc.Account.GetQuotaAsync();\n\nif (result.QuotaSnapshots.TryGetValue(\"premium_interactions\", out var premium))\n{\n    Console.WriteLine(\n        $\"Premium interactions: {premium.UsedRequests}/{premium.EntitlementRequests} \" +\n        $\"({premium.RemainingPercentage:F1}% left, resets {premium.ResetDate?.ToString(\"o\") ?? \"n/a\"})\");\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\nvar result = client.getRpc().account.getQuota().join();\nvar premium = result.quotaSnapshots().get(\"premium_interactions\");\n\nif (premium != null) {\n    System.out.printf(\"Premium interactions: %d/%d (%.1f%% left, resets %s)%n\",\n        premium.usedRequests(), premium.entitlementRequests(),\n        premium.remainingPercentage(), premium.resetDate());\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nlet result = client.rpc().account().get_quota().await?;\n\nif let Some(premium) = result.quota_snapshots.get(\"premium_interactions\") {\n    let resets = premium.reset_date.as_deref().unwrap_or(\"n/a\");\n    println!(\n        \"Premium interactions: {}/{} ({:.1}% left, resets {resets})\",\n        premium.used_requests, premium.entitlement_requests, premium.remaining_percentage,\n    );\n}\n```\n\n</div>\n\n</div>\n\n## 올바른 API 선택\n\n이 요약을 사용하여 사용 사례에 맞는 API를 결정합니다.\n\n* **턴이 진행되는 동안 실시간 비용 또는 토큰 미터를 표시**하려면: `assistant.usage` 및 `session.usage_info`를 구독하세요.\n* **턴 또는 세션 후 최종 비용 요약 표시**: 호출 `session.usage.getMetrics`.\n* **재개 시, 새 턴이 시작되기 전에 컨텍스트 윈도우 사용량을 표시**: `session.metadata.contextInfo` 호출.\n* **작업을 실행하기 전에 비용을 추정하세요**: `models.list` 토큰 가격을 확인하세요.\n* **사용자의 요금제가 소진되기 전에 경고**: `account.getQuota` 호출.\n\n## 추가 읽기\n\n* [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events): `assistant.usage`, `session.usage_info`, 및 그 밖의 모든 세션 이벤트에 대한 모든 필드의 상세 참조\n* [Observability](/ko/copilot/how-tos/copilot-sdk/observability): 비용 귀속을 위해 사용량 데이터를 OpenTelemetry로 내보내기\n* [다중 테넌트 및 서버 배포](/ko/copilot/how-tos/copilot-sdk/setup/multi-tenancy): GitHub 토큰을 사용하여 사용자별 할당량 및 모델 확인"}