세션 및 수명 주기 관리

온디바이스 에이전트 워크플로(AgentRunner 클래스 사용)는 여러 차례에 걸쳐 인메모리 대화 기록을 자동으로 기록하는 관리형 멀티턴 세션을 제공하므로 스크립트를 수동으로 관리할 필요가 없습니다. 자체 채팅 기록을 직접 관리하려면 직접 모델 액세스를 사용하여 USER 및 MODEL 역할과 sessionId 값이 있는 멀티턴 List<Content> 객체를 GenerateContentRequest 객체에 전달하면 됩니다.

이 페이지에서는 Android 구성요소 수명 주기, 구성 변경, 메모리 회수 전반에 걸쳐 AgentSession 인스턴스를 관리하는 방법을 설명합니다.

멀티턴 세션

runner.getOrCreateSession(sessionId) 메서드를 사용하여 가져온 범위가 지정된 AgentSession 인스턴스를 사용하여 멀티턴 대화를 관리합니다. 대화 차례 (사용자 메시지, 도구 호출, 모델 응답)는 세션 내에서 메모리에 자동으로 기록됩니다. session.runAsync(content) 메서드를 후속 호출하면 이전 대화가 컨텍스트로 보존됩니다.

세션 식별자는 비어 있지 않아야 하고 최대 128자(영문 기준)여야 하며 영숫자 문자, 밑줄, 하이픈, 마침표(^[a-zA-Z0-9_.-]+$, . 및 .. 제외)만 포함해야 합니다. UUID.randomUUID().toString() 메서드를 사용하여 생성된 UUID 문자열은 이러한 제약 조건을 준수합니다.

멀티턴 대화를 시작하려면 세션 식별자를 만들고 AgentRunner 인스턴스에서 AgentSession 인스턴스를 가져옵니다.

val sessionId = "user_chat_${System.currentTimeMillis()}"
val session = runner.getOrCreateSession(sessionId)

session.runAsync(content) 메서드를 호출할 때마다 해당 세션 내에서 새 프롬프트 차례가 전송됩니다. 모델은 대화의 이전 차례에서 컨텍스트를 유지합니다.

구성 변경 시 세션 유지

AgentSession 인터페이스는 대화 기록을 메모리에 보관하며 Parcelable 인터페이스를 구현하지 않습니다. Android 앱에서 활동과 프래그먼트는 구성 변경 (예: 화면 회전) 중에 소멸되고 다시 생성됩니다. 세션을 Activity에 직접 저장하면 회전 시 대화 기록이 손실됩니다.

구성 변경 시 대화 기록을 보존하려면 AndroidX ViewModel 클래스 내에 AgentSession 인스턴스를 유지합니다.

package com.example.ai.agent.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.mlkit.genai.agent.AgentRunner
import com.google.mlkit.genai.agent.AgentSession
import com.google.mlkit.genai.agent.textTokens
import com.google.mlkit.genai.prompt.Content
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class ChatViewModel(
    private val runner: AgentRunner,
    private val sessionId: String = "default_chat_session"
) : ViewModel() {

    // Retain the session inside the ViewModel to survive screen rotations
    private val session: AgentSession = runner.getOrCreateSession(sessionId)

    private val _responseText = MutableStateFlow("")
    val responseText: StateFlow<String> = _responseText.asStateFlow()

    fun sendMessage(userPrompt: String) {
        viewModelScope.launch {
            val content = Content.builder().text(userPrompt).build()
            session.runAsync(content)
                .textTokens()
                .collect { token ->
                    _responseText.update { it + token }
                }
        }
    }

    override fun onCleared() {
        super.onCleared()
        // Release session memory and cancel active coroutines when ViewModel is destroyed
        session.close()
    }
}

메모리 관리 및 세션 정리

앱 성능을 유지하려면 인메모리 대화 상태를 제한하세요.

  • 명시적 세션 삭제: 사용자가 대화 대화목록을 나가거나 '새 채팅'을 탭하면 session.delete() 또는 runner.deleteSession(sessionId) 메서드를 호출하여 이전 차례 및 도구 출력에 할당된 메모리를 동기식으로 확보합니다. 또는 session.close() 메서드를 호출하면 백그라운드 제거가 전달됩니다.
  • 로그아웃 정리: 사용자가 로그아웃하거나 앱 데이터를 삭제할 때 runner.clearAllSessions() 메서드를 호출합니다.
  • 수명 주기 종료 시 세션 정리: ViewModel 클래스 또는 상위 구성요소가 영구적으로 소멸되면(onCleared() 메서드에서) session.close() 메서드를 호출합니다. 이렇게 하면 대기 중인 진행 중인 코루틴이 취소되고 해당 대화 세션에 대한 백그라운드 제거가 전달됩니다.

싱글턴 임시 실행

과거 컨텍스트가 필요하지 않은 일회성 에이전트 작업 (예: 빠른 요약 생성, 입력 검증, 독립형 질문에 답변)의 경우 runner.runSingleTurnAsync(content) 메서드를 직접 호출합니다.

import com.google.mlkit.genai.agent.AgentEvent
import com.google.mlkit.genai.prompt.Content

val content = Content.builder()
    .text("Summarize order history for customer #1042: ...")
    .build()

runner.runSingleTurnAsync(content)
    .collect { event ->
        if (event is AgentEvent.TextMessage && !event.isPartial) {
            displaySummary(event.text)
        }
    }

runner.runSingleTurnAsync(content) 메서드를 직접 호출하면 AgentRunner 클래스가 내부적으로 임시 세션을 할당하고 응답 스트림이 완료되거나 취소되면 메모리에서 모든 대화 상태를 자동으로 삭제하여 메모리 누수를 방지합니다.

다음 단계