オンデバイスの Agentic ワークフロー(AgentRunner クラスを使用)は、ターン間でインメモリの会話履歴を自動的に記録するマネージド マルチターン セッションを提供するため、文字起こしを手動で管理する必要はありません。(独自のチャット履歴を直接管理する場合は、直接モデルアクセスを使用して、USER ロールと MODEL ロール、sessionId 値を持つマルチターン List<Content> オブジェクトを GenerateContentRequest オブジェクトに渡すことができます)。
このページでは、Android コンポーネントのライフサイクル、構成変更、メモリ再利用にわたる AgentSession インスタンスの管理について説明します。
マルチターン セッション
runner.getOrCreateSession(sessionId) メソッドを使用して取得したスコープ付き AgentSession インスタンスを使用して、マルチターンの会話を管理します。会話ターン(ユーザー メッセージ、ツール呼び出し、モデルのレスポンス)は、セッション内で自動的にメモリに記録されます。session.runAsync(content) メソッドをそれ以降に呼び出すと、以前のターンがコンテキストとして保持されます。
セッション ID は空白にできません。128 文字以下で、英数字、アンダースコア、ハイフン、ピリオド(^[a-zA-Z0-9_.-]+$、. と .. を除く)のみを使用できます。UUID.randomUUID().toString() メソッドを使用して生成された UUID 文字列は、これらの制約に準拠しています。
マルチターンの会話を開始するには、セッション ID を作成し、AgentRunner インスタンスから AgentSession インスタンスを取得します。
val sessionId = "user_chat_${System.currentTimeMillis()}"
val session = runner.getOrCreateSession(sessionId)
session.runAsync(content) メソッドを呼び出すたびに、そのセッション内で新しいプロンプト ターンが送信されます。モデルは、会話の前のターンからコンテキストを維持します。
構成の変更後もセッションを保持する
AgentSession インターフェースは、会話履歴をメモリに保持し、Parcelable インターフェースを実装しません。Android アプリでは、構成の変更(画面の回転など)時にアクティビティとフラグメントが破棄され、再作成されます。セッションをアクティビティに直接保存すると、回転時に会話履歴が失われます。
構成変更の前後で会話履歴を保持するには、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()メソッドを呼び出します。これにより、保留中の実行中のコルーチンがキャンセルされ、その会話セッションのバックグラウンドでの強制排除がディスパッチされます。
シングルターンのエフェメラル実行
過去のコンテキストが不要な 1 回限りのエージェント タスク(簡単な要約の生成、入力の検証、スタンドアロンの質問への回答など)の場合は、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 クラスは内部で一時セッションを割り当て、レスポンス ストリームが完了またはキャンセルされると、メモリからすべての会話状態を自動的にパージして、メモリリークを回避します。
次のステップ
- ストリーム イベントと UI の統合で、エージェントのリアクティブ ストリームを Compose に接続します。
- ツールの構成については、ツールを定義するをご覧ください。