Điều phối ADK 2: Đồ thị, quy trình làm việc cộng tác và linh hoạt

1. Tổng quan

Tiêu đề của ADK 2 là 3 mẫu điều phối. Lớp học lập trình này hướng dẫn cả 3 cách bằng cách tạo một ứng dụng – Huấn luyện viên cho ngày đua marathon – từng bước một. Mỗi cấp độ trả lời một câu hỏi, thêm một ý tưởng và chạy độc lập.

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

  • Quy trình công việc dạng biểu đồ (Trụ cột 1) – khi bạn có thể vẽ quy trình trước khi dữ liệu đầu vào đến.
  • Các tác nhân cộng tác (Trụ cột 2) – khi bạn biết nhóm nhưng yêu cầu chọn một nhóm nhỏ – và cả 3 chế độ cộng tác (chat / task / single_turn) đều chạy trực tiếp.
  • Quy trình công việc linh hoạt (Trụ cột 3) – khi hình thức của công việc phụ thuộc vào dữ liệu đầu vào.
  • Cách chọn – cây quyết định gồm một câu hỏi và cách các mẫu kết hợp với nhau.

Điểm chung

cấu trúc đã biết → nhóm / tập hợp biến đã biết → hình dạng không xác định → chọn hình dạng phù hợp

Lộ trình học tập của bạn

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

Một ứng dụng – Marathon Race Day Coach – đã lắp ráp từng cấp độ có thể chạy một lần. Mỗi cấp độ là một mô-đun Python đơn giản mà bạn chạy từ thiết bị đầu cuối; đến cấp độ 5, bạn sẽ có tất cả các phần bên dưới.

Hình ảnh được vẽ từ mã đang chạy: mọi đường liền nét đều được đọc từ Workflow.graph.edges. Đó là bài học đầu tiên – những phần có thể vẽ trước chính là Trụ cột 1, còn những phần không thể vẽ trước là lý do tồn tại của Trụ cột 2 và 3.

Toàn bộ ứng dụng và những gì mà biểu đồ không thể cho bạn biết

Bạn cần có

  • Tài khoản Google (đối với Colab) – không cần thiết lập cục bộ.
  • Khoảng 50 phút (hai cấp độ L4 là những cấp độ dài – hãy dành thời gian cho chúng).
  • Một trong hai cách để sử dụng mô hình Gemini. Chọn cách thiết lập – bạn chạy một bước thiết lập và bỏ qua bước còn lại:

🎓 Hội thảo

🏠 Mang về nhà

Người tham gia

Bạn đang tham gia một hội thảo trực tiếp và người hướng dẫn đã gửi cho bạn một đường liên kết nhận tín dụng

Những người khác (kể cả người tham dự hội thảo) sau đó

Bạn cần

Đường liên kết xác nhận quyền sở hữu và một Tài khoản Google có thể tạo dự án trên đám mây

Một khoá AI Studio API miễn phí

Chạy trên

Vertex AI, trong một dự án được tính phí vào tín dụng hội thảo của bạn

Google AI Studio

Chi phí

Được tính vào khoản tín dụng

Bậc miễn phí

Bước thiết lập

Thiết lập hội thảo (bước tiếp theo)

Thiết lập tại nhà (bước tiếp theo)

Mọi thứ từ phần Lời nói đầu trở đi đều giống hệt nhau theo cả hai cách – làn đường chỉ quyết định điểm cuối mô hình mà sổ tay tương tác.

Hai cách để theo dõi

Mỗi bước dưới đây tương ứng với một ô trong sổ tay Colabmột thư mục trong kho lưu trữ GitHub. Chọn một trong hai lựa chọn sau:

  • ▶ Colab (nên dùng): Mở sổ tay → chạy các ô từ trên xuống dưới.
  • 💻 Local: git clone repo, ./setup_venv.sh, sau đó chạy từng cấp độ dưới dạng một mô-đun (python -m ...) hoặc duyệt qua tất cả các cấp độ bằng ./run.sh (adk web).

2. Thiết lập hội thảo · Nhận tín dụng và chuyển sang Vertex AI

Tại hội thảo, bạn sẽ được cấp khoản tín dụng Google Cloud. Bạn sẽ xác nhận quyền sở hữu, tạo một dự án được tính phí cho dự án đó và trỏ sổ tay đến Vertex AI thay vì AI Studio. Một ô sẽ thực hiện mọi thao tác sau khi yêu cầu được gửi.

1 · Nhận khoản tín dụng (khoảng 1 phút)

  1. Mở đường liên kết nhận ưu đãi mà người hướng dẫn đã chia sẻ. Có vẻ như https://me.developers.google.com/benefits/claim/your-workshop-name.
  2. Đăng nhập và làm theo hướng dẫn trên trang để chấp nhận khoản tín dụng.
  3. Ghi lại Tài khoản Google mà bạn đã sử dụng. Mỗi bước dưới đây đều phải chạy dưới dạng tài khoản đó.

2 · Mở sổ tay và cài đặt ADK 2 (khoảng 1 phút)

Nhấp vào Mở trong Colab ▶, sau đó chạy ô mã đầu tiên. Thao tác này sẽ ghim chính xác phiên bản ADK 2 mà lớp học lập trình này đã được xác minh và in ✓ installed.

3 · Chạy ô "Thiết lập hội thảo" (khoảng 3 phút)

Đây là ô có tiêu đề 🎓 Lộ trình A · Hội thảo. Kích hoạt mã này và Colab sẽ yêu cầu bạn uỷ quyền – hãy chọn cùng một Tài khoản Google mà bạn vừa dùng để nhận tín dụng và cho phép truy cập.

Thao tác này sẽ thực hiện 4 việc: tạo một dự án có tên là adk-2-tutorial-XXXX trên tín dụng của bạn, bật Vertex AI API trên dự án đó, đặt 4 biến môi trường mà mọi ô sau này sẽ đọc, rồi thực hiện một cuộc gọi kiểm tra đến Vertex và đợi cho đến khi Vertex trả lời – do đó, quá trình thiết lập sẽ hoàn tất hoặc cho bạn biết lý do, thay vì thất bại sau này trong một cấp độ.

Kết quả đầu ra dự kiến – dòng cuối cùng là dòng quan trọng:

Signed in as: you@example.com
...
Successfully created GCP project 'adk-2-tutorial-4817'.
Successfully linked 'adk-2-tutorial-4817' to billing account '01ABCD-...'.
   waiting for Vertex AI to come up on the new project... (10s)
   waiting for Vertex AI to come up on the new project... (20s)

 Vertex AI on adk-2-tutorial-4817 · us-central1 · gemini-2.5-flash  answered a test call

4 · Bỏ qua bước "Thiết lập tại nhà"

Đừng chạy ô khoá AI Studio vì thao tác này sẽ chuyển sổ tay trở lại AI Studio và huỷ những gì bạn vừa làm. (Ô này sẽ ngăn chặn điều này và từ chối chạy, nhưng cách gọn gàng hơn là chỉ cần bỏ qua ô này.) Chuyển thẳng từ đây đến ô Khối xây dựng được chia sẻ.

5 · Chạy ô "Shared building blocks" (Thành phần dùng chung)

Kích hoạt một lần. Tệp này xác định các giản đồ Pydantic + các tình huống chạy bộ được tạo sẵn mà mọi cấp độ từ L2 trở đi đều sử dụng lại. Bạn sẽ thấy ✓ schemas + scenarios ready.

Sau buổi hội thảo

Khoản tín dụng và dự án mà bạn tạo sẽ không tồn tại mãi mãi. Để tiếp tục chạy lại các cấp độ này miễn phí sau khi hội thảo kết thúc, hãy chạy bước Thiết lập tại nhà thay vì bước thiết lập tại hội thảo. Đây là một khoá AI Studio miễn phí, không có dự án trên đám mây và không có thông tin thanh toán. Chỉ có ô đó là thay đổi.

Để dọn dẹp sớm hơn: mở Cloud Console, chọn adk-2-tutorial-XXXX rồi xoá. Không có nội dung nào khác trong lớp học lập trình này tạo ra các tài nguyên có tính phí.

3. Thiết lập tại nhà · Khoá API AI Studio

Mọi thứ trên lộ trình này đều chạy trên khoá API Google AI Studio miễn phí – không cần dự án trên đám mây của Google, không cần thanh toán, không cần cài đặt cục bộ. Toàn bộ bước này mất khoảng 3 phút.

1 · Mở sổ tay

Nhấp vào Mở trong Colab ▶. Bạn sẽ thấy sổ tay — phần giới thiệu bằng markdown, sau đó là một ô có thể chạy cho mỗi cấp độ. Bạn chạy các ô từ trên xuống dưới; mỗi ô sẽ in đầu ra riêng ngay bên dưới.

2 · Cài đặt ADK 2 (~1 phút)

Chạy ô mã đầu tiên. Thao tác này sẽ ghim chính xác phiên bản mà lớp học lập trình này được xác minh:

%pip install -q "google-adk==2.3.0" python-dotenv pydantic nest_asyncio

Chờ đến khi quá trình này kết thúc, bạn sẽ thấy biểu tượng ✓ installed. (Lần đầu tiên, quá trình cài đặt mất khoảng 30–60 giây; sau đó, quá trình này sẽ được lưu vào bộ nhớ đệm.)

3 · Lấy khoá Gemini API từ AI Studio (khoảng 1 phút)

  1. Mở aistudio.google.com/app/apikey trong một thẻ trình duyệt mới.
  2. Đăng nhập bằng Tài khoản Google của bạn.
  3. Nhấp vào Tạo khoá API (ở trên cùng bên phải).
  4. Chọn một dự án hiện có trên Google hoặc cho phép tạo một dự án.
  5. Sao chép khoá này. Khoá này bắt đầu bằng AIza... và có khoảng 40 ký tự.

4 · Thêm khoá vào Colab (khoảng 1 phút)

Cách A – Colab Secrets (nên dùng; khoá vẫn ẩn):

  1. Nhấp vào biểu tượng khoá 🔑 trong thanh bên trái của Colab.
  2. Nhấp vào + Thêm giá trị bí mật mới.
  3. Đặt Name (Tên) thành chính xác GOOGLE_API_KEY.
  4. Dán khoá vào Giá trị.
  5. Bật quyền truy cập vào sổ tay.

Cách B – dán khi được nhắc (nhanh): bỏ qua khoá bí mật; khi bạn chạy ô tiếp theo, một lời nhắc ẩn 🔑 Enter your Google AI Studio API key: sẽ xuất hiện – dán và nhấn Enter.

5. Chạy ô khoá

Thao tác này sẽ đọc khoá bí mật (hoặc quay lại lời nhắc dán), sau đó trỏ ADK đến AI Studio (không phải Vertex AI):

import os

# 🏠 TAKE-HOME ONLY — if you ran the Workshop setup cell, skip this one.
if os.environ.get("GOOGLE_GENAI_USE_VERTEXAI") == "True":
    raise SystemExit("✋ You're set up on the workshop path (Vertex AI). Skip this cell.")

# Google AI Studio API key — add GOOGLE_API_KEY in the 🔑 Secrets panel (or paste when prompted).
try:
    from google.colab import userdata
    key = userdata.get("GOOGLE_API_KEY")
except Exception:
    import getpass
    key = getpass.getpass("Enter your Google AI Studio API key: ")

os.environ["GOOGLE_API_KEY"] = "".join(key.split())    # drop any stray whitespace/newlines
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "False"      # use AI Studio, not Vertex AI
print("✅ API key set — using Google AI Studio.")

Kết quả đầu ra dự kiến: ✅ API key set — using Google AI Studio.

6 · Chạy ô "Shared building blocks" (Thành phần dùng chung)

Chạy ô Shared building blocks (Khối xây dựng dùng chung) một lần. Tệp này xác định các giản đồ Pydantic + các tình huống chạy bộ được tạo sẵn mà mọi cấp độ từ L2 trở đi đều sử dụng lại. Bạn sẽ thấy ✓ schemas + scenarios ready.

Bạn đã thiết lập xong! 🎽 Một bước chuyển hướng nhanh trước L0 – phiên bản mà mọi người xây dựng đầu tiên.

4. Lời mở đầu · Tại sao không dùng một câu lệnh lớn?

⚡ Trước khi chạy, hãy xác định MỘT điều cần theo dõi: mỗi con số cụ thể đến từ đâu? Đó là toàn bộ bài tập – mọi thứ khác chỉ là phần trang trí.

Trước khi có thang, hãy chạy thứ mà thang thay thế: một tác nhân có lời nhắc hứa hẹn mọi thứ – tìm nạp thời tiết, phân tích khoá học, đọc nhật ký huấn luyện, định tuyến theo điều kiện, xuất kế hoạch.

Những gì bạn sẽ thấy: một chiến lược tự tin, cụ thể, được định dạng rõ ràng... nhưng các con số lại là do bạn tự nghĩ ra. Trong một lần chạy trực tiếp, ứng dụng này mở đầu bằng câu "Tôi đã lấy các chỉ số thời tiết hôm nay" và báo cáo nhiệt độ là 11°C, gió 14 km/h và phân tích nhật ký huấn luyện mà ứng dụng chưa từng thấy. Không có API thời tiết, không có dữ liệu khoá học, không có nhật ký – một lệnh gọi mô hình mờ hoặc tạo ra các đầu vào hoặc đưa chúng vào trạng thái vô dụng.

Đó là căn bệnh và có 4 triệu chứng đáng được đặt tên:

  1. Bạn không thể tin tưởng vào dữ liệu này – dữ liệu được tạo ra một cách trôi chảy.
  2. Bạn không thể kiểm thử – quy trình định tuyến của bước 4 nằm trong văn bản; không có if để kiểm thử đơn vị.
  3. Bạn không thể hoán đổi một bước – không có điểm kết nối nào mà API thời tiết thực có thể cắm vào.
  4. Bạn trả tiền cho mọi thứ, mọi lúc – 5 bước, 1 lệnh gọi lớn, không lưu vào bộ nhớ đệm một phần xác định.

Giữ nguyên cảm xúc đó. 9 cấp độ tiếp theo sẽ loại bỏ từng bước khỏi câu lệnh: các hàm tìm nạp (L1–L2a), một câu lệnh if định tuyến (L2b), các chuyên gia phân chia công việc (L3a–L3b) và mã giới hạn hình dạng (L4a–L4b).

Huấn luyện viên siêu câu lệnh – tự tin, không có gì đằng sau biểu đồ

💻 Địa phương: python -m shared.prologue

5. L0 · Nhân viên hỗ trợ ADK 2 đầu tiên của bạn

Lộ trình – bạn đang ở đây: L0

⚡ Tóm tắt: tác nhân là một mô hình + một chỉ dẫn + các công cụ mà tác nhân có thể gọi; Runner sẽ thực thi tác nhân. Mọi thứ sau cấp độ này chỉ là nhiều tác nhân hơn, được sắp xếp theo hình dạng tốt hơn.

Câu hỏi: liệu bạn có thể yêu cầu một mô hình trả lời và tìm kiếm mã thực khi cần tính toán số học không?

Một ý tưởng – ba phần:

  • Agent – đối tượng đưa ra lý do (một mô hình Gemini + một chỉ dẫn).
  • Runner – đối tượng thực thi một tác nhân trong một phiên và truyền phát các sự kiện.
  • một công cụ – một hàm Python đơn giản (pace_splits) mà mô hình quyết định gọi. ADK đọc chữ ký + chuỗi tài liệu và đưa cho mô hình một khai báo; không cần viết giản đồ.

Sau phần mở đầu, đây là lần sửa chữa đầu tiên: một LLM thực hiện phép tính nhẩm trong đầu sẽ vui vẻ đưa ra câu trả lời sai – pace_splits là Python có tính xác định, vì vậy các con số trong câu trả lời là được tính toán chứ không phải ứng biến.

Colab: chạy ô L0 · 📁 GitHub: L0_first_agent/ · 💻 Local: python -m L0_first_agent.agent

Luồng L0

def pace_splits(target_finish: str) -> dict:
    """Convert a goal time like '3:30:00' into exact per-mile / per-km paces."""
    ...                                  # deterministic Python — no LLM

pace_coach = Agent(
    name="pace_coach", model=MODEL,
    tools=[pace_splits],                 # the model may call it; ADK reads the signature
    instruction="You are a friendly, concise marathon coach. ... If the runner "
                "mentions a goal time, call pace_splits — never do arithmetic yourself.",
)
runner = Runner(node=pace_coach, session_service=InMemorySessionService(), auto_create_session=True)
async for event in runner.run_async(user_id="u1", session_id="s1", new_message=msg):
    ...  # events carry the model's text

🔍 Các điểm đánh dấu: Agent(...) · tools=[pace_splits] · Runner(...). Và trong đầu ra, dòng 🔧mô hình quyết định, giữa câu trả lời, để gọi mã của bạn.

Những nội dung bạn sẽ thấy:

   🔧 model called tool  pace_splits({'target_finish': '3:30:00'})
   🔧 tool returned      {'per_mile': '8:00', 'per_km': '4:58', ...}
🧠 Coach: To finish in 3:30:00, you need an average pace of 8:00 per mile...

Các dòng 🔧 là bài học: ở giữa câu trả lời, mô hình đã chọn gọi hàm của bạn và 8:00/mile chính xác trong câu trả lời của mô hình là từ mã của bạn chứ không phải từ số liệu thống kê về mã thông báo.

Bạn có thể thắc mắc: mô hình có luôn gọi công cụ không? Không, hệ thống sẽ quyết định cho từng câu hỏi. Hãy hỏi một câu không có số và các dòng 🔧 sẽ biến mất (playground yêu cầu bạn thử chính xác điều này).

👀 Đọc: pace_splits (một hàm đơn giản) và dòng tools=[pace_splits]. · ▶ Chạy ứng dụng. · ✏️ Thay đổi: đặt câu hỏi chung (không có thời gian mục tiêu) – lưu ý rằng các dòng 🔧 sẽ biến mất: mô hình quyết định thời điểm nên gọi một công cụ. Sau đó, hãy viết lại instruction và chạy lại – hướng dẫn này là phần còn lại của chương trình.

6. L1 · Your first Workflow

Lộ trình – bạn đang ở đây: Cấp 1

⚡ Tóm tắt: một hàm đơn giản và một tác nhân LLM là cùng loại nút. Công việc có thể dự đoán → hàm (0 LLM, xác định); suy luận → tác nhân.

Câu hỏi: làm cách nào để kết hợp mã thuần tuý và một LLM trong một quy trình, mà không phải trả tiền cho lệnh gọi mô hình trên những phần chỉ là mã?

Một ý tưởng: trong Workflow, hàm Python thông thường và tác nhân LLM đều chỉ là các nút trong cùng một danh sách edges.

START ──► fetch_conditions (function, 0 LLM) ──► advise (agent, 1 LLM)

Colab: chạy ô L1 · 📁 GitHub: L1_graph_basics/ · 💻 Local: python -m L1_graph_basics.workflow

L1 flow

Nút hàm in dữ liệu mà nó tạo ra (không có lệnh gọi mô hình), sau đó tác nhân đưa ra lời khuyên tham chiếu đến nhiệt độ và gió thực tế mà nó nhận được:

def fetch_conditions(node_input):                # function node — 0 LLM
    return Event(output=Conditions(temp_f=78, wind_mph=12, conditions="sunny").model_dump())

advise = Agent(name="advise", model=MODEL, mode="single_turn",
               input_schema=Conditions, instruction="...give pacing + gear advice...")

workflow = Workflow(edges=[(START, fetch_conditions, advise)])

🔍 Các điểm đánh dấu: một bộ dữ liệu cạnh – (START, fetch_conditions, advise) – với một hàm Python đơn giản nằm ở giữa và input_schema= xác thực quá trình chuyển giao.

Điểm mới so với L0: Workflow(edges=[...]), START (nơi dữ liệu đầu vào đi vào), một nút hàm trả về Event(output=...)input_schema=Conditions để đầu ra của hàm được xác thực dựa trên giản đồ đó trước khi tác nhân nhìn thấy (dưới dạng văn bản JSON – input_schema xác thực ranh giới, không chuyển cho tác nhân một đối tượng Python).

Có thể bạn đang thắc mắc: có bắt buộc phải theo thứ tự hàm rồi đến tác nhân không? Không – bất kỳ thứ tự, bất kỳ sự kết hợp, bất kỳ số lượng nào. advise chỉ chạy thứ hai vì cần dữ liệu của fetch_conditions. Bài học là tước vị, không phải thứ tự.

👀 Đọc: fetch_conditions trả về dữ liệu không có lệnh gọi mô hình; adviseinput_schema=Conditions. · ▶ Chạy ứng dụng. · ✏️ Thay đổi: đặt temp_f=30 trong hàm và chạy lại – lời khuyên sẽ thay đổi và hàm vẫn tốn 0 lượt gọi LLM.

7. L2a · Parallel fan-out + JoinNode (Pillar 1a)

Lộ trình – bạn đang ở đây: L2a

⚡ Tóm tắt: phân phối song song (miễn phí), chờ tất cả, gói, cung cấp cho một tác nhân thông tin đầy đủ.

Câu hỏi: bạn có thể vẽ luồng trước khi dữ liệu đầu vào đến. Bắt đầu bằng cấu trúc cơ bản: thu thập dữ liệu song song, gói dữ liệu và chuyển cho một tác nhân.

Hình dạng:

START ──► fetch_weather ──┐
START ──► analyze_course ─┼─► JoinNode ─► strategy (1 agent)
START ──► pull_fitness ───┘   (bundles)

Colab: chạy ô L2a · 📁 GitHub: L2a_parallel_join/ · 💻 Local: python -m L2a_parallel_join.workflow

Quy trình L2a

🔍 Các điểm đánh dấu: 3 cạnh đều bắt đầu tại START – đó điểm phân nhánh – và JoinNode, điểm gặp nhau.

  • Ba lượt tìm nạp này là các hàm – chúng chạy song song, 0 lượt gọi LLM.
  • JoinNode sẽ chờ cả ba và kết hợp chúng thành một tải trọng được nhập (BundledRunData), được khoá theo tên hàm.
  • Một tác nhân strategy đọc gói và ghi RaceStrategy.

Những gì bạn sẽ thấy: mỗi lần tìm nạp sẽ in dấu thời gian started / finished. Cả ba đều bắt đầu ở 0,0 giây và phân đầu ra kết thúc ở 2,0 giây – lượt tìm nạp chậm nhất, chứ không phải 4,5 giây như tổng thời lượng của chúng. Sự trùng lặp đó chính là tính song song. (Tổng thời gian thực được in ở cuối là khoảng 8 giây vì thời gian này cũng bao gồm lệnh gọi LLM của tác nhân chiến lược – hãy đọc dấu thời gian tìm nạp cho yêu cầu song song, chứ không phải tổng thời gian.)

💡 Lệnh gọi lại phần mở đầu: mega-prompt đã tạo ra thời tiết của riêng nó. Ở đây, nhiệt độ xuất phát từ một hàm tìm nạp – mã thực, đường nối thực. Thay thế từ điển đóng hộp bằng một API thời tiết thực tế và không có gì khác thay đổi.

Có thể bạn đang thắc mắc: hãng tin của mình có thể kiếm được bao nhiêu tiền

JoinNode

Tôi có cần hiểu không? Một câu: nó chờ cho đến khi mọi nhánh song song kết thúc, đóng gói các đầu ra vào một từ điển được khoá theo tên của hàm ở nguồn trên và tự nó không tính toán gì. Chính từ điển đó là lý do bộ định tuyến của L2b có thể ghi node_input["fetch_weather"]["temp_f"].

👀 Đọc: 3 cạnh mở rộng ra từ START; JoinNode gói chúng cho một tác nhân. · ▶ Chạy và đọc dấu thời gian, chứ không phải tổng thời gian. · ✏️ Thay đổi: thực hiện một lần tìm nạp 3.0 — dự đoán thời gian kết thúc phân đầu ra mới trước, sau đó xác minh.

8. L2b · Thêm bộ định tuyến xác định (Pillar 1b)

Lộ trình – bạn đang ở đây: L2b

⚡ Tóm tắt: L2a không thay đổi + if đơn giản quyết định tác nhân nào sẽ chạy. Phân nhánh mà không cần hỏi mô hình.

Câu hỏi: kế hoạch nên khác nhau đối với thời tiết nóng và lạnh. Làm cách nào để phân nhánh — mà không yêu cầu mô hình quyết định?

Hình dạng (L2a + bộ định tuyến):

... JoinNode ─► route_by_weather ─► hot_strategy
               (if-statement)   ─► normal_strategy
                                ─► cold_strategy

Colab: chạy ô L2b – thử run("NORMAL") / run("COLD") · 📁 GitHub: L2b_router/ · 💻 Thiết bị cục bộ: python -m L2b_router.workflow COLD

Luồng L2b

def route_by_weather(node_input):                        # an if-statement, 0 LLM
    temp = node_input["fetch_weather"]["temp_f"]
    route = "HOT" if temp >= 70 else "COLD" if temp <= 40 else "NORMAL"
    return Event(output=node_input, route=route)

(route_by_weather, {"HOT": hot_strategy, "NORMAL": normal_strategy, "COLD": cold_strategy})

🔍 Các điểm đánh dấu: Event(output=..., route=...) – một nút hàm đặt tên cho đường dẫn – và dict-edge {"HOT": ..., "NORMAL": ..., "COLD": ...} ánh xạ tên đến các nút.

Điểm mấu chốt – 3 loại công việc, 3 nơi ở:

  • Công việc có thể dự đoán → hàm (3 lần tìm nạp song song)
  • Một quy tắc rõ ràng → định tuyến rõ ràng (route_by_weather là một câu lệnh if, không phải là quyết định của mô hình)
  • Suy luận → mô hình (chính xác một tác nhân chiến lược chạy)

Những gì bạn sẽ thấy: temp=78F -> route=HOT, sau đó là một RaceStrategy có cấu trúc. Chi phí thực tế: 1 lệnh gọi LLM.

⚠️ Nếu bạn thêm nhánh thứ tư, hãy cung cấp cho route-dict một mục DEFAULT_ROUTE. Một tuyến đường mà từ điển không khớp không phải là lỗi – nhánh chỉ kết thúc và chương trình thoát 0 mà không có đầu ra, đây là một ngõ cụt khó hiểu để gỡ lỗi.

Có thể bạn đang thắc mắc: vậy L2b có nghĩa là L2a cộng với một bộ định tuyến? Có – các lượt tìm nạp và thao tác kết hợp không thay đổi, và vẫn chính xác là 1 lệnh gọi LLM. Nội dung thay đổi: "luôn là cùng một nhân viên" đã trở thành "một trong ba nhân viên, do dữ liệu chọn".

👀 Đọc: route_by_weather – bộ định tuyến là một câu lệnh if, chứ không phải là một tác nhân. · ▶ Chạy run("COLD"). · ✏️ Thay đổi: thêm nhánh WINDY với một tác nhân thứ tư và đọc cảnh báo DEFAULT_ROUTE ở trên trước khi bạn thực hiện.

9. L3a · Collaborative agents: one flag, two worlds — Pillar 2

Lộ trình – bạn đang ở đây: L3a

⚡ Tóm tắt: cùng một nhóm, một cờ. chat chuyển toàn bộ cuộc trò chuyện cho một chuyên gia và không bao giờ quay lại; single_turn biến mỗi chuyên gia thành một công cụ – tập hợp con song song, tự động quay lại, một bản tổng hợp.

Câu hỏi: bạn biết nhóm, nhưng yêu cầu quyết định thành viên nào nên trả lời. Làm cách nào để cho phép một LLM chọn tập hợp con và chạy đồng thời các tập hợp con đó?

Vai trò: điều phối viên của 6 chuyên gia (y tế, thời tiết, tốc độ, trang thiết bị, dinh dưỡng, tinh thần). Cấp độ này chạy cùng một đội hai lần – cùng một lời nhắc cho người điều phối, cùng 6 chuyên gia. Điểm khác biệt duy nhất là một cờ trên các đại lý phụ. Độ tương phản là bài học.

Colab: chạy ô L3a · 📁 GitHub: L3a_collaborative/ · 💻 Local: python -m L3a_collaborative.concierge --mode chat "What about fueling?"

Quy trình L3a

🔍 Các điểm đánh dấu: mode="single_turn" trong factory và trong đầu ra, TRANSFER → (chuyên mục 1) so với một loạt DISPATCH → dòng có cùng một dấu thời gian (chuyên mục 2).

Nhịp 1: Chạy lần đầu theo mặc định và xem quá trình này không thành công

Không có mode= nào được ghi → tác nhân phụ mặc định là chat. Nội dung bạn sẽ thấy:

TRANSFER  nutrition_specialist   (transfer_to_agent  the only tool chat subagents provide)
Final speaker: nutrition_specialist

Điều phối viên không có công cụ uỷ quyền – các tác nhân phụ trò chuyện chỉ cung cấp cho điều phối viên transfer_to_agent, một quy trình chuyển giao tuần tự toàn bộ cuộc trò chuyện cho một chuyên gia. Chuyên gia đó sẽ trả lời trực tiếp cho người dùng và quy trình sẽ kết thúc tại đó. Không có tính năng gửi song song. Không trả lại. Không có quá trình tổng hợp. Đặt câu hỏi chung chung và tình hình trở nên tồi tệ hơn: sáu chuyên gia, một lần chuyển.

Đó không phải là lỗi mà là chế độ trò chuyện đang hoạt động. Cuộc trò chuyện thuộc về người đang giữ cuộc trò chuyện đó, cho đến khi người khác chuyển cuộc trò chuyện một cách rõ ràng. Phù hợp với trợ lý không giới hạn; không phù hợp với bước trong quy trình.

Chủ đề 2: Một lá cờ, hai thế giới

Điểm khác biệt duy nhất: mode="single_turn" cho mỗi chuyên gia. Cùng một câu hỏi, chạy lại:

[t= 7.8s] DISPATCH  medical_specialist       same timestamp =
[t= 7.8s] DISPATCH  weather_specialist         one turn, many calls
[t=14.5s]    medical_specialist replied      replies land inside
[t=14.5s]    weather_specialist replied        one short window
🧠 Concierge (synthesized): <one answer>

Giờ đây, ADK sẽ chèn một công cụ uỷ quyền cho mỗi chuyên gia – được đặt tên theo đại lý phụ, được mô tả bằng description= (đó là văn bản mà điều phối viên đọc khi chọn nhóm nhỏ; bỏ qua văn bản đó và bạn chỉ định tuyến theo tên). Trình điều phối phát ra một số lệnh gọi trong một lượt, ADK chạy các lệnh gọi đó song song, mỗi lệnh gọi tự động trả về kết quả và trình điều phối tổng hợp.

Câu hỏi

Chuyên gia về lửa

"Còn việc đổ nhiên liệu thì sao?"

chỉ dinh dưỡng

"Đầu gối của tôi bị đau ở dặm thứ 18"

chỉ nội dung y tế

"Hôm nay tôi có nên chạy đua không?"

y tế + thời tiết + nhịp độ

"Tôi có cần lo lắng về điều gì không?"

tất cả 6

Lý do mỗi chuyên gia đều nhận được toàn bộ bản tóm tắt: mỗi single_turn tác nhân phụ chạy trong nhánh phiên riêng biệt – tác nhân phụ đó không thể xem cuộc trò chuyện hoặc các tác nhân phụ ngang hàng. Không có gì là xung quanh: trình điều phối phải chuyển tiếp toàn bộ SpecialistInput (dữ liệu câu hỏi + chiến lược + trình chạy) riêng biệt vào mọi lệnh gọi song song.

💡 Trường hợp ADK 2 cung cấp một vị trí trực tiếp cho yêu cầu này: một LLM chọn một tập hợp con theo yêu cầu VÀ chạy tập hợp con đó song song – được khai báo thông qua sub_agents + mode="single_turn". Bạn có thể lắp ráp cùng một hình dạng trong 1.x bằng cách bao bọc từng chuyên gia trong AgentTool; điều thay đổi là giờ đây, đó là một khai báo chứ không phải là hệ thống ống nước. (ParallelAgent luôn là tất cả và transfer_to_agent là sê-ri.)

⚠️ Hai lưu ý quan trọng: (1) mô hình chọn tập hợp con, vì vậy, mô hình này ít xác định hơn so với bộ định tuyến được mã hoá cứng của L2 – tập hợp con chính xác có thể thay đổi theo từng lần chạy. (2) Đôi khi, bạn sẽ thấy đường Error validating input: ... cho một chuyên gia. Đây hầu như không phải là đầu ra của chuyên gia – output_schema khiến Gemini thực thi điều đó ở phía máy chủ. Đó là đầu vào: trình điều phối phải sao chép toàn bộ SpecialistInput lồng nhau một cách nguyên văn cho mọi lệnh gọi song song và đôi khi nó sẽ bị lỗi một lệnh gọi. ADK trả về lỗi dưới dạng kết quả của công cụ đó, trình điều phối khôi phục và quá trình tổng hợp vẫn diễn ra.

Có thể bạn đang thắc mắc:

chat

chỉ uỷ quyền theo kiểu 1.x – mỗi lần một người đại diện? Về cơ bản là có: đây là hành vi mặc định của phiên bản 1.x, hiện có tên. Khoảng cách đến single_turn là 3 chiều: những gì người điều phối nắm giữ (một transfer_to_agent so với một công cụ cho mỗi chuyên gia) · số lượng người có thể làm việc (một người, sở hữu cuộc trò chuyện so với N người song song) · liệu quyền kiểm soát có được trả lại hay không (không bao giờ so với tự động, có kết quả). Về mã: nhánh if mode == của nhà máy chỉ tồn tại để một nhóm có thể được tạo theo cả hai cách cho sự tương phản này – một ứng dụng thực mã hoá cứng một chế độ và if sẽ biến mất.

👀 Đọc: nhà máy _specialist – tham số mode là toàn bộ cấp độ. · ▶ Chạy cả hai nhịp. · ✏️ Thay đổi: hỏi "đầu gối của tôi bị đau ở dặm thứ 18"dự đoán tập hợp con trước, sau đó kiểm tra các dòng DISPATCH.

# The factory's mode parameter is THE variable this level teaches:
def _specialist(name, domain, focus, mode):
    kwargs = {}
    if mode == "single_turn":   # the structured contract only makes sense for a TOOL
        kwargs = dict(mode="single_turn",
                      input_schema=SpecialistInput, output_schema=SpecialistResponse)
    return Agent(name=name, model=MODEL,
                 description=f"Marathon {domain} specialist. Consult for: {focus}.",
                 instruction=..., **kwargs)

race_concierge = Agent(name="race_concierge", model=MODEL,
                       sub_agents=[...six specialists...],   # NOTE: no `mode` on the coordinator
                       instruction="...DECIDE which specialists are relevant... call them IN PARALLEL... SYNTHESIZE...")

10. L3b · Chế độ nhiệm vụ: cuộc trò chuyện có điểm kết thúc – Trụ cột 2

Lộ trình – bạn đang ở đây: L3b

⚡ Tóm tắt: chế độ trung gian – trò chuyện với người dùng cho đến khi thu thập được các trường, sau đó tự động trả về bằng một đối tượng đã xác thực.

Câu hỏi: L3a còn thiếu một khoảng trống. chat sở hữu toàn bộ cuộc trò chuyện; single_turn hoàn toàn không trò chuyện với người dùng. Nhưng công việc thực sự nằm ở giữa: "nói chuyện với người dùng CHO ĐẾN KHI bạn thu thập được X – sau đó quay lại với một đối tượng đã được xác thực." Đó là chế độ nào?

Hình dạng:

race_desk (coordinator)
  └─ gear_fitter (mode="task", output_schema=GearOrder)

Colab: chạy ô L3b · 📁 GitHub: L3b_task_desk/ · 💻 Local: python -m L3b_task_desk.desk

Luồng L3b

gear_fitter giữ tác vụ mở – tác vụ bị tạm dừng, không bị treo

🔍 Các điểm đánh dấu: mode="task" + output_schema= trên cùng một tác nhân – và trong đầu ra, lệnh ⏸ tạm dừng và lệnh gọi finish_task.

Những nội dung bạn sẽ thấy:

━━ TURN 1 ━━  user: 'I need shoes for the marathon.'
  race_desk  delegate: gear_fitter
  gear_fitter: What is your shoe size?
    The run ENDED  but nothing failed. This is a PAUSED task.

━━ TURN 2 ━━  user: 'Size 9, wide.'   (same session  resumes the task)
  gear_fitter  finish_task   (payload validates as GearOrder)
  race_desk: Your order ... in size 9 Wide has been confirmed.

Có 3 điều mà chế độ L3a không thể làm được:

  1. Lượt chạy thực sự dừng giữa chừng – một nhiệm vụ bị tạm dừng, không bị treo và không bị lỗi. Nhân viên hỗ trợ đã đặt câu hỏi làm rõ và đang giữ yêu cầu mở. (Trong adk web, bạn chỉ cần nhập câu trả lời; tập lệnh sẽ ghi lại câu trả lời đó dưới dạng tin nhắn thứ hai trong cùng một phiên.)
  2. Tin nhắn tiếp theo tiếp tục CÙNG MỘT tác nhân tác vụ – không cần chuyển hướng, không cần uỷ quyền lại. Phiên biết ai đang chờ.
  3. finish_task đã kết thúc — một công cụ mà ADK đã chèn mode="task". Tác nhân phải gọi phương thức này để hoàn tất và tải trọng của phương thức này phải xác thực dựa trên output_schema. Cuộc trò chuyện có đường kết thúc được nhập – sau đó, quyền kiểm soát sẽ tự động quay về người điều phối, kết quả được đính kèm.

Quy tắc một câu hỏi để chọn chế độ

💡 "Người dùng có cần nói chuyện với trợ lý không và cho đến KHI NÀO?" chat = vô thời hạn · task = cho đến khi thu thập xong các trường · single_turn = không bao giờ.

Chế độ

Có sự can thiệp của con người

Song song?

Quay lại phần tử mẹ

chat (tác nhân phụ mặc định) – trợ lý hỗ trợ, trợ lý ảo không giới hạn

toàn bộ cuộc trò chuyện

không

thủ công (thông qua chuyển khoản)

task – tiếp nhận, đặt chỗ, khắc phục sự cố

chỉ câu hỏi làm rõ

không

tự động (qua finish_task, có đối tượng được xác thực)

single_turn — phân loại · trích xuất · đánh giá · tạo

không có

yes

tự động (với kết quả)

mode chỉ áp dụng cho các tác nhân phụ, không bao giờ áp dụng cho điều phối viên. Các nút trong quy trình công việc mặc định là single_turn (đó là lý do L1–L2b không bao giờ ghi lại), trong khi các tác nhân phụ mặc định là chat (đó là lý do L3a phải ghi lại).

⚠️ Hai lưu ý về phiên bản trước khi bạn xây dựng trên phiên bản này: (1) task

dưới dạng một nút biểu đồ tĩnh phụ thuộc vào phiên bản – trên 2.0.0b1–2.3.0 (ghim của lớp học lập trình này), Workflow(...) sẽ tăng lên khi xây dựng; sử dụng chính xác những gì cấp độ này làm (một điều phối viên trò chuyện với các tác nhân phụ của tác vụ) hoặc gửi qua ctx.run_node. Được nâng cấp trong phiên bản 2.5.0. (2) "Tác nhân tác vụ phải là tác nhân lá" (không có tác nhân phụ của riêng mình) là một hạn chế đã được ghi lại của ADK – nhưng là một hợp đồng, chứ không phải là một cơ chế bảo vệ thời gian chạy: cả 2.3.0 và 2.5.0 đều sẽ không ngăn bạn. Đừng coi việc không có lỗi là có quyền.

💡 Tìm hiểu sâu hơn: một tác nhân task được nhúng trong quy trình công việc đồ thị (hình dạng 2.5.0 trở lên), với khả năng định tuyến có thể lặp lại cuộc trò chuyện để thử lại: kho lưu trữ đồng hành 22_agent_in_workflow · hướng dẫn đầy đủ về chế độ này: docs/agent-modes.md.

Có thể bạn đang thắc mắc:

task

mà hai người kia không mua được? Ba điều: tự động trả về (cuộc trò chuyện sẽ tiếp tục thay vì dừng lại) · đường kết thúc được nhập (tải trọng của finish_task phải xác thực theo lược đồ – bạn nhận được dữ liệu chứ không phải bản chép lời) · tạm dừng/tiếp tục (⏸ là một tác vụ đang chờ người dùng thực hiện, chứ không phải là tác vụ bị treo).

👀 Đọc: gear_fittermode="task" + output_schema là toàn bộ hợp đồng. · ▶ Chạy ứng dụng. · ✏️ Thay đổi: run_desk("I need a hydration vest", "2 liters, medium") – câu hỏi làm rõ sẽ điều chỉnh, đường kết thúc vẫn được nhập.

11. L4a · Runtime-sized parallel fan-out (Pillar 3a)

Lộ trình – bạn đang ở đây: L4a

⚡ Tóm tắt: khung vẫn có 3 bước tĩnh – các bước động ẩn bên trong bước ở giữa, trong đó chiều rộng được quyết định bằng dữ liệu trong thời gian chạy.

⚠️ Lưu ý: đây là bước khó nhất trong thang bậc. Cấp độ trước là 44 dòng; cấp độ này là khoảng 120 dòng – 3 tác nhân và 2 nút quy trình, không có dòng nào là phần đệm. Dành khoảng 15 phút và dựa vào dòng Đọc/Chạy/Thay đổi ở cuối: bạn không cần phải nắm bắt mọi dòng trong lần đầu tiên.

Câu hỏi: Hình dạng của tác phẩm phụ thuộc vào dữ liệu đầu vào. Bạn không thể vẽ biểu đồ trước. Bắt đầu bằng chiều rộng thời gian chạy: cho phép LLM quyết định số lượng câu hỏi phụ.

Hình dạng (một cấp):

START ─► decompose ─► research_topic (parallel_worker) ─► synthesize
                                 
                             └──┴──┴─ (flat: no children yet)

Một câu hỏi mở sẽ được phân tách thành N câu hỏi phụ – N được LLM chọn trong thời gian chạy (3–7) – mỗi câu hỏi phụ sẽ được nghiên cứu song song, sau đó tổng hợp thành một bản tóm tắt.

Colab: chạy ô L4a · 📁 GitHub: L4a_flat_research/ · 💻 Local: python -m L4a_flat_research.deep_research

Quy trình L4a

🔍 Các điểm đánh dấu – không có

dynamic=True

. Động là một cách viết, chứ không phải là một cấu hình. Chỉ có 2 điểm đánh dấu: @node(parallel_worker=True) (lấy danh sách có kích thước thời gian chạy, chạy một worker cho mỗi mục) và ctx.run_node(...) (lập lịch trực tiếp các nút mã). Nếu bạn thấy một trong hai biểu tượng này → bạn đang ở chế độ động.

Những gì bạn sẽ thấy: công cụ phân tách in ra, ví dụ: 5 câu hỏi phụ, các câu hỏi này được nghiên cứu song song, sau đó là một bản tóm tắt tổng hợp. Số này khác nhau ở mỗi lần chạy – biểu đồ cố định không thể làm được điều đó.

Bạn cần hiểu rõ 2 cờ trên worker:

  • rerun_on_resume=True là bắt buộc trên mọi nút gọi ctx.run_node – ADK sẽ tăng ValueError nếu không có nút này. Khi tiếp tục, nó phải thực thi lại nút điều phối để tạo lại các thành phần con mà nó đã tạo, vì những thành phần đó không có trong đồ thị tĩnh.
  • retry_config= giới hạn cách THẤT BẠI này. Một worker song song sẽ huỷ mọi worker ngang hàng và tăng lại ngay lập tức khi một worker con không thành công. Vì vậy, nếu không có cơ chế thử lại, một lỗi 429 tạm thời sẽ loại bỏ toàn bộ lượt chạy, bao gồm cả mọi lệnh gọi đã được thanh toán. Thử lại sẽ diễn ra trên nút bên trong theo từng mục, vì vậy, mỗi nhánh sẽ thử lại một cách độc lập.

Có thể bạn đang thắc mắc: làm cách nào ADK "biết" đây là nội dung động? Không cần thiết – không có gì được khai báo ở bất kỳ đâu. Trình phân tách tạo ra một danh sách trong thời gian chạy; worker song song tự điều chỉnh kích thước cho phù hợp với mọi thứ đến. Tính linh động là một thuộc tính của luồng dữ liệu mà bạn đã viết, chứ không phải là một chế độ mà bạn đã bật.

👀 Đọc: hai cờ trên research_topicparallel_workerrerun_on_resume. · ▶ Chạy ứng dụng. · ✏️ Thay đổi: thay thế bằng câu hỏi mở của riêng bạn – N thay đổi vì đầu vào quyết định chiều rộng.

12. L4b · Add recursive spawning (Pillar 3b)

Lộ trình – bạn đang ở đây: L4b

⚡ Tóm tắt: đệ quy là được viết chứ không phải được cho sẵn – worker gọi chính nó thông qua ctx.run_node, Python thông thường – vì vậy, bạn cũng phải viết phanh. Đó là MAX_DEPTH.

Câu hỏi: đôi khi một kết quả nghiên cứu sẽ cho thấy một chủ đề phụ hẹp đáng được điều tra riêng. Làm cách nào để cho phép một nhánh tạo ra nhiều công việc song song hơn và giữ cho nhánh đó bị giới hạn?

Hình dạng (hiện là đệ quy):

START ─► decompose ─► research_topic (parallel_worker, recursive) ─► synthesize
                                 
                                 └─ research(q3) ─► maybe spawn children
                               └─── research(q2) ─► maybe spawn children
                             └────── research(q1) ─► maybe spawn children

Colab: chạy ô L4b · 📁 GitHub: L4b_recursion/ · 💻 Local: python -m L4b_recursion.deep_research

Luồng L4b

@node(parallel_worker=True, rerun_on_resume=True)
async def research_topic(ctx, node_input):
    finding = coerce(await ctx.run_node(research_agent, node_input=...), ResearchFinding)
    if finding.needs_deeper and finding.deeper_questions and depth < MAX_DEPTH:   # boundary in CODE
        children = await ctx.run_node(research_topic, node_input=deeper)          # recursive fan-out
    yield Event(output={..., "children": children})

🔍 Các điểm đánh dấu: ctx.run_node(research_topic, ...) bên trong research_topic — tự tham chiếu đệ quy — và depth < MAX_DEPTH bảo vệ một dòng phía trên.

Những gì bạn sẽ thấy: các nút nghiên cứu in spawning N deeper – đệ quy diễn ra trực tiếp – sau đó là hình dạng cây thời gian chạy (ví dụ: 5 top-level + 10 recursive children). Cây này sẽ khác nhau ở mỗi lần chạy.

⚠️ Trước khi bạn tăng giá trị của núm: trần tăng nhanh – MAX_DEPTH=3 lấy trường hợp xấu nhất từ khoảng 30 lệnh gọi lên khoảng 93. Và ở cuối quá trình chạy, bạn có thể thấy dòng nhật ký cancelling N leftover tasks: đó là ADK đang huỷ nhóm tác vụ song song sau khi kết quả đã hoàn tất. Vô hại và tuỳ thuộc vào cấu hình ghi nhật ký, bạn có thể không bao giờ thấy thông báo này.

Có thể bạn đang thắc mắc: theo mặc định, không phải là đệ quy động sao? Không – L4a hoàn toàn linh động với không đệ quy. Ngôn ngữ động chỉ cung cấp cho bạn luồng kiểm soát Python thông thường; L4b chọn viết đệ quy bằng ngôn ngữ này. Và vì bạn đã viết hàm đệ quy, nên bạn phải viết ranh giới của hàm đó – đây là lúc "hãy để LLM định hình công việc, giữ ranh giới trong mã" không còn là một khẩu hiệu nữa.

👀 Đọc: người bảo vệ: if finding.needs_deeper and depth < MAX_DEPTH. · ▶ Chạy ứng dụng. · ✏️ Thay đổi: đặt MAX_DEPTH = 1 và chạy lại – cây sẽ được làm phẳng (và lần chạy sẽ rẻ hơn). Ranh giới là của BẠN, trong mã.

13. L5 · Bạn nên sử dụng mẫu nào?

Lộ trình – bạn đang ở đây: L5

⚡ Tóm tắt: một trục quyết định mọi thứ – ai chọn bước tiếp theo: biểu đồ bạn vẽ, LLM hay mã của bạn.

Bạn đã xây dựng cả 3. Đây là mô hình giúp bạn giải quyết vấn đề: so khớp mẫu với hình dạng của vấn đề.

Trục: ai quyết định nội dung nào sẽ chạy tiếp theo?

Cột

Ai quyết định nội dung sẽ chạy tiếp theo

Tích hợp

1 · Biểu đồ

đồ thị mà bạn đã vẽ

L2a / L2b

2 · Cộng tác

LLM

L3a / L3b

3 · Động

mã Python của bạn, trong thời gian chạy

L4a / L4b

Bước 0: bạn có cần biểu đồ không?

ADK cung cấp các tác nhân quy trình làm việc được tạo sẵnSequentialAgent, ParallelAgent, LoopAgent. Đối với một chuỗi tác nhân đơn giản, đó là câu trả lời chính xác rẻ nhất và không có biểu đồ nào để lắp ráp. Hãy vượt qua chúng khi bạn cần định tuyến rõ ràng (bộ định tuyến L2b), kết hợp (JoinNode của L2a) hoặc các nút không phải là tác nhân (một hàm đơn giản, không có lệnh gọi LLM) – lý do thường là lý do cuối cùng.

Would a prebuilt SequentialAgent / ParallelAgent / LoopAgent do?

├─ YES ──────────────────────────────► use it; stop here

└─ NO  I need routing, a join, or non-agent nodes
   
   Can you draw the workflow before the input arrives?
   
   ├─ YES ───────────────────────────► Pillar 1 · Graph workflow    (L2a/L2b)
   
   └─ NO
      ├─ Known team, request picks the subset? ─► Pillar 2 · Collaborative  (L3a/L3b)
      └─ Does the shape depend on the input?  ──► Pillar 3 · Dynamic        (L4a/L4b)

L5 · which pattern

Khung hình trung thực 1.x so với 2

Đây không phải là "2.0 có thể làm những việc mà 1.x không làm được" – 1.x có thể tạo tất cả những việc đó. Sự thay đổi là 2.0 giúp mỗi hình dạng có một vị trí cố định hơn, vì vậy, luồng kiểm soát đã biết sẽ rời khỏi câu lệnh và trở thành cấu trúc mà bạn có thể thấy và kiểm thử.

Mẫu

Chi phí 1.x

Trang chủ ADK 2

Biểu đồ

4 lệnh gọi LLM trong bản dựng chung; định tuyến ẩn trong câu lệnh

function + agent nodes as peers → 1 call, if-statement router

Cộng tác

có thể tạo qua AgentTool plumbing; ParallelAgent always-all, transfer_to_agent serial

một đội được khai báo: sub_agents + mode="single_turn"

Động

đệ quy sẽ loại bỏ bạn khỏi khung

parallel_worker + ctx.run_node đệ quy trong khung

Toàn bộ ứng dụng và những gì mà biểu đồ không thể cho bạn biết

Giờ đây, bạn đã tạo xong mọi thành phần bên dưới. Workflow cho thấy cấu trúc của nó tại graph.edges, vì vậy, hình ảnh này được tạo từ mã chứ không phải do bạn vẽ bằng tay. Những gì mà quá trình tự kiểm tra tìm thấy bản tóm tắt của lớp học này:

Cột

Nội dung của graph.edges

Lý do

1 · Biểu đồ (L2b)

10 cạnh, tuyến đường và mọi thứ

bạn đã vẽ trước khi có bất kỳ dữ liệu đầu vào nào

2 · Cộng tác (L3a)

0 đường viền – chỉ sub_agents + mode

LLM chọn một tập hợp con cho mỗi yêu cầu

3 · Động (L4a/L4b)

3 cạnh – giống nhau ở cả hai

phương thức đệ quy được viết bằng Python, không được kết nối trong biểu đồ

Hàng cuối cùng là bằng chứng cho câu hỏi mà L4b trả lời: L4a và L4b có cùng một đồ thị và chỉ một trong số chúng lặp lại.

Những gì bạn có thể tạo ngay bây giờ

Mỗi mẫu bạn vừa chạy là một hình dạng sản phẩm thực tế:

Bạn đã luyện tập

Trong tự nhiên, đó là

Xuất phát từ

Biểu đồ + bộ định tuyến (L2a/L2b)

các quy trình xử lý tài liệu, ETL-with-LLM-steps, chuỗi xem xét/phê duyệt, eval harnesses

L2b của kho lưu trữ này

Điều phối viên + Nhóm single_turn (L3a)

một trợ lý hỗ trợ AI với các nhóm chuyên gia, bàn phân loại, quy trình đánh giá đa chiều

Chế độ marathon demo 2

Nhân viên hỗ trợ task (Cấp 3b)

biểu mẫu thu thập thông tin, quy trình đặt phòng, quy trình tham gia, quy trình KYC – mọi quy trình "thu thập rồi hành động"

22_agent_in_workflow

Chiều rộng/chiều sâu linh hoạt (L4a/L4b)

các tác nhân nghiên cứu, trình tạo báo cáo, các đợt kiểm tra trên dữ liệu đầu vào có kích thước không xác định

chế độ marathon demo 3

Họ sáng tác

Ba mẫu này không loại trừ lẫn nhau. Một nút đồ thị có thể gọi một điều phối viên cộng tác; một chuyên gia có thể khởi chạy một quy trình làm việc linh hoạt. Chọn mẫu phù hợp cho mỗi phần của vấn đề – đó là cách bạn tránh biến mọi hệ thống tác nhân thành một câu lệnh khổng lồ.

Toàn bộ ứng dụng và những gì mà biểu đồ không thể cho bạn biết

💡 Hãy thử trên quy trình công việc của riêng bạn: tập lệnh đã vẽ hình này là scripts/graph_dump.py. Hướng camera vào bất kỳ Workflow nào và camera sẽ in các cạnh thực tế — sơ đồ cấu trúc miễn phí của mọi thứ bạn tạo.

14. Xin chúc mừng

9 đặc vụ, 1 cây baton, một kết thúc trật tự

Bạn đã tạo một Huấn luyện viên cho ngày chạy marathon và trong quá trình đó, bạn đã sử dụng cả 3 mẫu điều phối của ADK 2.

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

  • Lời mở đầu – câu lệnh siêu lớn tự tạo ra thời tiết: lý do cấu trúc tồn tại.
  • L0–L1Agent, Runner, một công cụ thực sự mà mô hình chọn gọi và Workflow đầu tiên của bạn (các nút chức năng + các nút tác nhân dưới dạng các nút ngang hàng).
  • L2a / L2b – quy trình công việc đồ thị: phân đầu ra song song + JoinNode, sau đó định tuyến xác định – một lệnh gọi LLM.
  • L3a – tác nhân cộng tác: cùng một nhóm chạy trong chat (bị mắc kẹt) rồi single_turn (tập hợp con song song + tổng hợp) – một cờ, hai thế giới.
  • L3b – Chế độ task: câu hỏi làm rõ bị tạm dừng, bản tóm tắt theo kịch bản, finish_task trả về một đối tượng đã xác thực.
  • L4a / L4b – quy trình công việc linh hoạt: độ rộng thời gian chạy (phân tán), sau đó là độ sâu thời gian chạy (đệ quy) với các ranh giới trong mã.
  • L5 – cây quyết định và cách các mẫu kết hợp.

Những dòng đáng giữ lại

Các hàm chuẩn bị ngữ cảnh. Các cạnh xác định quy trình làm việc. Bộ định tuyến sẽ chọn đường dẫn. Mô hình viết câu trả lời.

Cho phép LLM định hình công việc, nhưng vẫn giữ các ranh giới trong mã.

Tìm ra mẫu hình phù hợp với vấn đề của bạn.

Các bước tiếp theo

  • Chạy toàn bộ ứng dụng mà các cấp độ này được rút ra – Marathon Race Day Coach, một bản dựng FastAPI + SSE có giao diện người dùng trình duyệt cho thấy cả 3 chế độ trực tiếp: github.com/cuppibla/adk-2-marathon-demo.
  • Mở rộng phạm vi: adk-workflows-compared – 23 mẫu quy trình công việc chính thức của ADK 2, mỗi mẫu có một cổng 1.x và hướng dẫn về thời điểm sử dụng. Bắt đầu với docs/three-pillars.md, sau đó là những nội dung mà lớp học lập trình này bỏ qua: 07_loop, 17_request_input, 22_agent_in_workflow.
  • Vấn đề của riêng bạn: những phần nào có cấu trúc đã biết (L2), nhóm đã biết (L3a/L3b), hình dạng chưa biết (L4)?
  • Khám phá mã: github.com/cuppibla/adk2-tutorial.
  • Đã tham gia hội thảo chưa? Khoản tín dụng của bạn (và dự án mà bạn đã tạo) sẽ không tồn tại mãi mãi. Để tiếp tục chạy lại các cấp độ này miễn phí, hãy thực hiện bước Thiết lập tại nhà: khoá AI Studio miễn phí, không có dự án trên đám mây, không có thông tin thanh toán. Việc hoán đổi ô đó là thay đổi duy nhất.