Way Back Home – Kiến trúc hướng sự kiện với Google ADK, A2A và Kafka

1. The Mission

Câu chuyện

Bạn đang trôi dạt trong sự tĩnh lặng của một khu vực chưa được khám phá. Một Xung lực mặt trời cực mạnh đã xé toạc con tàu của bạn qua một vết nứt, khiến bạn mắc kẹt trong một vùng vũ trụ không có trên bất kỳ biểu đồ sao nào.

Sau nhiều ngày sửa chữa vất vả, cuối cùng bạn cũng cảm nhận được tiếng động cơ gầm rú dưới chân. Tàu vũ trụ của bạn đã được sửa chữa. Bạn thậm chí còn tìm được cách liên lạc tầm xa với Tàu mẹ. Bạn đã được phép khởi hành. Bạn đã sẵn sàng về nhà.

Nhưng khi bạn chuẩn bị kích hoạt ổ đĩa nhảy, một tín hiệu cấp cứu sẽ xuyên qua tĩnh điện. Các cảm biến của bạn sẽ nhận được tín hiệu đề nghị trợ giúp. 5 thường dân bị mắc kẹt trên bề mặt của hành tinh X-42. Hy vọng duy nhất của họ là 15 chiếc tàu cổ phải được đồng bộ hoá để truyền tín hiệu cấp cứu đến tàu mẹ đang bay trên quỹ đạo.

Tuy nhiên, các khoang này được điều khiển bởi một trạm vệ tinh có máy tính điều hướng chính bị hỏng. Các nhóm này đang trôi dạt không mục đích. Chúng tôi đã thiết lập được một kết nối bí mật với vệ tinh, nhưng đường truyền lên bị ảnh hưởng nghiêm trọng bởi nhiễu sóng giữa các vì sao, gây ra độ trễ lớn trong các chu kỳ yêu cầu-phản hồi.

Thách thức

Vì mô hình yêu cầu/phản hồi quá chậm, nên chúng ta cần triển khai Kiến trúc hướng sự kiện (EDA) bằng Sự kiện do máy chủ gửi (SSE) để truyền trực tuyến dữ liệu đo từ xa qua nhiễu.

Khu vực truyền giáo

Bạn sẽ cần tạo một Agent tuỳ chỉnh có thể tính toán phép toán vectơ phức tạp cần thiết để buộc các pod vào các đội hình tăng cường tín hiệu cụ thể (Vòng tròn, Ngôi sao, Đường thẳng). Bạn phải kết nối tác nhân này vào cấu trúc mới của vệ tinh.

Sản phẩm bạn sẽ tạo ra

Tổng quan

  • Màn hình hiển thị thông tin (HUD) dựa trên React để trực quan hoá và điều khiển một nhóm gồm 15 thiết bị theo thời gian thực.
  • Một Trợ lý AI tạo sinh sử dụng Bộ công cụ phát triển (ADK) của Google để tính toán các hình học phức tạp cho các nhóm dựa trên các lệnh bằng ngôn ngữ tự nhiên.
  • Một phần phụ trợ Trạm vệ tinh dựa trên Python đóng vai trò là trung tâm, giao tiếp với giao diện người dùng thông qua Sự kiện do máy chủ gửi (SSE).
  • Cấu trúc hướng sự kiện sử dụng Apache Kafka để tách tác nhân AI khỏi hệ thống điều khiển vệ tinh, cho phép giao tiếp linh hoạt và không đồng bộ.

Kiến thức bạn sẽ học được

Công nghệ / Khái niệm

Mô tả

Google ADK (Bộ công cụ phát triển tác nhân)

Bạn sẽ sử dụng khung này để xây dựng, kiểm thử và giàn giáo một tác nhân AI chuyên biệt dựa trên các mô hình Gemini.

Kiến trúc hướng sự kiện (EDA)

Bạn sẽ tìm hiểu các nguyên tắc xây dựng một hệ thống tách rời, trong đó các thành phần giao tiếp không đồng bộ thông qua các sự kiện, giúp ứng dụng có khả năng phục hồi và mở rộng hơn.

Apache Kafka

Bạn sẽ thiết lập và sử dụng Kafka làm nền tảng truyền phát sự kiện phân tán để quản lý luồng lệnh và dữ liệu giữa các vi dịch vụ.

Sự kiện do máy chủ gửi (SSE)

Bạn sẽ triển khai SSE trong một phần phụ trợ FastAPI để truyền dữ liệu đo từ xa theo thời gian thực từ máy chủ đến giao diện người dùng React, giúp giao diện người dùng luôn được cập nhật.

Giao thức A2A (Agent-to-Agent)

Bạn sẽ tìm hiểu cách bao bọc tác nhân của mình trong một máy chủ A2A, cho phép giao tiếp và khả năng tương tác được tiêu chuẩn hoá trong một hệ sinh thái tác nhân rộng lớn hơn.

FastAPI

Bạn sẽ tạo dịch vụ phụ trợ cốt lõi, Trạm vệ tinh, bằng cách sử dụng khung web Python hiệu suất cao này.

Bày tỏ cảm xúc

Bạn sẽ làm việc với một ứng dụng giao diện người dùng hiện đại đăng ký một luồng SSE để tạo giao diện người dùng linh động và có tính tương tác.

AI tạo sinh trong System Control

Bạn sẽ thấy cách một Mô hình ngôn ngữ lớn (LLM) có thể được nhắc thực hiện các tác vụ cụ thể, hướng đến dữ liệu (chẳng hạn như tạo toạ độ) thay vì chỉ trò chuyện thông thường.

2. Thiết lập môi trường

Truy cập Cloud Shell

👉Nhấp vào biểu tượng Kích hoạt Cloud Shell ở đầu bảng điều khiển Google Cloud (Đây là biểu tượng có hình dạng thiết bị đầu cuối ở đầu ngăn Cloud Shell), cloud-shell.png

👉Nhấp vào nút "Mở trình chỉnh sửa" (nút này trông giống như một thư mục đang mở có bút chì). Thao tác này sẽ mở Trình chỉnh sửa mã Cloud Shell trong cửa sổ. Bạn sẽ thấy một trình khám phá tệp ở bên trái. open-editor.png

👉Mở cửa sổ dòng lệnh trong IDE trên đám mây,

03-05-new-terminal.png

👉💻 Trong thiết bị đầu cuối, hãy xác minh rằng bạn đã được xác thực và dự án được đặt thành mã dự án của bạn bằng lệnh sau:

gcloud auth list

Bạn sẽ thấy tài khoản của mình được liệt kê là (ACTIVE).

Điều kiện tiên quyết

ℹ️ Cấp 0 là không bắt buộc (nhưng nên dùng)

Bạn có thể hoàn thành nhiệm vụ này mà không cần đạt Cấp 0, nhưng hoàn thành nhiệm vụ này trước sẽ mang đến trải nghiệm sống động hơn, cho phép bạn thấy đèn hiệu của mình sáng lên trên bản đồ toàn cầu khi bạn tiến bộ.

Thiết lập môi trường dự án

Quay lại thiết bị đầu cuối, hoàn tất cấu hình bằng cách đặt dự án đang hoạt động và bật các dịch vụ cần thiết của Google Cloud (Cloud Run, Vertex AI, v.v.).

👉💻 Trong thiết bị đầu cuối, hãy đặt Mã dự án:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Bật các dịch vụ bắt buộc:

gcloud services enable  compute.googleapis.com \
                        artifactregistry.googleapis.com \
                        run.googleapis.com \
                        cloudbuild.googleapis.com \
                        iam.googleapis.com \
                        aiplatform.googleapis.com \
                        cloudresourcemanager.googleapis.com

Cài đặt các phần phụ thuộc

👉💻 Chuyển đến Cấp 5 và cài đặt các gói Python bắt buộc:

cd $HOME/way-back-home/level_5
uv sync

Sau đây là các phần phụ thuộc chính:

Gói

Mục đích

fastapi

Khung web hiệu suất cao cho Trạm vệ tinh và tính năng truyền trực tuyến SSE

uvicorn

Cần có máy chủ ASGI để chạy ứng dụng FastAPI

google-adk

Bộ công cụ phát triển tác nhân dùng để tạo Tác nhân hình thành

a2a-sdk

Thư viện giao thức Agent-to-Agent để giao tiếp chuẩn hoá

aiokafka

Ứng dụng Kafka không đồng bộ cho Vòng lặp sự kiện

google-genai

Ứng dụng gốc để truy cập vào các mô hình Gemini

numpy

Các phép toán vectơ và phép tính toạ độ cho mô phỏng

websockets

Hỗ trợ giao tiếp hai chiều theo thời gian thực

python-dotenv

Quản lý các biến môi trường và bí mật cấu hình

sse-starlette

Xử lý hiệu quả các Sự kiện do máy chủ gửi (SSE)

requests

Thư viện HTTP đơn giản cho các lệnh gọi API bên ngoài

Xác minh chế độ thiết lập

Trước khi bắt đầu với mã, hãy đảm bảo rằng tất cả hệ thống đều hoạt động bình thường. Chạy tập lệnh xác minh để kiểm tra Dự án Google Cloud, API và các phần phụ thuộc Python.

👉💻 Chạy tập lệnh xác minh:

source $HOME/way-back-home/.venv/bin/activate
cd $HOME/way-back-home/level_5/scripts
chmod +x verify_setup.sh
. verify_setup.sh

👀 Bạn sẽ thấy một loạt Dấu kiểm màu xanh lục (✅).

  • Nếu bạn thấy Dấu chéo màu đỏ (❌), hãy làm theo các lệnh khắc phục được đề xuất trong đầu ra (ví dụ: gcloud services enable ... hoặc pip install ...).
  • Lưu ý: Cảnh báo màu vàng cho .env hiện có thể chấp nhận được; chúng ta sẽ tạo tệp đó ở bước tiếp theo.
🚀 Verifying Mission Charlie (Level 5) Infrastructure...

✅ Google Cloud Project: xxxxxx
✅ Cloud APIs: Active
✅ Python Environment: Ready

🎉 SYSTEMS ONLINE. READY FOR MISSION.

3. Định dạng vị trí của nhóm bằng LLM

Chúng ta cần xây dựng "Bộ não" cho hoạt động cứu hộ. Đây sẽ là một Đặc vụ được tạo bằng Google ADK (Bộ phát triển đặc vụ). Mục đích duy nhất của nó là hoạt động như một công cụ điều hướng hình học chuyên dụng. Mặc dù các LLM tiêu chuẩn thích trò chuyện, nhưng trong không gian sâu thẳm, chúng ta cần dữ liệu chứ không phải đối thoại. Chúng ta sẽ lập trình cho tác nhân này để nhận một lệnh như "Star" (Ngôi sao) và trả về toạ độ JSON thô cho 15 nhóm của chúng ta.

Nhân viên hỗ trợ

Tạo khung cho tác nhân

👉💻 Chạy các lệnh sau để chuyển đến thư mục tác nhân và khởi động trình hướng dẫn tạo ADK:

cd $HOME/way-back-home/level_5/agent
uv run adk create formation

CLI sẽ khởi chạy một trình hướng dẫn thiết lập tương tác. Sử dụng các phản hồi sau để định cấu hình tác nhân:

  1. Chọn một mô hình: Chọn Lựa chọn 1 (Gemini Flash).
    • Lưu ý: Phiên bản cụ thể có thể khác nhau. Luôn chọn biến thể "Flash" để có tốc độ nhanh.
  2. Chọn một phần phụ trợ: Chọn Lựa chọn 2 (Vertex AI).
  3. Nhập mã dự án trên Google Cloud: Nhấn Enter để chấp nhận giá trị mặc định (được phát hiện từ môi trường của bạn).
  4. Nhập khu vực của Google Cloud: Nhấn Enter để chấp nhận giá trị mặc định (us-central1).

👀 Tương tác của bạn với thiết bị đầu cuối sẽ có dạng như sau:

(way-back-home) user@cloudshell:~/way-back-home/level_5/agent$ adk create formation

Choose a model for the root agent:
1. gemini-2.5-flash
2. Other models (fill later)
Choose model (1, 2): 1

1. Google AI
2. Vertex AI
Choose a backend (1, 2): 2

You need an existing Google Cloud account and project...
Enter Google Cloud project ID [your-project-id]: <PRESS ENTER>
Enter Google Cloud region [us-central1]: <PRESS ENTER>

Agent created in /home/user/way-back-home/level_5/agent/formation:
- .env
- __init__.py
- agent.py

Bạn sẽ thấy thông báo thành công Agent created. Thao tác này sẽ tạo mã skeleton mà chúng ta sẽ sửa đổi.

👉✏️ Chuyển đến và mở tệp $HOME/way-back-home/level_5/agent/formation/agent.py mới tạo trong trình chỉnh sửa. Thay thế toàn bộ nội dung của tệp bằng đoạn mã bên dưới. Thao tác này sẽ cập nhật tên của tác nhân và cung cấp các thông số hoạt động nghiêm ngặt của tác nhân.

import os
from google.adk.agents import Agent

root_agent = Agent(
    name="formation_agent",
    model="gemini-2.5-flash",
    instruction="""
    You are the **Formation Controller AI**.
    Your strict objective is to calculate X,Y coordinates for a fleet of **15 Drones** based on a requested geometric shape.

    ### FIELD SPECIFICATIONS
    - **Canvas Size**: 800px (width) x 600px (height).
    - **Safe Margin**: Keep pods at least 50px away from edges (x: 50-750, y: 50-550).
    - **Center Point**: x=400, y=300 (Use this as the origin for shapes).
    - **Top Menu Avoidance**: Do NOT place pods in the top 100px (y < 100) to avoid UI overlap.

    ### FORMATION RULES
    When given a formation name, output coordinates for exactly 15 pods (IDs 0-14).
    1.  **CIRCLE**: Evenly spaced around a center point (R=200).
    2.  **STAR**: 5 points or a star-like distribution.
    3.  **X**: A large X crossing the screen.
    4.  **LINE**: A horizontal line across the middle.
    5.  **PARABOLA**: A U-shape opening UPWARDS. Center it at y=400, opening up to y=100. IMPORTANT: Lowest point must be at bottom (high Y value), opening up (low Y value). Screen coordinates have (0,0) at the TOP-LEFT. The vertex should be at the BOTTOM (e.g., y=500), with arms reaching up to y=200.
    6.  **RANDOM**: Scatter randomly within safe bounds.
    7.  **CUSTOM**: If the user inputs something else (e.g., "SMILEY", "TRIANGLE"), do your best to approximate it geometrically.

    ### OUTPUT FORMAT
    You MUST output **ONLY VALID JSON**. No markdown fencing, no preamble, no commentary.
    Refuse to answer non-formation questions.

    **JSON Structure**:
    ```json
    [
        {"x": 400, "y": 300},
        {"x": 420, "y": 300},
        ... (15 total items)
    ]
    ```
    """
)
  • Độ chính xác về hình học: Bằng cách xác định "Kích thước canvas" và "Lề an toàn" trong câu lệnh hệ thống, chúng tôi đảm bảo rằng tác nhân không đặt các khối ngoài màn hình hoặc bên dưới các phần tử trên giao diện người dùng.
  • Thực thi JSON: Bằng cách yêu cầu LLM "Từ chối trả lời các câu hỏi không phải là câu hỏi về thông tin" và cung cấp "Không có phần mở đầu", chúng tôi đảm bảo mã hạ lưu (Satellite) không gặp sự cố khi cố gắng phân tích cú pháp phản hồi.
  • Decoupled Logic (Logic tách biệt): Tác nhân này chưa biết về Kafka. Công cụ này chỉ biết cách làm toán. Trong bước tiếp theo, chúng ta sẽ gói "Brain" này trong một Máy chủ Kafka.

Kiểm thử Agent cục bộ

Trước khi kết nối tác nhân với "hệ thần kinh" Kafka, chúng ta phải đảm bảo rằng tác nhân này hoạt động chính xác. Bạn có thể tương tác trực tiếp với tác nhân trong thiết bị đầu cuối để xác minh rằng tác nhân tạo ra các toạ độ JSON hợp lệ.

👉💻 Sử dụng lệnh adk run để bắt đầu một phiên trò chuyện với tác nhân.

cd $HOME/way-back-home/level_5/agent
uv run adk run formation
  1. Đầu vào: Nhập Circle rồi nhấn Enter.
    • Tiêu chí thành công: Bạn sẽ thấy một danh sách JSON thô (ví dụ: [{"x": 400, "y": 200}, ...]). Đảm bảo không có văn bản đánh dấu như "Đây là toạ độ:" trước JSON.
  2. Đầu vào: Nhập Line rồi nhấn Enter.
    • Tiêu chí thành công: Xác minh rằng các toạ độ tạo thành một đường thẳng ngang (các giá trị y phải tương tự nhau).

Sau khi xác nhận rằng tác nhân xuất ra JSON rõ ràng, bạn đã sẵn sàng gói JSON đó trong Máy chủ Kafka.

👉💻 Nhấn Ctrl+C để thoát.

4. Tạo máy chủ A2A cho tác nhân Formation

Tìm hiểu về A2A (Nhân viên hỗ trợ với nhân viên hỗ trợ)

Giao thức A2A (Tác nhân với tác nhân) là một tiêu chuẩn mở được thiết kế để cho phép khả năng tương tác liền mạch giữa các tác nhân AI. Khung này giúp các trợ lý ảo không chỉ trao đổi văn bản đơn thuần mà còn có thể uỷ quyền các tác vụ, phối hợp các hành động phức tạp và hoạt động như một đơn vị gắn kết để đạt được các mục tiêu chung trong một hệ sinh thái phân tán.

A2A

Tìm hiểu về các phương thức truyền dữ liệu A2A: HTTP, gRPC và Kafka

Giao thức A2A cung cấp 2 cách riêng biệt để máy khách và tác nhân giao tiếp, mỗi cách phục vụ một nhu cầu về cấu trúc khác nhau. HTTP (JSON-RPC) là tiêu chuẩn mặc định, phổ biến và hoạt động trên mọi môi trường web. gRPC là lựa chọn có hiệu suất cao của chúng tôi, tận dụng Protocol Buffers (Bộ đệm giao thức) để giao tiếp hiệu quả và được nhập một cách nghiêm ngặt. Và trong phòng thí nghiệm, tôi cũng cung cấp một phương thức truyền tải Kafka. Đây là một chế độ triển khai tuỳ chỉnh được thiết kế cho các cấu trúc mạnh mẽ, hướng sự kiện, trong đó việc tách rời các hệ thống là ưu tiên hàng đầu.

Giao thông vận tải

Trong trường hợp này, các phương thức truyền tải này xử lý luồng dữ liệu theo cách hoàn toàn khác. Trong mô hình HTTP, ứng dụng gửi một yêu cầu JSON và giữ kết nối mở, chờ tác nhân hoàn tất nhiệm vụ và trả về kết quả hoàn chỉnh trong một lần. gRPC tối ưu hoá quy trình này bằng cách sử dụng dữ liệu nhị phân và HTTP/2, cho phép cả chu kỳ yêu cầu-phản hồi đơn giản và truyền trực tuyến theo thời gian thực, trong đó tác nhân gửi thông tin cập nhật (chẳng hạn như "suy nghĩ" hoặc "tạo tác phẩm") khi chúng xảy ra. Việc triển khai Kafka hoạt động không đồng bộ: máy khách xuất bản một yêu cầu đến "chủ đề yêu cầu" có độ bền cao và lắng nghe trên một "chủ đề trả lời" riêng biệt. Máy chủ sẽ nhận tin nhắn khi có thể, xử lý tin nhắn đó và đăng kết quả trở lại, tức là hai máy chủ này không bao giờ giao tiếp trực tiếp với nhau.

Lựa chọn này phụ thuộc vào các yêu cầu cụ thể của bạn về tốc độ, độ phức tạp và độ bền. HTTP là giao thức dễ bắt đầu và gỡ lỗi nhất, nên rất phù hợp với các hoạt động tích hợp đơn giản. gRPC là lựa chọn vượt trội cho hoạt động giao tiếp nội bộ giữa các dịch vụ với nhau, trong đó độ trễ thấp và thông tin cập nhật về tác vụ truyền phát trực tiếp là yếu tố quan trọng. Tuy nhiên, Kafka nổi bật là lựa chọn linh hoạt vì nó lưu trữ các yêu cầu trên đĩa trong một hàng đợi, các tác vụ của bạn vẫn tồn tại ngay cả khi máy chủ tác nhân gặp sự cố hoặc khởi động lại, mang lại mức độ bền bỉ và tách biệt mà cả HTTP lẫn gRPC đều không thể cung cấp.

Lớp truyền tải tuỳ chỉnh: Kafka

Kafka đóng vai trò là nền tảng không đồng bộ tách biệt bộ não của hoạt động (Formation Agent) khỏi các chế độ kiểm soát thực tế (Satellite Station). Thay vì buộc hệ thống phải chờ kết nối đồng bộ trong khi tác nhân tính toán các vectơ phức tạp, tác nhân sẽ xuất bản kết quả dưới dạng các sự kiện cho một chủ đề Kafka. Điều này đóng vai trò như một vùng đệm liên tục, cho phép Vệ tinh sử dụng các chỉ dẫn theo tốc độ của riêng nó và đảm bảo rằng dữ liệu đội hình không bao giờ bị mất, ngay cả khi có độ trễ mạng đáng kể hoặc hệ thống tạm thời gặp sự cố.

Bằng cách sử dụng Kafka, bạn sẽ chuyển đổi một quy trình tuyến tính chậm thành một quy trình truyền phát trực tuyến linh hoạt, trong đó các hướng dẫn và dữ liệu đo từ xa sẽ truyền độc lập, giúp HUD của nhiệm vụ phản hồi ngay cả trong quá trình xử lý AI chuyên sâu.

Kafka

Kafka là gì?

Kafka là một nền tảng truyền phát sự kiện phân tán. Trong Cấu trúc hướng sự kiện (EDA):

  1. Nhà sản xuất xuất bản thông báo lên "Chủ đề".
  2. Người dùng đăng ký các chủ đề đó và phản ứng khi có thông báo đến.

Tại sao nên sử dụng Kafka?

Nó tách rời các hệ thống của bạn. Formation Agent hoạt động độc lập, chờ các yêu cầu đến mà không cần biết danh tính hoặc trạng thái của người gửi. Điều này tách rời trách nhiệm, đảm bảo rằng ngay cả khi Satellite không kết nối mạng, quy trình làm việc vẫn nguyên vẹn; Kafka chỉ cần lưu trữ các thông báo cho đến khi Satellite kết nối lại.

Còn Google Cloud Pub/Sub thì sao?

Bạn hoàn toàn có thể sử dụng Google Cloud Pub/Sub cho việc này! Pub/Sub là dịch vụ nhắn tin không máy chủ của Google. Mặc dù Kafka rất phù hợp với các luồng có thông lượng cao và "có thể phát lại", nhưng Pub/Sub thường được ưu tiên vì dễ sử dụng. Trong lớp học lập trình này, chúng ta sẽ sử dụng Kafka để mô phỏng một bus thông báo ổn định và liên tục.

Khởi động Cụm Kafka cục bộ

Sao chép và dán toàn bộ khối lệnh bên dưới vào thiết bị đầu cuối. Thao tác này sẽ tải hình ảnh Kafka chính thức xuống và khởi động hình ảnh đó ở chế độ nền.

👉💻 Thực thi các lệnh sau trong cửa sổ dòng lệnh:

# Navigate to the correct mission directory first
cd $HOME/way-back-home/level_5

# Run the Kafka container in detached mode
docker run -d \
  --name mission-kafka \
  -p 9092:9092 \
  -e KAFKA_PROCESS_ROLES='broker,controller' \
  -e KAFKA_NODE_ID=1 \
  -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
  -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092 \
  -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@127.0.0.1:9093 \
  -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
  apache/kafka:4.2.0-rc1

👉💻 Kiểm tra để đảm bảo rằng vùng chứa đang chạy bằng lệnh docker ps.

docker ps

👀 Bạn sẽ thấy một kết quả xác nhận rằng vùng chứa mission-kafka đang chạy và cổng 9092 được hiển thị.

CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                               NAMES
c1a2b3c4d5e6   apache/kafka:4.2.0-rc1    "/opt/kafka/bin/kafka..."   15 seconds ago   Up 14 seconds   0.0.0.0:9092->9092/tcp, 9093/tcp   mission-kafka

Chủ đề Kafka là gì?

Hãy coi chủ đề Kafka như một kênh hoặc danh mục chuyên biệt cho các thông báo. Đây là một sổ nhật ký lưu trữ các bản ghi sự kiện theo thứ tự chúng được tạo ra. Producer ghi thông báo vào các chủ đề cụ thể và consumer đọc từ các chủ đề đó. Điều này tách người gửi khỏi người nhận; nhà sản xuất không cần biết người tiêu dùng nào sẽ đọc dữ liệu, mà chỉ cần gửi dữ liệu đến "kênh" phù hợp. Trong nhiệm vụ này, chúng ta sẽ tạo 2 chủ đề: một chủ đề để gửi yêu cầu hình thành đến tác nhân và một chủ đề khác để tác nhân xuất bản câu trả lời cho vệ tinh đọc.

Kafka

👉💻 Chạy các lệnh sau để tạo những chủ đề cần thiết trong vùng chứa Docker đang chạy.

# Create the topic for formation requests
docker exec mission-kafka /opt/kafka/bin/kafka-topics.sh \
  --create \
  --topic a2a-formation-request \
  --bootstrap-server 127.0.0.1:9092

# Create the topic where the satellite dashboard will listen for replies
docker exec mission-kafka /opt/kafka/bin/kafka-topics.sh \
  --create \
  --topic a2a-reply-satellite-dashboard \
  --bootstrap-server 127.0.0.1:9092

👉💻 Để xác nhận rằng các kênh của bạn đang mở, hãy chạy lệnh list:

docker exec mission-kafka /opt/kafka/bin/kafka-topics.sh \
  --list \
  --bootstrap-server 127.0.0.1:9092

👀 Bạn sẽ thấy tên của các chủ đề mà bạn vừa tạo.

a2a-formation-request
a2a-reply-satellite-dashboard

Giờ đây, phiên bản Kafka của bạn đã được định cấu hình đầy đủ và sẵn sàng định tuyến dữ liệu quan trọng.

Triển khai Máy chủ Kafka A2A

Giao thức Agent-to-Agent (A2A) thiết lập một khung tiêu chuẩn để có khả năng tương tác giữa các hệ thống độc lập dựa trên tác nhân. Điều này cho phép các tác nhân do nhiều nhóm phát triển hoặc chạy trên nhiều cơ sở hạ tầng khác nhau tìm thấy nhau và cộng tác hiệu quả mà không cần logic tích hợp riêng cho mọi kết nối.

Phương thức triển khai tham chiếu a2a-python là một thư viện nền tảng để chạy các ứng dụng dựa trên tác nhân này. Một tính năng cốt lõi trong thiết kế của nó là khả năng mở rộng; nó trừu tượng hoá lớp giao tiếp, cho phép nhà phát triển thay thế các giao thức như HTTP bằng các giao thức khác.

Quy trình A2A

Trong dự án này, chúng tôi tận dụng khả năng mở rộng này bằng cách sử dụng một quy trình triển khai Kafka tuỳ chỉnh: a2a-python-kafka. Chúng ta sẽ sử dụng cách triển khai này để minh hoạ cách tiêu chuẩn A2A cho phép bạn điều chỉnh hoạt động giao tiếp của tác nhân cho phù hợp với các nhu cầu về cấu trúc khác nhau. Trong trường hợp này, bạn có thể thay thế HTTP đồng bộ bằng một bus sự kiện không đồng bộ.

Bật A2A cho Formation Agent

Giờ đây, chúng ta sẽ bao bọc tác nhân trong một Máy chủ A2A, biến tác nhân đó thành một dịch vụ có khả năng tương tác, có thể:

  • Theo dõi các tác vụ từ một chủ đề Kafka.
  • Chuyển các tác vụ đã nhận cho tác nhân ADK cơ bản để xử lý.
  • Xuất bản kết quả vào một chủ đề trả lời.

👉✏️ Trong $HOME/way-back-home/level_5/agent/agent_to_kafka_a2a.py, hãy thay thế #REPLACE-CREATE-KAFKA-A2A-SERVER bằng đoạn mã sau:

async def create_kafka_server(
    agent: BaseAgent,
    *,
    bootstrap_servers: str | List[str] = "localhost:9092",
    request_topic: str = "a2a-formation-request",
    consumer_group_id: str = "a2a-agent-group",
    agent_card: Optional[Union[AgentCard, str]] = None,
    runner: Optional[Runner] = None,
    **kafka_config: Any,
) -> KafkaServerApp:
  """Convert an ADK agent to a A2A Kafka Server application.
  Args:
      agent: The ADK agent to convert
      bootstrap_servers: Kafka bootstrap servers.
      request_topic: Topic to consume requests from.
      consumer_group_id: Consumer group ID for the server.
      agent_card: Optional pre-built AgentCard object or path to agent card
                  JSON. If not provided, will be built automatically from the
                  agent.
      runner: Optional pre-built Runner object. If not provided, a default
              runner will be created using in-memory services.
      **kafka_config: Additional Kafka configuration.

  Returns:
      A KafkaServerApp that can be run with .run() or .start()
  """
  # Set up ADK logging
  adk_logger = logging.getLogger("google_adk")
  adk_logger.setLevel(logging.INFO)

  async def create_runner() -> Runner:
    """Create a runner for the agent."""
    return Runner(
        app_name=agent.name or "adk_agent",
        agent=agent,
        # Use minimal services - in a real implementation these could be configured
        artifact_service=InMemoryArtifactService(),
        session_service=InMemorySessionService(),
        memory_service=InMemoryMemoryService(),
        credential_service=InMemoryCredentialService(),
    )

  # Create A2A components
  task_store = InMemoryTaskStore()

  agent_executor = A2aAgentExecutor(
      runner=runner or create_runner,
  )
  
  # Initialize logic handler
  from a2a.server.request_handlers.default_request_handler import DefaultRequestHandler
  
  logic_handler = DefaultRequestHandler(
      agent_executor=agent_executor, task_store=task_store
  )

  # Prepare Agent Card
  rpc_url = f"kafka://{bootstrap_servers}/{request_topic}"
      
  # Create Kafka Server App
  server_app = KafkaServerApp(
      request_handler=logic_handler,
      bootstrap_servers=bootstrap_servers,
      request_topic=request_topic,
      consumer_group_id=consumer_group_id,
      **kafka_config
  )
  
  return server_app

Đoạn mã này thiết lập các thành phần chính:

  1. Trình chạy: Cung cấp thời gian chạy cho tác nhân (xử lý bộ nhớ, thông tin đăng nhập, v.v.).
  2. Task Store: Theo dõi trạng thái của các yêu cầu khi chúng chuyển từ "Đang chờ xử lý" sang "Đã hoàn thành".
  3. Agent Executor: Nhận một tác vụ từ Kafka và chuyển tác vụ đó cho tác nhân để tính toán toạ độ.
  4. KafkaServerApp: Quản lý kết nối thực tế với Kafka Broker.

A2A Kafka

Định cấu hình các biến môi trường

Chế độ thiết lập ADK đã tạo một tệp .env có các chế độ cài đặt Google Vertex AI bên trong thư mục của tác nhân. Chúng ta cần di chuyển tệp này đến thư mục gốc của dự án và thêm toạ độ cho cụm Kafka.

Chạy các lệnh sau để sao chép tệp và thêm địa chỉ máy chủ Kafka:

cd $HOME/way-back-home/level_5
# 1. Copy the API keys from the agent folder to the project root
cp agent/formation/.env .env

# 2. Append the Kafka Bootstrap Server address to the file
echo -e "\nKAFKA_BOOTSTRAP_SERVERS=localhost:9092" >> .env

# 3. Verify the file content
echo "✅ Environment configured. Here are the last few lines:"
tail .env

Xác minh Vòng lặp liên sao A2A

Giờ đây, chúng ta sẽ đảm bảo vòng lặp sự kiện không đồng bộ hoạt động chính xác bằng một bài kiểm thử thực tế: gửi tín hiệu thủ công thông qua cụm Kafka và theo dõi phản hồi của tác nhân.

Xác minh Vòng lặp liên sao A2A

Để xem toàn bộ vòng đời của một sự kiện, chúng ta sẽ sử dụng 3 thiết bị đầu cuối riêng biệt.

Thiết bị đầu cuối A: Tác nhân hình thành (Máy chủ A2A Kafka)

👉💻 Thiết bị đầu cuối này chạy quy trình Python để theo dõi Kafka và sử dụng Gemini để thực hiện phép tính hình học.

cd $HOME/way-back-home/level_5
source $HOME/way-back-home/.venv/bin/activate
. scripts/check_kafka.sh 

# Install the custom Kafka-enabled A2A library
uv pip install git+https://github.com/weimeilin79/a2a-python-kafka.git

# Start the Agent Server
uv run agent/server.py

Chờ đến khi bạn thấy:

[INFO] Kafka Server App Started. Starting to consume requests...

Terminal B: The Satellite Listener (Người tiêu dùng)

👉💻 Trong thiết bị đầu cuối này, chúng ta sẽ lắng nghe chủ đề phản hồi. Thao tác này mô phỏng trạng thái Vệ tinh đang chờ hướng dẫn.

# Listen for the AI's response on the satellite channel
docker exec mission-kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic a2a-reply-satellite-dashboard \
  --from-beginning \
  --property "print.headers=true"

Thiết bị đầu cuối này sẽ ở trạng thái không hoạt động. Đang đợi Nhân viên hỗ trợ xuất bản thông báo.

Terminal C: The Commander's Signal (Nhà sản xuất)

👉💻 Bây giờ, chúng ta sẽ gửi một yêu cầu thô có định dạng A2A vào chủ đề a2a-formation-request. Chúng ta phải thêm Tiêu đề Kafka cụ thể để Agent biết nơi gửi câu trả lời.

echo 'correlation_id=ping-manual-01,reply_topic=a2a-reply-satellite-dashboard|{"method": "message_send", "params": {"message": {"message_id": "msg-001", "role": "user", "parts": [{"text": "STAR"}]}}, "streaming": false, "agent_card": {"name": "DiagnosticTool", "version": "1.0.0"}}' | \
docker exec -i mission-kafka /opt/kafka/bin/kafka-console-producer.sh \
  --bootstrap-server localhost:9092 \
  --topic a2a-formation-request \
  --property "parse.headers=true" \
  --property "headers.key.separator==" \
  --property "headers.delimiter=|"

Phân tích kết quả

👀 Nếu vòng lặp thành công, hãy chuyển sang Thiết bị đầu cuối B. Một khối JSON lớn sẽ xuất hiện ngay lập tức. Nội dung này sẽ bắt đầu bằng tiêu đề mà chúng tôi đã gửi correlation_id:ping-manual-01. Tiếp theo là một đối tượng task. Nếu xem kỹ phần parts trong JSON đó, bạn sẽ thấy toạ độ X và Y thô mà Gemini đã tính toán cho 15 nhóm của bạn:

{"type": "task", "data": {"artifacts": [{"artifactId": "...", "parts": [{"kind": "text", "text": "```json\n[\n  {\"x\": 400, \"y\": 150},\n  {\"x\": 257, \"y\": 254},\n  {\"x\": 312, \"y\": 421},\n ... \n]\n```"}]}], ...}}

Bạn đã huỷ liên kết thành công thiết bị nhận với thiết bị truyền. "Tiếng ồn giữa các vì sao" của độ trễ yêu cầu-phản hồi không còn quan trọng nữa vì hệ thống của chúng tôi hiện hoàn toàn Dựa trên sự kiện.

Trước khi tiếp tục, hãy dừng các quy trình chạy nền để giải phóng các cổng mạng.

👉💻 Trong mỗi thiết bị đầu cuối (A, B và C):

  • Nhấn Ctrl + C để kết thúc quy trình đang chạy.

5. The Satellite Station (A2A Kafka Client và SSE)

Ở bước này, chúng ta sẽ xây dựng Trạm vệ tinh. Đây là cầu nối giữa cụm Kafka và màn hình hiển thị trực quan của phi công (Giao diện người dùng React). Máy chủ này đóng vai trò là cả Ứng dụng Kafka (để giao tiếp với Agent) và SSE Streamer (để giao tiếp với trình duyệt).

Kafka Client là gì?

Hãy coi Cụm Kafka như một đài phát thanh. Kafka Client là thiết bị nhận tín hiệu vô tuyến. KafkaClientTransport cho phép ứng dụng của chúng tôi:

  1. Tạo một thông báo: Gửi một "Việc cần làm" (ví dụ: "Star formation" (Sự hình thành sao) cho Trợ lý.
  2. Tiêu thụ một câu trả lời: Lắng nghe một "Chủ đề trả lời" cụ thể để nhận lại toạ độ từ Agent.

1. Khởi tạo kết nối

Chúng ta sử dụng trình xử lý sự kiện lifespan của FastAPI để đảm bảo kết nối Kafka bắt đầu khi máy chủ khởi động và đóng một cách gọn gàng khi máy chủ tắt.

👉✏️ Trong $HOME/way-back-home/level_5/satellite/main.py, hãy thay thế #REPLACE-CONNECT-TO-KAFKA-CLUSTER bằng đoạn mã sau:

@asynccontextmanager
async def lifespan(app: FastAPI):
    global kafka_transport
    logger.info("Initializing Kafka Client Transport...")
    
    bootstrap_server = os.getenv("KAFKA_BOOTSTRAP_SERVERS")
    request_topic = "a2a-formation-request"
    reply_topic = "a2a-reply-satellite-dashboard"
    
    # Create AgentCard for the Client
    client_card = AgentCard(
        name="SatelliteDashboard",
        description="Satellite Dashboard Client",
        version="1.0.0",
        url="https://example.com/satellite-dashboard",
        capabilities=AgentCapabilities(),
        default_input_modes=["text/plain"],
        default_output_modes=["text/plain"],
        skills=[]
    )
    
    kafka_transport = KafkaClientTransport(
            agent_card=client_card,
            bootstrap_servers=bootstrap_server,
            request_topic=request_topic,
            reply_topic=reply_topic,
    )
    
    try:
        await kafka_transport.start()
        logger.info("Kafka Client Transport Started Successfully.")
    except Exception as e:
        logger.error(f"Failed to start Kafka Client: {e}")
        
    yield
    
    if kafka_transport:
        logger.info("Stopping Kafka Client Transport...")
        await kafka_transport.stop()
        logger.info("Kafka Client Transport Stopped.")

2. Gửi lệnh

Khi bạn nhấp vào một nút trên trang tổng quan, điểm cuối /formation sẽ được kích hoạt. Nó đóng vai trò là một Producer (Nhà sản xuất), gói yêu cầu của bạn vào một Message A2A chính thức và gửi yêu cầu đó đến tác nhân.

Hình thành

Logic chính:

  • Giao tiếp không đồng bộ: kafka_transport.send_message gửi yêu cầu và chờ toạ độ mới xuất hiện trên reply_topic.
  • Phân tích cú pháp câu trả lời: Gemini có thể trả về toạ độ bên trong các khối đánh dấu (ví dụ: json ...). Mã dưới đây sẽ loại bỏ các dấu này và chuyển đổi chuỗi thành danh sách các điểm trong Python.

👉✏️ Trong $HOME/way-back-home/level_5/satellite/main.py, hãy thay thế #REPLACE-FORMATION-REQUEST bằng đoạn mã sau:

@app.post("/formation")
async def set_formation(req: FormationRequest):
    global FORMATION, PODS
    FORMATION = req.formation
    logger.info(f"Received formation request: {FORMATION}")
    
    if not kafka_transport:
        logger.error("Kafka Transport is not initialized!")
        return {"status": "error", "message": "Backend Not Connected"}
    
    try:
        # Construct A2A Message
        prompt = f"Create a {FORMATION} formation"
        logger.info(f"Sending A2A Message: '{prompt}'")
        
        from a2a.types import TextPart, Part, Role
        import uuid
        
        msg_id = str(uuid.uuid4())
        message_parts = [Part(TextPart(text=prompt))]
        
        msg_obj = Message(
            message_id=msg_id,
            role=Role.user,
            parts=message_parts
        )
        
        message_params = MessageSendParams(
            message=msg_obj
        )
        
        # Send and Wait for Response
        ctx = ClientCallContext()
        ctx.state["kafka_timeout"] = 120.0 # Timeout for GenAI latency
        response = await kafka_transport.send_message(message_params, context=ctx)
        
        logger.info("Received A2A Response.")
        
        content = None
        if isinstance(response, Message):
            content = response.parts[0].root.text if response.parts else None
        elif isinstance(response, Task):
            if response.artifacts and response.artifacts[0].parts:
                content = response.artifacts[0].parts[0].root.text

        if content:
            logger.info(f"Response Content: {content[:100]}...")
            try:
                clean_content = content.replace("```json", "").replace("```", "").strip()
                coords = json.loads(clean_content)
                
                if isinstance(coords, list):
                    logger.info(f"Parsed {len(coords)} coordinates.")
                    for i, pod_target in enumerate(coords):
                        if i < len(PODS):
                            PODS[i]["x"] = pod_target["x"]
                            PODS[i]["y"] = pod_target["y"]
                    return {"status": "success", "formation": FORMATION}
                else:
                    logger.error("Response JSON is not a list.")
            except json.JSONDecodeError as e:
                logger.error(f"Failed to parse Agent JSON response: {e}")
        else:
            logger.error(f"Could not extract content from response type {type(response)}")

    except Exception as e:
        logger.error(f"Error calling agent via Kafka: {e}")
        return {"status": "error", "message": str(e)}

Sự kiện do máy chủ gửi (SSE)

API chuẩn sử dụng mô hình "Yêu cầu-Phản hồi". Đối với HUD, chúng tôi cần một "Luồng trực tiếp" về vị trí của các nhóm.

Tại sao nên dùng SSE Không giống như WebSocket (có tính năng hai chiều và phức tạp hơn), SSE cung cấp một luồng dữ liệu đơn giản, một chiều từ máy chủ đến trình duyệt. Đây là lựa chọn hoàn hảo cho bảng điều khiển, bảng giá chứng khoán hoặc hệ thống đo từ xa liên hành tinh.

SSE

Cách hoạt động trong mã của chúng ta: Chúng ta tạo một event_generator, một vòng lặp vô tận lấy vị trí hiện tại của tất cả 15 nhóm sau mỗi nửa giây và "đẩy" các nhóm đó vào trình duyệt dưới dạng bản cập nhật.

👉✏️ Trong $HOME/way-back-home/level_5/satellite/main.py, hãy thay thế #REPLACE-SSE-STREAM bằng đoạn mã sau:

@app.get("/stream")
async def message_stream(request: Request):
    async def event_generator():
        logger.info("New SSE stream connected")
        try:
            while True:
                current_pods = list(PODS) 
                
                # Send updates one by one to simulate low-bandwidth scanning
                for pod in current_pods:
                     payload = {"pod": pod}
                     yield {
                         "event": "pod_update",
                         "data": json.dumps(payload)
                     }
                     await asyncio.sleep(0.02)
                
                # Send formation info occasionally
                yield {
                    "event": "formation_update",
                    "data": json.dumps({"formation": FORMATION})
                }
                
                # Main loop delay
                await asyncio.sleep(0.5)
                
        except asyncio.CancelledError:
             logger.info("SSE stream disconnected (cancelled)")
        except Exception as e:
             logger.error(f"SSE stream error: {e}")
             
    return EventSourceResponse(event_generator())

Thực hiện Vòng lặp nhiệm vụ đầy đủ

Hãy xác minh hệ thống hoạt động từ đầu đến cuối trước khi ra mắt giao diện người dùng cuối cùng. Chúng ta sẽ kích hoạt tác nhân theo cách thủ công và xem phần dữ liệu thực tế thô trên dây.

Xác minh

Mở 3 thẻ dòng lệnh riêng biệt.

Thiết bị đầu cuối A: Tác nhân hình thành (Máy chủ A2A)

👉💻 Đây là ADK Agent, có chức năng lắng nghe các tác vụ và thực hiện phép toán hình học.

cd $HOME/way-back-home/level_5
. scripts/check_kafka.sh 
# Start the Agent Server
uv run agent/server.py

Thiết bị B: Trạm vệ tinh (Ứng dụng Kafka)

👉💻 Máy chủ FastAPI này đóng vai trò là "Receiver" (Trình nhận), lắng nghe các phản hồi của Kafka và chuyển chúng thành một luồng SSE trực tiếp.

cd $HOME/way-back-home/level_5

# Start the Satellite Station
uv run satellite/main.py

Terminal C: The Manual HUD

Gửi lệnh hình thành (Điều kiện kích hoạt): 👉💻 Trong cùng một thiết bị đầu cuối C, hãy kích hoạt quy trình hình thành:

# Trigger the STAR formation via the Satellite's API
curl -X POST http://localhost:8000/formation \
     -H "Content-Type: application/json" \
     -d '{"formation": "STAR"}'

👀 Bạn sẽ thấy toạ độ mới.

INFO:satellite.main:Received formation request: STAR
INFO:satellite.main:Sending A2A Message: 'Create a STAR formation'
INFO:satellite.main:Received A2A Response.
INFO:satellite.main:Response Content: ```json ...
INFO:satellite.main:Parsed 15 coordinates.

Điều này xác nhận rằng Vệ tinh đã cập nhật toạ độ của nhóm nội bộ.

👉💻 Chúng ta sẽ dùng curl để trước tiên theo dõi luồng dữ liệu đo từ xa trực tiếp, sau đó kích hoạt thay đổi đội hình.

# Connect to the live telemetry feed.
# You should see 'pod_update' events ticking by.
curl -N http://localhost:8000/stream

👀 Xem kết quả của lệnh curl -N. Toạ độ xy trong các sự kiện pod_update sẽ bắt đầu phản ánh vị trí mới của đội hình Star.

Trước khi tiếp tục, hãy dừng tất cả các quy trình đang chạy để giải phóng các cổng giao tiếp.

Trong mỗi thiết bị đầu cuối (A, B, C và thiết bị đầu cuối kích hoạt): Nhấn Ctrl + C.

6. Go Rescue!

Bạn đã thiết lập hệ thống thành công. Giờ là lúc bạn thực hiện nhiệm vụ. Giờ đây, chúng ta sẽ ra mắt Màn hình hiển thị ngang tầm mắt (HUD) dựa trên React. Bảng điều khiển này kết nối với Trạm vệ tinh thông qua SSE, cho phép bạn hình dung 15 nhóm theo thời gian thực.

Tổng quan

Khi đưa ra một lệnh, bạn không chỉ gọi một hàm mà còn kích hoạt một sự kiện truyền qua Kafka, được xử lý bởi một tác nhân AI và truyền trực tiếp trở lại màn hình của bạn dưới dạng dữ liệu đo từ xa trực tiếp.

Xác minh

Mở hai thẻ dòng lệnh riêng biệt.

Thiết bị đầu cuối A: Tác nhân hình thành (Máy chủ A2A)

👉💻 Đây là ADK Agent, có chức năng lắng nghe các tác vụ và thực hiện phép toán hình học bằng Gemini. Trong thiết bị đầu cuối, hãy chạy:

cd $HOME/way-back-home/level_5
# Start the Agent Server
uv run agent/server.py

Nhà ga B: Trạm vệ tinh và trang tổng quan trực quan

👉💻 Trước tiên, hãy tạo ứng dụng giao diện người dùng.

cd $HOME/way-back-home/level_5/frontend/
npm install
npm run build

👉💻 Bây giờ, hãy khởi động máy chủ FastAPI. Máy chủ này sẽ phục vụ cả logic phụ trợ và giao diện người dùng.

cd $HOME/way-back-home/level_5
. scripts/check_kafka.sh 
# Start the Satellite Station
uv run satellite/main.py

Phát hành và xác minh

  1. 👉 Mở bản xem trước: Trong thanh công cụ Cloud Shell, hãy nhấp vào biểu tượng Xem trước trên web. Chọn Thay đổi cổng, đặt thành 8000 rồi nhấp vào Thay đổi và xem trước. Một thẻ trình duyệt mới sẽ mở ra và cho thấy HUD của Starfield. *Web-Preview
  2. 👉 Xác minh luồng dữ liệu đo từ xa:
    • Sau khi giao diện người dùng tải, bạn sẽ thấy 15 nhóm được phân tán ngẫu nhiên.
    • Nếu các pod đang nhấp nháy nhẹ hoặc "rung", thì luồng SSE của bạn đang hoạt động và Trạm vệ tinh đang phát sóng vị trí của các pod thành công. Bắt đầu
  3. 👉 Bắt đầu một Formation: Nhấp vào nút "STAR" trên trang tổng quan. Hình ngôi sao
  4. 👀 Theo dõi Vòng lặp sự kiện: Theo dõi các thiết bị đầu cuối để xem kiến trúc đang hoạt động:
    • Nhà ga B (Nhà ga vệ tinh) sẽ ghi nhật ký: Sending A2A Message: 'Create a STAR formation'.
    • Terminal A (Formation Agent) sẽ cho biết hoạt động khi tham khảo Gemini.
    • Terminal B (Satellite Station) sẽ ghi nhật ký: Received A2A Response và phân tích cú pháp toạ độ.
  5. 👀 Xác nhận bằng hình ảnh: Xem 15 khối trên trang tổng quan của bạn di chuyển mượt mà từ vị trí ngẫu nhiên thành hình ngôi sao 5 cánh.
  6. 👉 Thử nghiệm:
    • Đối với 3 đội hình khác nhau, hãy thử "X" hoặc "LINE". X
    • Ý định tuỳ chỉnh: Sử dụng phương thức nhập thủ công để nhập một nội dung nào đó độc đáo, chẳng hạn như "Trái tim" hoặc "Hình tam giác". Hình tròn
    • Vì bạn đang sử dụng AI tạo sinh, nên tác nhân sẽ cố gắng tính toán toán học cho mọi hình dạng hình học mà bạn có thể mô tả!

Sau khi tạo 3 mẫu hình, bạn đã kết nối lại thành công. XONG

HOÀN THÀNH NHIỆM VỤ!

Luồng dữ liệu ổn định khi dữ liệu truyền qua nhiễu mà không bị gián đoạn. Theo lệnh của bạn, 15 chiếc vỏ cổ đại bắt đầu điệu nhảy đồng bộ trên khắp các vì sao.

Kết thúc

Qua 3 giai đoạn hiệu chuẩn đầy gian nan, bạn đã chứng kiến dữ liệu đo từ xa được ghi nhận. Với mỗi lần điều chỉnh, tín hiệu ngày càng mạnh hơn, cuối cùng xuyên qua nhiễu loạn giữa các vì sao như một ngọn hải đăng hy vọng.

Nhờ bạn và việc bạn triển khai Event-Driven Agent một cách thành thạo, 5 người sống sót đã được đưa lên máy bay từ bề mặt của X-42 và hiện đang an toàn trên tàu cứu hộ. Nhờ bạn, 5 sinh mạng đã được cứu sống.

Nếu bạn đã tham gia Cấp độ 0, đừng quên kiểm tra tiến trình của bạn trong nhiệm vụ Way Back Home! Hành trình trở về các vì sao của bạn vẫn tiếp diễn.BẢN CHÍNH THỨC