지능형 앱

A2UI를 사용하여 Android 앱에서 에이전트가 UI를 생성하도록 허용

스피커

정보

강연 소개

A2UI가 웹 중심 구성요소에서 네이티브 Android로 전환되고 있습니다. A2UI v0.9의 새로운 Jetpack Compose 렌더러를 사용하면 개발자가 LLM에서 생성한 동적 UI를 네이티브로 렌더링할 수 있습니다. 웹뷰 대신 코루틴 기반 액터 프레임워크, sealed 클래스 수명 주기, 네이티브 Material 3 통합을 활용합니다.

이 세션에서는 새로운 아키텍처를 살펴보고, 서버 기반 구성요소 트리가 반응형 Compose 노드로 변환되는 방식과 기본 제공 레이아웃 전환이 UI를 차단하지 않고 구조적 업데이트를 원활하게 처리하는 방식을 설명합니다.

요약

  • A2UI는 에이전트 백엔드가 텍스트 응답 대신 동적 사용자 인터페이스를 설명할 수 있도록 선언적 개방형 JSON 프로토콜을 제공합니다.
  • 이 프로토콜은 허용되는 구성요소와 함수를 정의하는 카탈로그와 에이전트 제어 UI 요소를 나타내는 표시 경로를 중심으로 작동합니다.
  • Jetpack Compose의 A2UI 라이브러리는 내장된 접근성과 점진적 렌더링을 갖춘 Material 3 구성요소를 사용하여 스트리밍된 표시 경로 모델을 기본적으로 렌더링합니다.
  • 인메모리 데이터 모델은 에이전트에 연결하지 않고도 바인딩된 UI 요소를 즉시 업데이트하며, 아웃바운드 이벤트는 사용자 작업을 다시 라우팅합니다.
  • 개발자는 기존 카탈로그 항목을 맞춤설정하거나 커스텀 구성요소를 만들어 에이전트가 표시할 수 있는 항목을 엄격하게 제어할 수 있습니다.

리소스

Gemini Notebook

주제

  • a2ui
  • generative-ui
  • jetpack-compose
  • Android
  • ai-agents
  • material-design

스크립트

생성형 UI 및 A2UI 소개

  • 안녕하세요. 이번 세션에서는 새로운 A2UI 라이브러리를 사용하여 Android 앱에서 UI를 생성하는 방법을 알아보겠습니다.

  • 저는 Jetpack Compose를 담당하는 제품 관리자 닉 부처입니다.

  • 안녕하세요. 저는 Compose팀의 엔지니어인 안톤입니다.

  • 저는 새로운 Jetpack Compose A2UI 렌더러를 개발하고 있으며, 오늘 이 렌더러를 소개해 드리게 되어 매우 기쁩니다.

  • 예, AI 기능이 발전함에 따라 많은 앱에서 AI를 활용하여 사용자 경험을 개선하거나 새로운 경험을 구축하는 방법을 모색하고 있습니다.

  • 일부 사용자가 주목하는 흥미로운 경험 중 하나는 생성형 UI입니다. 이는 런타임에 에이전트 백엔드가 사용자를 위해 완전히 새로운 UI를 생성하는 방식으로, 매우 흥미로운 기술이라고 생각합니다.

  • 하지만 안타깝게도 현재 많은 에이전트 백엔드의 응답은 이와 같이 텍스트로 가득한 화면에 갇혀 있습니다.

  • 여기서는 에이전트에게 여행 예약이라는 새로운 기능을 생성해 달라고 요청한 예시입니다.

  • 프롬프트는 다음과 같습니다.

  • 보시다시피 꽤 괜찮은 답변을 제공하지만, 쉽게 상호작용할 수 없는 텍스트 벽에 갇혀 있으며 애플리케이션의 나머지 부분과 전혀 다르게 보입니다.

  • 생성형 UI를 사용하면 동적 입력에 대한 응답으로 즉시 새로운 UI를 생성할 수 있어 더 많은 맞춤설정이나 새로운 경험을 제공할 수 있습니다.

  • 다음은 표준 네이티브 구성요소를 사용하여 만든 UI의 예입니다.

  • 따라서 지금도 이러한 환경을 직접 구축할 수 있지만 백엔드와의 교환을 위한 자체 형식, 자체 이벤트 스트림, 함수 등을 정의해야 합니다.

  • A2UI(Agent-to-UI)는 이 모든 것을 정의하는 JSON 형식의 개방형 프로토콜입니다.

  • A2UI에서 정말 마음에 드는 점 중 하나는 선언적 형식이라는 것입니다.

  • 에이전트는 렌더링할 UI의 JSON 표현을 반환할 뿐입니다.

  • 클라이언트가 실행해야 하는 코드를 반환하지 않으므로 특정 보안 취약점에 노출될 수 있습니다.

  • 선언적입니다.

  • 그렇다면 A2UI에 대해 알아야 할 다른 개념은 무엇일까요?

핵심 개념: 카탈로그 및 표시 경로

  • 카탈로그와 표시 경로라는 두 가지 주요 개념만 있습니다.

  • 카탈로그에는 에이전트가 UI를 빌드하는 데 사용할 수 있는 텍스트, 버튼, 행, 열과 같은 구성요소가 있습니다.

  • 카탈로그에는 에이전트가 텍스트 형식을 지정하거나, 사용자 입력을 검증하거나, URL을 여는 데 사용할 수 있는 함수도 있습니다.

  • 카탈로그는 앱에서 지원하는 구성요소와 함수를 정의하는 계약이며, 에이전트는 이러한 구성요소와 함수만 사용하여 빌드할 수 있습니다.

  • 즉, 닉이 언급한 것처럼 에이전트는 앱에서 임의의 코드를 실행하지 않습니다.

  • 설계하고 신뢰하는 구성요소로 UI를 구성합니다.

  • 또 다른 중요한 개념은 표시 경로입니다.

  • 표면은 슬라이드의 여행 플래너 예시와 같이 에이전트가 제어하는 UI의 한 부분입니다.

  • 에이전트는 A2UI 프로토콜 메시지(예: createSurface, updateComponents)를 사용하고 카탈로그에 정의된 구성요소와 함수를 사용하여 JSON으로 표시되는 UI를 설명합니다.

  • 카탈로그는 에이전트가 인터페이스를 구성하는 데 사용할 수 있는 구성요소를 제어하므로 A2UI에서 매우 기본적인 개념입니다.

  • A2UI 사양은 대부분의 UI를 구성하는 데 사용할 수 있는 공통 구성요소 집합인 기본 카탈로그를 정의합니다.

  • Jetpack Compose A2UI 렌더러는 Material 3 구성요소를 사용하여 기본 카탈로그를 구현합니다.

  • 대부분의 카탈로그 구성요소는 즉시 사용할 수 있습니다.

  • 이미지, 동영상, 오디오 플레이어의 세 가지 미디어 구성요소가 있으며, 여기에 원하는 라이브러리를 연결해야 합니다.

  • 예를 들어 이미지 로드에는 Coil을, 동영상 및 오디오 플레이어에는 Media3를 선택할 수 있습니다.

  • 하지만 A2UI와 새로운 렌더러 라이브러리의 진정한 강점은 완전히 맞춤설정된 자체 구성요소와 카탈로그를 만들고 에이전트가 UI를 빌드하는 데 사용할 수 있는 요소를 완전히 제어할 수 있다는 점입니다.

  • 카탈로그는 나중에 다시 살펴보겠습니다.

  • 그럼 어떻게 보이는지 살펴보겠습니다.

  • 데모 기기로 전환해 주세요.

  • 이 앱은 우리가 사용할 데모 앱이며, A2UI 렌더러를 빌드하여 얼마나 쉬운지 보여드리겠습니다.

  • 화면 중앙에 있는 작은 칩에서 볼 수 있듯이 에이전트에 보낼 수 있는 프롬프트 집합입니다.

  • 따라서 프롬프트 중 하나를 클릭하면 해당 프롬프트가 실제 상담사 백엔드로 전송됩니다. 데모가 잘 작동하기를 바랍니다. 프롬프트 외에도 몇 가지 시스템 안내도 추가합니다.

  • 따라서 백엔드에 A2UI 프로토콜과 구성요소 카탈로그(이 경우 여기에서 사용하는 기본 카탈로그)에 대해 알려주고, 이를 사용하여 UI를 빌드할 수 있도록 하며, 이를 빌드하는 방법에 대한 몇 가지 예시를 제공합니다.

  • 데모 앱의 채팅 세션 구현은 이미 에이전트의 대답에서 원시 JSON A2UI 메시지를 추출하는 방법을 알고 있습니다.

  • 이 경우 에이전트는 텍스트와 함께 A2UI 프로토콜 메시지(createSurface, updateComponents)로 대답했습니다.

  • 하지만 현재 앱은 이 원시 JSON을 표시할 뿐 아직 UI로 렌더링하지는 않습니다.

  • 코드를 구현하기 전에 잠시 슬라이드로 돌아가서 이 구현에 사용할 시스템 설계에 대해 알아보겠습니다.

  • 아, 여기 있네요.

애플리케이션 아키텍처 및 메시지 처리

  • 계획은 이렇습니다.

  • 따라서 AI 에이전트는 ChatSession 클래스에서 수신하는 응답을 앱으로 스트리밍합니다.

  • ChatSession은 에이전트의 응답이 스트리밍될 때 응답에서 원시 A2UI JSON 메시지를 추출하여 A2UI 메시지 프로세서에 전달합니다.

  • 메시지 프로세서는 원시 JSON 메시지를 시맨틱 표현으로 변환하는 파서로 구성됩니다.

  • 그런 다음 프로세서는 카탈로그 정의를 기준으로 메시지를 검증하고 이를 표시 경로 모델 집합에 매핑합니다.

  • 표면 모델은 UI의 모양과 에이전트가 제어하는 UI 요소를 정의합니다.

  • 그런 다음 이러한 표시 경로 모델은 라이브러리에서 제공하는 A2UI 표시 경로 컴포저블을 사용하여 네이티브 Compose UI로 렌더링됩니다.

  • 에이전트와 UI 간의 통신은 양방향이므로 사용자가 UI와 상호작용할 때 사용자 작업과 오류가 에이전트로 다시 전달됩니다.

  • 요약하자면 카탈로그, 메시지 프로세서, 표시 영역이라는 세 가지 주요 구성요소가 있습니다.

  • 코드를 작성해 보겠습니다.

  • 네, 기계를 바꿀 수 있다면 만들어 보죠.

  • 첫 번째 단계는 종속 항목을 추가하는 것입니다.

  • 여기에서 Material 3 A2UI 종속 항목이 이미 포함되어 있고 프로젝트가 이미 동기화되어 있으므로 Gradle을 지켜볼 필요가 없습니다.

  • 이는 Material 3 구성요소를 사용하여 기본 카탈로그의 구현을 정의하는 최상위 종속 항목이지만, 그 아래에는 더 세분화된 다른 종속 항목이 있습니다.

  • 따라서 기본 카탈로그를 사용하지 않으려면(이유는 나중에 설명) 더 세분화된 카탈로그를 사용할 수 있습니다.

  • 하지만 이렇게 하면 나머지가 전이적으로 가져와집니다.

  • 좋습니다.

  • 세 가지가 있다고 말씀드렸습니다.

  • 첫 번째 단계는 카탈로그를 정의하는 것이었습니다.

  • 따라서 애플리케이션에서 기본 카탈로그의 Material 3 구현 인스턴스를 빌드하는 데 도움이 되는 팩토리 함수를 만들겠습니다.

  • 따라서 여기서는 버전이 지정된 라이브러리 함수인 Material A2UI 기본 카탈로그를 사용합니다.

  • 앞서 말씀드렸듯이 이 라이브러리는 필요한 모든 공통 구성요소를 제공하지만, 특정 이미지 로드 라이브러리나 미디어 렌더링 라이브러리를 사용하도록 강제하지는 않으므로 직접 제공해야 합니다.

  • 예를 들어 여기에서 안톤은 이미 Coil의 AsyncImage 컴포저블을 둘러싼 래퍼를 만들었습니다. 이 래퍼는 이미지를 로드하는 데 사용되며, 데모에서 위키백과의 이미지를 조회하는 데 사용되는 약간의 추가 로직도 포함되어 있습니다.

  • 따라서 이를 카탈로그 구성요소에 매우 쉽게 연결할 수 있습니다.

  • 마찬가지로 렌더링, 동영상, 오디오에도 유사한 구현이 있으며, Media3 라이브러리를 사용하여 ExoPlayer로 렌더링합니다.

  • 이렇게 아주 간단하게 자체 구성요소를 연결할 수 있습니다.

  • 카탈로그에 필요한 다음 요소는 표준 함수 집합입니다.

  • 즉, 클라이언트가 제공할 수 있는 기능입니다.

  • 기본 카탈로그와 함께 이 구현을 제공하지만, 사용자가 항목을 탭하면 URI를 여는 것과 같은 특정 작업을 수행하는 데 사용할 컨텍스트를 제공해야 합니다.

  • 이렇게 첫 번째 단계가 완료되었습니다.

  • 카탈로그를 만들었습니다.

  • 다음 단계는 메시지 프로세서를 설정하는 것입니다.

  • 이것이 실제로 응답 등을 파싱하는 것입니다.

  • 애플리케이션의 뷰 모델로 전환하여 이전에 설정한 카탈로그를 인스턴스화합니다. 이 카탈로그가 필요하기 때문입니다.

  • 그런 다음 이 메시지 파서, 메시지 프로세서 객체를 만듭니다. 이 객체는 사용하려는 구성요소에 대해 응답의 유효성을 검사하기 위해 카탈로그에 액세스해야 합니다.

  • 만들어야 하는 또 다른 구성요소는 파서입니다. 파서는 실제로 JSON 메시지가 반환될 때 파싱을 수행하는 객체입니다.

  • 여기에서 ChatSession 객체를 만듭니다.

  • 앞서 언급했듯이 ChatSession은 이미 에이전트의 응답에서 원시 A2UI 메시지를 추출합니다.

  • 그리고 새로운 A2UI 메시지가 준비되면 이 onA2uiMessage 콜백을 호출합니다.

  • 따라서 각 메시지가 도착하면 프로세서에 전달하기만 하면 됩니다.

  • processInput 함수를 호출하고 파서와 메시지를 전달합니다.

  • 따라서 processInput 함수는 각 메시지를 파싱한 다음 프로세서가 카탈로그와 비교하여 검증하고 표시 경로 모델을 업데이트할 수 있도록 작업을 큐에 추가합니다.

  • 따라서 프로세서는 현재 활성 표면 모델 집합을 activeSurfaces StateFlow로 노출합니다.

  • ChatSession에는 렌더링할 에이전트 답장의 UI 상태에 표시 모델을 추가하는 로직이 있습니다.

  • 따라서 이 activeSurfaces StateFlow를 ChatSession에 매개변수로 전달하면 됩니다.

  • 또한 앞서 언급했듯이 processInput 함수는 프로세서의 작업을 큐에 추가합니다.

  • 하지만 실제로 처리를 시작하려면 백그라운드 스레드에서 코루틴을 실행해야 합니다.

  • 따라서 뷰 모델 범위를 사용하고 기본 디스패처를 설정합니다.

  • 그리고 이 코루틴에서 processor.collectMessages를 호출하기만 하면 됩니다.

  • 따라서 이 코루틴이 활성 상태인 동안 프로세서는 메시지 큐에서 메시지를 처리합니다.

  • 따라서 사용자가 채팅 기록을 지울 때 현재 표시 영역도 지워야 합니다.

  • 따라서 clearSurfaces를 호출합니다.

UI에서 표면 모델 렌더링

  • 좋습니다.

  • 처음 두 단계를 완료했습니다.

  • 카탈로그를 만들고 메시지를 파싱하는 프로세서를 만들었습니다.

  • 다음 단계는 UI에 이러한 응답을 실제로 렌더링하는 것입니다.

  • 따라서 파서에서 파싱되는 표면을 수집합니다.

  • 이제 UI에서 이 에이전트 응답 객체에 이를 전달하고 반복합니다.

  • 그런 다음 이 A2UI Surface 컴포저블을 사용하고 각 모델을 반복하면서 모델을 전달하여 원하는 위치에 콘텐츠를 렌더링합니다.

  • 여기서 한 가지 유의할 점은 에이전트가 많은 양의 콘텐츠를 표시하기로 선택한 경우 목록과 같은 것을 사용하도록 선택할 수 있다는 것입니다.

  • 따라서 이 구성요소에 제한된 높이를 최대 높이로 설정하여 제대로 렌더링되도록 해야 합니다.

  • 이렇게 해서 기본 A2UI 렌더러를 구현했습니다.

  • 이제 앱으로 돌아가서 다시 실행하고 프롬프트를 다시 입력하면 에이전트가 이를 사용하여 실제 UI를 렌더링할 것입니다.

  • 그래서 실시간으로 코딩합니다.

  • 이것은 눈속임이 아닙니다.

  • 하지만 실제 이미지를 사용합니다.

  • 탭, 대화상자, 날짜 선택 도구, 슬라이더 등 앱을 빌드할 때 사용하는 모든 표준 Material 구성요소를 사용하여 텍스트 응답만 표시하는 대신 앱을 빌드합니다.

  • 실제 Material 구성요소를 사용하는 실제 앱이므로 실제 구성요소가 하는 일을 합니다.

  • 네이티브 성능을 제공합니다.

  • 여기에서 어두운 모드에 응답하는 등의 작업을 수행합니다.

  • 이것이 Material 구성요소입니다.

  • 따라서 색상, 도형, 서체 등을 맞춤설정한 외부 Material 테마 컴포저블이 있는 경우 이러한 구성요소는 이를 선택하여 애플리케이션의 나머지 부분과 동일하게 표시됩니다.

  • 닉이 언급했듯이 이러한 구성요소는 네이티브 Compose 구성요소이므로 네이티브 시맨틱스를 갖습니다.

  • 즉, Compose의 모든 내장 접근성 기능이 지원됩니다.

  • 따라서 TalkBack, 글꼴 크기 조정, 키보드 탐색과 같은 기능이 기본적으로 작동합니다.

  • 런타임에 에이전트를 호출하여 새 UI를 생성하므로 지연 시간이 발생할 수 있습니다.

  • 상담사가 응답할 때까지 기다려야 할 수도 있습니다.

  • 라이브러리는 이 지연 시간을 최소화하기 위해 최선을 다합니다.

  • 따라서 이러한 종류의 대기 시간을 삽입하여 조금 더 천천히 보여주고 이를 최소화하는 방법을 보여드리겠습니다.

  • 예, 에이전트가 전체 응답을 스트리밍하는 데 시간이 걸릴 수 있으므로 점진적 렌더링이라는 것을 사용합니다.

  • 따라서 루트 구성요소가 도착하는 즉시 노출 영역의 UI가 표시되기 시작합니다.

  • 모든 컨테이너 구성요소는 하위 요소가 아직 도착하지 않은 경우 하위 요소의 로드 자리표시자를 표시합니다.

  • 하위 구성요소가 도착하면 Material 3 모션 스키마를 사용하여 애니메이션이 적용됩니다.

  • 좋습니다.

  • 라이브러리의 다른 기능을 보여주기 위해 다음 프롬프트로 전환할 수 있습니다.

  • 저녁 식사 테이블을 예약하는 또 다른 프롬프트입니다.

  • 여기서 에이전트는 이 슬라이더 구성요소를 사용하기로 선택합니다. 네, 사용했습니다.

  • 여기에서 에이전트가 즉석에서 만든 UI를 드래그하고 상호작용할 수 있습니다.

  • 구성요소의 숫자만 변경하는 것이 아니라 아래에 있는 형식 문자열도 계산하고 있습니다.

  • 그렇다면 업데이트를 위해 에이전트로 다시 돌아가는 왕복 작업이 아니라는 말씀이시죠?

  • 이는 양방향 결합입니다.

  • 따라서 슬라이더 구성요소는 이 표시 경로의 인메모리 데이터 모델에 바인딩됩니다.

  • 값이 변경되면 데이터 모델의 동일한 경로에 바인딩된 모든 구성요소가 자동으로 업데이트됩니다.

  • 따라서 슬라이더는 표시할 값을 읽고, 슬라이더를 드래그하면 모델에 다시 기록하여 업데이트합니다.

  • 이 모든 작업은 에이전트로 왕복하지 않고 로컬에서 이루어집니다.

  • 하지만 에이전트에게 데이터를 업데이트하도록 요청할 수도 있습니다.

  • 6명으로 하겠습니다.

  • 에이전트가 대답할 때 슬라이더에 주의를 기울입니다.

  • 6으로 증가했습니다.

  • 상담사로부터 받은 내용을 살펴보겠습니다.

  • 에이전트는 UI에 대한 완전히 새로운 설명을 보내는 대신 슬라이더의 경로를 업데이트하는 작은 메시지 updateDataModel 하나만 보냈습니다.

  • 슬라이더가 해당 경로에 바인딩되어 있으므로 제자리에서 업데이트되었습니다.

  • 따라서 각 표시 경로의 데이터 모델은 Compose 스냅샷 상태를 기반으로 빌드되며 경로에 바인딩된 각 구성요소 속성은 파생 상태입니다.

  • 따라서 사용자 또는 에이전트가 데이터 모델의 값을 업데이트할 때마다 동일한 값에 결합된 모든 구성요소가 자동으로 재구성됩니다.

  • 좋습니다.

  • 그럼 조치를 취하고 예약 버튼을 누르면 어떻게 되나요, 안톤?

  • 현재는 아무 일도 일어나지 않습니다.

  • 버튼이 작업을 전달하지만 아직 에이전트에 전송하지는 않습니다.

  • 이 문제를 해결해 보겠습니다.

사용자 작업 및 이벤트 흐름 처리

  • 입력을 처리하기 위해 프로세서에 연결해야 했던 것처럼, 에이전트가 만든 UI에서 사용자가 수행하는 모든 작업, 즉 모든 출력에도 연결해야 합니다.

  • 이를 위해 프로세서가 노출하는 outboundEvents 흐름을 사용하고 이를 수집합니다.

  • 따라서 사용자가 작업을 탭하거나 UI로 무언가를 수행할 때 원하는 로직을 연결할 수 있습니다.

  • 여기서는 에이전트에게 작업을 다시 전송하여 수행할 작업을 결정하지만, 이 시점에서 자체 백엔드를 호출할지 아니면 애플리케이션의 다른 화면으로 이동할지 결정할 수도 있습니다.

  • 여기에서 안톤이 연결했으므로 이제 예약 확인 작업을 누르면 수행한 작업이 에이전트로 다시 전송됩니다.

  • 이때 백엔드에서 일부 기능을 호출하도록 결정할 수도 있습니다.

  • 에이전트에 실제로 전송되는 내용을 살펴보겠습니다.

  • 이것이 A2UI 액션 메시지입니다.

  • 컨텍스트가 있으며, 컨텍스트에는 이 작업이 수행될 때 에이전트가 전송을 요청한 속성 집합이 포함됩니다.

  • 따라서 버튼을 클릭하면 데이터 모델의 현재 값을 기반으로 해당 속성이 확인되고 에이전트에 전송됩니다.

  • 지금까지는 에이전트가 상당히 협조적이었지만, AI는 실수를 할 수 있습니다.

  • 에이전트가 UI에서 실수를 저지르고 이를 다시 설명하는 경우 어떤 일이 발생하는지 살펴보겠습니다.

  • 마지막 프롬프트에서는 시연을 위해 에이전트에게 오류를 발생시키도록 요청합니다.

  • 어떻게 되는지 살펴보겠습니다.

  • 네.

  • 보시다시피 구성요소 중 하나에 오류가 표시되어 있습니다.

  • 이제 문제가 해결되었습니다.

  • 이것이 에이전트 자체 수정 루프입니다.

  • 각 구성요소가 UI에 도달하기 전에 카탈로그 스키마를 기준으로 메시지를 검증합니다.

  • 구성요소가 스키마와 일치하지 않으면 오류로 표시됩니다.

  • 기본 카탈로그 구현의 렌더러는 해당 특정 구성요소에만 오류가 발생하고 나머지 UI는 계속 표시됨을 보여줍니다.

  • 내부적으로 렌더러는 에이전트에 오류 메시지를 전송하여 무엇이 잘못되었는지 에이전트에 알립니다.

  • 따라서 이 경우 존재하지 않는 알 수 없는 구성요소 유형이 카탈로그에 없다는 메시지가 전송되었습니다.

  • 그런 다음 에이전트는 기존 UI를 업데이트하는 후속 응답을 보내고 UI가 제자리에 고정되었습니다.

  • 네.

  • Material 기본 카탈로그의 현재 구현에서는 오류가 즉시 표시되지만, 커스텀 구성요소에서는 에이전트가 오류를 수정하는 동안 구성요소의 로딩 표시기를 계속 표시하도록 결정할 수 있습니다.

  • 이렇게 하면 오류가 사용자에게 완전히 숨겨질 수 있습니다.

커스텀 구성요소 만들기 및 카탈로그 확장

  • 카탈로그와 커스텀 구성요소에 대해 말씀드리자면, 지금까지는 기본 카탈로그를 기본 제공되는 그대로 사용해 왔지만, 물론 필요에 맞게 맞춤설정할 수도 있습니다.

  • 팩토리 함수를 사용하여 카탈로그를 만들면 모든 구성요소에 기본값이 적용되는 것을 확인할 수 있습니다.

  • 따라서 원하는 경우 자체 구성요소를 쉽게 연결할 수 있습니다.

  • 예를 들어 앱에 자체 디자인 시스템과 자체 버튼이 있는 경우 자체 버튼을 쉽게 연결할 수 있습니다.

  • 따라서 카탈로그 인스턴스를 만들 때 이 매개변수를 재정의하고 이 구성요소 정의를 만듭니다.

  • 이를 구현하기 위해 새 클래스를 만들면 여기에 A2UI 기본 카탈로그 유형 버튼 인터페이스가 표시됩니다.

  • 따라서 이를 구현하면 자체 구성요소를 연결할 수 있습니다.

  • 네.

  • 기본 카탈로그의 구성요소를 재정의하므로 이 A2UI 기본 카탈로그 버튼 인터페이스를 구현해야 합니다.

  • 이 인터페이스에는 이미 이름, 설명, 속성 스키마와 같은 구성요소에 관한 정보가 있습니다.

  • 따라서 자체 버전을 구현하려면 이 컴포저블 함수를 구현하기만 하면 됩니다.

  • 몇 가지 매개변수를 사용합니다.

  • 따라서 이러한 파라미터는 검증 후 에이전트로부터 수신된 값입니다.

  • 여기에는 버튼의 콘텐츠가 될 구성요소를 참조하는 하위 ID 등이 있습니다.

  • 또한 버튼 유형, 작업 정의, 기타 매개변수를 설명하는 변형도 있습니다.

  • 버튼을 프로덕션에 구현할 때는 이러한 매개변수를 모두 사용해야 하지만 데모에서는 하위 요소와 작업만 있으면 됩니다.

  • 이 컴포저블을 구현해 보겠습니다.

  • 이 컴포저블 함수에서 맞춤 좋아요 버튼 유형을 내보내겠습니다.

  • 보시다시피 A2UI에서 제공하고 검증한 매개변수를 사용할 수 있습니다.

  • 예를 들어 onClick 함수에서 이 작업을 전달할 수 있습니다.

  • 이 라이브러리 유형 DispatchAction을 사용하여 A2UI가 정의한 작업을 전달할 수 있습니다.

  • 따라서 자체 버튼을 사용하지만 하위 콘텐츠, 라벨 또는 에이전트가 사용하기로 결정한 모든 항목을 렌더링하려고 합니다.

  • 이를 위해 observeA2uiComponentState 함수를 사용하고 childId를 전달하여 렌더링해야 하는 하위 콘텐츠에 대한 핸들을 가져옵니다.

  • 그런 다음 이 A2uiComponent 컴포저블 함수를 사용하고 하위 구성요소 상태를 전달하여 렌더링합니다.

  • 여기에서는 성공적으로 로드된 경우에만 하위 콘텐츠를 렌더링하지만, 로드 중이거나 오류 상태인 경우 표시할 내용을 결정하는 자체 로직을 여기에 포함할 수도 있습니다.

  • 데모 앱의 예시 프롬프트 중 하나로 돌아가서 표준 Material 버튼을 사용하여 버튼을 교체해 보겠습니다.

  • 아주 미묘한 차이입니다.

  • 여기에서도 매우 맞춤설정된 버튼을 사용하고 있습니다.

  • 좋습니다. 이렇게 하면 라이브러리 유형 중 일부를 대체할 수 있습니다. 하지만 자체 맞춤 유형으로 라이브러리를 확장하려면 어떻게 해야 할까요?

  • 카탈로그 자체에 추가하는 방식으로 매우 쉽게 할 수 있습니다.

  • 안톤은 별표 평점 구성요소를 구현하기 위해 새 클래스를 만들 예정입니다.

  • 따라서 이 가상의 여행 중에 식당을 평가할 수 있도록 애플리케이션에 무언가를 추가할 것입니다.

  • 기존 구성요소를 대체하는 것이 아니므로 이 더 일반적인 인터페이스, 즉 A2UI 구성요소 인터페이스를 사용합니다. 이 인터페이스에는 재정의해야 하는 몇 가지 매개변수가 있습니다.

  • 처음 두 개는 이름과 설명입니다.

  • 이것이 구성요소의 정의와 역할입니다.

  • 이러한 설명은 매우 중요합니다. 카탈로그를 직렬화하고 백엔드로 전송하여 UI를 빌드하는 데 사용할 수 있는 항목을 알려줄 때, 에이전트가 응답 시 이 구성요소를 사용할지 여부를 결정하는 데 사용하기 때문입니다.

  • 따라서 AI에게 이 코드가 무엇을 하는지 정확히 알고 있다고 설명해야 합니다.

  • 재정의해야 하는 다음 속성은 properties 속성입니다. 이 속성은 기본적으로 이 구성요소가 처리하는 데이터를 정의합니다.

  • 레스토랑을 평가할 수 있는 별표 평점 막대를 만들고 있으며, 필요한 속성은 두 가지입니다.

  • 사용자가 선택한 별표 수와 같은 값이 될 것입니다. 이는 사용자가 상호작용하고 변경할 수 있는 변경 가능한 속성이며 최대 별표 수입니다.

  • 여기에서 안톤은 이 동적 숫자 유형 속성을 값으로 사용하고 있습니다.

  • 이것은 실제로 선택된 별의 개수입니다.

  • 이 값의 용도를 에이전트에 알려주는 자체 설명이 있습니다.

  • 그리고 정적 유형 속성이 있습니다. 이 구성요소에서 표시할 수 있는 최대 별표 수를 정의하기 위해 숫자 유형의 A2UI 속성을 사용합니다.

  • 두 속성을 정의한 후에는 반환하기만 하면 됩니다.

  • 따라서 이 properties 속성을 재정의하여 목록을 반환합니다.

  • 이것이 바로 에이전트에게 이 구성요소가 처리하는 내용을 알려주는 방법입니다.

  • 네.

  • 닉이 언급했듯이 이 속성 정의는 에이전트가 이 구성요소를 사용하는 방법을 알 수 있도록 카탈로그 스키마의 일부로 전송됩니다.

  • 하지만 이 속성, 즉 동일한 속성 정의는 런타임 시 유형이 지정된 값을 추출하는 데도 사용됩니다.

  • 따라서 단일 정보 소스가 있습니다.

  • 이를 구현하기 위해 무엇을 해야 하는지 살펴보겠습니다.

  • 먼저 max 속성에 액세스하려면 max 속성이 정적 속성이므로 에이전트가 속성 객체에 인라인으로 값을 전송합니다.

  • 따라서 이 속성에 액세스하려면 proper-max 속성 객체를 키로 사용하여 속성 객체에서 가져오면 됩니다.

  • 이 속성은 숫자로 정의되므로 int로 변환하고 기본값을 설정해야 합니다.

  • 다음은 값 속성입니다.

  • 값 속성은 동적 속성이므로 데이터 모델의 무언가를 참조하고 있음을 의미합니다.

  • 따라서 이 속성에 액세스하려면 properties.bind API를 사용하고 속성 객체를 키로 매개변수로 전달해야 합니다.

  • 이 속성의 데이터 모델에 저장된 현재 값을 반환하고 향후 업데이트를 구독합니다.

  • 따라서 데이터 모델이 업데이트될 때마다 이 구성요소가 자동으로 재구성됩니다.

  • 마찬가지로 int로 변환하고 기본값을 설정했습니다.

  • 평점을 변경할 수 있도록 양방향 결합을 설정해야 합니다.

  • 이를 위해 bindUpdater API를 사용합니다.

  • 속성을 정의하는 동일한 속성 객체를 전달하고, 그 결과 bindUpdater는 데이터 모델에서 이 속성의 값을 변경할 수 있는 람다를 반환합니다.

  • 이제 별표 평점 구성요소를 내보낼 준비가 되었습니다.

  • 좋습니다.

  • 자체 커스텀 구성요소를 정의했으므로 이제 사용 중인 카탈로그에 추가해야 합니다.

  • 이전에는 기본 카탈로그를 그대로 사용했습니다.

  • 이제 모든 기본 카탈로그를 가져와 커스텀 구성요소를 추가하는 새 카탈로그를 만들어야 합니다.

  • 따라서 카탈로그는 세 가지 요소로 구성됩니다.

  • ID, 구성요소 집합, 함수 집합입니다.

  • ID의 경우 URI를 사용하여 카탈로그와 작업 중인 버전을 고유하게 식별합니다.

  • 그런 다음 구성요소의 경우 기본 카탈로그에서 모든 구성요소를 가져온 다음 추가 연산자를 사용하여 방금 만든 커스텀 구성요소를 추가합니다.

  • 함수의 경우 기본 카탈로그의 함수를 사용합니다.

  • 이렇게 해서 기본 카탈로그를 확장하여 새 맞춤 구성요소 유형을 추가했습니다.

  • 맞춤 카탈로그를 만드는 것은 매우 간단합니다.

  • 따라서 에이전트는 전송된 시스템 안내를 통해 카탈로그를 사용하는 방법을 학습합니다.

  • 이제 커스텀 카탈로그를 만들었으니 시스템 요청 사항도 업데이트해 보겠습니다.

  • 따라서 시스템 요청 사항을 빌드하는 함수에 카탈로그 객체를 전달합니다.

  • 바로 이렇습니다.

  • 지금까지는 이 표준 카탈로그를 사용하고 있었기 때문에 기본 카탈로그의 스키마에 대한 정적 정의를 전송했습니다.

  • 이제 커스텀 카탈로그가 있으므로 toJsonSchemaString 함수를 사용하여 스키마를 동적으로 생성할 수 있습니다.

  • 그러면 방금 추가한 별표 평점 구성요소를 포함하여 이 카탈로그의 완전한 JSON 표현이 생성됩니다.

  • 시스템 요청 사항에는 에이전트의 응답 예시도 포함되어 있습니다.

  • 예시가 올바른 카탈로그를 참조하도록 여기에서 카탈로그 ID도 변경합니다.

  • 좋습니다.

  • 이렇게 해서 기본 카탈로그를 확장하여 자체 커스텀 유형을 추가했습니다.

  • 따라서 이를 다시 배포하고 이러한 프롬프트 중 하나를 시도하면 평가 UI가 표시됩니다.

  • 그러면 에이전트가 대답합니다.

  • 여기에서 이 별표 구성요소는 방금 구현하기 전까지는 에이전트가 본 적이 없는 새로운 구성요소입니다.

  • 이것은 기본 카탈로그의 일부가 아니며, 방금 만들었습니다.

  • 별표를 클릭하면 bindUpdater 람다가 호출되고 데이터 모델에서 값이 업데이트됩니다.

  • 평점을 제출하면 작업을 살펴볼 수 있으며 작업의 컨텍스트에는 방금 설정한 값이 포함됩니다.

  • 이제 슬라이드로 돌아가겠습니다.

  • 지금까지 많은 내용을 빠르게 살펴보았지만, 에이전트가 텍스트로만 응답하는 방식에서 실제 네이티브 UI를 생성하는 방식으로 쉽게 전환하는 방법을 보여드렸습니다.

핵심 내용 및 리소스

  • 통합이 매우 쉽다는 것을 보여드렸기를 바랍니다.

  • 구성요소 카탈로그를 만들고, 파싱 로직을 구현하고, UI에서 렌더링하는 세 가지 주요 구성요소를 수행해야 합니다.

  • 또한 이 라이브러리가 점진적 렌더링, 스키마 검증, 자체 수정 루프, 오류 처리 등 다양한 작업을 기본적으로 수행한다는 점을 보여드렸습니다.

  • 오늘 시연을 통해 맞춤설정이 매우 쉽다는 것을 보여드렸습니다.

  • Material을 사용하는 경우 기본 카탈로그가 Material Theming에 어떻게 반응하는지 보여드렸지만, 카탈로그 내에서 구성요소를 확장하거나 교체하는 것은 매우 간단합니다.

  • 하지만 가장 강력한 기능은 자체 카탈로그를 만들 때 발휘된다고 생각합니다.

  • 상담사가 실제로 사용할 수 있는 UI를 최대한 제어하려면 완전히 커스텀 구성요소를 만들면 됩니다.

  • 완전히 자유롭게 맡기고 싶다면 텍스트 라벨이나 버튼과 같은 아주 기본적인 구성요소를 제공하고 'UI를 만들어 줘'라고 요청하면 됩니다.

  • 더 세밀하게 제어하려면 더 정교한 구성요소를 만들고 '이것만 사용할 수 있습니다'라고 지정하면 됩니다.

  • 따라서 에이전트가 수행할 수 있는 작업과 사용자에게 표시할 수 있는 내용을 제어할 수 있습니다.

  • 이것이 바로 Google에서 방금 출시한 새로운 A2UI 렌더러 라이브러리와 Jetpack 라이브러리입니다.

    implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha02")
  • 현재 알파 버전이며 알파 02가 최근에 출시되었습니다.

  • 다음 링크를 통해 확인해 보세요.

  • developer.android.com에 문서와 몇 가지 샘플이 있습니다.

  • 기본 카탈로그를 보여주는 기본 샘플과 더 정교한 샘플이 있으며, 방금 만든 이 JetPacker 샘플 앱은 오늘 ADS 기조연설에서 다시 보게 될 것입니다. 이 앱은 사용자가 보는 것을 제어하기 위해 더 정교한 구성요소를 만드는 방법을 보여줍니다.

  • 말씀드린 것처럼 현재 알파 단계이므로 지금 확인해 보고 의견과 기능 요청을 보내주시면 좋습니다. 어떻게 사용하고 싶은지, 어떤 기능이 있으면 사용하고 싶은지 알려주세요.

  • 라이브러리를 확인하고 의견을 보내주세요.

  • 그렇게 해서 얻은 결과입니다.

  • 여러분과 여러분의 에이전트가 이 도구를 사용하여 어떤 결과물을 만들어낼지 정말 기대됩니다.

  • 정말 감사합니다.

  • 감사합니다.

코드

코드 스니펫

'핵심 내용 및 리소스'의 27:40에 있는 Kotlin 스크립트 스니펫
implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha02")