Usage

Usage (사용량)

Agents SDK는 매 실행에 대해 토큰 사용량을 자동으로 추적해요. 실행 컨텍스트에서 접근해서 비용 모니터링, 한도 강제, 분석 기록에 쓸 수 있어요.

출처: 문서

본문

추적되는 항목

  • requests — 만들어진 LLM API 호출 수
  • input_tokens — 보내진 입력 토큰 합계
  • output_tokens — 받은 출력 토큰 합계
  • total_tokens — 입력 + 출력
  • request_usage_entries — 요청별 사용량 내역 목록
  • details:
    • input_tokens_details.cached_tokens
    • input_tokens_details.cache_write_tokens
    • output_tokens_details.reasoning_tokens

실행에서 사용량 접근하기

Runner.run(...) 뒤에는 result.context_wrapper.usage로 사용량에 접근할 수 있어요.

result = await Runner.run(agent, "What's the weather in Tokyo?")
usage = result.context_wrapper.usage

print("Requests:", usage.requests)
print("Input tokens:", usage.input_tokens)
print("Output tokens:", usage.output_tokens)
print("Total tokens:", usage.total_tokens)

사용량은 도구 호출이나 handoff를 만들어 내는 모델 호출을 포함해 실행 중 모든 모델 호출에 걸쳐 집계돼요.

OpenAIResponsesCompactionSession이 실행이 끝나기 전에 자동으로 기록을 압축하면, 그 responses.compact 요청이 보고한 사용량도 같은 실행 합계에 더해져요. 실행 밖에서 만든 수동 run_compaction() 호출은 둘러싸는 실행 컨텍스트가 없으므로, 이전 실행이 반환한 사용량 객체를 갱신하지 않아요. 자세한 내용은 OpenAI Responses compaction sessions를 참고하세요.

서드파티 어댑터에서 사용량 켜기

사용량 보고는 서드파티 어댑터와 프로바이더 백엔드에 따라 달라져요. 서드파티 어댑터로 모델에 접근하는데 정확한 result.context_wrapper.usage 값이 필요하다면:

  • AnyLLMModel에서는 상위 프로바이더가 사용량을 반환하면 자동으로 전파돼요. Chat Completions 백엔드에서 응답을 스트리밍할 때는 usage 청크가 방출되도록 ModelSettings(include_usage=True)가 필요할 수 있어요.
  • LitellmModel에서는 일부 프로바이더 백엔드가 기본적으로 사용량을 보고하지 않아서 ModelSettings(include_usage=True)가 자주 필요해요.

Models 가이드의 Third-party adapters 섹션에 있는 어댑터별 메모를 검토하고, 배포하려는 정확한 프로바이더 백엔드에서 사용량 보고를 검증하세요.

요청별 사용량 추적

SDK는 request_usage_entries에서 각 API 요청의 사용량을 자동으로 추적해서, 상세 비용 계산과 컨텍스트 창 소비 모니터링에 유용해요.

result = await Runner.run(agent, "What's the weather in Tokyo?")

for i, request in enumerate(result.context_wrapper.usage.request_usage_entries):
    print(f"Request {i + 1}: {request.input_tokens} in, {request.output_tokens} out")

SDK가 한 Usage 객체를 다른 객체로 집계할 때는 요청별 항목과 그 중첩 입력/출력 토큰 세부 정보를 복사해요. 이후 원본 사용량 객체를 변형해도 집계의 request_usage_entries를 바꿀 수 없고, 집계를 변형해도 원본 항목을 바꿀 수 없어요.

프로바이더 사용량 페이로드 보존하기

Agents SDK는 프로바이더 사용량을 모든 모델 프로바이더에 걸쳐 일관된 합계를 주는 Usage 필드로 정규화해요. 애플리케이션이 프로바이더 특유의 사용량 필드를 유지하거나, 생략된 필드와 프로바이더가 보고한 0을 구분해야 한다면 ModelSettings.preserve_raw_usageTrue로 설정하세요.

from agents import Agent, ModelSettings, Runner

agent = Agent(
    name="Assistant",
    model_settings=ModelSettings(preserve_raw_usage=True),
)
result = await Runner.run(agent, "What's the weather in Tokyo?")

for response in result.raw_responses:
    print(response.raw_usage)

Agents SDK는 각 ModelResponse.raw_usage 값을 그 모델 호출의 프로바이더 페이로드에 대한 분리된(디태치된), JSON 호환 스냅샷으로 저장해요. Agents SDK는 raw_usage를 실행 전체에 걸쳐 집계하지 않아요. 보존이 꺼져 있거나, 프로바이더가 사용량 페이로드를 반환하지 않거나, 상위 어댑터가 이미 원래 필드 존재 정보를 버렸다면 그 값은 None으로 남아요.

preserve_raw_usage는 모델 어댑터에 도달하는 사용량 페이로드만 보존해요. 이 설정이 프로바이더에게 사용량을 요청하는 건 아니에요. 스트리밍 Chat Completions 프로바이더가 명시적 사용량 요청을 요구할 때는 ModelSettings(include_usage=True)도 설정하세요.

LitellmModel은 현재 스트리밍이든 비스트리밍이든 ModelResponse.raw_usage를 채우지 않으므로, 그 어댑터에서는 preserve_raw_usage=True가 효과가 없어요. LitellmModel을 쓸 때는 정규화된 Usage 필드를 계속 쓰거나, 프로바이더 특유 필드 존재가 필요할 때 raw usage 보존을 지원하는 어댑터를 고르세요.

세션과 사용량 접근

Session(예: SQLiteSession)을 쓸 때 각 Runner.run(...) 호출은 그 특정 실행의 사용량을 돌려줘요. 세션은 대화 기록을 컨텍스트로 유지하지만, 각 실행의 사용량은 독립적이에요.

session = SQLiteSession("my_conversation")

first = await Runner.run(agent, "Hi!", session=session)
print(first.context_wrapper.usage.total_tokens)  # Usage for first run

second = await Runner.run(agent, "Can you elaborate?", session=session)
print(second.context_wrapper.usage.total_tokens)  # Usage for second run

세션이 실행 사이에 대화 컨텍스트를 보존해도, 각 Runner.run() 호출이 반환하는 사용량 지표는 그 특정 실행만 나타내요. 세션에서는 이전 메시지가 각 실행의 입력으로 다시 공급될 수 있는데, 이는 후속 턴의 입력 토큰 수에 영향을 줘요.

RunState 체크포인트에서의 사용량

RunResult.to_state()는 지금까지 누적된 사용량의 독립 스냅샷을 잡아요. 그 체크포인트에서 재개된 실행은 잡힌 합계로 시작해 자기 모델 호출의 사용량을 더해요. 재개된 실행은 그 새 합계를 원본 RunResult나 그 결과에서 만든 다른 체크포인트에 더하지 않아요.

first = await Runner.run(agent, "First request")
checkpoint_a = first.to_state()
checkpoint_b = first.to_state()

resumed_a = await Runner.run(agent, checkpoint_a)
resumed_b = await Runner.run(agent, checkpoint_b)

assert resumed_a.context_wrapper.usage is not first.context_wrapper.usage
assert resumed_b.context_wrapper.usage is not resumed_a.context_wrapper.usage

이 격리는 Usage 안의 request_usage_entries 목록에도 적용돼요. 재개된 중첩 Agent.as_tool() 실행은 독립 최상위 회계의 예외예요. 그 재개 후 모델 사용량은 중첩 실행의 이전 모델 호출처럼 활성 바깥 실행의 사용량으로 의도적으로 집계돼요.

훅에서 사용량 쓰기

RunHooks를 쓴다면 각 훅에 전달되는 컨텍스트 객체에 사용량이 들어 있어요. 그래서 핵심 lifecycle 순간에 사용량을 기록할 수 있어요.

class MyHooks(RunHooks):
    async def on_agent_end(self, context: RunContextWrapper, agent: Agent, output: Any) -> None:
        u = context.usage
        print(f"{agent.name} → {u.requests} requests, {u.total_tokens} total tokens")

API 레퍼런스

상세 API 문서는 다음을 참고하세요.

  • Usage — 사용량 추적 데이터 구조
  • RequestUsage — 요청별 사용량 세부 정보
  • RunContextWrapper — 실행 컨텍스트에서 사용량 접근
  • RunHooks — 사용량 추적 lifecycle에 훅 연결

더 알아보기 (Learn more)