---
season: 3
season_name: "Season 3 — October 2026 (Autumn / Halloween Edition)"
day: 29
title: "Dynamic Model Routing: Cut Agent Cost Without Losing Quality"
summary: "Route incoming requests across tiered Gemini models using a deterministic ADK FunctionNode heuristic over structured metadata, with zero LLM calls in the router."
tags: ["Model Routing", "Latency Optimization", "Cost Governance", "Graph Workflows"]
canonical_url: "https://adventofagents.com/2026/10/29"
markdown_url: "https://adventofagents.com/2026/10/29.md"
video_url: "https://www.youtube.com/embed/AEbhyJbjOKo"
primary_video:
  title: "Day 29: Dynamic Model Routing & Latency Optimization"
  creator_name: "Charles Frenzel"
  duration: "6:12"
  video_url: "https://www.youtube.com/embed/AEbhyJbjOKo"
---

# ⚡ Day 29: Dynamic Model Routing: Cut Agent Cost Without Losing Quality

> **Season 3 — October 2026 (Autumn / Halloween Edition)** · [Interactive Web View](https://adventofagents.com/2026/10/29?utm_source=adventofagents&utm_medium=markdown&utm_campaign=adventofagents_s3_2026&utm_content=day29) · [Raw Markdown](https://adventofagents.com/2026/10/29.md?utm_source=adventofagents&utm_medium=markdown&utm_campaign=adventofagents_s3_2026&utm_content=day29)

**Summary:** Route incoming requests across tiered Gemini models using a deterministic ADK FunctionNode heuristic over structured metadata, with zero LLM calls in the router.

**Day 29 of Google's Advent of Agents — Season 3**

Sending every incoming request to a deep-reasoning model forces routine traffic to pay unnecessary thinking latency and token cost, backing up production queues. Replacing that bottleneck with an LLM-based router only compounds the problem by adding an extra network round-trip and prefill overhead before the real work even starts.

**How It Works**

![Dynamic Model Routing Architecture](/season3-day29-architecture.png)

In ADK 2.0, `Workflow` graphs let you place a deterministic `FunctionNode` in front of tiered `LlmAgent` nodes, so the routing decision takes about a millisecond instead of a model call:

- **Fail-Safe Metadata Router**: `triage_router` inspects structured alert fields (`severity`, `correlated_signals`, and `mitre_techniques` against an auditable `ROUTINE_TECHNIQUES` allowlist) and emits `Event(route="FAST")` only for provably routine alerts. Everything else emits `Event(route="DEEP")`, because in security a missed incident costs far more than extra tokens.
- **Tiered Gemini 3.x Thinking Levels**: Routine alerts route to `fast_triage` on `gemini-3.5-flash-lite` with `thinking_level` set to `MINIMAL`, which pre-triages for human review. All other alerts route to `deep_triage` on `gemini-3.8-flash` with `thinking_level` set to `MEDIUM`. Both return a structured `TriageVerdict`.
- **Auditable Policy & Traceability**: The routing policy is one allowlist and one boolean expression, so it is code-reviewed, diffed, and unit-tested like any business rule. Every node transition and model span is visible in the ADK Dev UI Trace tab and Google Cloud Trace.
- **Routing vs. Consulting**: ADK Python 2.11 adds `ModelConsultTool`, which lets a fast executor ask a stronger advisor for guidance mid-turn. It suits multi-step tool loops where difficulty emerges during the task. Here the alert metadata already signals difficulty, so the router decides before any model runs and defaults to the stronger tier.

**Production Placement**

Keep the enforcement layer boundaries distinct in production architectures: Agent Gateway serves as the zero-trust egress and identity perimeter (mTLS, Agent Identity, default-deny `AuthzPolicies`, and Model Armor via `outbound_agent_gateway_config`) rather than a model-tier router. Organization-wide model routing policy, token quotas, and semantic caching live in Apigee AI/MCP Gateway, while ADK `Workflow` graphs own the routing decision whenever the branch logic depends on structured application state inside the agent.

**Resources:**

- [ADK Graph Routes Documentation](https://g.dev/cloud/adventofagents-season3-docs-adk-graph-routes)
- [Gemini Thinking Level Configuration](https://g.dev/cloud/adventofagents-season3-docs-gemini-thinking)
- [ADK Agent Routing Patterns](https://g.dev/cloud/adventofagents-season3-docs-adk-agent-routing)
- [ADK Model Consult Tool](https://g.dev/cloud/adventofagents-season3-docs-adk-model-consult)

## Code & Commands

### Deterministic Metadata Router for Tiered Gemini Models

```python
from typing import Any, Literal

from google.adk import Event, Workflow
from google.adk.agents import Agent
from pydantic import BaseModel

# Brute force, active scanning
ROUTINE_TECHNIQUES = {"T1110", "T1595"}


class SecurityAlert(BaseModel):
    alert_id: str
    severity: Literal["LOW", "MEDIUM", "HIGH", "CRITICAL"]
    correlated_signals: int
    mitre_techniques: list[str]
    summary: str
    telemetry: dict[str, Any]


class TriageVerdict(BaseModel):
    verdict: Literal["BENIGN", "INVESTIGATE", "CONTAIN"]
    rationale: str
    confidence: float


def triage_router(node_input: str) -> Event:
    alert = SecurityAlert.model_validate_json(node_input)
    techniques = set(alert.mitre_techniques)
    routine = (
        alert.severity == "LOW"
        and alert.correlated_signals == 1
        and len(techniques) > 0
        and techniques <= ROUTINE_TECHNIQUES
    )
    return Event(route="FAST" if routine else "DEEP", output=node_input)


fast_triage = Agent(
    name="fast_triage",
    model="gemini-3.5-flash-lite",
    mode="single_turn",
    output_schema=TriageVerdict,
    instruction="You are a Tier-1 SOC analyst. Pre-triage this alert for human review.",
    generate_content_config={"thinking_config": {"thinking_level": "MINIMAL"}},
)

deep_triage = Agent(
    name="deep_triage",
    model="gemini-3.8-flash",
    mode="single_turn",
    output_schema=TriageVerdict,
    instruction="You are a Principal Incident Responder; trace the full attack chain.",
    generate_content_config={"thinking_config": {"thinking_level": "MEDIUM"}},
)

root_agent = Workflow(
    name="soc_alert_triage_router",
    edges=[
        ("START", triage_router),
        (triage_router, {"FAST": fast_triage, "DEEP": deep_triage}),
    ],
)
```

### Run the Triage Workflow & Inspect the Trace

```bash
export CLOUDSDK_METRICS_ENVIRONMENT="advent-of-agents-s3-day29"

pip install "google-adk>=2.0.0"
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
export GOOGLE_CLOUD_LOCATION=global

# Package agent.py so the ADK CLI can load root_agent
mkdir -p soc_triage && mv agent.py soc_triage/ && echo "from . import agent" > soc_triage/__init__.py

# HIGH severity + lateral movement technique: routes DEEP to gemini-3.8-flash
adk run soc_triage '{"alert_id": "ALT-2026-002", "severity": "HIGH", "correlated_signals": 4, "mitre_techniques": ["T1021", "T1041"], "summary": "Service account lateral movement followed by large outbound transfer", "telemetry": {}}'

# Inspect the span waterfall in the Dev UI Trace tab
# (for Cloud Trace export: pip install "google-adk[gcp]>=2.0.0" and run adk web --otel_to_cloud)
adk web
```

## Resources & Links

- **[ADK Graph Routes](https://g.dev/cloud/adventofagents-season3-docs-adk-graph-routes)** — Official guide to building conditional branches, FunctionNode routers, and Event(route=...) edges in ADK 2.0.
- **[Gemini Thinking Configuration](https://g.dev/cloud/adventofagents-season3-docs-gemini-thinking)** — Configure ThinkingLevel (MINIMAL, LOW, MEDIUM, HIGH) on Gemini 3.x models in Vertex AI.
- **[ADK Agent Routing Patterns](https://g.dev/cloud/adventofagents-season3-docs-adk-agent-routing)** — Architectural comparison of deterministic graph routing versus LLM-driven sub-agent delegation.
- **[ADK Model Consult Tool](https://g.dev/cloud/adventofagents-season3-docs-adk-model-consult)** — Let a fast executor model escalate hard decisions to a stronger advisor model mid-turn, with per-turn and session consultation budgets.
