This post is my submission for DEV Education Track: Build Multi-Agent Systems with ADK.
This article provides a step by step architectural and deployment guide for StreamForge, a real-time event-driven multi-agent pipeline built with the Google Agent Development Kit (ADK), open-weights Gemma 3 (gemma3:12b), Google Cloud Eventarc, Cloud Pub/Sub, and Google Cloud Run.
Repository: github.com/RobinaMirbahar/streamforge-event-adk
Enterprise data platforms operate on real-time state changes: a product engineering team uploads a release specification (vertex-vector-sync-v4.2.json) to a Google Cloud Storage bucket, a streaming job commits a partition to BigQuery, or a partner service publishes a schema event to Cloud Pub/Sub. Connecting Google Cloud Eventarc directly to a multi-agent Google ADK workflow runtime on Cloud Run triggers autonomous workflows within 200 ms of an object landing in storage while scaling to 0 instances when the bucket is idle.
Why Combine Eventarc with ADK ParallelAgent and LoopAgent?
Processing a multi-regional product release requires three distinct tasks: extracting technical benchmarks from the raw JSON payload, translating launch messaging across target locales (en_US, de_DE, ja_JP), and simulating 12-month Annual Recurring Revenue (ARR) expansion under regional B2B currency rules. Running those three steps sequentially increases end-to-end latency, while running them in parallel without a verification step risks publishing unrounded foreign-exchange prices.
| Architecture Pattern | Trigger Mechanism | Execution Topology | Cross-Agent Consistency Check | Duplicate Event Protection |
|---|---|---|---|---|
| 🥇 Eventarc + ADK ParallelAgent & LoopAgent | Real-time CloudEvents v1.0 (< 200 ms lag) |
3 concurrent branches (3x fan-out) + LoopAgent critic
|
Iterative audit repairs EUR/JPY pricing until quality_score == 1.0
|
Firestore ce-id ledger short-circuits replays in < 5 ms
|
| 🥈 Scheduled ADK SequentialAgent | Fixed cron schedule | Linear 3-stage chain | Single-pass sequential handoff | Date-keyed Firestore lock |
| 🥉 Single Monolithic Prompt | Manual human chat prompt | Single LLM call | Unchecked single-pass output | Manual retry handling |
End-to-End Event-Driven Architecture on Google Cloud
-
Tier 1: Event Ingestion and Routing: Uploading
releases/2026-10/vertex-vector-sync-v4.2.jsontogs://streamforge-launch-inboxemits a nativegoogle.cloud.storage.object.v1.finalizedevent. Google Cloud Eventarc wraps the notification in a CNCF CloudEvents v1.0 envelope (ce-id,ce-type,ce-source,ce-time) and delivers it over an OIDC-authenticated Cloud Pub/Sub push subscription. -
Tier 2: Serverless Multi-Agent Runtime (Cloud Run): A private FastAPI receiver checks the incoming
ce-idheader (ce-98104271-gcs-finalized) against Cloud Firestore. New events execute the Google ADK workflow (ParallelAgent→LoopAgent→LlmAgent) powered by Gemma 3 12B viaLiteLlm. -
Tier 3: State and Downstream Sink: The final publisher agent validates the output against the Pydantic
EventDrivenLaunchManifestschema and commits both the manifest (MANIFEST-SF-VECTOR-SYNC-4.2) and thece-iddeduplication record to Cloud Firestore.
Orchestrating ParallelAgent Fan-Out and LoopAgent Self-Correction
In Google ADK, all branches inside a ParallelAgent share the same InvocationContext.session.state. Assigning a distinct output_key to each branch isolates their writes cleanly:
-
TechnicalSpecExtractorAgentwrites engineering benchmarks tooutput_key="extracted_specs". -
GlobalLocalizationAgentwrites localized headlines and draft currency tiers tooutput_key="localized_copy". -
RevenuePricingSimulatorAgentwrites the 12-month ARR forecast and regional FX compliance rules tooutput_key="pricing_simulation".
Once all 3 parallel branches complete, QualityCritiqueRefinementLoop (LoopAgent with max_iterations=3) invokes LaunchReadinessCriticAgent to audit the combined state. When GlobalLocalizationAgent converts the $499/mo Growth Tier at the raw 0.92 EUR exchange rate (€459.08/mo), Iteration 1 of the LoopAgent flags the violation against the de_DE rule requiring VAT-exclusive B2B prices rounded to the nearest €5 (quality_score = 0.72) and updates the pricing tier to €460/mo. On Iteration 2, the audit reaches quality_score = 1.0 and invokes exit_quality_loop(), setting tool_context.actions.escalate = True to exit the loop immediately.
At This Point You Should Have
- Python
3.10+(3.11recommended) withgoogle-adk>=1.0.0,litellm,fastapi, andpydanticinstalled. - A Google Cloud project with
Cloud Run,Eventarc,Cloud Pub/Sub,Cloud Storage, andCloud FirestoreAPIs enabled. - Access to Gemma 3 12B (
ollama_chat/gemma3:12blocally via Ollama orgoogle/gemma-3-12b-iton a Cloud RunNVIDIA L424 GBGPU service).
Step 1: Define the CloudEvent and Launch Manifest Schemas
The pipeline enforces typed contracts at both boundaries: CloudEventEnvelope validates the incoming Eventarc HTTP headers and payload, while EventDrivenLaunchManifest constrains the final ReleasePublisherAgent output in streamforge_agent/schemas.py.
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
Step 2: Implement the Parallel Enrichment and Loop Escalation Tools
In streamforge_agent/tools.py, each specialist tool exposes typed parameters and docstrings for Gemma 3 function calling, while exit_quality_loop sets tool_context.actions.escalate = True on the injected ADK ToolContext.
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
Step 3: Wire ParallelAgent, LoopAgent, and SequentialAgent
In streamforge_agent/agent.py, build_streamforge_event_pipeline() composes the 3 parallel enrichment agents, the iterative quality critic loop, and the schema-constrained publisher agent into a single parent SequentialAgent.
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
Step 4: Verify the Pipeline and CloudEvent Deduplication Locally
Run scripts/simulate_cloudevent_pipeline.py to execute the 3-branch ParallelAgent fan-out, inspect the 2-iteration LoopAgent self-correction trace, and verify the ce-id idempotency guard against a duplicate Pub/Sub delivery.
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
Step 5: Deploy the Private Cloud Run Receiver and Eventarc Trigger
Run deploy/deploy_eventarc_adk.sh to deploy the container to Google Cloud Run (2 vCPU, 2 GiB memory, --no-allow-unauthenticated, --min-instances=0, --max-instances=10) and bind the Eventarc trigger to google.cloud.storage.object.v1.finalized.
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
==> [1/6] Enabling Cloud Run, Eventarc, Pub/Sub, Storage, and Firestore APIs...
==> [2/6] Creating Cloud Storage Inbox Bucket & Dead-Letter Pub/Sub Topic...
==> [3/6] Creating Least-Privilege Service Accounts...
==> [4/6] Deploying StreamForge ADK Service to Cloud Run (private ingress)...
Service [streamforge-event-adk] revision [streamforge-event-adk-00001-x8k] has been deployed and is serving 100 percent of traffic.
==> [5/6] Granting Cloud Run Invoker + Eventarc EventReceiver to Eventarc SA...
==> [6/6] Creating Eventarc Trigger for google.cloud.storage.object.v1.finalized...
Created trigger [streamforge-gcs-release-trigger] in [us-central1].
Official Google Cloud and ADK Documentation
- Google Agent Development Kit (ADK) Documentation
- Google ADK Workflow Agents (
SequentialAgent,ParallelAgent,LoopAgent) - Google ADK Python SDK Repository (
google/adk-python) - Google Gemma Open Models Documentation
- Google Cloud Eventarc Documentation
- Google Cloud Run Documentation
- Google Cloud Pub/Sub Push Subscriptions Guide
- Google Cloud Firestore Documentation
Summary
The goal of this article was to build and verify a real-time, event-driven multi-agent pipeline on Google Cloud using Eventarc, Cloud Pub/Sub, Cloud Run, open-weights Gemma 3, and the Google Agent Development Kit. The key to the solution was pairing ParallelAgent for concurrent 3-branch fan-out with LoopAgent for iterative cross-branch self-correction and a Cloud Firestore ce-id deduplication ledger. The verification results were:
- 🟢 Concurrent Fan-Out (
ParallelAgent): Extracted engineering specs (73.8%latency drop from145 msto38 msat250,000rows/sec), localized copy across3locales (en_US,de_DE,ja_JP), and forecasted$2,856,000in 12-month Net New ARR lift across340upgraded accounts (18.5%of1,840active Growth Tier accounts at$8,400annual expansion). - 🟢 Self-Correcting Quality Loop (
LoopAgent): Detected the€459.08/moand¥75,848/mocurrency formatting violations on Iteration1(quality_score = 0.72), repaired them to€460/moand¥75,800/mo, and exited cleanly on Iteration2(quality_score = 1.0) viaexit_quality_loop(). - 🟢 At-Least-Once Idempotency: Short-circuited duplicate
ce-98104271-gcs-finalizedredelivery in< 5 mswith0redundant parallel branches or LLM calls.
The strategy for orchestrating event-driven multi-agent pipelines with Google ADK and Gemma 3 on Cloud Run was validated with an incremental step by step approach.

