사용량과 옵저버빌리티

사용량과 옵저버빌리티

Realtime 오디오는 양방향으로 초 단위로 청구돼요. 그래서 세션이 얼마였는지 아는 것 — 그리고 그것을 상한을 두는 것 — 은 텍스트 실행보다 더 중요해요. Realtime 세션은 표준 RunUsage를 축적하고, 표준 UsageLimits를 시행하며, Pydantic AI의 일반 인스트루멘테이션을 통해 OpenTelemetry 스팬을 방출해요(Pydantic Logfire에서 볼 수 있어요). 이것은 음성과 후속 텍스트 실행이 하나의 사용량 예산과 추적을 공유하게 해줘요.

출처: 문서

본문

사용량과 한도

누적 사용량은 RealtimeSession.usage에서 읽어요. 입력/출력 토큰, 사용 가능한 곳의 프로바이더 오디오·캐시 세부, 툴 호출 횟수를 포함해요. 사용량 업데이트는 세션 이벤트로 방출되지 않아요. genai-prices가 모델에 가격이 있을 때 session.usage.cost는 누적 USD 비용을 담고 cost_limit이 적용돼요. 가격이 없을 때(가격이 없는 모델, 또는 호출 시간으로 청구하는 프로바이더) 비용은 None으로 남고 cost_limit은 절대 발동하지 않으며, 응답당 한 번 시행할 수 없다고 경고해요. 표준 실행의 사용량 한도처럼, usage=를 전달해 공유 객체(예: 음성 호출과 그 후속 텍스트 실행에 걸쳐 나르는 것)로 축적하고 usage_limits=로 세션에 상한을 두세요:

from pydantic_ai import Agent
from pydantic_ai.realtime import RealtimeTurnCompleteEvent
from pydantic_ai.usage import RunUsage, UsageLimits

agent = Agent()
shared = RunUsage()


async def main():
    async with agent.realtime(
        'openai:gpt-realtime',
        usage=shared,
        usage_limits=UsageLimits(total_tokens_limit=100_000),
    ).session() as session:
        await session.send('Say hello.')
        async for event in session:
            if isinstance(event, RealtimeTurnCompleteEvent):
                break
        print(shared)
        #> RunUsage(requests=1)

입력 전사 사용량은 RunUsage.detailsinput_transcription_* 키 아래에 따로 보고돼요. 전사가 별도 모델과 청구 미터를 사용할 수 있으므로 응답 토큰 총계에 포함되지 않고 ModelResponse에 귀속되지 않아요.

session.new_messages()의 각 기록된 ModelResponse는 그 응답의 사용량을 담아요. 하나의 툴 호출 턴이 여러 응답에 걸칠 수 있으므로 누적 총계에는 session.usage를 사용하세요.

토큰, 비용, 툴 호출 한도는 사용량이 축적될 때 확인돼요. 요청 한도는 텍스트 보내기, respond=True로 이미지 보내기, 응답 명시 생성, 툴 결과 반환 전에 확인돼요. 서버 측 VAD에서는 프로바이더가 클라이언트 요청 없이 응답을 시작할 수 있어요. 그 한도는 첫 응답 이벤트에서 확인돼요. 위반은 이터레이션에서 발행되거나, 오디오/전사 뷰만 소비되면 세션 컨텍스트가 종료될 때 UsageLimitExceeded를 발생시켜요.

프로바이더별 사용량 필드는 OpenAI, Azure OpenAI, Google Gemini, xAI 페이지에 있어요.

Logfire 인스트루멘테이션

logfire.instrument_pydantic_ai()를 호출하거나 에이전트에 instrument=True를 설정하세요:

import logfire

logfire.configure()
logfire.instrument_pydantic_ai()

세션은 누적 사용량과 대화 콘텐츠를 가진 invoke_agent 스팬을 만들고, 일반 콘텐츠 리댁션 설정을 받아요. 중첩 프로바이더 응답 스팬은 OpenTelemetry 이름 chat {model}을 가지지만 Logfire에는 response {model}로 표시돼요. execute_tool 스팬은 툴을 나타내고, 위임된 실행은 execute_tool 안에 자체 invoke_agent 스팬을 추가해요. model turn completeinterrupt 스팬은 그 경계를 표시해요. 툴 라운드는 한 턴 안에서 여러 응답 스팬을 만들 수 있어요.

둘 사이에 chat 스팬이 없는 model turn complete (interrupted) 스팬의 연속을 볼 수 있어요. 그것은 OpenAI 서버 VAD에서 정상이에요. 프로바이더가 감지된 각 음성 세그먼트에 대해 응답을 시작하므로, 계속 말하는 사용자는 각 자동 응답을 그것이 출력을 만들기 전에 취소해요. 취소되거나 중단된 모든 응답은 경계를 그리고 model turn complete (interrupted)로 표시돼요.

속성 설정 대상 의미
pydantic_ai.realtime 세션이 스스로 방출하는 스팬(세션, 응답, 경계, user speech 스팬) 항상 True; realtime 세션에 속한 스팬을 표시. execute_tool 스팬은 Instrumentation 기능에서 와서 그것을 담지 않음
gen_ai.output.type 세션과 응답 스팬 speech 또는 text
pydantic_ai.response.state 중단된 응답 스팬 'interrupted'
응답 수준 사용량 OpenAI, Azure OpenAI, xAI 응답 스팬 그 응답에 귀속된 토큰

Gemini는 함수 호출 응답 후 이후 완료된 턴에서만 사용량을 보고할 수 있어요. 누적 세션 사용량이 여전히 권위적이에요.

프로바이더가 사용자 음성 시작과 끝을 모두 보고하면 Pydantic AI는 user speech 스팬을 기록해요. 두 경계가 모두 없는 프로바이더는 추측된 기간을 얻지 않아요.

WebRTC 사이드밴드에서는 speak {model} 스팬이 모델이 들렸던 시간을 추가로 다뤄요. 응답 스팬이 보여줄 수 없는 거예요. 프로바이더가 오디오를 재생보다 훨씬 앞서 생성하므로, 이 스팬은 보통 응답을 끝낸 model turn complete보다 오래 지속돼요.

세션 스팬은 또한 바운드된 오디오와 전사 소비자에 걸쳐 합산된 pydantic_ai.audio_chunks_droppedpydantic_ai.transcript_items_dropped를 보고해요. 이 총계는 세션이 닫힐 때 기록돼요. pydantic_ai.queue_dropped_deltaspydantic_ai.queue_dropped_structural은 아무것도 반복하지 않는 동안 세션 이벤트 큐에서 버려진 더 오래된 파트 델타 이벤트와 구조적 이벤트를 세요.

Logfire 설정과 프라이버시 컨트롤은 디버깅과 모니터링을 참고하세요.

Gateway 추적 전파

Pydantic AI Gateway를 통한 라우팅 — 예: agent.realtime('gateway/openai:gpt-realtime') — 은 OpenAIGemini 페이지에 문서화된 프로바이더 구성이에요. WebSocket 핸드셰이크 중에 스팬이 활성화되면 Pydantic AI는 W3C 추적 컨텍스트를 전파해 gateway 스팬이 추적에 합류할 수 있게 해요.

프로바이더 연결은 realtime 세션 스팬이 시작되기 전에 확립돼요. 핸드셰이크 자체를 포함해야 할 때는 전체 세션 컨텍스트를 바깥 스팬으로 감싸세요:

import logfire

from pydantic_ai import Agent

agent = Agent()


async def main():
    with logfire.span('voice call'):
        async with agent.realtime('openai:gpt-realtime').session() as session:
            await session.send('Say hello.')

엣지 케이스

  • 사용량은 이벤트 스트림이 아니라 누적 세션 상태예요. 관련 응답 후나 세션이 닫힐 때 읽으세요.
  • 프로바이더는 로컬 툴이나 턴 경계와 다른 지점에서 응답 수준 사용량을 보고할 수 있어요. 청구와 한도에는 세션 총계를 사용하세요.
  • 드롭된 스트림 카운터는 각 느린 소비자를 독립적으로 나타내요. 뒤처진 두 오디오 이터레이터가 같은 생성 오디오에 대해 둘 다 드롭에 기여할 수 있어요.

더 알아보기 (Learn more)