Zarządzanie sesjami i cyklem życia

Przepływy pracy oparte na agentach na urządzeniu (korzystające z klasy AgentRunner) zapewniają zarządzane sesje wieloturowe, które automatycznie rejestrują historię rozmów w pamięci, dzięki czemu nie musisz ręcznie zarządzać transkrypcjami. (Jeśli wolisz bezpośrednio zarządzać własną historią czatu, możesz przekazać obiekt wieloetapowy List<Content> z rolami USER i MODEL oraz wartością sessionId do obiektu GenerateContentRequest, korzystając z bezpośredniego dostępu do modelu).

Na tej stronie opisujemy zarządzanie instancjami AgentSession w cyklach życia komponentów Androida, zmianach konfiguracji i odzyskiwaniu pamięci.

Sesje wieloetapowe

Zarządzaj rozmowami wieloetapowymi za pomocą instancji AgentSession o określonym zakresie uzyskanych za pomocą metody runner.getOrCreateSession(sessionId). Tury dialogu (wiadomości użytkownika, wywołania narzędzi i odpowiedzi modelu) są automatycznie zapisywane w pamięci w ramach sesji. Kolejne wywołania metody session.runAsync(content) zachowują poprzednie tury jako kontekst.

Identyfikatory sesji nie mogą być puste, mogą mieć maksymalnie 128 znaków i zawierać tylko znaki alfanumeryczne, podkreślenia, łączniki lub kropki (^[a-zA-Z0-9_.-]+$, z wyjątkiem . i ..). Ciągi UUID wygenerowane za pomocą metody UUID.randomUUID().toString() są zgodne z tymi ograniczeniami.

Aby rozpocząć rozmowę wieloturową, utwórz identyfikator sesji i pobierz instancję AgentSession z instancji AgentRunner:

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

Każde wywołanie metody session.runAsync(content) wysyła nową turę prompta w ramach tej sesji. Model zachowuje kontekst z poprzednich etapów rozmowy.

Zachowywanie sesji mimo zmian konfiguracji

Interfejs AgentSession przechowuje historię dialogu w pamięci i nie implementuje interfejsu Parcelable. W aplikacjach na Androida aktywności i fragmenty są niszczone i tworzone ponownie podczas zmian konfiguracji (np. obracania ekranu). Jeśli przechowujesz sesję bezpośrednio w aktywności, historia rozmowy zostanie utracona po obróceniu.

Aby zachować historię rozmów po zmianach konfiguracji, zachowaj instancję AgentSession w klasie AndroidX ViewModel:

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()
    }
}

Zarządzanie pamięcią i czyszczenie sesji

Aby utrzymać wydajność aplikacji, ogranicz stan rozmowy w pamięci:

  • Jawne usuwanie sesji: gdy użytkownik opuści wątek rozmowy lub kliknie „Nowy czat”, wywołaj metodę session.delete() lub runner.deleteSession(sessionId), aby synchronicznie zwolnić pamięć przydzieloną na poprzednie tury i dane wyjściowe narzędzia. Możesz też wywołać metodę session.close(), aby wysłać żądanie usunięcia w tle.
  • Czyszczenie po wylogowaniu: wywołaj metodę runner.clearAllSessions(), gdy użytkownik się wyloguje lub wyczyści dane aplikacji.
  • Czyszczenie sesji na koniec cyklu życia: wywołaj metodę session.close(), gdy klasa ViewModel lub komponent nadrzędny zostaną trwale zniszczone (w metodzie onCleared()). Spowoduje to anulowanie oczekujących współprogramów i uruchomienie w tle usuwania tej sesji rozmowy.

Jednoetapowe wykonywanie efemeryczne

W przypadku jednorazowych zadań agenta (takich jak generowanie krótkiego podsumowania, sprawdzanie danych wejściowych lub odpowiadanie na samodzielne pytanie), w których nie jest potrzebny wcześniejszy kontekst, wywołaj bezpośrednio metodę 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)
        }
    }

Podczas bezpośredniego wywoływania metody runner.runSingleTurnAsync(content) klasa AgentRunner wewnętrznie przydziela tymczasową sesję i automatycznie usuwa z pamięci cały stan rozmowy po zakończeniu lub anulowaniu strumienia odpowiedzi, co pozwala uniknąć wycieków pamięci.

Dalsze kroki