앱에서 A2UI 노출 영역 렌더링

Jetpack Compose 에이전트-UI (A2UI) 렌더러를 사용하는 경우 AI 에이전트는 UI 구조, 구성요소 속성, 데이터 업데이트를 설명하는 메시지를 전송합니다. 앱에서 이러한 인터페이스를 네이티브로 표시하려면 앱의 Jetpack Compose 계층 구조 내에서 A2UI 표시를 호스팅하고 렌더링합니다.

Compose A2UI 렌더러는 메시지 파싱, 반응형 스냅샷 상태 관리, 애니메이션 표면 상태 전환을 조정합니다. 핵심 렌더러는 특정 디자인 시스템과 독립적이지만 제공된 기본 카탈로그를 통해 Material Design 3와의 기본 통합을 제공합니다.

Compose 지원 데이터 영역 초기화

A2UI 렌더러는 앱의 데이터 레이어에서 스냅샷 인식 상태를 지원하므로 앱의 UI가 에이전트의 증분 업데이트에 반응할 수 있습니다. 이 지원을 추가하려면 다음 코드 스니펫에 표시된 대로 ViewModel에서 A2uiMessageParserA2uiMessageProcessor 팩토리 함수를 사용하여 파서와 프로세서를 초기화합니다.

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

기본 카탈로그 (Material 3)를 사용하여 노출 영역 렌더링

제공된 기본 카탈로그 구현(androidx.compose.material3:material3-a2ui)을 사용하여 서페이스를 렌더링할 때 로드 표시기, 오류 경계, 애니메이션 전환을 위한 기본 지원을 비롯한 완전히 스타일이 지정된 Material 3 서페이스를 렌더링할 수 있습니다. 이렇게 하려면 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.
                )
            }
        }
    }
}

노출 영역 상태 및 애니메이션 전환 처리

A2uiSurface는 루트 구성요소 상태 확인을 조정하고 로드, 오류, 성공 상태 전반에 AnimatedContent 전환을 적용합니다.

@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))
        },
    )
}

맞춤 라우터를 사용한 하위 수준 표면 렌더링

observeA2uiComponentState를 사용하여 서피스 루트 구성요소 상태를 직접 관찰하고 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.
                )
            }
        }
    }
}

구현 세부정보

에이전트-UI 렌더러는 화면 상태 해결과 방어적 오류 경계를 처리합니다.

방어적 오류 경계 및 에이전트 환각 처리

A2UI 표시 영역은 생성형 LLM 에이전트에 의해 구동되므로 수신 페이로드가 형식이 잘못되었거나 알 수 없는 구성요소 유형을 참조할 수 있습니다.

렌더러는 비정상 종료 가능성을 최소화하기 위해 다음과 같은 방어 경계를 설정합니다.

  • 상담사 자체 수정을 위한 오류 디스패치: 오류가 아웃바운드 클라이언트 메시지로 디스패치되어 상담사가 후속 상호작용 턴에서 자체 수정할 수 있습니다. 렌더링 시간에 API가 구성요소별 오류를 감지하는 경우 구성요소 구현이 에이전트에 오류를 디스패치할 수 있는 API도 있습니다.
  • 알 수 없는 구성요소: 인식할 수 없는 구성요소 유형이 발견되면 UI 트리에 도달하기 전에 가로채서 오류 상태로 표시하고 자체 수정할 수 있도록 에이전트에 다시 보고합니다.
  • 스키마 검사 실패: 페이로드는 구성요소 스키마 (A2uiSchema)에 대해 검사됩니다. 형식이 잘못된 속성은 Compose UI 레이아웃에 도달해서는 안 됩니다.
  • 스파스 배열 보호: 매우 큰 목록 색인이 수신되면 데이터 모델이 밀도 높은 목록에서 적응형 스파스 맵으로 전환되어 메모리 부족 오류를 방지합니다.