VibeStudio: ADK ile Çok Formatlı Temsilci İş Akışı, Korku Sürümü

1. Giriş

VibeStudio, Haunted Edition

VibeTube'da samimi ve ürkütücü bir kanalınız var. Cadılar Bayramı'na kadar her gece bir Shorts videosu yayınlıyorsunuz. Kitle, küçük odalarda küçük sihirler istiyor ve bunu size her şekilde gönderiyor: yorumlar, sesli notlar, kendi perili çekmecelerinin fotoğrafları ve akşam karanlığında verandalarının klipleri. İş listesi fikirlerle doludur. Her akşam aynı işleri yapıyor: Akışta nelerin trend olduğunu araştırıyor, birikmiş işleri tarıyor, kitlenin gönderdiklerini okuyor, bir yön seçiyor, kanalın politikasına uygunluğunu kontrol ediyor, senaryoyu yazıyor, posteri çiziyor, klibi oluşturuyor ve yayınlıyor.

Üretken modeller her işi tek başına yapabilir. Gemini araştırır, dinler, bakar ve yazar; görüntü modeli çizer; Veo ise oluşturur. Tek başlarına yapamayacakları şeyler ise geceyi sırayla yürütmek, sizin kararınız için durmak, para kaybettirmeden önce kötü bir yönlendirmeyi reddetmek, hiçbir şeyi açık tutmadan bir render için dakikalarca beklemek ve kayıt bırakmaktır.

Bu codelab'de, o akşamı bir ADK Workflow'ya dönüştüreceğiz. Bu ADK, kendi kendine çalışan, yalnızca karar vermeniz gereken yerlerde size soru soran ve her çalıştırmayı VibeTube'da bir klip ve posteriyle sonlandıran, düğümler ve kenarlardan oluşan bir grafiktir.

İstemler; sipariş, durdurma veya kontrol sözü veremez. Grafik bunu yapabilir.

Öğrenecekleriniz

  • Bir temsilci ve araç olarak görüntü modeli. Agent; bir model, bir talimat ve araçlardan oluşur. Üçüncü araç, görüntü modelini çağırır ve ilk çalıştırma bir posterle sona erer. Ardından, laboratuvarın geri kalanını yönlendiren cümle: Bir istem, düzen, durdurma veya kontrol vaat edemez.
  • Grafiği oluşturan yapılar. Workflow, bir kenar listesidir. Çoklu çıkış ve birleştirme (JoinNode noktasında buluşan paralel okuyucular) ve kendi çıkışını adlandıran bir yönlendirici oluşturursunuz. Reddedilen çıkışın arkasında, araç çağrılarının döngüsünde bir yönü temizleyen ve ana hatta yeniden katılan bir görev modu temsilcisi bulunur.
  • Çok formatlı besleme ardışık düzeni. Kitle tarafından gönderilen dört tür içerik, her tür için bir okuyucu: Gemini sesli notları metne dönüştürür, fotoğraflara altyazı ekler, klipleri izler ve ses parçalarını dinler. Her okuyucu aynı satır şeklini bir RAG Engine derlemine yazar. Fan-out'taki üçüncü bir okuyucu, anlamı temel alarak bilgileri alır ve medyayı pasajlarla birlikte geri verir.
  • İki tür askıya alma, tek mekanizma Bir kişi (RequestInput: dört kart, siz yanıtlıyorsunuz) ve yavaş bir araç (Veo'nun arkasında LongRunningFunctionTool: bir makbuz) için bir koşu durur. İkisi de aynı şeydir: Oturum deposunda, formdan veya başka bir işlemden kimliğiyle devam ettirilen açık bir çağrı. Medya masasının iki şubesi, posteri eyaletteki adıyla paylaşır.
  • Geceler boyunca hafıza. Hafıza Bankası'nda iki yaşam döngüsü geri çağırma yöntemi: before_model_callback, öneren okumadan önce içerik üreticinin zevkini hatırlar, after_agent_callback senaristten sonra bu akşamın seçimini hatırlar.
  • Sürüm. ADK içeren bir uygulamanın içindeki grafik Runner, sayfaya sunucu tarafından gönderilen etkinlikler, oturum benzeşimi içeren Cloud Run ve klibi posteri küçük resim olarak kullanarak VibeTube'a yerleştiren çok parçalı bir POST.

Ne oluşturacaksınız?

Tarayıcınızda çalışan bir uygulama: VibeStudio Workbench. Bu, sayfa içi kod düzenleyici, diskteki dosyaları ve çalıştırmalarınızın yazdığı oturumları okuyan doğrulayıcılar ve yerleşik bir adk web içeren tamamlayıcı bir sayfadır. Bu codelab'in yedi sayfası, bu yedi oturumu temsil eder. Sayfalar, oturumlarla aynı numaralara ve bölüm harflerine sahiptir. Böylece ikisi de aynı adımları takip eder. Her sayfa, oturumu tek bir cümleyle ve orada yaptığınız üç şeyi (düzenleme, çalıştırma, doğrulama) açıklayan bir bantla açılır. Buradaki bir bölümü okuyun, ardından çalışma alanında düzenlemeyi yapın. Her düzenleme, gerçekte ne olduğunu gösteren bir doğrulama paneliyle sona erer.

Nerede ne çalışır: VibeStudio Workbench, arka ucunuz ve Google Cloud hizmetleri

Üç bileşen çalışır: Workbench (4600 numaralı bağlantı noktasındaki sayfa, düzenleyici, doğrulayıcılar), arka ucunuz (agent/ içindeki Workflow ve stage6_video/ üzerinden stage0_prompt/ içinde oturum başına bir korumalı alan uygulaması, adk web tarafından sunulur) ve Google Cloud (Gemini, görüntü modeli, RAG Engine, Veo, Memory Bank. Bunların tümüne kendi kimlik bilgilerinizle Vertex AI üzerinden erişilir).

Yedi oturum

Oturum

Oluşturacağınız uygulama

Düzenlemeleriniz

1 · Hikaye

Henüz bir şey yok. Gece ve grafiği

—

2 · Görüntü üretme

Bir temsilci ilk posteri çiziyor

POSTER_TOOL

3 · İş akışları

Geceyi bir grafik olarak düşünün: fan-out ve birleştirme, yönlendirici ve döngüsü

FANOUT, ROUTER

4 · Çok formatlı besleme

Kitlenin gönderdikleri tek bir derlemde okunur; üçüncü okuyucu

INGEST_READERS, RAG_MEDIA

5 · Video üretimi

İki tür askıya alma; afiş, eyalette adıyla paylaşılır

GATE, VIDEO_TOOL, DELIVER_RESPONSE, STATE_SHARE

6 · Bellek

Kanalın geceler arasında hatırladığı bilgiler

MEMORY_RECALL, MEMORY_REMEMBER

7 · Dağıtma ve yayınlama

Cloud Run'da VibeStudio; VibeTube'da gece

odanın etkinlik kodunu girin ve yayınlayın.

Bu codelab nasıl kullanılır? Önce kavramlar ele alınır: Her oturumda önce fikir açıklanır, ardından değişiklik yapıldıktan sonraki haliyle kod gösterilir ve kodun üzerinden geçilir. Burada hiçbir zaman bir dosyayı düzenlemeniz istenmez. Düzenleme işlemi, çalışma alanında yapılır. Çalışma alanı size her seferinde bir düzenleme, yanında bir ipucu ve altında bir doğrulama paneli sunar. Oturumu okuyun, ardından sayfanın sizi yönlendirmesine izin verin.

Bu ayarın yeri

VibeTube'daki grafik, tema ve oda, Lin'in VibeStudio'daki Haunted Edition'ından alınmıştır. Bu, Agent Valley laboratuvarlarının tek sayfalık etkileşimli formatında, kitlenin gönderdiklerine ve iki tür askıya almaya yeniden odaklanan çok formatlı bir kesittir. Stüdyo bir sahnedir. Altındaki her mekanizma, destek hattı, içerik inceleme uzmanı akışı veya bir kişi için duraklatılması ve yavaş bir işi beklemesi gereken diğer her şey için kullanacağınız sıradan bir mekanizmadır.

2. 🧰 Kurulum

  • What: Ödeme yapabilen bir hesap, bir proje, yüklü laboratuvar, yanıt verebildiği kanıtlanmış model ve arka planda bir bağlantı noktasında çalışan çalışma ortamı.
  • Neden: Tek bir bağlantı noktasında tek bir işlem: Sayfa, düzenleyici, doğrulayıcılar, /api/* ve adk web aynı kaynağı paylaştığından bu laboratuvardaki hiçbir şey için ikinci bir terminal veya ikinci bir bağlantı noktası gerekmez.
  • Nasıl: Klonlama, iki senaryo. İkinci komut, gerçek bir model çağrısı yapar, çalışma alanını başlatır ve siz okurken RAG derlemesi ile bellek bankasını oluşturmaya başlar. Böylece 4. ve 6. oturumlar bunları hazır bulur.

Bu laboratuvardaki her şey Cloud Shell'de çalışır. gcloud, Python, Node, ffmpeg ve git zaten yüklüdür. Gemini, görüntü modeli, Veo, RAG Engine ve Memory Bank'e kendi kimlik bilgilerinizle Vertex AI üzerinden erişilir. Bu laboratuvarda API anahtarı yoktur ve dizüstü bilgisayarınıza herhangi bir şey yüklemeniz gerekmez. Google Cloud SDK, Python 3.12 ve Node 20+ yüklü bir dizüstü bilgisayar da aynı şekilde çalışır.

Bu laboratuvarın size sağlayamayacağı tek şey, faturalandırmanın etkin olduğu bir Google Cloud projesidir. 1. adımda ödeme yapabilecek bir hesap oluşturursunuz, 4. adımda ise bu hesabı projeye dönüştürürsünüz. Adımları bu sırayla uygulayın. 4. adımdan sonraki her adım, 4. adımda belirlenen projeyi okur.

1 · Faturalandırma hesabı oluşturun (~1 dk.)

Faturalandırmanın etkin olduğu bir Google Hesabı ile oturum açın. Bu tür hesaplar kullanılabilir. Hesabınızda bu özellik yoksa ücretsiz deneme başlatın. Bu sayede, 4. adımda gereken faturalandırma hesabına sahip olursunuz. Eğitmen eşliğinde bir laboratuvardaysanız önce bu oturumun kredilerini kullanın. Bu işlem, faturalandırma hesabınızı oluşturur.

2 · Cloud Shell'i açma (~2 dk.)

👉🖥 Google Cloud konsolunun üst kısmındaki Cloud Shell'i etkinleştir'i tıklayın. Bu, başlıktaki terminal şeklindeki simgedir.

Google Cloud konsolu başlığından Cloud Shell'i etkinleştirme

👉🖥 Open Editor'ı (Düzenleyiciyi aç) (kalemli açık klasör simgesi) tıklayın. Bu işlem, sol tarafında bir dosya gezgini bulunan Cloud Shell Düzenleyici'yi açar. Bir dosyanın tamamını okumak istediğinizde buraya gidersiniz.

Cloud Shell Düzenleyici'yi açma

👉🖥 Bugün herhangi bir noktada yetkilendirme yapmanız istenirse devam etmek için Authorize'ı (Yetkilendir) tıklayın.

👉🖥 Düzenleyicide bir terminal açın. Bu, 1. sekmedir ve her 👉💻 adım burada çalıştırılır. 2. sekme, çalışma alanının kendisidir ve 7. adımda açılır. Terminal henüz ekranın alt kısmında değilse View (Görünüm) → Terminal'i kullanarak açın:

Cloud Shell Düzenleyici'de yeni bir terminal açma

👉💻 Hangi hesapta oturum açtığınızı kontrol edin. Bu hesap, 1. adımdaki hesap olmalıdır:

gcloud auth list

3 · Laboratuvarı alma (~1 dk.)

👉💻 Depoyu klonlayın:

cd ~
git clone https://github.com/cuppibla/vibe-studio-multimodal
cd vibe-studio-multimodal

4 · Projenizi oluşturma (~2 dk.)

👉💻 Bir komut dosyası, faturalandırma hesabınızı bulur, bu hesapta bir proje oluşturur, faturalandırmayı bağlar ve Cloud Shell'i bu projeye yönlendirir:

cd ~/vibe-studio-multimodal
./setup_project.sh

Seçtiği faturalandırma hesabı için ✓, oluşturduğu proje için ✓ ve şuna benzer bir bitiş bekleyin:

Project ready: vibe-studio-4271
  Next:  ./setup_codelab.sh

vibe-studio-4271, proje kimliğinizdir. Sizin kimliğinizde farklı rakamlar olacaktır. Bu aşamada dört şey gerçekleşir:

faturalandırma

Varsa en yeni [YYYY-MM-DD] GDP Credit: hesabını, yoksa diğer açık faturalandırma hesaplarından birini kullanır.

project

vibe-studio-XXXX oluşturur ve bu faturalandırma hesabını projeye bağlar

seçer

Kimliği ~/project_id.txt dosyasına yazar ve gcloud config set project komutunu çalıştırır. Bu nedenle, bu işlemden sonra kimliği yazmanız istenmez.

waits

projenin yayınlanmasına izin verilene kadar iki dakikaya kadar yoklama yapar.

👉🖥 Aynı proje artık konsolda yer alır. Projenin kimliği, kontrol panelindeki Proje bilgileri kartında bulunur:

Konsol kontrol panelindeki proje kimliğiniz

5 · Laboratuvarı yükleme ve kurma (~4 dk.)

👉💻

cd ~/vibe-studio-multimodal
./setup_codelab.sh

Tek bir komut dosyası, tekrar çalıştırılması güvenli. İkinci çalıştırmada ilk seferde verdiğiniz her yanıt korunur. Başlangıca yakın bir yerde iki soru sorar ve Enter tuşuna basıldığında her ikisi için de varsayılan değer kullanılır:

etkinlik kodu

7. oturumda videonuzun yayınlandığı VibeTube odası. Eğitmeninizden aldığınız oda kodunu yazın veya dilediğiniz zaman herkese açık olan sandbox için Enter tuşuna basın. Kodlar büyük/küçük harfe duyarlıdır ve bir oda yalnızca kendi penceresindeki yüklemeleri kabul eder. Komut dosyası, adlandırdığınız odanın açık olup olmadığını size bildirir.

görünen ad

Odanın size atfettiği adı girin veya hesabınızdan oluşturulan bir oda için Enter tuşuna basın.

Her ikisi de .env sayfasında yer alır ve daha sonra .env sayfasında veya yayınlama sayfasında değiştirilebilir. Ardından, geri kalan işlemleri sırayla kendi kendine yapar:

uv env

Eksikse uv'yi yükler, ardından uv venv ve uv sync, uv.lock'nin sabitlediği her şeyi (google-adk, google-genai, vertexai, fastapi, uvicorn) .venv dizinine yükler.

apis

4. adımda seçilen projede altı API'yi etkinleştirir ve devam etmeden önce her birinin yanıt verdiğini onaylar: aiplatform (Gemini, görüntü modeli, Veo, Memory Bank, RAG Engine), vectorsearch (RAG derlemesinin arkasındaki mağaza), run, cloudbuild, artifactregistry (7. oturum), cloudtrace (uygulamanın izleri)

account

Projenin varsayılan Compute hizmet hesabının mevcut olduğundan ve 7. oturumun derleme ve hizmet için ihtiyaç duyduğu rollere sahip olduğundan emin olur.

.env

.env dosyasını yazar ve projenizdeki her çağrıyı Vertex AI'a yönlendirir (global uç noktasında Gemini, us-central1 bölgesinde Veo, Memory Bank ve RAG Engine). Hiçbir yerde API anahtarı kullanılmaz. Önceki .env dosyası .env.bak olarak saklanır ve manuel olarak eklediğiniz her şey korunur.

veo · room

veo-3.1-fast-generate-001 adlı videonun us-central1 adlı cihazda yayınlandığını onaylar (meta veri okuma, oluşturma yok) ve VibeTube'a odanızın açık olup olmadığını sorar.

model

Gemini'a gerçek bir çağrı yapar. Böylece, hatalı bir proje oturum sırasında değil, kurulum sırasında başarısız olur.

starter

Düzenleyeceğiniz dokuz dosyayı starter/ konumundan yerleştirir ve TODO satırlarını korur. Yalnızca eksik olanlar eklenir ve düzenlemelerinizin üzerine hiçbir zaman yazılmaz.

page

web/ adlı çalışma alanı sayfasını yükleyip derler, ardından sunucuyu 4600 numaralı bağlantı noktasında arka planda başlatır.

bulut

Arka planda RAG Engine derlemesini ve bellek bankasını oluşturmaya başlar. Böylece 4. ve 6. oturumlar bunları hazır bulur.

preflight

scripts/preflight.py komutunu çalıştırır ve açılacak bağlantıyı yazdırır.

6 · Ön kontrolü okuyun (~1 dk.)

5. adımda yazdırılan son şey, ön kontroldür. Her satır bir tahmini değil, gerçek bir araştırmayı gösterir:

  ✓ python 3.12
  ✓ auth path A: Vertex via ADC (STUDIO_VERTEX=1)
  ✓ Google Cloud ADC (project vibe-studio-4271)
  ✓ Memory Bank SDK
  ✓ stage0_prompt loads
  ✓ stage1_fanout loads (0 edges)
  ✓ stage3_router loads (... edges)
  ✓ stage4_memory loads (... edges)
  ✓ stage5_rag loads (... edges)
  ✓ stage6_video loads (... edges)
  ✓ node and npm (build the learning center's page)
  ✓ learning center page built (web/dist)
  ✓ aiplatform.googleapis.com enabled (Gemini, Veo, Memory Bank, RAG Engine)
  ...
  - Memory Bank: still being created in the background
  - RAG corpus: still being created in the background
  ✓ session 7 runtime account 123456789-compute@developer.gserviceaccount.com has its roles
  ✓ learning center running on port 4600

PREFLIGHT GREEN

Open session 1 here:  https://4600-cs-...cloudshell.dev/step/story

stage1_fanout loads (0 edges) haklı: Bu grafik boş olarak gönderilir ve 3. oturumda doldurulur. İki - satırı da doğru. Bir derlemin oluşturulması bir veya iki dakika, bankanın oluşturulması ise yaklaşık yirmi saniye sürer ve 4. oturumdan önce ikisine de ihtiyacınız olmaz.

👉💻 Ne durumda olduğunuzu görmek için istediğiniz zaman tekrar çalıştırabilirsiniz. Bu komut, bir yapılacaklar listesini değil, dosyalarınızı, projenizi ve çalışan sunucuyu okur:

cd ~/vibe-studio-multimodal
uv run python scripts/preflight.py

7 · Çalışma alanını açma (~1 dk.)

Çalışma alanı zaten çalışıyor. 5. adımda arka planda başlatılan bir uvicorn işlemi, 4600 numaralı bağlantı noktasında sayfayı, her /api/* rotasını ve /workbench konumuna bağlı adk web dizinini sunar. Başlatılacak bir şey yoktur ve bu laboratuvarda hiçbir zaman yeniden başlatmanız istenmez: Düzenleme bir sonraki çalıştırmanızda uygulanır.

👉🖥 Ön kontrolün yazdırdığı bağlantıyı tıklayın veya Cloud Shell'de Web Preview (Web Önizlemesi) → Change port (Bağlantı noktasını değiştir) → 4600'ü seçin. Bu sekmeye sekme 2 adını verin. 1. Oturum: Hikaye açılır.

Daha sonra kullanmak isteyebileceğiniz üç komut (tümü ~/vibe-studio-multimodal üzerinden):

scripts/stop.sh

çalışma alanını durdurur

scripts/start.sh

komutu ön planda başlatır; Ctrl+C komutu ve başlattığı her işlemi durdurur

scripts/restart.sh --pull

git pull, ardından arka planda yeniden başlatarak venv'yi yeniden senkronize eder ve sayfayı yalnızca değiştiğinde yeniden oluşturur

Depo düzeni

vibe-studio-multimodal/
├── agent/                  # the workflow and the platform clients
│   ├── graph.py            # the graph: three readers, the proposer, the gate, the router, the script, the desk
│   ├── desk.py             # render_desk and render_submit, the LongRunningFunctionTool
│   ├── deliver.py          # the delivery console: find the pending call, wait for Veo, answer by id
│   ├── schemas.py          # Direction, Directions, CleanedDirection, Script, each with a poster idea
│   ├── cleanup_tools.py    # find_policy_hits, suggest_replacement: the task agent's tools
│   ├── policy_words.txt    # the policy, as data; policy_replacements.txt, the approved stand-ins
│   ├── backlog.txt         # the creator's Halloween ideas; comments.md, the audience's comments
│   ├── audience/           # what else the audience sent: voice/*.mp3, photo/*.jpg, clip/*.mp4
│   ├── media/past/         # six past posters and captions.md, what Gemini sees in each
│   └── platform/           # config, audience (the readers), rag (RAG Engine), images, videogen (Veo), memory (Memory Bank)
├── stage0_prompt/ ... stage6_video/   # one sandbox app per session, runnable in adk web
├── server/ & web/          # the VibeStudio Workbench (FastAPI + React, port 4600)
├── vibestudio/             # the app deployed in session 7, with its own copy of agent/
├── checks/ & scripts/      # the hole registry, the verifiers, preflight, start/stop/restart
└── starter/                # the nine files you edit, as students receive them

3. 1 · Hikaye: Gece ve dönüştüğü grafik

👉🖥 2. sekme, 1. Oturum · Hikaye sayfasında açılır. Şöyle yazıyor: Bir kişinin etrafında halka şeklinde dizilmiş altı iş (trendleri araştır, biriken işleri tara, bir yön seç, politikayı kontrol et, senaryoyu yaz, klibi oluştur) ve bu halka her gece tekrarlanıyor. Gemini araştırma, birikmiş işler ve senaryo yazma işlerini tek başına yapabilir. Veo tek başına render alabilir. Seçim ve kontrol ise insanın sorumluluğundadır.

Halkanın altında, laboratuvarın geri kalanının oluşturduğu grafik yer alır. Bu grafik, bir fikirden klibe ve posterine kadar on üç düğümden oluşur. Düğümün ne yaptığını ve onu oluşturan oturumu görmek için fareyle üzerine gelin. Burada düzenlenecek bir şey yok. Sayfanın İlk posteri oluştur düğmesi 2. oturumdur.

Kelime dağarcığı, sonraki altı sayfa durmadan okunur:

kelime

burada ne anlama geldiğini

temsilci

ADK Agent: model, talimat, araçlar. 2. oturum

node

Grafiğin bir adımı: Python işlevi, temsilci, birleştirme, yönlendirici

edge

Sırayla çalışan düğümlerden oluşan bir demet. Grafik, bu düğümlerin listesidir. 3. Oturum

session

runs/sessions.db içinde bir çalıştırmanın kaydı: etkinlikleri, durumu ve açık bırakılan tüm aramalar. 5. Oturum

state

Düğümlerin anahtar adına göre paylaştığı bir sözlük; bir düğüm Event(state=...) yazar, diğeri aynı ada sahip bir parametre bildirir. 5. Oturum

memory

Oturumdan daha uzun süre saklanan bilgiler: Geri çağırmalar aracılığıyla Memory Bank. 6. Oturum

4. 2 · Görüntü üretme: Bir temsilci ve araç olarak görüntü modeli

2. oturum: Görüntü üretme

👉🖥 Çalışma alanında 2. Oturum · Görüntü üretme'yi açın. Grafikten önce, işe yarayabilecek en basit şey: Talimatı tüm geceyi düz yazı olarak içeren bir Agent, elleri olarak üç Python işlevi ve bir resimle biten bir çalıştırma.

Temsilci; model, talimat ve araçlardan oluşur.

stage0_prompt/agent.py, ADK temsilcisinin üç alanıyla root_agent tanımlar. model, agent/platform/config.py tarafından geliştirilen Gemini modelidir. instruction, sistem istemidir: Tek seferde altı iş, sonuncusu bir resim. tools üç işlev barındırır.

root_agent = Agent(
    name="solo_channel", model=config.MODEL,
    tools=[check_trends, read_backlog, make_poster],
    instruction=(
        "You run the creator's cozy-spooky short-video channel, alone, every "
        "night until Halloween.\n"
        "When the creator gives you an idea (or nothing), do ALL of this:\n"
        "check what is trending. look at your backlog of ideas. propose a "
        "direction and agree on it with the creator. refuse blacklisted "
        "subjects (competitor, hateful, gore). then describe the video you "
        "would make: a title (<=60 chars) and 3 shots, one visual sentence "
        "each. then draw its poster: call make_poster once with one line that "
        "names the single image that sells the video, and tell the creator "
        "where the poster is.\n"
        "Ask the creator to confirm the direction before describing the "
        "video."))

Model, kapalı bir dünyadır. Ağırlıkları ve bağlamındaki jetonlar üzerinden akıl yürütür. Araç, modelin isteyebileceği bir Python işlevidir. ADK, her işlevin imzasını ve docstring'ini okuyup modele bildirir. Model bir işlev istediğinde function_call etkinliği yayınlar, çalışma zamanı Python'u çalıştırır ve bağlama bir function_response etkinliği yazar. Model de önündeki sonuçla devam eder.

Üç işlev var ve bunlardan biri çizim yapıyor.

Üç kişiden ikisi araştırmayı okudu. Üçüncü istemde, görüntü modelinden bir poster oluşturması istenir:

def check_trends() -> dict:
    """Ten formats trending on the platform right now, with a heat score each."""
    from agent.trends import sample_trends
    return {"trends": sample_trends()}


def read_backlog() -> dict:
    """The creator's backlog: ideas they noted down to make someday."""
    from agent.graph import backlog_notes
    return {"backlog": backlog_notes()}


def make_poster(subject: str) -> dict:
    """Draw tonight's poster: one image of `subject` in the channel's cozy
    low-poly style. Returns where the PNG landed (path, url) in a few seconds."""
    ...

make_poster, agent/platform/images.py adlı görüntü modelini çağırır. Bu model, videogen.py'nin Veo'yu sarmaladığı gibi basit bir işlev olarak sarmalanmıştır: kanalın tarzını yansıtan bir ön ek (kanalın rahat, düşük poligonlu Cadılar Bayramı görünümü, gece yarısı moru arka plan üzerinde balkabağı turuncusu ve mum ışığı krem rengi), konu, dikey 9:16 çerçeve, runs/media/posters boyutunun altında bir PNG, /static/posters çözünürlükte sunulur. STUDIO_REAL_IMAGES=0 ile bir poster kopyalar ve sonucu prebaked olarak işaretler. Böylece laboratuvar her yerde çalışır.

MODEL = os.environ.get("STUDIO_IMAGE_MODEL", "gemini-2.5-flash-image")
ASPECT = "9:16"

def generate(subject: str, visual_style: str = "", name: str | None = None) -> dict:
    """One poster for `subject`. Returns where it landed: status, path, url,
    prompt, and prebaked=True when the stand-in was used instead of the model."""

Aynı çağrı, 5. oturumdaki grafikte bir düğümdür.

Uygulamalı: Tek düzenleme

Gönderildiği haliyle make_poster, posterin atlandığını belirten bir sözlük döndürür. 👉🖥 Workbench düzenleyicide, TODO satırı yerine görüntü modelini çağırmasını sağlayın:

    from agent.platform import images
    return images.generate(subject, name="solo")

Kaydet'i tıklayın. Doğrulama satırları dosyayı okur: temsilcideki üç araç, görüntü modeli çağrısı yerinde. 👉🖥 Check the workflow loads'u (İş akışı yüklerini kontrol et) ve ardından Open adk web'i (ADK web'i aç) tıklayıp şunları gönderin:

tonight's idea: a tiny ghost learning to haunt a sock drawer

Sizi neler bekliyor ve neden?

  • Yanıttan önce iki araç etkinliği, ardından bir soru. check_trends ve read_backlog çalıştırıldı. Çünkü talimatta kontrol etme ve bakma işlemleri belirtilmişti ve modelin ağırlıklarında bu işlemler yoktu. Talimatta önce onay istendiği için yanıtta bir yön önerilir ve sizden onay istenir.
  • İkinci mesaj her şeyi alır. skip the questions, describe the video and draw the poster gönder. Model, videoyu açıklar, kendi yazdığı bir konu satırıyla make_poster aracını bir kez çağırır ve PNG'nin nereye kaydedildiğini size bildirir. Doğrulama panelinde, satırların yanında poster gösteriliyor: Kanalın görünümünde, yaklaşık sekiz saniyede çizilmiş bir Cadılar Bayramı sahnesi.
  • Bu neden bir kanal değildir? Araştırma, hiçbir şeyin alıntı yapamayacağı bir düz yazıya dönüştürülür. Politika, talimatı yazan model tarafından onaylandı ve poster, kontrol edilmeden önce çizildi. Sözleşme bir mesajda konuşuldu. İstem metni bir engel değildir. Laboratuvarın geri kalanında bu altı iş, çizilmiş bir grafiğe ayrılır.

Sayfa, daha sonra tekrar başvurabileceğiniz bir referans olan ADK temsilcisinin bileşenleri bölümüyle sona erer. Bu bölümde model, modelin akıl yürütme için kullandığı bağlam, işlem yaptığı araçlar ve ortak çalışanlar, her çağrıyı sarmalayan geri çağırmalar ve modelin dışında bulunan oturum ve bellek açıklanır.

5. 3 · İş akışları: Dağıtım ve birleştirme, yönlendirici ve döngü

3. Oturum: İş Akışları

👉🖥 Çalışma alanında Session 3 · Workflows (3. Oturum · İş Akışları) bölümünün 3a ve 3b kısımlarını açın. Her parça, korumalı alan uygulamasında oluşturulur. Böylece her parçayı adk web içinde tek başına çalıştırabilirsiniz: stage1_fanout içinde fan-out, stage3_router içinde yönlendirici ve döngüsü.

Fan-out ve join (3a)

ADK Workflow, bir kenar listesidir. Her giriş, sırayla çalışan düğümlerden oluşan bir zincirdir. START noktasından ayrılan iki zincir paralel olarak çalışır. JoinNode ile biten bir zincir, bu düğüme rapor verir ve birleştirme, devam etmeden önce orada biten her zinciri bekler ve düğüm adına göre anahtarlanmış bir sözlük iletir. Sözlük olarak yazılan bir hedef, yönlendiricinin rota adlarını düğümlerle eşler. Çalışma kitabının 3a sayfasında şekiller çizilir ve kenarları yazma alıştırması yapılır.

Düğüm türü

Yazılışı:

Ne işe yarar?

İşlev düğümü

def scan_trends(node_input): ... return Event(output=...)

Düz Python. Event(state=...) ile paylaşılan durumu da yazabilir.

Birleştirme düğümü

JoinNode(name="join_research")

Gelen her zincir rapor verene kadar bekler, ardından tüm çıkışlarını tek bir sözlük olarak iletir.

Temsilci düğümü

Agent(...)

single_turn modunda bir model çağrısı, yapılandırılmış bir yanıt, sohbet yok.

Yönlendirici

return Event(output=..., route="OK")

Dönüşü, giden kenarı adlandıran bir işlev düğümü.

İnsan girdisi düğümü

yield RequestInput(...)

Bir kullanıcı formu yanıtlayana kadar grafiği askıya alır. 5. oturum.

Araştırma fan-out'u: START'tan bir birleştirmeye iki okuyucu

İlk grafik, 2. oturumdaki araştırmayı düğümler olarak gösterir. agent/graph.py'deki scan_trends ve read_backlog iki okuyucudur. read_backlog, bu akşamki fikri paylaşılan duruma da yazar. stage1_fanout/agent.py, birleştirmeyi tanımlar ve Workflow değerini, boş olarak gönderilen EDGES adlı bir listeden (ön kontrolün 0 edges) oluşturur. 👉🖥 Bu listeyi iki zincirle doldurun:

EDGES = [(START, scan_trends, join_research),
         (START, read_backlog, join_research)]

👉🖥 adk web uygulamasında çalıştırın. İki düğüm birlikte yanar, ardından birleşir; join_research etkinliğini açın ve scan_trends anahtarı ile read_backlog anahtarı içeren bir sözlüğü okuyun. Model çağrısı yapılmadı. Birleştirme düğümünün sözlüğünü yeniden biçimlendiren bir şey yoktur: 3b'de ondan sonraki düğüm bir temsilcidir ve bir temsilci düğümü, mesajı olarak node_input alır. Bu nedenle, bir sözlük, modelin doğrudan okuduğu JSON olarak gelir.

Yönlendirici ve döngü (3b)

Workflow içindeki bir Agent, single_turn modunda çalışır: Önceki düğümün çıkışını mesaj olarak alır, bir model çağrısı yapar ve bir kez yanıt verir. output_schema ile yanıt, bir sonraki düğüm tarafından görülmeden önce bir Pydantic modeline göre doğrulanır. Bu nedenle grafik, düz metin yerine yazılı nesneleri iletir. propose_directions, birleştirme işleminin araştırma sözlüğünü okur ve her biri Cadılar Bayramı sahnesi olan dört aday önerir. 4. aday, yemdir. Başlığında kanalın reddettiği bir kelime olduğu için yönlendirici tarafından yakalanır. Her adayın bir poster_idea vardır. Bu, videoyu satan tek görseli adlandıran tek bir satırdır. Senarist bunu saklar ve medya masası 5. oturumda çizer.

Yönlendirici, döndürdüğü değerle çalıştırmanın izleyeceği kenarı belirleyen bir işlev düğümüdür. Model çağrısı yok: policy_check, karar anında agent/policy_words.txt okur, tam kelimeleri talimatın başlığı ve açısıyla eşleştirir ve herhangi bir komut dosyası yazılmadan veya para harcanmadan önce yönlendirir. Politika veridir: Dosyayı düzenleyin, bir sonraki çalıştırmada okunur.

def policy_check(node_input):
    """The policy gate: a router. Refused words in the direction send it to
    quarantine; a clean one goes to the scripter. Code, not a model."""
    chosen = _as_dict(node_input)
    bad = policy_hits(f"{chosen.get('title', '')} {chosen.get('angle', '')}")
    return Event(output=node_input, route="BLOCK" if bad else "OK")

Politika kapısı: İki etiketli çıkışı olan bir yönlendirici

stage3_router/agent.py, fan-out artı propose_directions ve choose_direction'dir. 5. oturumda oluşturduğunuz insan kapısının yerine geçer: Numarası bu akşamın fikriyle (..., pick 4) biten adayı seçer, aksi takdirde ilkini seçer ve seçimi duruma yazar. scripter, onaylanmış bir talimatı Script haline getiren bir single_turn temsilcisidir: başlık, açıklama, etiketler, açılış cümlesi, üç çekim ve poster fikri. Her çekim, kanalın görünümünde bir Cadılar Bayramı görüntüsüdür.

Reddedilen çıkışın arkasındaki döngü. quarantine, görev modu temsilcisi olarak sunulur. Agent, mode içerir: chat, kök temsilcinin bir kişiyle yürüttüğü görüşme döngüsüdür; single_turn, yapılandırılmış yanıt içeren bir çağrıdır; task ise temsilcinin, bağımsız değişkenleri ADK tarafından output_schema'dan türetilen yerleşik finish_task'i çağırana kadar kendi başına yürüttüğü araç çağrısı döngüsüdür. Karantina, reddedilen yönde find_policy_hits çağrısı yapar, her kelime için kanalın onaylı alternatifini suggest_replacement'den ister (agent/policy_replacements.txt, yine veri), yeniden yazar, tekrar kontrol eder ve yazılı bir CleanedDirection ile tamamlar. Sayfada okursunuz, yazmazsınız.

quarantine = Agent(
    name="quarantine",
    model=config.MODEL,
    mode="task",
    instruction=QUARANTINE_INSTRUCTION,
    tools=[find_policy_hits, suggest_replacement],
    output_schema=CleanedDirection)

Seçimden sonra zincir doğrudan senaryo yazarına gider. 👉🖥 Yönlendiriciyi, iki çıkışı ve karantinadan dönüş yoluyla birlikte ikisinin arasına yerleştirin. Bir satırın yerine üç satır gelir:

           (join_research, propose_directions, choose_direction, policy_check),
           (policy_check, {"OK": scripter, "BLOCK": quarantine}),
           (quarantine, scripter),

👉🖥 Her iki rotayı da çalıştırın. Fikri olduğu gibi gönderin: choose_direction, 1. adayı alır, policy_check, OK'yi oluşturur ve senaryo yazarı yapılandırılmış bir senaryo yazar. Yeni oturum'u tıklayın ve fikri sonuna , pick 4 ekleyerek tekrar gönderin: 4. aday yemdir, policy_check BLOCK yayar, karantina araçlarını çağırır, reddedilen kelimeleri yeniden yazar, finish_task'i çağırır ve temizlenen talimat senaryo yazarına geri döner. Doğrulama satırları, oturum deposundan her iki çalıştırmayı da okur.

2. oturumun istemindeki her cümlenin artık bir düğümü var: Araştırma iki okuyucu ve bir birleştirme, ret bir yönlendirici ve bir görev temsilcisi, senaryo ise bir temsilci düğümüdür. Grafiğin tamamında, yedek seçim iki işlev düğümüdür (direction_gate ve persist_direction). Bunların, 5. oturum kapıyı durdurana kadar doğrudan çalıştığını göreceksiniz. İçerik üreticiyle yapılan anlaşma henüz kesinleşmedi. Araştırma da henüz kitleye ulaşmadı.

6. 4 · Çok formatlı besleme: Kitlenin gönderdiği her şey tek bir derlemde okunur.

4. oturum: Çok formatlı besleme

👉🖥 Çalışma alanında Session 4 · Multimodal ingestion (4. Oturum: Çok formatlı besleme) bölümünün 4a ve 4b kısımlarını açın. Kitle sadece yazmakla kalmadı. Her tür için bir okuyucu, gönderilen her şeyi aynı şekle sahip metne dönüştürür. Bir RAG Engine derlemi her şeyi barındırır ve fan-out'taki üçüncü bir okuyucu, anlamı arar ve medyayı geri verir.

Kitlenin gönderdiği mesajlar (4a)

agent/comments.md, kanalın altı Cadılar Bayramı videosunun altına yazılan on iki yorumu barındırıyor. agent/audience/ ise geri kalanları içeriyor: sekiz sesli not (voice/*.mp3), izleyicilerin kendi odalarının on dört fotoğrafı (photo/*.jpg) ve altı klip (clip/*.mp4), izleyicinin seslendirmesiyle bir fotoğrafın üzerinde yavaşça kayan bir kamera. 4a sayfasında her şey açılır: her sesli not çalınır, her fotoğraf gösterilir, her klip oynatılır.

İçerik alımından sonraki kitle tablosu: Her kartta Gemini'ın duyduğu veya gördüğü bilgiler gösterilir.

RAG Engine, metin alır. Sesli not, fotoğraf veya klip, derleme yalnızca rag.caption_posters uygulamasında geçmişte yayınlananlar gibi katılabilir: Bir model, bunu dosyasını adlandıran bir metin satırına dönüştürür, satır bir pasaj haline gelir ve pasaj geri geldiğinde dosya da onunla birlikte geri gelir. agent/platform/audience.py, her tür için bir okuyucuya sahiptir. Her biri Gemini'a bir dosya ve bir istem gönderir ve dosya başına bir satır yazar:

VOICE_PROMPT = ("Transcribe this voice note word for word inside double quotes. Then add: mood: and one word. "
                "Plain text on one line, nothing else.")
PHOTO_PROMPT = ("Two sentences: what is in the picture, the palette, the mood. Then: tags: and three short tags. "
                "Plain text on one line, no headings, no markdown.")
CLIP_PROMPT = ("Describe the shots in two sentences, then quote what you HEAR on the soundtrack as: heard: \"...\". "
               "Plain text on one line, no headings, no markdown.")


def _ask(path: pathlib.Path, mime: str, prompt: str) -> str:
    """One media file in, one line of text out."""
    from google.genai import types as gt
    client = images._client()
    resp = client.models.generate_content(
        model=config.MODEL,
        contents=[gt.Part.from_bytes(data=path.read_bytes(), mime_type=mime), prompt],
        config=gt.GenerateContentConfig(automatic_function_calling=gt.AutomaticFunctionCallingConfig(disable=True)))
    return " ".join((resp.text or "").split())


def transcribe_voice() -> pathlib.Path:
    """voice note -> text: Gemini listens."""
    files = sorted((AUDIENCE / "voice").glob("*.mp3"))
    lines = []
    for p in files:
        said = _ask(p, "audio/mpeg", VOICE_PROMPT)
        lines.append(f"- voice: {p.name} — {said}")
    return _write(AUDIENCE / "voice" / "transcripts.md", "voice", "What Gemini heard in the audience's voice notes", lines)

caption_photos, image/jpeg ve PHOTO_PROMPT ile; watch_clips ise video/mp4 ve CLIP_PROMPT ile aynı şeyi yapıyor. Gemini ise tek bir çağrıda resmi izleyip müziği dinliyor. Her okuyucu aynı satır şeklini yazar. Bu nedenle parçalama, yerleştirme ve alma işlemleri, bir pasajın hangi türden geldiğini asla bilemez:

- voice: note-03.mp3 — "I want a whole series of the cat judging costumes ..." mood: delighted
- photo: photo-01-ghost-drawer.jpg — A cream wooden drawer, striped socks, a paper-cup ghost ... tags: drawer, socks, cozy
- clip:  clip-05.mp4 — A hallway floor, a snail in a sheet and a round vacuum ... heard: "The snail won."
- poster: sock-ghost.png — A sheet ghost one inch above a striped sock ...

Her tür için bir okuyucu, bir çizgi şekli, bir derlem

Derlem. Vertex AI RAG Engine, dokümanlar üzerinden bilgi getirme işlemidir: Bir korpus yaklaşık 120 jetonluk parçalara ayrılır, her parça text-embedding-005 ile yerleştirilir ve bir sorgu aynı şekilde yerleştirilir ve paylaşılan kelimelere göre değil, anlama göre en yakın parçalarla yanıtlanır. "evde küçük sevimli hayaletler" araması, küçük odalarda küçük sihirler isteyen yorumu, ampule sarılan yarasa hakkındaki sesli notu ve müziğinde hayaletin kağıt bardak olduğunu söyleyen klibi bulur.

corpus = rag.create_corpus(
    display_name="vibestudio-feedback",
    backend_config=rag.RagVectorDbConfig(
        rag_embedding_model_config=rag.RagEmbeddingModelConfig(
            vertex_prediction_endpoint=rag.VertexPredictionEndpoint(
                publisher_model="publishers/google/models/text-embedding-005"))))

rag.upload_file(
    corpus_name=corpus.name, path="agent/comments.md", display_name="comments.md",
    transformation_config=rag.TransformationConfig(
        chunking_config=rag.ChunkingConfig(chunk_size=120, chunk_overlap=20)))

Kurulum, derlemeyi oluşturmaya zaten başladı. 4a sayfasının bağlantı satırında, derlemenin çalışır durumda olup olmadığı belirtilir ve kurulum oluşturamadıysa derleme oluşturulur. Sayfanın düğmelerinden veya terminalden: python -m agent.platform.rag, derlemeyi oluşturur ve runs/ragcorpus.json dosyasına kaydeder; python -m agent.platform.rag load --audience, audience.READERS içindeki her okuyucuyu çalıştırır, ardından yazdıklarını yorumların ve posterlerin başlıklarının yanına yükler (her dosya kendi adıyla) ve dizinin yanıt vermesini bekler; python -m agent.platform.rag query "cozy little hauntings at home", sorguyla hiçbir kelime paylaşmayan pasajları bulan erişimi gösterir.

Düzenleme. READERS, gönderildiği haliyle yalnızca read_comments barındırır. Üç medya okuyucu, bir # arkasında yer alır. 👉🖥 İçe aktarma işlemini bir kez çalıştırın: Çıkışta not read (no reader wired in audience.READERS): voice, photo, clip yazar ve yalnızca yorumlar ile altyazılar eklenir. Ardından # silin :

    transcribe_voice, caption_photos, watch_clips,

👉🖥 Kaydedin ve beslemeyi tekrar çalıştırın. Okuyucuların kırk öğeyi okuması yaklaşık üç dakika sürer. Konsol, her seferinde bir satır olmak üzere heard, saw ve watched der ve ızgaradaki her kart kendi satırıyla doldurulur. Doğrulama satırları dosyayı, okuyucuların çıkışını ve derlemi okur: Dört okuyucu bağlı, sekiz sesli not dinlendi, on dört fotoğraf görüldü, altı klip izlendi, derlemde beş dosya var.

Üçüncü okuyucu (4b)

Kitle geri bildirimi, her çalıştırmada paylaşılan bir araştırmadır. Bu nedenle, araştırmanın girdiği grafiğe girer: birleştirmeye üçüncü bir okuyucu olarak. agent/graph.py içindeki read_feedback, bu akşamki fikri alıp dizinden en yakın pasajları ister ve üç tane bekleyen join_research'ye bildirir. (START, read_feedback, join_research) kenarı, 3. şekil oturumunda öğretilen stage5_rag/agent.py şekline girer. Düzenlemeniz düğümün içindedir. Model çağrısı değil, alma işlemi ve deterministik: Aynı fikir, farklı önerenlerle aynı pasajları bulur.

def read_feedback(node_input):
    """The third reader: what the audience sent - comments, and what Gemini
    heard and saw in their voice notes, photos and clips - the passages
    nearest to tonight's idea, and the media those passages came with.
    Retrieval, not a model call."""
    from .platform import rag
    idea = idea_text(node_input)
    query = idea or "what viewers liked and what they complained about"
    try:
        hits = rag.retrieve(query)
    except Exception as e:
        print(f"  [rag] feedback unavailable ({str(e)[:80]})")
        return Event(output={"query": query, "feedback": [], "media": [],
                             "note": "no corpus connected - run: python -m agent.platform.rag"})
    return Event(output={"query": query, "feedback": [h["text"] for h in hits]})  # TODO: RAG_MEDIA

Derlemde sesli not, fotoğraf, klip veya posterden alınan her satırda dosya adı belirtilir. rag.media_in(hits), bu adları pasajlardan okur ve sayfanın gösterip oynatabileceği URL'lere dönüştürür. 👉🖥 Medyayı pasajlarla birlikte geri verin. Böylece, kitlenin gönderdiği şeyler söyledikleriyle birlikte iletilir:

    return Event(output={"query": query, "feedback": [h["text"] for h in hits],
                         "media": rag.media_in(hits)})

👉🖥 stage5_rag ile bir fikir üzerinde çalışın. Açık read_feedback: Sorgu sizin fikrinizdir, çıkışta en yakın beş pasaj ve her dosya için bir URL içeren bir media listesi bulunur. join_research uygulamasını açın: üç tuş. propose_directions açık: 1 ila 3 numaralı adaylar, kanıtlarında feedback adlı kişiden alıntı yapıyor. Doğrulama panelinde, okuyucunun satırların altında baktığı öğeler gösterilir: bir klip, üç sesli not ve buzdolabı ışığındaki hayalet posteri.

Üçüncü okuyucunun baktığı şey: Alınan pasajların birlikte geldiği medya

7. 5 · Video üretimi: İki tür askıya alma, tek mekanizma

5. oturum · Video üretimi

👉🖥 Çalışma alanında, stage6_video ile oluşturulan 5. oturum: Video üretimi'nin 5a ve 5b bölümlerini (grafiğin tamamı) açın. Klip birkaç dakika, poster ise birkaç saniye sürer. Çalışma sırasında iki kez duraklama olur: biri sizin için, diğeri Veo için. İki durak tek bir mekanizmadır ve masanın iki kolu, adlarıyla yaptıkları işleri paylaşır.

İki tür askıya alma (5a)

Hiçbir şey beklemez. Durdurulması gereken bir çalıştırma, oturumuna açık bir çağrı yazar ve sona erer. Bu çağrıyı yanıtlayan kişi veya işlem, çalıştırmayı devam ettirir. Sayfa bir tabloyla açılır:

kişi için · direction_gate

yavaş bir araç için · render_desk

koşuyu durduran

direction_gate, RequestInput kazandırır

render_submit, {status: pending} döndürür; LongRunningFunctionTool bunu bir durak yapar

ne beklediği

bir kişi: dört karttan biri

yavaş bir iş: Veo'nun çalışması, dakikalar

oturumda ne olduğunu

açık bir adk_request_input çağrısı: mesaj, form, yük

açık bir render_submit çağrısı: işlem adını içeren makbuz

nasıl devam eder?

Seçiminizi içeren ve ilgili görüşmenin kimliğine sahip bir function_response

Klibin URL'sini içeren, ilgili görüşmenin kimliğine sahip bir function_response

who sends it

adk web, formu gönderdiğinizde

python -m agent.deliver, başka bir işlemden, daha sonra

ve bu süre boyunca nerede barındırılacağı

runs/sessions.db · bir oturum kimliği · hiçbir şey çalışmıyor

aynı satır, aynı kimlik · hiçbir şey çalışmıyor

İki tür askıya alma, bir tablo

Bir kişi için. Tek bir istemde "içerik üreticiden onaylamasını isteme" tavsiye niteliğindedir ve 2. oturumda bu konu tek bir mesajda ele alınmıştır. İş akışında duraklatma, motorun sorumluluğundadır. RequestInput döndüren bir düğüm, çalıştırmayı askıya alır: ADK, message, response_schema ve payload ile oturuma adk_request_input adlı bir açık çağrı yazar, buna bir interrupt_id verir ve arayana geri döner. İleti dizisi beklemesi yok. Yalnızca şemanıza göre doğrulanmış, bu kimliği taşıyan bir function_response işlemi devam ettirir. İş akışına gönderilen sohbet mesajı, yanıt değil yeni bir sıradır. Şema aynı zamanda formdur: adk web bunu oluşturur ve VibeStudio uygulaması aynı şemayı dört kart olarak oluşturur. direction_gate, adayları zaten eyalete yazıyor. 👉🖥 Durdurma:

    yield RequestInput(
        message="Pick tonight's direction: 1, 2, 3 or 4.",
        response_schema={
            "type": "object",
            "properties": {
                "pick": {"type": "string", "enum": ["1", "2", "3", "4"]}}},
        payload={"candidates": cands})

Yanıtınız, persist_direction adlı değişkene node_input olarak ulaşır. Bu, pick adlı tek bir anahtara sahip bir sözlüktür. Dört aday başka bir şekilde gelir: Kapı, bunları candidates altında paylaşılan duruma yazdı ve ADK, bir durum anahtarını aynı ada sahip bir parametreye bağlar. Düğüm, seçimi bir adaya indirger ve direction, angle, hook ve user:prefs değerlerini Event(state=...) ile geri yazar. user: ön ekine sahip anahtarlar, ilgili kullanıcı için oturumlar arasında kalıcı olur.

Yavaş bir araç için. Veo'nun oluşturma işlemi birkaç dakika sürer ve bir grafiğin bu kadar uzun süre beklemesi gerekmez. agent/desk.py içindeki render_submit, işi başlatır ve hemen durumu pending olan bir makbuz döndürür:

def render_submit(prompt: str) -> dict:
    """Submit one Veo render of `prompt`. Returns at once with a pending
    receipt; the clip is delivered later, to this call, by id."""
    receipt = videogen.start(f"{prompt} {videogen.NO_TEXT}")
    return {"status": "pending", "operation": receipt["operation"], "prompt": receipt["prompt"]}

LongRunningFunctionTool ile sarmalanan bu makbuz, ADK için bir anlam ifade eder: Temsilcinin sırası sona erer, iş akışı render_desk noktasında askıya alınır ve kimliği ile makbuzu içeren açık çağrı, runs/sessions.db içinde bir satır olarak kaydedilir. 👉🖥 stage6_video/agent.py uygulamasında aracı sarmalayın:

    tools=[LongRunningFunctionTool(render_submit)])

Başka bir işlemden kimliğe göre devam ettirme agent/deliver.py, oturum deposunda bekleyen çağrıyı bulur, klip oluşturulana kadar Veo'yu sorgular, sonucu runs/state.json dosyasına yazar ve aynı oturuma bu çağrının kimliğini içeren bir function_response gönderir. 👉🖥 Yanıt bölümünü oluşturun:

    part = Part(function_response=FunctionResponse(
        id=row["call_id"], name=row["name"], response=response))

👉🖥 stage6_video iki kez durana kadar çalıştırın. Fikir gönder: Çalışma, şemanızdan oluşturulan bir formda durur ve yükünde dört aday bulunur. pick alanına 2 yazıp gönderin. Grafik persist_direction itibarıyla devam eder. Sonlandırma testini burada deneyin: Formda askıya alın, sunucuyu durdurun (1. sekmede scripts/stop.sh), tekrar başlatın (scripts/restart.sh), oturumu yeniden açın. Form hâlâ duruyor çünkü duraklatma bir ileti dizisi değil, satırdır. script_ready tarihinden sonra render_desk, render_submit işlevini çağırır, makbuzu alır, WAITING yanıtını verir ve çalıştırma sona erer. Oturum, çağrı kimliğini saklar. Sayfanın konsolundan veya 1. sekmeden yayını çalıştırın:

cd ~/vibe-studio-multimodal
uv run python -m agent.deliver status   # the pending renders, by session, call id and operation
uv run python -m agent.deliver          # wait for Veo, answer the newest pending call by id

👉🖥 Refresh adk web'i (adk web'i yenile) tıklayın: function_response, bekleyen çağrıyı takip eder, join_media serbest bırakılır ve store_release çalışır. Sekiz doğrulama satırı, oturumdaki iki duraklamayı okur: kapının çağrısı ve yanıtınız, oluşturucunun makbuzu ve teslimatı.

Eyalet ve masa (5b)

Medya masası, yine 3a'nın yapısına sahiptir. Bir yavaş dalı olan bir fan-out ve bir birleştirme vardır. script_ready, senaryoyu iki şekilde gönderir. render_desk klibi gönderir ve çalıştırma askıya alınır. make_poster, düğüm olarak 2. oturum aracıdır: Senaryonun poster_idea, kanalın stili ve Hafıza Bankası'nın içerik üreticinin poster zevki hakkında bildikleri (memory_facts olarak durumdan bağlı, 6. oturum) görüntü modeline gider ve saniyeler içinde 9:16 PNG geri gelir. join_media, yavaş olanı bekler ve store_release, bulduğu bilgileri duruma yazar.

Ada göre paylaşma. store_release posteri hiç almaz. poster_url adlı bir parametre tanımlar ve ADK, diğer daldaki bir düğüm bu anahtarı yazdığı için bu parametreyi paylaşılan durumdan bağlar. Dallar arasında veri yükü geçişi olmaz:

def store_release(node_input, poster_url: str = "", poster_path: str = ""):
    """`poster_url` and `poster_path` are not passed by anyone: ADK binds them
    from shared STATE because the parameter names match the keys make_poster
    wrote (the STATE_SHARE edit). The two branches of the desk never hand each
    other payloads; they share what they made by name."""
    render = state.load().get("render") or {}          # the delivered clip, written by deliver
    url, status = render.get("url") or "", render.get("status", "")
    ...
    if not poster_url:
        said += " · poster: not in state (did make_poster write poster_url to state? the STATE_SHARE edit)"
    yield Event(output={"status": status, "url": url, "poster_url": poster_url},
                state={"render_url": url, "render_status": status, "poster_url": poster_url},
                message=f"video: {said} · poster: {poster_url or 'none'}")

Mevcut haliyle make_poster, posteri çıktı ve mesaj olarak verir, store_release ise poster: not in state der. 👉🖥 Durum yazma işlemini nihai verimine ekleyin:

                state={"poster_url": rec.get("url", ""), "poster_path": rec.get("path", "")},
                message=f"poster: {said}")

👉🖥 Bir kez daha çalıştırın ve teslim edin. make_poster etkinliğini açın: Çıkışında posterin URL'si ve poster_url ile bir durum deltası. store_release adlı dosyayı açın: Mesajda, posteri hazırlayan kişinin adı yer alır. Sayfanın This run's session (Bu çalıştırmanın oturumu) bloğunda, aynı satırın adk web's State (Durum) sekmesinde gösterilenler yer alır: devam ettirme için gereken oturum kimliği, açık olan çağrı ve düğümlerin yazdığı anahtarlar (poster_url). Doğrulama panelinde klip ve poster yan yana gösterilir.

Yayınlandıktan sonra yan yana gösterilen klip ve posteri

8. 6 · Bellek: Kanalın geceler arasında hatırladığı bilgiler

6. oturum · Bellek

👉🖥 Çalışma alanında, stage4_memory ile oluşturulan Session 6 · Memory (6. Oturum · Bellek) bölümünün 6a ve 6b kısımlarını açın. 5. oturum, bir çalıştırmanın durumuyla ilgiliydi. Bu oturumda, kanalın çalıştırmalar arasında neleri hatırladığı ele alınmaktadır: Grafiğin iki geri çağırma aracılığıyla dışarıdan duydukları.

Memory Bank (6a)

Vertex AI Memory Bank, bir kişiyle ilgili yönetilen uzun süreli bellektir. Gerçekler bir kapsam (uygulama adı ve kullanıcı kimliği) ve tanımladığınız konular altında bulunur. memories.generate ile bir etkileşimde bulunduğunuzda, konuya uygun olan bilgileri çıkarır, yerleştirir ve zaten sahip olduğu bilgilerle birleştirir: Yeni bir bilgi oluşturulur, değişen bir bilgi güncellenir, tekrar eden bir bilgi birleştirilir. memories.retrieve, bir kapsamla ilgili bilgileri döndürür. Her iki çağrı da agent/platform/memory.py içinde yer alır.

SCOPE = {"app_name": config.APP, "user_id": config.USER}
TOPICS = {
    "CREATOR_TASTE": "Which video directions this creator picks and passes on, "
                     "and how that preference changes over time.",
    "CHANNEL_RULES": "Standing instructions the creator states for every video "
                     "(style, subjects to avoid, format rules).",
    "VISUAL_STYLE": "What this creator approves and rejects in a poster: palettes, "
                    "framing, props and mood of the posters they shipped.",
}

Üçüncü konu ise kanalın resimlerdeki zevki. Sürüm, 5. oturumda bu dosyaya yazdı: Gönderilen bir poster tek bir cümleyle açıklanıp hatırlanıyor ve bir sonraki poster, isteminde bu cümleyle çiziliyor.

Kurulum, bankayı oluşturmaya başladı. 6a sayfasının bağlantı satırında bankanın çalışır durumda olup olmadığı belirtilir. Sayfanın düğmelerinden veya terminalden: python -m agent.platform.bank, bankayı ve konularını oluşturur ve kaynak adını runs/memorybank.json içinde önbelleğe alır; python -m agent.platform.bank load, geçmişteki dört oturumu (stil kuralı olan iki hayvan dönemi, bir cihaz dönemi, yakın zamandaki bir fantezi dönemi) başlatır; python -m agent.platform.bank list, transkriptlerin neye dönüştüğünü gösterir: transkriptler değil, birleştirilmiş gerçek ifadeleri.

Geri aramalar (6b)

Hafıza bir düğüm değildir. Geri çağırma, Agent öğesine ilettiğiniz bir işlevdir. ADK, bu işlevi canlı bağlamla sabit bir anda çağırır ve None döndürerek normal işlemin gerçekleşmesini sağlar. Üç çift: Temsilcinin sırası (before_agent_callback, after_agent_callback, CallbackContext ile), her model çağrısı (LlmRequest ile before_model_callback, LlmResponse ile after_model_callback), her araç çağrısı. Güvenlik önlemleri, telemetri, önbellekler ve bağlam ekleme, grafikte bir düğüm olmadan buraya eklenir.

stage4_memory/agent.py, propose_directions model çağrısından önce bankayı okur: recall_taste bilgileri getirir, en eskiden başlayarak MEMORY bloğu olarak isteğe ekler ve modele 1 ila 3 arasındaki adayları mevcut zevke göre değerlendirmesini ve kuralları kısıtlama olarak ele almasını söyler. Ayrıca, gerçekleri memory_facts olarak yazar ve make_poster bunları bulur. 👉🖥 Kabloyla bağlayın:

    output_schema=Directions,
    before_model_callback=recall_taste)

Senarist, içerik üreticinin sırası bittikten sonra seçtiği şeyi yazar: remember_pick, durumdan direction okur, seçimle ilgili bir cümle yazar ve bunu memories.generate'ye verir. 👉🖥 Kabloyla bağlayın:

    output_schema=Script,
    after_agent_callback=remember_pick)

👉🖥 Boş bir mesajla çalıştırın ve bir kart seçin. propose_directions etkinliğini açın: İstek üç dönemi içeriyor ve 1 ila 3 numaralı adaylar mevcut zevke yönelirken trendler başka bir şey öneriyor. Senaryo yazarı, Bankayı göster'i tıklayın: Bu geceki seçim için bir anı değiştirildi veya eklendi. İkinci gece çalıştırın: İlk geceyi hatırlar.

9. 7 · Dağıtma ve yayınlama: Uygulama içindeki grafik, VibeTube'da gece

7. oturum: Dağıtma ve yayınlama

👉🖥 Çalışma alanında 7. Oturum: Dağıtma ve yayınlama'nın 7a ve 7b bölümlerini açın.

VibeStudio'yu dağıtma (7a)

Korumalı alanlarda grafiği adk web yönlendirdi. VibeStudio, ADK'nin Runner ile bunu yönlendirir. Bu işlem, kendi etkinlik döngüsüne sahip bir çalışan iş parçacığında gerçekleşir ve her etkinliği, sayfanın Sunucu Tarafından Gönderilen Etkinlikler üzerinden okuduğu tek bir çalıştırma durumuna katlar: okuyucular, dört kart olarak seçiminiz, posterin ulaştığı hali ve oluşturulan hali. Ağ geçidinin yanıtı ve oluşturulan içeriğin yayınlanması aynı çağrıda (function_response bölümü) gerçekleşir ve uygulama, konsolu beklemek yerine doğrudan Veo'yu sorgular.

self._svc = DatabaseSessionService(db_url=config.DB_URL)
self._runner = Runner(app_name=config.APP, agent=wf, session_service=self._svc)

async for ev in self._runner.run_async(user_id=config.USER, session_id=run_id, new_message=message):
    self._absorb(ev)    # fold the ADK event into the run state, publish one app event

part = Part(function_response=FunctionResponse(id=call_id, name=name, response=response))

vibestudio/server/agent/, laboratuvarın agent/ dosyasının bayt bazında kopyasıdır ve checks/verify_app.py tarafından kontrol edilmiştir. agent/graph.py içindeki tam kenar listesi, bu codelab'deki her yapıyı tek bir yerde (on üç düğüm) içerir. Bu liste, yazmanız için değil, okumanız için doldurulmuş olarak gönderilir:

        (START, scan_trends, join_research),
        (START, read_backlog, join_research),
        (START, read_feedback, join_research),
        (join_research, propose_directions, direction_gate,
         persist_direction, policy_check),
        (policy_check, {"OK": scripter, "BLOCK": quarantine}),
        (quarantine, scripter),
        (scripter, script_ready),
        (script_ready, render_desk, join_media),
        (script_ready, make_poster, join_media),
        (join_media, store_release),

👉🖥 Çalışma alanının Deploy (Dağıt) düğmesini kullanarak veya 👉💻 1. sekmeden dağıtın:

cd ~/vibe-studio-multimodal
uv run python vibestudio/deploy.py

Bu komut, .env değerleriniz doldurulmuş olarak çalışır:

gcloud run deploy vibestudio --source vibestudio \
  --project $GOOGLE_CLOUD_PROJECT --region us-central1 \
  --labels dev-tutorial-codelab=vibetube --allow-unauthenticated \
  --memory 2Gi --cpu 2 --timeout 3600 --concurrency 40 \
  --max-instances 1 --min-instances 1 --session-affinity \
  --set-env-vars GOOGLE_CLOUD_PROJECT=...,STUDIO_VERTEX=1,STUDIO_MEMORY_BANK=...,STUDIO_RAG_CORPUS=...,VIBETUBE_URL=...,VIBETUBE_EVENT=...,VIBETUBE_NAME=...,VIBETUBE_PROJECT=...

--source, container'ı Cloud Build ile derler ve tek adımda dağıtır. İlk derleme dört veya beş dakika sürer. Tek bir sıcak örneğe sahip --session-affinity, askıya alınmış bir çalıştırmayı, onu tutan örnekte (5. oturumun oturum deposu) tutar. Daha büyük bir dağıtımda oturum deposu VertexAiSessionService'e taşınır ve yakınlık ortadan kalkar. Derleme ve hizmet, projenin varsayılan Compute hizmet hesabı olarak çalışır. Kurulum, bu hesaba ihtiyaç duyduğu rolleri vermiştir.

👉🖥 Hizmet URL'sini açın ve uygulamada bir gece çalıştırın: bir fikir, bir seçim, klibi ve posteri bekleyin. Geçmiş sekmesinde her ikisi de tutulur.

Yayınla (7b)

Yayınlama, uygulamadan VibeTube'daki odanın uç noktasına vibestudio/server/platform/publish.py biçiminde gönderilen çok parçalı bir POST isteğidir. Klip videoyu, poster küçük resmi, profil ise odayı ve sizi temsil eder:

url = f"{prof['platform_url']}/api/events/{prof['event_code']}/videos"
data = {"title": state.script["title"], "description": state.script["description"],
        "duration": "0:08", "displayName": prof["display_name"],
        "projectId": prof["project_id"]}        # one video per project and room: publishing again replaces it
files = {"videoFile": (clip.name, clip.open("rb"), "video/mp4"),
         "thumbnailFile": (poster.name, poster.open("rb"), "image/png")}   # the poster, not a frame
r = httpx.post(url, data=data, files=files, timeout=120)
video_id = r.json()["id"]                       # watch it at {platform}/e/{event}?v={video_id}

VibeTube, her projectId ve oda için bir video saklar. Uygulamanın gönderdiği proje, Google Cloud projenizdir. Bu nedenle, tekrar yayınladığınızda yeni bir video eklenmez, mevcut videonuz değiştirilir. Hiçbir zaman geçici bir poster yüklenmez. Gerçek poster, küçük resimdir (bayt bazında).

Son düzenleme bir kod satırı değil, yapılandırmadır. 👉🖥 7b sayfasında: VibeStudio URL'si (7a'nın dağıtımından doldurulur), odanın etkinlik kodu (VibeTube'un yazdığı şekilde, eğitmeniniz başka bir kod açmadıysa kurulumda verdiğiniz kod) ve adınız. Yayınla'ya basın. Çalışma alanı, tıklamayı uygulamaya iletir, uygulama geceyi yayınlar ve aşağıdaki satırlar uygulamadan ve VibeTube'dan sonucu okur: Uygulama yanıt verir, gece gerçek bir posterle tamamlanır, kod açık bir odayı adlandırır, VibeTube bir video kimliği döndürür, video duvardadır ve küçük resmi posterinizdir. Sonuç kartında, uygulamadaki posterin yanında VibeTube'daki küçük resim gösterilir.

Yayınlandı: VibeTube'daki küçük resim, görüntü modelinin çizdiği posterdir.

10. Oluşturduğunuz öğe

👉🖥 7b sayfasının finalinde, bir fikirden klibe ve posterine kadar on üç düğümden oluşan grafiğin tamamı çizilir. Bir düğümün ne yaptığını ve onu oluşturan oturumu görmek için fareyle üzerine gelin.

Oturum

Öğrettikleri

Yazılışı:

2 · Görüntü üretme

Temsilci: model, talimat, araçlar; araç olarak görüntü modeli; istemin vaat edemeyeceği şeyler

Agent(tools=[...]), function_call / function_response, images.generate

3 · İş akışları

Kenar listesi, fan-out ve birleştirme, arkasında görev modu döngüsü olan bir yönlendirici

Workflow, START, JoinNode, Event(route=...), mode="task", finish_task

4 · Çok formatlı besleme

Her türden bir okuyucu, bir satır şekli, bir derlem; anlam bakımından üçüncü bir okuyucu, medya ile birlikte

generate_content; ses, resim ve video bölümleri, rag.upload_file, rag.retrieve, media_in ile

5 · Video üretimi

İki tür askıya alma, tek mekanizma; oturum deposu; poster adıyla paylaşılır

RequestInput, LongRunningFunctionTool, FunctionResponse(id=...), Event(state=...), parametre bağlama

6 · Bellek

Gece boyunca hafıza, iki geri çağırma

memories.generate / retrieve, before_model_callback, after_agent_callback

7 · Dağıtma ve yayınlama

Cloud Run'da bir uygulamanın içindeki grafik; VibeTube'da gece

Runner(agent=wf), run_async, sunucu tarafından gönderilen etkinlikler, bir çok parçalı POST

Grafiğin uyduğu beş kural:

  1. Beklemek yerine askıya alın. Duraklatma, bir ileti dizisi değil, oturum deposundaki bir satırdır.
  2. Her şeyi aynı şekilde devam ettirin: Açık aramanın kimliğine göre, bir kişi veya işlem yanıt verir.
  3. Verileri her yükte işleyerek değil, durumdaki ada göre paylaşın.
  4. Bir model için ödeme yapmadan önce kodla karar verin. Politika, bir metin dosyası ve yönlendiricidir ve oluşturma işleminden önce çalışır.
  5. Metin olmayan her şeyi, derleme ulaşmadan önce metne dönüştürün. Dosyanın geri dönebilmesi için dosyanın adını satırın içine ekleyin.

İstemler; sipariş, durdurma veya kontrol sözü veremez. Grafik bunu yapabilir.

Bundan sonra ne yapabilirsiniz?

  • Bir örnekten daha uzun süren oturumlar için VertexAiSessionService ve --session-affinity bırakın.
  • Yoklayıcı yerine oluşturma çağrısını yanıtlayan bir webhook: aynı FunctionResponse(id=...), farklı gönderen.
  • Yayınlamadan önce ikinci bir RequestInput: Şema formdur, bu nedenle bir düğümdür ve sayfa kodu yoktur.
  • Kitlenin yeni yorumları, sesli notları ve klipleri, her yayından sonra gönderildikleri posterle birlikte derleme eklenir.

Temizleme

Bu laboratuvarda oluşturulan her şey 4. adımda oluşturulan projede yer alır. Bu nedenle, en ucuz temizleme yöntemi projeyi silmektir. Cloud Shell'de:

gcloud projects delete $(cat ~/project_id.txt)

Projeyi koruyup yalnızca ücretli parçaları kaldırmak için: Cloud Run hizmeti (gcloud run services delete vibestudio --region us-central1), RAG derlemi ve Memory Bank (kaynak adları runs/ragcorpus.json ve runs/memorybank.json'dedir ve konsolun Agent Engine ile RAG Engine sayfaları bunları siler) ve Artifact Registry'deki container görüntüsü.