Connect with us

Разработка

Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

В этой статье вы узнаете, как создавать автономные агентные сценарии внутри приложения, работающие в облаке.

Опубликовано

/

     
     

Добро пожаловать обратно в серию публикаций «Интеллектуальные приложения для Android», где мы берём базовое Android-приложение и постепенно превращаем его в персонализированный, интеллектуальный и агентный продукт. В предыдущей статье вы узнали, как подключаться к системе интеллектуальных функций с помощью AppFunctions.

В этой статье вы узнаете, как создавать автономные агентные сценарии внутри приложения, работающие в облаке.

Иногда задача слишком сложна, чтобы выполнить её за одну сессию на устройстве. Например, полное планирование отпуска включает согласование времени перелётов, выбор гостиничных номеров, бронирование билетов в музеи и резервирование столиков в ресторанах. Если запускать весь этот многошаговый процесс непосредственно на мобильном устройстве, приложение может быть закрыто, и прогресс потеряется. Кроме того, управление всеми этапами и учётными данными API на телефоне быстро становится слишком сложным.

Для таких долгих многошаговых сценариев можно использовать собственный самостоятельно размещённый сервер. Сервер выполняет работу агентов бронирования в фоновом режиме, а Android-приложение подключается к сессии, показывает прогресс и запрашивает действия пользователя только тогда, когда это действительно необходимо.

Использование облачного агентного сервера даёт несколько преимуществ:

  • Фоновое выполнение: агенты бронирования автономно работают в облаке, поэтому прогресс не теряется, если мобильное приложение уходит в фон или теряет подключение к интернету.
  • Сложная оркестрация нескольких агентов: координирующий агент может делегировать бронирования специализированным субагентам и учитывать зависимости между ними.
  • Независимый от клиента рендеринг UI: сервер динамически описывает структуру интерфейса, позволяя обновлять компоновку без выпуска новой версии приложения.
Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

Ассистент бронирования показывает весь прогресс, сгруппированный по типам событий.

С учётом этих преимуществ мы добавили в Jetpacker помощника Booking Assistant, который координирует перелёты, гостиницы, музеи и бронирование ресторанов. Давайте посмотрим, как мы организовали многоагентную систему на базе Agent Development Kit (ADK), используя протокол Agent-User Interaction (AG-UI) и Agent-to-User Interface (A2UI), чтобы отправлять и нативно отображать интерактивные карточки в Jetpack Compose.

Обеспечиваем сложные сценарии с помощью агентов ADK

Вместо того чтобы вручную координировать поток выполнения через собственные REST-endpoint’ы или сложные WebSocket-соединения, можно использовать Agent Development Kit (ADK). С ADK вы можете определять агентов и подключать к ним инструменты на Python для запросов к базам данных и выполнения бронирований.

Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

Android-приложение отправляет текущие данные маршрута поездки на сервер. Координирующий агент выбирает, каких субагентов нужно запустить. Каждый субагент помещает результат в общую очередь сессии, откуда данные потоково отправляются обратно в Android-приложение.

Вот как можно определить простого агента и запустить его через ADK:

# android/booking-server/booking_server.py

# Note: ADK supports many different coding languages. For now, use the Python version as it includes support for A2UI which we'll use later in this blog post.

from google.adk import Agent
from google.adk.runners import InMemoryRunner
from google.adk.tools import FunctionTool

# Define custom tools to interact with database
def search_flights(destination: str, date: str) -> list[str]:
    # In production, here you would query our flight database and return dynamic results
    return ["10:00 AM", "2:00 PM"]

def reserve_flight(flight_time: str) -> str:
    # In production, here you would save the reservation transaction
    return "Reserved flight at " + flight_time

# Instantiate the booking agent with specialized tools
flight_agent = Agent(
    name="Flight Booker",
    model="gemini-3.1-flash-lite",
    instruction="Help the user search for flights and book a reservation.",
    tools=[
        FunctionTool(search_flights),
        FunctionTool(reserve_flight, require_confirmation=True)
    ]
)

# Run the agent in memory using a session ID
runner = InMemoryRunner(flight_agent)
async for event in runner.run_async(user_id=user_id, session_id=session_id):
    if event.content:
        print("Agent said:", event.content)

Когда вы запускаете агента таким образом, ADK берёт на себя этапы выполнения. Он автоматически отслеживает контекст разговора, маршрутизирует сообщения между пользователем и моделью и вызывает зарегистрированные инструменты, когда модель их запрашивает. Благодаря этому вы можете сосредоточиться на чистой процедурной логике, пока фреймворк занимается оркестрацией в фоне.

Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

Веб-интерфейс ADK показывает, как можно взаимодействовать с многоагентной системой бронирования.

Чтобы подключить этого серверного агента к нашему приложению Jetpacker, серверу нужен способ отправлять обновления на устройство в реальном времени — для этого используется протокол AG-UI. Агенту также нужен структурированный способ описывать и обновлять интерактивные компоненты, например переключатели вариантов или схемы выбора мест, прямо на телефоне — и здесь используется протокол A2UI.

Стандартизируем связь между агентом и клиентом с помощью AG-UI

Работа агентов в облаке и отображение UI на Android требуют стандартного канала связи. Для этого используется протокол AG-UI.

AG-UI — это двунаправленный протокол транспортного уровня, стандартизирующий типы сообщений между агентами и UI-клиентами. Агент может сообщать клиенту о событиях жизненного цикла, текстовых сообщениях, вызовах инструментов и изменениях состояния. Клиент, в свою очередь, может отправлять агенту пользовательские текстовые сообщения, результаты вызовов инструментов и собственные события действий.

На серверной стороне обновления выдаются в виде стандартных Server-Sent Events, например event: TEXT_MESSAGE_CONTENT, содержащего JSON-дельту. На Android Kotlin SDK слушает этот поток и автоматически преобразует данные в типобезопасные клиентские события:

// https://github.com/android/ai-samples/tree/main/jetpacker/android/feature/trip/booking_assistant/src/main/kotlin/com/example/jetpacker/feature/booking_assistant/BookingAssistantViewModel.kt
import com.agui.client.agent.HttpAgent
import com.agui.client.agent.HttpAgentConfig
import com.agui.core.types.RunAgentInput
import com.agui.core.types.UserMessage
import com.agui.core.types.TextMessageStartEvent
import com.agui.core.types.TextMessageContentEvent
import com.agui.core.types.TextMessageEndEvent

val config = HttpAgentConfig(
    agentId = "booking-assistant",
    threadId = threadId,
    url = "https://<your-backend-url>"
)
val agent = HttpAgent(config, httpClient)

// Set up the input with the session thread and user instruction
val input = RunAgentInput(
    threadId = threadId,
    runId = runId,
    messages = listOf(UserMessage("Book a flight to Paris"))
)

// Run the agent flow and collect lifecycle events
agent.runAgentObservable(input)
    .collect { event ->
        when (event) {
            is TextMessageStartEvent -> { /* ... */ }
            is TextMessageContentEvent -> { /* ... */ }
            is TextMessageEndEvent -> {
                // Handle the completed message
            }
        }
    }

После этого можно написать интерфейс, отображающий различные типы стандартизированных событий AG-UI. В результате получится классический интерфейс чат-бота:

Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

Базовый интерфейс, позволяющий пользователю общаться с ассистентом.

Позволяем агенту «говорить на языке UI» с помощью A2UI

Традиционные чат-боты обычно возвращают обычный текст или собственные JSON-структуры. При создании сложных интерфейсов клиентскому приложению приходится разбирать эти данные и сопоставлять их с заранее созданными экранами. Возникает зависимость: каждый раз, когда вы добавляете новую функцию, меняете компоновку или поддерживаете новый вид пользовательского взаимодействия, приходится обновлять и серверного агента, и мобильное приложение. Это требует выпуска новой версии приложения и ожидания, пока пользователи её установят.

Для решения этой проблемы используется протокол A2UI. A2UI позволяет агентам динамически описывать компоненты интерфейса, которые нужно отрисовать на клиенте. Клиентское приложение объявляет каталог поддерживаемых компонентов, а сервер отправляет JSON с описанием структуры компонентов и их свойств:

{
  "version": "v0.9",
  "updateComponents": {
    "surfaceId": "Flight Reservation",
    "components": [
      {
        "id": "flight_option_picker",
        "component": "InteractiveOptionPicker",
        "properties": {
          "prompt": "Select a flight time:",
          "options": [
            "10:00 AM",
            "2:00 PM"
          ],
          "selectedIdx": null,
          "confirmBtnText": "Confirm Flight"
        }
      }
    ]
  }
}

Сервер указывает, какие компоненты из каталога нужно отрисовать и какие значения свойств они должны иметь. Это аккуратно отделяет детали визуальной реализации клиента от состояния рабочего процесса агента.

Проектируем серверную схему UI

Чтобы агент мог корректно генерировать такие JSON-структуры, он должен знать, какие компоненты доступны и какие свойства они поддерживают.

Для этого используется интеграция ADK с A2UI. Вместо того чтобы вручную писать инструкции для каждого компонента каталога, A2uiSchemaManager компилирует их JSON-схемы и инструкции по компоновке прямо в системный промпт. Благодаря этому модель получает точные сведения о структуре и правилах форматирования, которым она должна следовать при генерации корректных A2UI-данных:

# android/booking-server/booking_server.py
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.schema.constants import VERSION_0_9
from a2ui.schema.catalog import CatalogConfig
from a2ui.basic_catalog.provider import BasicCatalog

# Initialize A2UI Schema Manager with custom booking component catalog
schema_manager = A2uiSchemaManager(
    version=VERSION_0_9,
    catalogs=[
        BasicCatalog.get_config(version=VERSION_0_9),
        CatalogConfig.from_path(
            name="https://example.com/catalogs/booking_assistant/v1/catalog.json",
            catalog_path="booking_catalog.json"
        )
    ]
)

# Compile prompt instructions including the A2UI JSON schema
A2UI_SYSTEM_INSTRUCTION = schema_manager.generate_system_prompt(
    role_description="You are a helpful travel booking assistant.",
    ui_description="Use InteractiveOptionPicker for choices, SeatSelectionPicker for seat selection...",
    include_schema=True,
    include_examples=True,
    allowed_components=["InteractiveOptionPicker", "SeatSelectionPicker", "BookingStatus"]
)

С такой сгенерированной системной инструкцией LLM привязана к структуре схемы и точно знает, как формировать обновления компонентов, которые Android-клиент способен отрисовать.

Нативно отображаем A2UI с помощью Jetpack Compose

Чтобы нативно отображать деревья таких компонентов на Android, используется новая библиотека Jetpack Compose A2UI Renderer.

Сначала добавьте зависимости в файл build.gradle.kts соответствующего модуля:

// android/feature/trip/booking_assistant/build.gradle.kts
dependencies {
    implementation("androidx.a2ui:a2ui-model:1.0.0-alpha01")
    implementation("androidx.a2ui.compose:compose-runtime:1.0.0-alpha01")
    implementation("androidx.a2ui.compose:compose-ui:1.0.0-alpha01")
    implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha01")
}

Каждый класс компонента в каталоге, например BookingStatusComponent, определяет, как свойства из JSON преобразуются в composable-функцию Jetpack Compose.

Зарегистрируйте собственные компоненты в каталоге:

// android/feature/trip/booking_assistant/src/main/kotlin/com/example/jetpacker/feature/booking_assistant/CustomBookingAssistantCatalog.kt

import androidx.a2ui.compose.ui.A2uiCatalog

fun bookingAssistantCatalog(): A2uiCatalog {
    return A2uiCatalog(
        catalogId = "https://example.com/catalogs/booking_assistant/v1/catalog.json",
        components = listOf(
            InteractiveOptionPickerComponent(),
            SeatSelectionPickerComponent(),
            BookingStatusComponent()
        )
    )
}

Совет: Jetpacker реализует собственные компоненты InteractiveOptionPicker, SeatSelectionPicker и BookingStatus, специально созданные для сценариев бронирования. Если ваш агент использует стандартные элементы — текст, карточки, кнопки, строки, столбцы, чекбоксы и выбор даты и времени, — material3-a2ui также предоставляет materialA2uiBasicCatalogV1(...) с готовыми реализациями Material 3, поэтому писать собственные компоненты не потребуется.

Примечание: чтобы сервер и мобильный клиент оставались синхронизированы, оба используют один и тот же идентификатор определения каталога (https://example.com/catalogs/booking_assistant/v1/catalog.json). Если вы добавляете или изменяете свойства в серверном каталоге, необходимо увеличить номер версии и обновить соответствующий Kotlin-класс компонента, иначе могут возникнуть ошибки разбора данных.

В BookingAssistantViewModel сообщения A2UI обрабатываются с помощью A2uiMessageProcessor, после чего обновляется список активных поверхностей:

// android/feature/trip/booking_assistant/src/main/kotlin/com/example/jetpacker/feature/booking_assistant/BookingAssistantViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.a2ui.model.processor.A2uiSurfaceModel
import androidx.a2ui.compose.ui.A2uiMessageProcessor
import kotlinx.coroutines.flow.StateFlow

class BookingAssistantViewModel : ViewModel() {
    private val messageProcessor = A2uiMessageProcessor(
        catalogs = listOf(bookingAssistantCatalog())
    )
    val activeSurfaces: StateFlow<List<A2uiSurfaceModel>> = messageProcessor.activeSurfaces
    
    init {
        viewModelScope.launch(Dispatchers.Default) { processor.collectMessages() }
    }

    // ...
}

На Compose-экране соберите эти поверхности и отрисуйте каждую с помощью официальной composable-функции A2uiSurface из androidx.compose.material3:material3-a2ui. A2uiSurface автоматически управляет реактивным наблюдением за состоянием компонентов, индикаторами загрузки Material 3, fallback-интерфейсами при ошибках и анимированными переходами между обновлениями:

// android/feature/trip/booking_assistant/src/main/kotlin/com/example/jetpacker/feature/booking_assistant/BookingAssistantScreen.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.a2ui.A2uiSurface

@Composable
fun BookingAssistantScreen(
    viewModel: BookingAssistantViewModel,
    modifier: Modifier = Modifier
) {
    val activeSurfaces by viewModel.activeSurfaces.collectAsState()
    LazyColumn(
        modifier = modifier.fillMaxWidth(),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        items(activeSurfaces) { surfaceModel ->
            Card(modifier = Modifier.fillMaxWidth()) {
                A2uiSurface(
                    surfaceModel = surfaceModel,
                    modifier = Modifier.fillMaxWidth().wrapContentHeight()
                )
            }
        }
    }
}

Теперь вы увидите несколько UI-поверхностей, сгенерированных агентом, работающим на сервере:

Интеллектуальные приложения для Android: агентские рабочие процессы внутри приложения

Хорошо спроектированный ассистент бронирования, который взаимодействует с пользователем через интерфейс, а не только через текст.

Собираем всё вместе

Размещая агентные сценарии в облаке и одновременно используя протоколы AG-UI и A2UI, можно создавать динамические нативные Android-интерфейсы, которыми напрямую управляют ИИ-модели. AG-UI предоставляет двунаправленный потоковый канал реального времени для сообщений и событий жизненного цикла, а A2UI позволяет облачному агенту динамически описывать интерактивные UI-компоненты. Благодаря этому клиентское приложение остаётся полностью отделено от пошаговой логики серверной оркестрации.

Посмотрите полный исходный код Jetpacker на GitHub и видео Build Intelligent Android apps with Google’s AI, чтобы подробнее узнать, как встраивать агентные сценарии непосредственно в приложение.

Другие части этой серии:

  • Часть 1: знакомство с приложением и общий обзор архитектуры.
  • Часть 2: ИИ на устройстве. Подробный разбор GenAI API в ML Kit и Gemini Nano для создания функций с приоритетом конфиденциальности: суммаризация маршрутов, разбор чеков и локальная обработка аудио.
  • Часть 3: гибридные и облачные рассуждения. Как использовать Firebase AI Logic, чтобы привязывать ответы LLM к реальным данным вроде Google Maps и веб-контекста.
  • Часть 4: интеграция с системой. Подключение к системе интеллектуальных функций Android через AppFunctions.
  • Часть 5 (эта статья!): агентные сценарии внутри приложения. Расширяем приложение полноценными ассистентами бронирования на базе A2UI и ADK.

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: