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