Renderowanie powierzchni A2UI w aplikacji

Gdy używasz renderera Jetpack Compose agent-to-UI (A2UI), agent AI wysyła wiadomości opisujące struktury interfejsu, właściwości komponentów i aktualizacje danych. Aby wyświetlać te interfejsy natywnie w aplikacji, musisz hostować i renderować powierzchnię A2UI w hierarchii Jetpack Compose aplikacji.

Renderowanie interfejsu Compose A2UI koordynuje analizowanie wiadomości, zarządzanie stanem reaktywnego zrzutu i animowane przejścia stanu powierzchni. Podstawowy moduł renderujący jest niezależny od konkretnego systemu projektowania, ale oferuje gotową integrację z Material Design 3 za pomocą dostarczonego katalogu podstawowego.

Inicjowanie warstwy danych opartej na Compose

Renderowanie A2UI obsługuje w warstwie danych aplikacji stan uwzględniający migawki, co pozwala interfejsowi aplikacji reagować na przyrostowe aktualizacje z agenta. Aby dodać tę obsługę, zainicjuj parser i procesor za pomocą funkcji fabrycznych A2uiMessageParserA2uiMessageProcessor w pliku ViewModel, jak pokazano w tym fragmencie kodu:

class AgenticUiViewModel : ViewModel() {
    // Create a parser that leverages the built-in JSON parser.
    private val parser = A2uiMessageParser()

    // Create an A2UI message processor with your catalog and optional
    // action interceptor (implementing A2uiActionInterceptor).
    private val processor = A2uiMessageProcessor(
        // You can also use the provided Material catalog instead of
        // a custom one.
        catalogs = listOf(CustomDesignSystemCatalog)
    )

    // Expose active surfaces to the UI as a StateFlow.
    val a2uiSurfaces: StateFlow<List<A2uiSurfaceModel>> =
        processor.activeSurfaces

    init {
        // Collect messages on a background thread tied to the ViewModel lifecycle.
        viewModelScope.launch(Dispatchers.Default) {
            processor.collectMessages()
        }

        // Add support for two-way communication with the agent.
        viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) {
            processor.outboundEvents.collect(::handleOutboundA2uiEvent)
        }
    }

    // Called by your app's networking layer or business logic whenever
    // a new A2UI protocol message arrives from the AI agent.
    fun onNetworkMessage(json: String) {
        processor.processInput(parser, json)
    }
}

Renderowanie powierzchni za pomocą katalogu podstawowego (Material Design 3)

Podczas renderowania platform za pomocą podanej implementacji katalogu podstawowego (androidx.compose.material3:material3-a2ui) możesz renderować w pełni ostylowaną platformę Material 3, w tym wbudowaną obsługę wskaźników ładowania, granic błędów i animowanych przejść. Aby to zrobić, użyj punktu wejścia komponentu A2uiSurface:

@Composable
fun AgenticUiScreen(viewModel: AgenticUiViewModel) {
    // Observe active surfaces managed by the data layer.
    val surfaces by viewModel.a2uiSurfaces.collectAsStateWithLifecycle()

    Column(Modifier.fillMaxSize()) {
        surfaces.forEach { surface ->
            key(surface.id) {
                A2uiSurface(
                    surfaceModel = surface,
                    // Add your surface's custom modifiers here.
                )
            }
        }
    }
}

Obsługa stanów powierzchni i animowanych przejść

A2uiSurface koordynuje rozpoznawanie stanu komponentu głównego i stosujeAnimatedContent przejścia między stanami wczytywania, błędu i powodzenia:

@Composable
fun CustomStyledSurface(surface: A2uiSurfaceModel) {
    A2uiSurface(
        surfaceModel = surface,
        modifier = Modifier.fillMaxSize(),
        loadingContent = {
            Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                CircularProgressIndicator()
            }
        },
        errorContent = { exception ->
            Text(
                text = "Failed to load: ${exception.message}",
                color = MaterialTheme.colorScheme.error,
                // Add your custom error styling, such as modifiers, here.
            )
        },
        transitionSpec = {
            (fadeIn(animationSpec = tween(600)) togetherWith
                    fadeOut(animationSpec = tween(600)))
                .using(SizeTransform(clip = false))
        },
    )
}

Renderowanie powierzchni niskiego poziomu za pomocą niestandardowych routerów

Stan komponentu głównego powierzchni możesz obserwować bezpośrednio za pomocą observeA2uiComponentState, a renderowanie możesz przekazać do A2uiComponent:

@Composable
fun RawSurfaceCoordinator(surface: A2uiSurfaceModel) {
    // Extract the catalog to provide its readiness evaluator to the
    // composition. This lets components wait for their dynamic data bindings
    // before they're rendered.
    val coreSurface = surface as? A2uiCoreSurfaceModel
        ?: throw IllegalArgumentException(
            "Surface must implement A2uiCoreSurfaceModel")
    val composeCatalog = coreSurface.catalog as? A2uiCatalog
        ?: throw IllegalArgumentException("Catalog must implement A2uiCatalog")
    val readinessEvaluator = remember(composeCatalog) {
        composeCatalog.asReadinessEvaluator() }

    CompositionLocalProvider(
        LocalA2uiReadinessEvaluator provides readinessEvaluator
    ) {
        val rootState = observeA2uiComponentState(surface = surface)
        when (rootState) {
            is A2uiComponentState.Loading -> {
                LoadingSpinner()
            }
            is A2uiComponentState.Error -> {
                ErrorBanner(rootState.exception)
            }
            is A2uiComponentState.Success -> {
                // Delegate component routing to the Compose A2UI router.
                A2uiComponent(
                    component = rootState.component,
                    // Add your custom modifiers here.
                )
            }
        }
    }
}

Szczegóły implementacji

Moduł renderujący interfejsu użytkownika agenta obsługuje rozwiązywanie stanu powierzchni i granice błędów obronnych.

Ochronne granice błędów i obsługa halucynacji agenta

Ponieważ interfejsy A2UI są obsługiwane przez generatywne modele LLM, przychodzące ładunki mogą być nieprawidłowo sformatowane lub odwoływać się do nieznanych typów komponentów.

Proces renderowania ustanawia te granice ochronne, aby zminimalizować prawdopodobieństwo awarii:

  • Wysyłanie błędów w celu samodzielnego poprawiania przez agenta: błędy są wysyłane jako wychodzące wiadomości klienta, co umożliwia agentowi samodzielne poprawianie błędów w kolejnych turach interakcji. Istnieje też interfejs API, który umożliwia implementacjom komponentów wysyłanie błędów do agenta w przypadkach, gdy interfejs API wykryje błędy specyficzne dla komponentu w czasie renderowania.
  • Nieznane komponenty: gdy napotkany zostanie nierozpoznany typ komponentu, zostanie on przechwycony, zanim dotrze do drzewa interfejsu, oznaczony jako stan błędu i zgłoszony z powrotem do agenta w celu samodzielnego skorygowania.
  • Błędy weryfikacji schematu: ładunki są weryfikowane pod kątem schematów komponentów (A2uiSchema). Nieprawidłowe właściwości nigdy nie powinny trafiać do układów interfejsu Compose.
  • Ochrona przed rzadkimi tablicami: gdy otrzymywane są bardzo duże indeksy list, model danych przechodzi z gęstej listy na adaptacyjną rzadką mapę, co zapobiega błędom braku pamięci.