Lorsque vous utilisez le moteur de rendu A2UI (agent-to-UI) Jetpack Compose, un agent d'IA envoie des messages qui décrivent les structures d'UI, les propriétés des composants et les mises à jour des données. Pour afficher ces interfaces de manière native dans votre application, vous hébergez et affichez une surface A2UI dans la hiérarchie Jetpack Compose de votre application.
Le moteur de rendu A2UI de Compose coordonne l'analyse des messages, la gestion de l'état des instantanés réactifs et les transitions d'état des surfaces animées. Bien que le moteur de rendu principal soit indépendant de tout système de conception spécifique, il offre une intégration prête à l'emploi avec Material Design 3 grâce au catalogue de base fourni.
Initialiser la couche de données basée sur Compose
Le moteur de rendu A2UI est compatible avec l'état prenant en compte les instantanés dans la couche de données de votre application, ce qui permet à l'UI de votre application de réagir aux mises à jour incrémentielles de l'agent. Pour ajouter cette prise en charge, initialisez l'analyseur et le processeur à l'aide des fonctions de fabrique A2uiMessageParser et A2uiMessageProcessor dans votre ViewModel, comme indiqué dans l'extrait de code suivant :
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)
}
}
Afficher des surfaces à l'aide du catalogue de base (Material 3)
Lorsque vous affichez des surfaces à l'aide de l'implémentation Basic Catalog fournie (androidx.compose.material3:material3-a2ui), vous pouvez afficher une surface Material 3 entièrement stylisée, y compris la prise en charge intégrée des indicateurs de chargement, des limites d'erreur et des transitions animées. Pour ce faire, utilisez le point d'entrée composable 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.
)
}
}
}
}
Gérer les états de surface et les transitions animées
A2uiSurface coordonne la résolution de l'état du composant racine et applique les transitions AnimatedContent entre les états de chargement, d'erreur et de réussite :
@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))
},
)
}
Rendu de surface de bas niveau avec des routeurs personnalisés
Vous pouvez observer l'état du composant racine de surface directement avec observeA2uiComponentState et déléguer le rendu à 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.
)
}
}
}
}
Détails de mise en œuvre
Le moteur de rendu de l'agent vers l'UI gère la résolution de l'état de la surface et les limites d'erreur défensives.
Limites d'erreur défensives et gestion des hallucinations des agents
Étant donné que les surfaces A2UI sont gérées par des agents LLM génératifs, les charges utiles entrantes peuvent être mal formées ou faire référence à des types de composants inconnus.
Le moteur de rendu établit les limites défensives suivantes pour minimiser le risque de plantages :
- Envoi d'erreurs pour l'autocorrection de l'agent : les erreurs sont envoyées sous forme de messages client sortants, ce qui permet à l'agent de s'autocorriger lors des tours d'interaction suivants. Il existe également une API qui permet aux implémentations de composants d'envoyer des erreurs à l'agent dans les cas où l'API détecte des erreurs spécifiques aux composants au moment du rendu.
- Composants inconnus : lorsqu'un type de composant non reconnu est détecté, il est intercepté avant d'atteindre l'arborescence de l'UI, marqué comme étant en état d'erreur et renvoyé à l'agent pour auto-correction.
- Échecs de validation du schéma : les charges utiles sont validées par rapport aux schémas de composants (
A2uiSchema). Les propriétés mal formées ne doivent jamais atteindre les mises en page de l'UI Compose. - Protection des tableaux creux : lorsque des index de liste très volumineux sont reçus, le modèle de données passe d'une liste dense à une carte creuse adaptative, ce qui évite les erreurs de mémoire insuffisante.