A2UI đang chuyển đổi từ các thành phần tập trung vào web sang Android gốc. Trình kết xuất Jetpack Compose mới cho A2UI phiên bản 0.9 cho phép nhà phát triển kết xuất giao diện người dùng động, do LLM tạo theo cách gốc. Thay vì chế độ xem web, ứng dụng này tận dụng khung tác nhân dựa trên Coroutine, vòng đời lớp kín và tính năng tích hợp Material 3 gốc.
Phiên này sẽ giới thiệu cấu trúc mới, giải thích cách cây thành phần do máy chủ điều khiển chuyển đổi thành các nút Compose phản ứng và cách các hiệu ứng chuyển đổi bố cục tích hợp sẵn xử lý các bản cập nhật cấu trúc một cách mượt mà mà không chặn giao diện người dùng.
Bản chép lời
Chào mọi người, chào mừng các bạn đến với buổi trò chuyện này. Chúng ta sẽ nói về cách tạo giao diện người dùng trong ứng dụng Android bằng thư viện A2UI hoàn toàn mới của chúng tôi.
Tôi là Nick Butcher, nhà quản lý sản phẩm phụ trách Jetpack Compose.
Chào mọi người, tôi là Anton, kỹ sư trong nhóm Compose.
Tôi đang phát triển trình kết xuất A2UI mới này của Jetpack Compose và chúng tôi rất vui được giới thiệu với bạn hôm nay.
Đúng vậy, giờ đây, nhờ sự phát triển của các tính năng AI, nhiều ứng dụng đang tìm hiểu cách AI có thể giúp cải thiện hoặc xây dựng trải nghiệm mới cho người dùng.
Một trong những trải nghiệm thú vị mà một số người đang xem xét là giao diện người dùng tạo sinh. Đây là cách mà trong thời gian chạy, phần phụ trợ dựa trên tác nhân có thể tạo ra giao diện người dùng hoàn toàn mới cho người dùng của bạn. Chúng tôi cho rằng điều này rất thú vị.
Nhưng không may là hiện tại, nhiều câu trả lời của các hệ thống phụ trợ dựa trên tác nhân bị kẹt trong những khối văn bản như thế này.
Sau đây là ví dụ về trường hợp tôi yêu cầu một tác nhân tạo cho tôi một tính năng mới để đặt chuyến đi.
Sau đây là câu lệnh.
Và như bạn có thể thấy, câu trả lời thực sự khá ổn, nhưng nó bị kẹt trong một khối văn bản mà tôi không thể dễ dàng tương tác và trông không giống với phần còn lại của ứng dụng.
Giao diện người dùng tạo sinh cho phép bạn tạo ra một trải nghiệm như thế này, trong đó bạn có thể tạo một giao diện người dùng mới ngay lập tức để phản hồi thông tin đầu vào linh hoạt, mở ra khả năng tuỳ chỉnh nhiều hơn hoặc mang đến nhiều trải nghiệm mới hơn.
Dưới đây là ví dụ về một giao diện người dùng được tạo bằng các thành phần gốc, chuẩn.
Vì vậy, bạn hoàn toàn có thể tự xây dựng loại trải nghiệm này ngay hôm nay, nhưng bạn sẽ phải xác định định dạng riêng của mình để trao đổi với phần phụ trợ, loại luồng sự kiện và hàm riêng, v.v.
A2UI (viết tắt của Agent-to-UI) là một giao thức mở, có định dạng JSON để xác định tất cả những điều này.
Một trong những điều tôi thực sự thích ở A2UI là định dạng khai báo.
Tác nhân chỉ trả về một bản trình bày JSON của giao diện người dùng để hiển thị.
Nó không trả về bất kỳ mã nào mà ứng dụng của bạn cần thực thi, điều này có thể khiến bạn gặp phải một số lỗ hổng bảo mật nhất định.
Nó chỉ mang tính khai báo.
Vậy chúng ta cần biết những khái niệm nào khác về A2UI?
Chỉ có hai khái niệm chính: danh mục và nền tảng.
Danh mục có các thành phần như văn bản, nút, hàng và cột mà tác nhân có thể sử dụng để tạo giao diện người dùng.
Danh mục cũng có các hàm mà nhân viên hỗ trợ có thể dùng để định dạng văn bản, xác thực dữ liệu đầu vào của người dùng hoặc mở URL.
Danh mục là một hợp đồng xác định các thành phần và chức năng mà ứng dụng của bạn hỗ trợ, và tác nhân chỉ có thể xây dựng bằng các thành phần và chức năng đó.
Điều này có nghĩa là, như Nick đã đề cập, tác nhân không bao giờ thực thi mã tuỳ ý trong ứng dụng của bạn.
Gemini sẽ tạo giao diện người dùng từ các khối dựng mà bạn thiết kế và tin tưởng.
Một khái niệm quan trọng khác là nền tảng.
Nền tảng là một phần của giao diện người dùng mà tác nhân kiểm soát, chẳng hạn như ví dụ về Chuyên gia lên kế hoạch chuyến đi trên trang trình bày này.
Tác nhân mô tả giao diện người dùng cho một nền tảng trong JSON bằng cách sử dụng các thông báo giao thức A2UI, chẳng hạn như createSurface, updateComponents, và sử dụng các thành phần cũng như hàm được xác định trong danh mục của bạn.
Nói về danh mục, danh mục là một khái niệm rất cơ bản trong A2UI, vì danh mục kiểm soát những thành phần mà tác nhân có thể sử dụng để tạo giao diện.
Thông số kỹ thuật của A2UI xác định một danh mục cơ bản, là một tập hợp các thành phần phổ biến mà bạn có thể dùng để xây dựng hầu hết giao diện người dùng.
Trình kết xuất A2UI của Jetpack Compose cung cấp một cách triển khai danh mục cơ bản bằng các thành phần Material 3.
Hầu hết các thành phần trong danh mục đều có thể sử dụng ngay.
Có 3 thành phần nội dung nghe nhìn: hình ảnh, video và trình phát âm thanh. Bạn cần phải đưa thư viện mà bạn chọn vào các thành phần này.
Ví dụ: bạn có thể chọn Coil để tải hình ảnh và Media3 cho trình phát video và âm thanh.
Tuy nhiên, điểm mạnh thực sự của A2UI và thư viện trình kết xuất mới của chúng tôi là bạn có thể tạo các thành phần và danh mục hoàn toàn tuỳ chỉnh của riêng mình, đồng thời kiểm soát hoàn toàn những gì tác nhân có thể sử dụng để xây dựng giao diện người dùng.
Chúng ta sẽ tìm hiểu về danh mục sau.
Hãy cùng xem giao diện của tính năng này.
Vậy nên, vui lòng chuyển sang máy minh hoạ.
Đây là ứng dụng minh hoạ mà chúng tôi sẽ sử dụng và chúng tôi sẽ xây dựng trình kết xuất A2UI để cho bạn thấy việc này dễ dàng như thế nào.
Vì vậy, đây là một tập hợp các câu lệnh (như bạn có thể thấy trong các khối nhỏ này ở giữa màn hình) mà bạn có thể gửi đến một tác nhân.
Vì vậy, nếu chúng ta nhấp vào một trong các câu lệnh, câu lệnh đó sẽ được gửi đến một hệ thống phụ trợ của nhân viên hỗ trợ thực tế, vì vậy, hãy hy vọng bản minh hoạ này sẽ thành công. Ngoài câu lệnh, chúng ta cũng thêm một số chỉ dẫn hệ thống.
Vì vậy, chúng tôi cho phần phụ trợ biết về giao thức A2UI, về danh mục thành phần, trong trường hợp này là danh mục cơ bản mà chúng tôi đang sử dụng ngay tại đây, mà phần phụ trợ có thể sử dụng để xây dựng giao diện người dùng và chúng tôi cung cấp cho phần phụ trợ một số ví dụ về cách xây dựng giao diện này.
Quá trình triển khai phiên trò chuyện trong ứng dụng minh hoạ của chúng tôi đã biết cách trích xuất thông báo A2UI JSON thô từ phản hồi của nhân viên hỗ trợ.
Vì vậy, trong trường hợp này, tác nhân đã trả lời bằng một số văn bản, theo sau là các thông báo giao thức A2UI: createSurface, updateComponents.
Nhưng hiện tại, ứng dụng của chúng ta chỉ hiển thị JSON thô này và chưa kết xuất dưới dạng giao diện người dùng.
Được rồi, trước khi tìm hiểu sâu và triển khai mã, nếu có thể quay lại trang trình bày chỉ trong 1 giây, hãy lùi lại một bước và cho bạn biết về thiết kế hệ thống mà chúng ta sẽ sử dụng để triển khai việc này.
Ồ, đây rồi.
Đúng vậy, kế hoạch như sau.
Vì vậy, tác nhân AI sẽ truyền trực tuyến một câu trả lời vào ứng dụng của chúng ta, câu trả lời này sẽ được lớp ChatSession nhận.
ChatSession trích xuất các thông báo JSON thô của A2UI từ phản hồi của nhân viên hỗ trợ khi phản hồi đó đang được truyền trực tuyến và chuyển các thông báo đó đến trình xử lý thông báo của A2UI.
Bộ xử lý thông báo được định cấu hình bằng một trình phân tích cú pháp để chuyển đổi các thông báo JSON thô đó thành một bản trình bày ngữ nghĩa.
Sau đó, bộ xử lý sẽ xác thực thông báo dựa trên định nghĩa danh mục và liên kết thông báo với một tập hợp các mô hình hiển thị.
Mô hình giao diện, đây là những yếu tố xác định giao diện người dùng trông như thế nào và các phần của giao diện người dùng mà tác nhân kiểm soát.
Sau đó, các mô hình giao diện đó sẽ được kết xuất dưới dạng giao diện người dùng Compose gốc bằng cách sử dụng thành phần kết hợp giao diện A2UI do thư viện của chúng tôi cung cấp.
Quá trình giao tiếp giữa tác nhân và giao diện người dùng là hai chiều, vì vậy, khi người dùng tương tác với giao diện người dùng, các hành động và lỗi của người dùng sẽ được chuyển về tác nhân.
Tóm lại, có 3 thành phần chính: danh mục, trình xử lý thông báo và nền tảng.
Hãy viết mã cho việc này.
Được, hãy xây dựng nếu chúng ta có thể chuyển đổi máy.
Được rồi, bước đầu tiên là thêm phần phụ thuộc.
Tại đây, bạn có thể thấy chúng tôi đã thêm phần phụ thuộc Material 3 A2UI và đã đồng bộ hoá dự án để không phải ngồi xem Gradle.
Đây là phần phụ thuộc cấp cao nhất xác định cách triển khai danh mục cơ bản bằng các thành phần Material 3 đó, nhưng có các phần phụ thuộc khác chi tiết hơn bên dưới.
Vì vậy, nếu không muốn sử dụng danh mục cơ bản (chúng tôi sẽ giải thích lý do sau), bạn có thể sử dụng các danh mục chi tiết hơn.
Nhưng điều này sẽ mang lại – kéo phần còn lại vào một cách bắc cầu.
Được rồi.
Như vậy, chúng ta có 3 điều cần lưu ý.
Bước đầu tiên là xác định danh mục.
Vì vậy, trong ứng dụng của mình, chúng ta sẽ tạo một hàm nhà máy để giúp tạo một thực thể của việc triển khai Material 3 cho danh mục cơ bản.
Vì vậy, chúng ta sử dụng hàm thư viện này ở đây, danh mục cơ bản của Material A2UI, cũng được tạo phiên bản.
Và như chúng tôi đã nói, thư viện này cung cấp tất cả các thành phần phổ biến mà bạn cần, ngoại trừ việc chúng tôi không muốn buộc bạn phải sử dụng một số thư viện tải hình ảnh hoặc kết xuất nội dung nghe nhìn nhất định, vì vậy, bạn phải tự cung cấp các thư viện đó.
Ví dụ: Anton đã tạo trình bao bọc này xung quanh thành phần composable AsyncImage của Coil mà chúng ta sẽ dùng để tải hình ảnh, cũng như một chút logic bổ sung cho bản minh hoạ để tra cứu hình ảnh trên Wikipedia.
Và như vậy, chúng ta có thể dễ dàng đưa thành phần này vào các thành phần danh mục.
Tương tự, chúng ta có các cách triển khai tương tự cho việc kết xuất, video và âm thanh, trong đó chúng ta sẽ sử dụng thư viện Media3 để kết xuất bằng ExoPlayer.
Vì vậy, rất đơn giản như thế này, chúng ta có thể cắm các thành phần của riêng mình vào đó.
Điều tiếp theo mà danh mục cần là một tập hợp các hàm chuẩn.
Vì vậy, đây là những chức năng mà khách hàng có thể cung cấp.
Một lần nữa, chúng tôi cung cấp một phương thức triển khai cùng với danh mục cơ bản, nhưng chúng tôi cần cung cấp cho danh mục đó một ngữ cảnh mà bạn sẽ sử dụng để thực hiện một số hành động nhất định, chẳng hạn như mở một URI nếu người dùng nhấn vào một mục.
Như vậy là chúng ta đã hoàn tất bước đầu tiên.
Chúng tôi đã tạo một danh mục.
Bước tiếp theo chúng ta phải làm là thiết lập trình xử lý thông báo.
Vì vậy, đây là thứ thực sự phân tích cú pháp, phản hồi, v.v.
Vì vậy, chúng ta sẽ chuyển sang mô hình khung hiển thị của ứng dụng, nơi chúng ta sẽ tạo thực thể cho danh mục đã thiết lập trước đó, vì chúng ta sẽ cần danh mục đó.
Sau đó, chúng ta sẽ tạo trình phân tích cú pháp thông báo, đối tượng trình xử lý thông báo, cần quyền truy cập vào danh mục để xác thực các phản hồi đối với các thành phần mà chúng ta muốn sử dụng.
Một thành phần khác mà chúng ta cần tạo là trình phân tích cú pháp, đây thực sự là đối tượng chịu trách nhiệm phân tích cú pháp các thông báo JSON khi chúng được trả về.
Đây là nơi chúng ta tạo đối tượng ChatSession.
Như đã đề cập trước đó, ChatSession đã trích xuất các tin nhắn A2UI thô từ câu trả lời của nhân viên hỗ trợ.
Và khi mọi thông báo A2UI mới đã sẵn sàng, nó sẽ gọi lệnh gọi lại onA2uiMessage này.
Vì vậy, tất cả những gì chúng ta cần làm là chuyển từng thông báo đó khi chúng đến bộ xử lý.
Chúng ta gọi hàm processInput, cung cấp cho hàm này một trình phân tích cú pháp và một thông báo.
Vì vậy, hàm processInput sẽ phân tích cú pháp từng thông báo, sau đó đưa công việc vào hàng đợi để trình xử lý xác thực thông báo đó dựa trên danh mục và cập nhật các mô hình bề mặt.
Vì vậy, trình xử lý sẽ hiển thị tập hợp các mô hình nền tảng đang hoạt động hiện tại dưới dạng activeSurfaces StateFlow.
ChatSession có một số logic để thêm các mô hình giao diện vào trạng thái giao diện người dùng của các câu trả lời của nhân viên hỗ trợ để hiển thị.
Vì vậy, chúng ta chỉ cần truyền StateFlow activeSurfaces này dưới dạng tham số cho ChatSession.
Ngoài ra, như tôi đã đề cập, hàm processInput sẽ đưa công việc vào hàng đợi cho bộ xử lý.
Nhưng để thực sự bắt đầu xử lý, chúng ta cần chạy một coroutine trên luồng trong nền.
Vì vậy, chúng ta sẽ sử dụng phạm vi mô hình khung hiển thị cho việc đó và đặt trình điều phối mặc định.
Và trong coroutine đó, chúng ta chỉ cần gọi processor.collectMessages.
Vì vậy, trong khi coroutine này đang hoạt động, bộ xử lý sẽ xử lý các thông báo từ hàng đợi thông báo.
Vì vậy, chúng ta cần làm thêm một việc nữa là khi người dùng xoá nhật ký trò chuyện, chúng ta cũng cần xoá các nền tảng hiện tại.
Vì vậy, chúng ta gọi clearSurfaces.
Được rồi.
Vậy là chúng ta đã hoàn thành hai bước đầu tiên.
Chúng tôi đã tạo danh mục và bộ xử lý để phân tích cú pháp thông báo.
Bước tiếp theo chúng ta cần làm là hiển thị các phản hồi đó trong giao diện người dùng.
Vì vậy, chúng ta sẽ thu thập các bề mặt đó khi chúng được trình phân tích cú pháp phân tích.
Và giờ đây, trong giao diện người dùng, chúng ta sẽ truyền các đề xuất đó vào đối tượng phản hồi của nhân viên hỗ trợ này và chỉ cần lặp lại các đề xuất đó.
Sau đó, chúng ta sẽ sử dụng thành phần kết hợp giao diện người dùng A2UI này và truyền mô hình cho từng mô hình khi lặp lại để hiển thị nội dung ở nơi chúng ta muốn.
Một lưu ý ở đây là tác nhân có thể chọn sử dụng một danh sách nếu muốn hiển thị một lượng lớn nội dung.
Vì vậy, chúng ta cần đặt chiều cao tối đa cho thành phần này để đảm bảo thành phần này hiển thị đúng cách.
Và thế là chúng ta đã triển khai một trình kết xuất A2UI cơ bản.
Bây giờ, nếu chúng ta quay lại ứng dụng, chạy lại và nhấn vào câu lệnh đó một lần nữa, thì hy vọng tác nhân sẽ sử dụng câu lệnh đó để hiển thị giao diện người dùng thực.
Vì vậy, chúng tôi chỉ cần lập trình trực tiếp.
Đây không phải là trò lừa bịp.
Nhưng đúng vậy, tính năng này sử dụng hình ảnh thực tế.
Nó sử dụng các thẻ, hộp thoại, bộ chọn ngày, thanh trượt, bạn biết đấy, tất cả các thành phần Material tiêu chuẩn mà bạn biết, xây dựng ứng dụng của bạn thay vì chỉ hiển thị phản hồi bằng văn bản.
Vì đây là một ứng dụng thực tế sử dụng các thành phần Material thực tế, nên bạn biết đấy, ứng dụng này thực hiện những việc mà các thành phần thực tế làm.
Hiệu suất của ứng dụng này tương tự như ứng dụng gốc.
Nó thực hiện những việc như phản hồi chế độ tối tại đây.
Đây là các thành phần Material.
Vì vậy, nếu bạn có một thành phần kết hợp giao diện Material bên ngoài, nơi bạn đã tuỳ chỉnh màu sắc, hình dạng, kiểu chữ, v.v., thì các thành phần này sẽ chọn chúng để trông giống như phần còn lại của ứng dụng.
Như Nick đã đề cập, vì đây là các thành phần Compose gốc nên chúng có ngữ nghĩa gốc.
Điều này có nghĩa là tất cả bộ tính năng hỗ trợ tiếp cận tích hợp sẵn của Compose đều được hỗ trợ.
Vì vậy, những tính năng như TalkBack, điều chỉnh tỷ lệ phông chữ, điều hướng bằng bàn phím đều hoạt động ngay lập tức.
Giờ đây, vì bạn đang gọi một tác nhân để tạo giao diện người dùng mới trong thời gian chạy, nên có thể có một số độ trễ.
Bạn biết đấy, có thể bạn sẽ phải đợi nhân viên hỗ trợ phản hồi.
Thư viện sẽ làm mọi cách để giảm thiểu độ trễ này.
Vì vậy, nếu sử dụng loại này, chúng tôi sẽ chèn một số thời gian chờ để hiển thị chậm hơn một chút nhằm cho bạn thấy điều gì xảy ra và cách chúng tôi giảm thiểu điều đó.
Đúng vậy, vì tác nhân có thể mất một chút thời gian để truyền trực tuyến toàn bộ câu trả lời hoàn chỉnh, nên chúng tôi sử dụng một kỹ thuật gọi là kết xuất tăng tiến.
Vì vậy, ngay khi thành phần gốc xuất hiện, chúng ta sẽ bắt đầu hiển thị giao diện người dùng cho nền tảng.
Tất cả thành phần vùng chứa đều hiển thị phần giữ chỗ đang tải cho các thành phần con nếu các thành phần con chưa xuất hiện.
Khi các thành phần con xuất hiện, chúng sẽ được tạo ảnh động bằng lược đồ chuyển động Material 3.
Được rồi.
Và nếu chúng ta có thể chuyển sang câu lệnh tiếp theo chỉ để cho thấy một tính năng khác của thư viện.
Sau đây là một câu lệnh khác để đặt bàn ăn tối.
Và ở đây, tác nhân chọn sử dụng thành phần thanh trượt này, đúng vậy, tác nhân đã sử dụng thành phần này.
Tại đây, bạn có thể thấy rằng bạn có thể kéo xung quanh và tương tác với giao diện người dùng mà tác nhân đã tạo ngay lập tức.
Và hãy lưu ý rằng không chỉ thay đổi số trên thành phần, mà còn có chuỗi định dạng này ở phía dưới nơi đếm số.
Như vậy có nghĩa là không cần phải gửi yêu cầu khứ hồi đến nhân viên hỗ trợ chỉ để cập nhật thông tin đó, đúng không?
Đây là một liên kết hai chiều.
Vì vậy, thành phần thanh trượt được liên kết với mô hình dữ liệu trong bộ nhớ của nền tảng này.
Tất cả thành phần liên kết với cùng một đường dẫn trong mô hình dữ liệu sẽ tự động được cập nhật khi giá trị thay đổi.
Vì vậy, thanh trượt sẽ đọc giá trị để hiển thị và khi tôi kéo thanh trượt, thanh trượt sẽ ghi lại giá trị đó vào mô hình để cập nhật.
Vì vậy, tất cả những việc này đều diễn ra trên thiết bị mà không cần khứ hồi đến tác nhân.
Tuy nhiên, chúng tôi cũng có thể yêu cầu nhân viên hỗ trợ cập nhật dữ liệu.
Vậy hãy đặt bàn cho 6 người.
Chú ý đến thanh trượt khi nhân viên hỗ trợ trả lời.
Nó vừa nhảy lên 6.
Hãy xem chúng ta nhận được gì từ tác nhân.
Thay vì gửi toàn bộ nội dung mô tả mới về giao diện người dùng, tác nhân chỉ gửi một thông báo nhỏ updateDataModel để cập nhật đường dẫn cho thanh trượt.
Vì thanh trượt được liên kết với đường dẫn đó, nên thanh trượt sẽ cập nhật tại chỗ.
Vì vậy, mô hình dữ liệu của mỗi nền tảng được xây dựng dựa trên trạng thái ảnh chụp nhanh của Compose và mỗi thuộc tính thành phần liên kết với một đường dẫn là một trạng thái phái sinh.
Vì vậy, bất cứ khi nào người dùng hoặc tác nhân cập nhật giá trị trong mô hình dữ liệu, tất cả thành phần liên kết với cùng một giá trị sẽ tự động được kết hợp lại.
Được rồi.
Giả sử chúng ta muốn hành động và nhấn vào nút đặt trước, điều gì sẽ xảy ra, Anton?
Hiện không có gì xảy ra.
Nút này có gửi một hành động, nhưng chúng ta chưa gửi hành động đó đến tác nhân.
Hãy cùng khắc phục vấn đề này.
Được rồi, giống như việc chúng ta phải kết nối với bộ xử lý để xử lý dữ liệu đầu vào, chúng ta cũng cần kết nối với mọi dữ liệu đầu ra, mọi hành động mà người dùng thực hiện trên giao diện người dùng mà tác nhân đã tạo.
Vì vậy, để làm được điều đó, chúng ta sử dụng luồng outboundEvents mà bộ xử lý hiển thị và thu thập trên luồng này.
Vì vậy, đây là cơ hội để bạn có thể đưa vào bất kỳ logic nào bạn muốn dựa trên, bạn biết đấy, khi người dùng nhấn vào một hành động hoặc thực hiện điều gì đó với giao diện người dùng.
Vì vậy, ngay tại đây, chúng tôi sẽ gửi mọi hành động trở lại tác nhân để sau đó quyết định việc cần làm, nhưng tại thời điểm này, bạn cũng có thể quyết định xem có gọi phần phụ trợ của riêng mình hay không hoặc chuyển đến một màn hình khác trong ứng dụng, tuỳ bạn.
Vì vậy, Anton đã cắm nó vào, và bây giờ khi chúng ta nhấn vào hành động xác nhận đặt chỗ, nó sẽ gửi hành động mà bạn đã thực hiện trở lại cho tác nhân.
Và đây là nơi bạn có thể quyết định gọi một số chức năng ở phần phụ trợ.
Hãy xem những gì chúng ta thực sự gửi cho tác nhân.
Đây là thông báo hành động của A2UI.
Ý định này có một ngữ cảnh và ngữ cảnh này chứa một tập hợp các thuộc tính mà tác nhân yêu cầu gửi khi hành động này được thực hiện.
Vì vậy, khi tôi nhấp vào nút, các thuộc tính cụ thể này sẽ được phân giải tại thời điểm đó dựa trên các giá trị hiện tại trong mô hình dữ liệu và đó là những gì chúng tôi gửi đến nhân viên hỗ trợ.
Được rồi, cho đến nay, tác nhân này khá hợp tác với chúng ta, nhưng chúng ta đang nói về AI và AI có thể mắc sai sót.
Vậy hãy cùng xem điều gì sẽ xảy ra nếu tác nhân trả về một giao diện người dùng không chính xác hoặc mắc lỗi trong giao diện người dùng mà tác nhân mô tả lại cho chúng ta.
Vì vậy, trong câu lệnh cuối cùng này, chúng tôi thực sự yêu cầu nhân viên hỗ trợ mắc lỗi để có thể minh hoạ cho bạn.
Hãy xem điều gì sẽ xảy ra.
Vâng.
Như bạn có thể thấy, một trong các thành phần được đánh dấu là có lỗi.
Và giờ thì vấn đề đã được khắc phục.
Đây là vòng lặp tự sửa lỗi của tác nhân.
Trước khi mỗi thành phần đến được giao diện người dùng, chúng tôi sẽ xác thực thông báo đó dựa trên giản đồ danh mục.
Nếu thành phần không khớp với giản đồ, thành phần đó sẽ được đánh dấu là lỗi.
Trình kết xuất của bản triển khai danh mục cơ bản cho thấy lỗi đó chỉ xảy ra với thành phần cụ thể đó, trong khi phần còn lại của giao diện người dùng vẫn hiển thị.
Trong nền, trình kết xuất sẽ gửi thông báo lỗi đến nhân viên hỗ trợ để cho nhân viên hỗ trợ biết vấn đề.
Vì vậy, trong trường hợp này, chúng tôi đã gửi một thông báo cho biết không tìm thấy loại thành phần không xác định không tồn tại trong danh mục.
Sau đó, nhân viên hỗ trợ có thể phản hồi bằng cách gửi một câu trả lời tiếp theo để cập nhật giao diện người dùng hiện có và giao diện người dùng đã được khắc phục tại chỗ.
Vâng.
Trong cách triển khai hiện tại của danh mục cơ bản Material, chúng tôi sẽ hiển thị lỗi ngay lập tức, nhưng trong thành phần tuỳ chỉnh, bạn có thể quyết định tiếp tục hiển thị chỉ báo đang tải cho một thành phần nếu có lỗi trong khi chờ tác nhân khắc phục.
Và theo cách này, lỗi có thể bị ẩn hoàn toàn khỏi người dùng.
Và nói về danh mục và thành phần tuỳ chỉnh, cho đến nay, chúng ta chỉ sử dụng danh mục cơ bản khi danh mục này được cung cấp sẵn, nhưng tất nhiên bạn có thể tuỳ chỉnh danh mục đó theo nhu cầu của riêng mình.
Vì vậy, bạn có thể thấy rằng khi chúng ta sử dụng hàm factory để tạo danh mục, thì các giá trị mặc định sẽ được áp dụng cho tất cả các thành phần.
Vì vậy, bạn có thể dễ dàng thêm các thành phần của riêng mình nếu muốn.
Ví dụ: nếu muốn thêm nút riêng khi có hệ thống thiết kế riêng trong ứng dụng, chúng ta có thể dễ dàng thêm nút đó.
Vì vậy, chúng ta chỉ cần ghi đè tham số này khi tạo một thực thể của danh mục và chúng ta sẽ tạo định nghĩa thành phần này.
Vì vậy, nếu chúng ta tạo một lớp mới để triển khai lớp đó, bạn có thể thấy một giao diện ở đây, danh mục cơ bản A2UI của nút loại.
Vì vậy, nếu triển khai giao diện này, chúng ta có thể bổ sung thành phần của riêng mình.
Vâng.
Vì vậy, vì đang ghi đè một thành phần trong danh mục cơ bản, nên chúng ta cần triển khai giao diện nút danh mục cơ bản A2UI này.
Vì vậy, giao diện này đã có một số thông tin về thành phần như tên, nội dung mô tả và giản đồ thuộc tính.
Vì vậy, tất cả những gì chúng ta cần làm để triển khai phiên bản của riêng mình là triển khai hàm composable này.
Thành phần này cần có một số tham số.
Vì vậy, các tham số này là giá trị nhận được từ tác nhân sau khi được xác thực.
Vì vậy, đây là những thứ như mã nhận dạng con, tham chiếu đến một thành phần sẽ là nội dung của nút.
Hàm này cũng có một biến thể mô tả loại nút, định nghĩa hành động và một số tham số khác.
Trong quá trình triển khai nút này, chúng ta cần sử dụng tất cả các tham số này, nhưng cho mục đích minh hoạ, chúng ta chỉ cần phần tử con và hành động.
Hãy triển khai composable này.
Được rồi, trong hàm composable này, chúng ta sẽ phát ra loại nút thích tuỳ chỉnh của riêng mình tại đây.
Như bạn có thể thấy, chúng ta có thể sử dụng các tham số được A2UI cung cấp và xác thực.
Ví dụ: trong hàm onClick, chúng ta có thể gửi hành động đó.
Chúng ta có thể sử dụng loại thư viện DispatchAction này và truyền cho nó hành động mà A2UI đã xác định.
Vì vậy, chúng ta đang sử dụng nút của riêng mình, nhưng vẫn muốn hiển thị nội dung con, nhãn hoặc bất cứ nội dung nào mà tác nhân quyết định sử dụng.
Vì vậy, chúng ta sẽ sử dụng hàm observeA2uiComponentState này và truyền childId vào hàm để lấy một handle cho nội dung con cần hiển thị.
Sau đó, chúng ta sẽ sử dụng hàm composable A2uiComponent này rồi truyền state thành phần con đó để hiển thị.
Và tại đây, bạn có thể thấy chúng ta chỉ hiển thị nội dung con nếu nội dung đó tải thành công, nhưng bạn cũng có thể có logic riêng tại đây nếu nội dung đó đang tải hoặc nếu có trạng thái lỗi, bạn có thể quyết định nội dung mình muốn hiển thị.
Vì vậy, nếu quay lại một trong các câu lệnh mẫu trong ứng dụng minh hoạ và thay thế nút bằng nút Material tiêu chuẩn.
Rất tinh tế, hy vọng bạn có thể nhìn thấy.
Bạn có thể thấy chúng tôi cũng đang sử dụng một nút rất tuỳ chỉnh ở đây.
Tuyệt, vậy là bạn đã biết cách thay thế một số loại thư viện, nhưng nếu bạn muốn mở rộng thư viện bằng các loại tuỳ chỉnh của riêng mình thì sao?
Chúng ta có thể thực hiện việc đó rất dễ dàng bằng cách thêm vào chính danh mục.
Vì vậy, Anton sẽ tạo một lớp mới tại đây để triển khai thành phần xếp hạng theo sao.
Vì vậy, chúng ta sẽ thêm một số nội dung vào ứng dụng để có thể xếp hạng nhà hàng trong chuyến đi giả định này.
Vì vậy, do không thay thế một thành phần hiện có, chúng ta sẽ sử dụng giao diện chung hơn này, giao diện thành phần A2UI này. Bạn có thể thấy giao diện này có một vài tham số mà chúng ta cần ghi đè.
Vì vậy, hai tham số đầu tiên là tên và nội dung mô tả.
Vì vậy, phần này mô tả thành phần của chúng ta là gì và có chức năng gì.
Đây là những thông tin rất quan trọng vì khi chúng ta chuyển đổi danh mục và gửi đến phần phụ trợ để cho biết những gì có thể dùng để xây dựng giao diện người dùng, thì đây là thông tin mà tác nhân sẽ dùng để quyết định xem có nên sử dụng thành phần này khi phản hồi hay không.
Vì vậy, bạn cần mô tả khá chi tiết và cho AI biết chính xác chức năng của đoạn mã này.
Thuộc tính tiếp theo mà chúng ta cần ghi đè là thuộc tính properties, về cơ bản là cho biết thành phần này xử lý dữ liệu nào.
Vì vậy, chúng ta sẽ tạo một thanh xếp hạng theo sao để bạn có thể xếp hạng nhà hàng và sẽ có hai thuộc tính mà chúng ta cần.
Đó sẽ là giá trị, chẳng hạn như số sao mà người dùng đã chọn, đây sẽ là một thuộc tính có thể thay đổi mà người dùng có thể tương tác và thay đổi, cũng như số sao tối đa.
Vì vậy, tại đây, chúng ta có thể thấy Anton sử dụng thuộc tính loại số động này cho giá trị.
Vì vậy, đây là số sao thực tế được chọn.
Giá trị này cũng có nội dung mô tả riêng để cho tác nhân biết giá trị này dùng để làm gì.
Sau đó, chúng ta có một thuộc tính kiểu tĩnh, vì vậy, chúng ta chỉ sử dụng thuộc tính A2UI này của kiểu số để xác định số sao tối đa mà thành phần này có thể hiển thị.
Sau khi xác định hai thuộc tính đó, chúng ta chỉ cần trả về hai thuộc tính này.
Vì vậy, khi ghi đè thuộc tính properties này, chúng ta sẽ tạo một danh sách và trả về các thuộc tính đó.
Đó là cách bạn cho tác nhân biết thành phần này xử lý nội dung gì.
Vâng.
Như Nick đã đề cập, các định nghĩa thuộc tính này được dùng để gửi dưới dạng một phần của giản đồ danh mục để tác nhân biết cách sử dụng thành phần này.
Nhưng thuộc tính này, các định nghĩa thuộc tính tương tự cũng được dùng để trích xuất các giá trị đã nhập trong thời gian chạy.
Vì vậy, chỉ có một nguồn đáng tin cậy duy nhất.
Hãy xem chúng ta cần làm gì để triển khai việc này.
Vì vậy, trước tiên, để truy cập vào thuộc tính max, vì thuộc tính max là thuộc tính tĩnh, nên tác nhân sẽ gửi giá trị cho thuộc tính đó cùng dòng trong đối tượng thuộc tính.
Vì vậy, để truy cập vào, chúng ta chỉ cần lấy từ đối tượng thuộc tính bằng cách tham chiếu đến đối tượng đó bằng cách sử dụng đối tượng thuộc tính max thích hợp làm khoá.
Vì thuộc tính này được xác định là một số, nên chúng ta cũng cần chuyển đổi thuộc tính này thành số nguyên và đặt giá trị mặc định.
Tiếp theo là thuộc tính giá trị.
Vì thuộc tính value là một thuộc tính động, nên thuộc tính này tham chiếu đến một thành phần trong mô hình dữ liệu.
Vì vậy, để truy cập vào thuộc tính này, chúng ta cần sử dụng API properties.bind và truyền đối tượng thuộc tính dưới dạng khoá làm tham số.
Vì vậy, thao tác này sẽ trả về giá trị hiện tại được lưu trữ trong mô hình dữ liệu cho thuộc tính này, đồng thời đăng ký nhận thông tin cập nhật trong tương lai.
Vì vậy, bất cứ khi nào mô hình dữ liệu được cập nhật, thành phần này sẽ tự động kết hợp lại.
Tương tự, chúng ta cũng chuyển đổi thành int và đặt một số giá trị mặc định.
Một việc nữa chúng ta cần làm là thiết lập liên kết hai chiều để có thể thay đổi điểm xếp hạng.
Để làm việc đó, chúng ta sử dụng API bindUpdater.
Chúng ta truyền cùng một đối tượng thuộc tính xác định thuộc tính đó và kết quả là chúng ta nhận được Vì vậy, bindUpdater trả về một lambda cho phép chúng ta thay đổi giá trị cho thuộc tính này trong mô hình dữ liệu.
Bây giờ, chúng ta đã sẵn sàng phát ra thành phần xếp hạng theo sao.
Được rồi.
Giờ đây, khi đã xác định thành phần tuỳ chỉnh của riêng mình, chúng ta cần thêm thành phần đó vào danh mục đang sử dụng.
Trước đây, chúng ta chỉ sử dụng danh mục cơ bản như hiện tại.
Giờ đây, việc chúng ta cần làm là tạo một danh mục mới, lấy tất cả danh mục cơ bản và thêm vào thành phần tuỳ chỉnh.
Vì vậy, một danh mục được xác định gồm 3 yếu tố.
Đó là một mã nhận dạng, một tập hợp các thành phần và một tập hợp các hàm.
Đối với mã nhận dạng, chúng ta sẽ sử dụng một URI để xác định, bạn biết đấy, một danh mục nhận dạng duy nhất cũng như phiên bản mà chúng ta đang làm việc.
Sau đó, đối với các thành phần, chúng ta sẽ lấy tất cả thành phần từ danh mục cơ bản, rồi sử dụng toán tử thêm để thêm thành phần tuỳ chỉnh mà chúng ta vừa tạo.
Sau đó, đối với các hàm, chúng ta sẽ chỉ sử dụng các hàm trong danh mục cơ bản.
Và như vậy, chúng ta đã mở rộng danh mục cơ bản để thêm loại thành phần tuỳ chỉnh mới.
Bạn thấy đấy, việc tạo danh mục tuỳ chỉnh khá dễ dàng.
Vì vậy, nhân viên hỗ trợ sẽ tìm hiểu cách sử dụng danh mục từ các chỉ dẫn hệ thống mà chúng tôi gửi cho nhân viên hỗ trợ.
Vì chúng ta đã tạo một danh mục tuỳ chỉnh, nên hãy cập nhật cả chỉ dẫn hệ thống.
Vì vậy, chúng ta sẽ truyền đối tượng danh mục vào hàm tạo chỉ dẫn hệ thống.
Vậy nên, đây là kết quả.
Vì vậy, cho đến nay, chúng ta đã gửi một định nghĩa tĩnh về giản đồ cho danh mục cơ bản vì chúng ta đang sử dụng danh mục chuẩn này.
Giờ đây, khi đã có danh mục tuỳ chỉnh, chúng ta có thể tạo giản đồ một cách linh động bằng hàm toJsonSchemaString.
Vì vậy, thao tác này sẽ tạo ra một bản trình bày JSON hoàn chỉnh cho danh mục này, bao gồm cả thành phần xếp hạng theo sao mà chúng ta vừa thêm.
Chỉ dẫn hệ thống cũng bao gồm một số câu trả lời mẫu cho nhân viên hỗ trợ.
Vì vậy, chúng ta cũng thay đổi mã danh mục tại đây để các ví dụ tham chiếu đến đúng danh mục.
Được rồi.
Và như vậy, chúng ta đã mở rộng danh mục cơ bản để thêm các loại tuỳ chỉnh của riêng mình.
Vì vậy, nếu chúng ta triển khai lại và thử một trong những câu lệnh này, thì hy vọng chúng ta sẽ có được giao diện người dùng xếp hạng.
Sau đó, tác nhân trả lời.
Và tại đây, bạn có thể thấy thành phần ngôi sao này là thành phần hoàn toàn mới mà tác nhân chưa từng thấy cho đến khi chúng ta triển khai ngay bây giờ.
Đây không phải là một phần của danh mục cơ bản, chúng ta vừa tạo danh mục này.
Khi tôi nhấp vào dấu sao, đó là lúc hàm lambda bindUpdater được gọi và giá trị được cập nhật trong mô hình dữ liệu.
Và nếu gửi điểm xếp hạng, chúng ta có thể xem xét hành động và bối cảnh của hành động sẽ bao gồm các giá trị mà chúng ta vừa đặt.
Được rồi, giờ chúng ta hãy quay lại trang trình bày.
Chúng ta đã đi qua khá nhiều nội dung trong thời gian ngắn, nhưng hy vọng chúng tôi đã cho bạn thấy cách dễ dàng chuyển từ việc tác nhân phản hồi bằng một khối văn bản sang việc tác nhân thực sự tạo ra giao diện người dùng gốc.
Hy vọng chúng tôi đã cho bạn thấy rằng việc tích hợp khá dễ dàng.
Có 3 thành phần chính mà bạn cần thực hiện: tạo danh mục thành phần, triển khai một số logic phân tích cú pháp, sau đó kết xuất danh mục đó trong giao diện người dùng.
Và hy vọng chúng tôi đã cho bạn thấy rằng thư viện này có thể làm được rất nhiều việc cho bạn ngay từ đầu, chẳng hạn như kết xuất tăng dần hoặc xác thực giản đồ, vòng lặp tự sửa lỗi hoặc xử lý lỗi. Thư viện này làm được rất nhiều việc.
Và hy vọng rằng hôm nay chúng tôi đã nhanh chóng chứng minh được rằng bạn có thể dễ dàng tuỳ chỉnh báo cáo này.
Chúng tôi đã trình bày cách danh mục cơ bản phản hồi Tuỳ chỉnh giao diện Material nếu bạn đang sử dụng Material, nhưng việc mở rộng hoặc thay thế các thành phần trong danh mục thực sự rất đơn giản.
Nhưng tôi nghĩ rằng sức mạnh lớn nhất đến từ việc bạn thực sự tạo ra danh mục của riêng mình.
Nếu muốn có quyền kiểm soát cao nhất đối với giao diện người dùng mà tác nhân có thể thực sự sử dụng, bạn có thể tạo các thành phần hoàn toàn tuỳ chỉnh.
Nếu muốn để Gemini hoàn toàn tự do, bạn có thể cung cấp cho Gemini các thành phần rất cơ bản, chẳng hạn như nhãn văn bản và nút, rồi nói: "Hãy tạo giao diện người dùng".
Nếu muốn có nhiều quyền kiểm soát hơn, bạn có thể tạo các thành phần phức tạp hơn và nói: "Đây là những thành phần duy nhất mà bạn có thể sử dụng".
Vì vậy, bạn có thể kiểm soát những việc mà tác nhân có thể làm và hiển thị cho người dùng.
Đây là thư viện trình kết xuất A2UI và thư viện Jetpack mới mà chúng tôi vừa ra mắt.
implementation("androidx.compose.material3:material3-a2ui:1.0.0-alpha02")Thư viện này hiện đang ở giai đoạn Alpha, Alpha 02 vừa mới ra mắt gần đây.
Vì vậy, hãy truy cập vào các đường liên kết sau để tìm hiểu.
Chúng tôi có tài liệu trên developer.android.com, cũng như một số mẫu.
Chúng tôi có một mẫu cơ bản cho thấy danh mục cơ bản, cũng như một mẫu chi tiết hơn và ứng dụng mẫu JetPacker mà chúng tôi vừa tạo. Bạn sẽ thấy lại ứng dụng này trong bài phát biểu chính của ADS vào cuối ngày hôm nay, minh hoạ cách bạn có thể tạo các thành phần chi tiết hơn để kiểm soát nội dung mà người dùng nhìn thấy.
Như tôi đã nói, chúng tôi hiện đang trong giai đoạn Alpha, vì vậy, đây là thời điểm tuyệt vời để bạn dùng thử và gửi ý kiến phản hồi cũng như yêu cầu về tính năng cho chúng tôi, đồng thời cho chúng tôi biết bạn muốn sử dụng tính năng này như thế nào hoặc bạn muốn sử dụng tính năng này nếu tính năng này có thể làm được X hoặc Y.
Vì vậy, hãy xem thư viện và cho chúng tôi biết ý kiến phản hồi của bạn.
Và đó là những gì chúng tôi nhận được.
Tôi rất mong được thấy những gì bạn và các nhân viên hỗ trợ của bạn xây dựng bằng công cụ này.
Cảm ơn bạn rất nhiều.
Cảm ơn bạn.