이력과 핸드오프

이력과 핸드오프

realtime 세션은 표준 에이전트 실행과 같은 ModelMessage 이력을 쌓아요. 메시지와 채팅 이력 참고. 음성 대화는 이전 텍스트나 음성 이력에서 시작하거나, 새 realtime 세션에서 계속하거나, 요약, 추출, 후속 처리를 위해 텍스트 모델로 핸드오프할 수 있어요.

말로 한 턴은 SpeechPart를 사용하고, 텍스트, 이미지, 툴은 평범한 ModelRequestModelResponse 형태를 유지해요.

출처: 문서

본문

세션 이력 읽기

세션은 읽기 시 복사(copy-on-read) 스냅샷을 노출해요:

메서드 반환
all_messages() 시드된 이력 + 이 세션 동안 기록된 메시지
new_messages() 이 세션 동안 기록된 메시지만

세션 시딩

message_history=를 전달하면 새 세션을 시드해요. 재생 가능한 텍스트, 음성 전사, thinking 텍스트, 툴 라운드, 지원되는 이미지가 프로바이더 대화 항목으로 투영돼요. 이력 프로세서는 시딩 때 실행되지 않아요. 기능과 훅 참고.

from pydantic_ai import Agent

voice = Agent(instructions='You are a helpful voice assistant.')


async def main(prior_history=()):
    async with voice.realtime(
        'openai:gpt-realtime',
        message_history=prior_history,
    ).session() as session:
        await session.send('Continue where we left off.')

프로바이더는 프로토콜이 허용하는 곳에서 네이티브 함수 호출을 재생해요. Gemini는 Live가 시드된 턴에 함수 파트를 넣을 수 없기 때문에 시드된 툴 호출과 결과를 읽을 수 있는 텍스트로 표현해요. thinking 시그니처와 프로바이더 네이티브 실행 메타데이터는 그것을 만든 세션에 속하므로 생략돼요.

콘텐츠 없는 음성 파트는 재생 가능한 콘텐츠를 담지 않으므로 건너뛰어져요. 지원되지 않는 콘텐츠는 조용히 버리는 대신 UserError를 발생시켜요. 비디오, 문서, 업로드된 파일 참조, 모델 생성 파일은 시드할 수 없어요.

음성 전사는 보존된 오디오보다 선호돼요. OpenAI와 Azure OpenAI는 전사가 없을 때 보존된 사용자 오디오를 재생할 수 있어요. Gemini와 xAI는 그러지 못해요. 어시스턴트 음성은 시딩에 항상 전사가 필요해요. 이식 가능한 흐름을 만들기 전에 RealtimeModelProfile에서 supports_session_seeding, supports_seeding_images, supports_seeding_audio를 확인하세요(프로필이 어떻게 해석되는지는 프로바이더 지원 참고).

텍스트 에이전트로 핸드오프

세션 스냅샷을 Agent.run()에 직접 전달하세요:

from pydantic_ai import Agent
from pydantic_ai.realtime import RealtimeTurnCompleteEvent

voice = Agent(instructions='You are a helpful voice assistant.')
notetaker = Agent('openai:gpt-5', instructions='Summarize the conversation as bullet points.')


async def main():
    async with voice.realtime('openai:gpt-realtime').session() as session:
        await session.send('Please remind me to book a train tomorrow.')
        async for event in session:
            if isinstance(event, RealtimeTurnCompleteEvent):
                break

    result = await notetaker.run(
        'Summarize the conversation.', message_history=session.all_messages()
    )
    print(result.output)
    #> - Book a train tomorrow.

보존된 사용자 오디오는 오디오 입력을 지원하는 프로필을 가진 표준 모델로 전달돼요. 다른 모델은 전사를 받아요. 어시스턴트 음성은 항상 전사 텍스트로 핸드오프돼요. 중단된 어시스턴트 턴은 Pydantic AI가 텍스트 모델 요청을 준비할 때 읽을 수 있는 중단 노트를 받아요.

호출이 열려 있는 동안 끝나야 하는 구조화된 작업에는 위임된 텍스트 에이전트를 realtime 함수 툴로 노출하세요.

오디오 보존

기본적으로 전사만 보존되고 SpeechPart.audioNone이에요. session()audio_retention=을 전달하면 완성된 WAV 오디오를 이력에 보존해요:

AudioRetention 보존
'transcript_only'(기본) 전사만
'input_audio' 사용자 오디오
'output_audio' 모델 오디오
'all' 양쪽 오디오

보존은 이력에만 영향을 줘요. 라이브 입력과 출력은 원시 PCM16로 남고, 완성된 보존 오디오는 WAV 컨테이너로 감싸져요.

입력 보존은 로컬에서 음성을 다듬지 않고 프로바이더가 보고한 경계를 따르지 않아요. OpenAI, Azure OpenAI, xAI는 보고된 음성 끝 경계 사이의 마이크 입력을 보통 보존해요. Gemini는 그 경계를 보고하지 않아서 응답 완료 사이의 입력을 보존해요. 어느 형태든 침묵이나 다른 마이크 입력을 포함할 수 있으므로 정밀하게 다듬어진 발화로 취급해서는 안 돼요.

이미지 보존

session()retain_images_every_n=retain_images_max=를 전달하면 로컬 이력에 남는 이미지 수를 바운드해요:

from pydantic_ai import Agent

agent = Agent()


async def main():
    async with agent.realtime('openai:gpt-realtime').session(
        retain_images_every_n=10, retain_images_max=25
    ):
        ...

이 설정은 로컬 이력을 바운드하지만 프로바이더 컨텍스트는 바운드하지 않아요. 프로바이더는 여전히 모든 프레임을 받아요. send()로 보낸 이미지는 기본으로 기록돼요. retain_images_every_n=N은 첫 이미지를 유지하고 그다음 N마다 하나를 유지해요. retain_images_max는 기본 100이고 상한에 도달하면 가장 오래된 보존 이미지를 퇴거해요. 아무것도 보존하지 않으려면 0으로, 바운드를 제거하려면 None으로 설정하세요.

샘플링은 이력 성장률을 제어하고, 최대값은 실제 메모리 바운드를 제공해요. 이미지를 연속적으로 스트리밍하면 라이브 비디오에 근접해요. 카메라 예제는 초당 한 프레임을 보내요. 그래서 카메라와 화면 스트림에서는 둘 다 의도적으로 사용하세요.

전사와 이력 엣지 케이스

입력 전사는 기본 'auto'예요. 구성은 입력 전사와 각 프로바이더 페이지를 참고하세요. 전사는 그 턴의 응답 이후에 도착하거나 다음 턴과 겹쳐도, 그것이 묘사하는 사용자 턴과 함께 기록돼요. 보고된 음성 세그먼트가 전사를 받지 못하면, 세션은 여전히 보존된 오디오 또는 세션이 닫힐 때 콘텐츠 없는 SpeechPart를 기록해요.

전사가 비활성화되면:

  • 보존된 입력 오디오는 오디오 전용 사용자 SpeechPart를 만들어요.
  • 입력 보존이 없으면 세션은 콘텐츠 없는 사용자 SpeechPart를 기록해요.
  • 콘텐츠 없는 파트는 로컬 턴 경계를 보존하지만 텍스트 핸드오프에 어떤 단어도 기여하지 않고, 다른 realtime 세션을 시드할 때 건너뛰어져요.
  • 전사 없는 어시스턴트 오디오는 어떤 프로바이더에서도 핸드오프하거나 시드할 수 없어요.

미래 세션이 프로바이더나 모델 간에 이식 가능해야 한다면 전사를 보존하세요. message_history를 전달하기 전에 지원되지 않는 파트를 필터하거나 변환하세요. 이력 처리 기능은 realtime 시딩 중에 실행되지 않아요.

더 알아보기 (Learn more)