ai newsMi., 21. Okt.
EilmeldungMeta to create a new class of shares to fund AI push

Gemini 4 Argon auf GKE: Multi-Tier-Routing gegen Latenz und Kosten

Wer jede Anfrage an ein teures Reasoning-Modell schickt, treibt Tokenkosten und p99-Latenz unnötig nach oben. Mit Multi-Tier-Routing auf GKE lassen sich die tiefe Mehrschritt-Rechenkraft von Gemini 4 Argon gezielt nur fuer anspruchsvolle Anfragen nutzen.

dev.toMittwoch 20:56 · 21.10.DE10 Min. Lesezeit
Bild: dev.to

Jeden eingehenden Nutzerprompt an ein Frontier-Reasoning-Modell weiterzuleiten, ist der schnellste Weg, das Token-Budget aufzubrauchen und die p99-Tail-Latenz zu verschlechtern. Mit der Veröffentlichung von Gemini 4 Argon auf der Gemini-Plattform haben Engineering-Teams Zugriff auf tiefe mehrstufige Reasoning-Fähigkeiten in gemini-4-argon sowie auf hochdurchsatzige und latenzarme Ausführung in gemini-3.8-flash und Open-Weights-Modellen, die direkt auf den Cluster-Beschleunigern laufen.

In den meisten Produktionsanwendungen folgt die Komplexität der Workloads einem steilen Potenzgesetz. Rund 70 Prozent der Anfragen umfassen Klassifizierung, Zusammenfassung, Schemaextraktion oder unkomplizierten Abruf, die eine schnelle Stufe in wenigen hundert Millisekunden bewältigt. Die übrigen 30 Prozent erfordern mehrstufige Synthese, komplexe Codegenerierung oder die Lösung mehrdeutiger Constraints, wo gemini-4-argon glänzt. Wird eine einzelne Modellkennung hart in die Anwendungscontainer kodiert, zahlt man entweder bei einfachen Abfragen drauf oder liefert bei komplexen zu wenig.

Durch den Aufbau einer zentralisierten AI-Routing-Schicht auf der Google Kubernetes Engine (GKE) mit der GKE Gateway API können Plattformteams die Prompt-Komplexität am Ingress-Rand klassifizieren, Anfragen über die Gemini-Stufen (gemini-4-argon und gemini-3.8-flash) und selbst gehostete GKE Inference Gateway Pools verteilen und bei Rate Limits einen automatischen Fallback erzwingen.

In diesem Artikel zerlege ich die Architektur eines mehrstufigen Gemini 4 Argon Routers auf GKE, konfiguriere die GKE-Standard- und Autopilot-Infrastruktur mit Workload Identity Federation for GKE und führe durch die Routing-, Health-Check- und Observability-Konfigurationen.

Wenn Anwendungsteams Dutzende einzelne Microservices direkt in LLM-Endpunkte integrieren, zeigen sich schnell drei operationale Probleme:

Die Zentralisierung des Modell-Routings hinter einem GKE Gateway und einem intelligenten Router-Service entkoppelt die Client-Microservices von der zugrunde liegenden Modellstufe.

In dieser Architektur senden interne Microservices Standardanfragen an ein regionales internes GKE Gateway (gke-l7-rilb). Das Gateway leitet den Traffic an einen ai-model-router Service weiter, der die Request-Metadaten auswertet oder eine schnelle Komplexitätsprüfung durchführt, bevor er die Anfrage an eine von drei Modellstufen ausliefert:

So schneiden die drei Stufen über die operativen Produktionsdimensionen hinweg ab:

Der Beispielrouter weiter unten in diesem Artikel implementiert das Standort-Failover der Stufen 1 und 2 sowie das Downgrade der Stufe 1. Die Pfade in und aus dem In-Cluster-Pool der Stufe 3 hängen von Ihrem Inference Gateway Setup ab und bleiben Ihrer eigenen Dispatch-Logik überlassen.

Um die Gemini-Plattform aufzurufen, ohne statische Service-Account-Schlüssel zu verteilen, bindet man das Kubernetes ServiceAccount des ai-model-router direkt über Workload Identity Federation for GKE an eine IAM-Rolle. Dies funktioniert identisch auf GKE Standard- und GKE Autopilot-Clustern ab GKE 1.32 mit aktiviertem GKE Gateway Controller ( --gateway-api=standard ) und einem aktiven regionalen Proxy-only-Subnetz ( --purpose=REGIONAL_MANAGED_PROXY ) in Ihrer VPC.

Hinweis zu Modellkennungen und Standorten: Die folgenden Beispiele verwenden gemini-4-argon (Gemini 4 Argon) und gemini-3.8-flash (Gemini 3.8 Flash), konfiguriert über Umgebungsvariablen ( PRO_MODEL und FLASH_MODEL ). Beide Modelle werden über den globalen Endpunkt und die Multi-Region-Endpunkte us und eu bereitgestellt, nicht über einzelne Regionen wie us-central1, sodass der Router vom globalen Endpunkt auf us umschaltet.

export PROJECT_ID = "production-ai-platform" export PROJECT_NUMBER = $( gcloud projects describe " ${ PROJECT_ID } " --format = "value(projectNumber)" ) export LOCATION = "us-central1" export CLUSTER_NAME = "ai-gateway-cluster" # kubectl auf den Cluster richten gcloud container clusters get-credentials " ${ CLUSTER_NAME } " --location = " ${ LOCATION } " --project = " ${ PROJECT_ID } " # Namespace und Kubernetes ServiceAccount anlegen kubectl create namespace ai-routing kubectl create serviceaccount gemini-router-sa --namespace = ai-routing # Dem Kubernetes ServiceAccount die Berechtigung zum Aufruf von Gemini-Plattformmodellen erteilen # (der zugrunde liegende IAM-Rollen-String bleibt roles/aiplatform.user) gcloud projects add-iam-policy-binding " ${ PROJECT_ID } " \ --member = "principal://iam.googleapis.com/projects/ ${ PROJECT_NUMBER } /locations/global/workloadIdentityPools/ ${ PROJECT_ID }.svc.id.goog/subject/ns/ai-routing/sa/gemini-router-sa" \ --role = "roles/aiplatform.user" \ --condition = None Enter fullscreen mode Exit fullscreen mode Kapazitätsbereitstellung auf GKE Autopilot im Vergleich zu Standard Für die Router-Deployment selbst genügt eine übliche CPU-Computing-Ressource. Betreiben Sie zusätzlich die Stufe 3 (In-Cluster-Open-Weights-Inferenz über das GKE Inference Gateway für hochvolumiges Offloading), konfigurieren Sie die Beschleunigerkapazität entsprechend Ihrem Cluster-Modus:

Der ai-model-router Service prüft eingehende Anfragen, schätzt die Aufgabenkomplexität (über explizite Client-Header, Token-Anzahl-Schwellenwerte oder Keyword-Trigger) und gibt den Aufruf über das google-genai SDK mit standortübergreifendem Failover und stufenübergreifendem Fallback weiter. Zudem stellt er einen /healthz Endpunkt bereit, den sowohl die Pod readinessProbe als auch der Health Check des GKE Gateway Load Balancers zur Verifikation der Backend-Bereitschaft nutzen.

Speichern Sie die folgende Implementierung als router_app.py:

import os import time from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel from google import genai from google.genai import types from google.genai.errors import APIError app = FastAPI ( title = " GKE Gemini 4 Argon Multi-Tier Router " ) PROJECT_ID = os. environ [ " GOOGLE_CLOUD_PROJECT " ] PRIMARY_LOCATION = os. environ. get ( " PRIMARY_LOCATION ", " global " ) SECONDARY_LOCATION = os. environ. get ( " SECONDARY_LOCATION ", " us " ) PRO_MODEL = os. environ. get ( " PRO_MODEL ", " gemini-4-argon " ) FLASH_MODEL = os. environ. get ( " FLASH_MODEL ", " gemini-3.8-flash " ) # Projektscope Gemini-Plattform-Clients, authentifiziert über Workload Identity Federation for GKE. # Der Schalter vertexai=True ist die SDK-Option für IAM-Authentifizierung im Projektscope statt eines API-Keys. primary_client = genai. Client ( vertexai = True, project = PROJECT_ID, location = PRIMARY_LOCATION ) secondary_client = genai. Client ( vertexai = True, project = PROJECT_ID, location = SECONDARY_LOCATION ) REASONING_KEYWORDS = { " architect ", " debug ", " prove ", " multi-step ", " optimize ", " trade-off ", " root cause " } class PromptRequest ( BaseModel ): prompt: str system_instruction: str | None = None require_deep_reasoning: bool = False def select_model_tier ( req: PromptRequest, routing_hint: str | None ) -> str: """ Wählt die Gemini 4 Argon (Frontier)- oder Gemini 3.8 Flash-Stufe anhand von Client-Hinweisen und Prompt-Eigenschaften.

""" wenn routing_hint == " pro " oder req. require_deep_reasoning: return PRO_MODEL wenn routing_hint == " flash ": return FLASH_MODEL prompt_lower = req. prompt. lower () word_count = len ( req. prompt. split ()) has_reasoning_trigger = any ( kw in prompt_lower für kw in REASONING_KEYWORDS ) wenn word_count > 600 oder has_reasoning_trigger: return PRO_MODEL return FLASH_MODEL def build_config ( model: str, system_instruction: str | None ) -> types. GenerateContentConfig: """ Gemini 4 Argon ignoriert Sampling-Parameter und nutzt standardmässig das Thinking-Level MEDIUM, daher wird die Temperatur nur auf der Flash-Stufe gesetzt. """ wenn model == PRO_MODEL: return types.

GenerateContentConfig ( system_instruction = system_instruction ) return types. GenerateContentConfig ( system_instruction = system_instruction, temperature = 0.2 ) @app.get ( " /healthz " ) def health_check (): return { " status ": " ok " } @app.post ( " /v1/generate " ) def generate_response ( req: PromptRequest, x_model_tier: str | None = Header ( default = None ), ): target_model = select_model_tier ( req, x_model_tier ) start_time = time. monotonic () # Versucht zuerst den globalen Endpunkt, dann den us-Multiregion-Endpunkt, und stuft anschließend auf Flash herunter, # es sei denn, der Aufrufer hat ausdrücklich Deep Reasoning verlangt attempt_chain = [ ( primary_client, PRIMARY_LOCATION, target_model ), ( secondary_client, SECONDARY_LOCATION, target_model ), ] explicit_pro = x_model_tier == " pro " or req. require_deep_reasoning if target_model == PRO_MODEL and not explicit_pro: attempt_chain. append (( primary_client, PRIMARY_LOCATION, FLASH_MODEL )) for attempt_client, location, candidate_model in attempt_chain: try: response = attempt_client. models. generate_content ( model = candidate_model, contents = req. prompt, config = build_config ( candidate_model, req. system_instruction ), ) latency_ms = round (( time. monotonic () - start_time ) * 1000, 2 ) usage = response. usage_metadata return { " model_used ": candidate_model, " location ": location, " fallback_triggered ": ( location!= PRIMARY_LOCATION or candidate_model!= target_model ), " latency_ms ": latency_ms, " usage ": { " prompt_tokens ": ( usage. prompt_token_count or 0 ) if usage else 0, " output_tokens ": ( usage. candidates_token_count or 0 ) if usage else 0, " thoughts_tokens ": ( usage. thoughts_token_count or 0 ) if usage else 0, }, " output ": response. text, } except APIError as exc: if exc. code in ( 429, 500, 503, 504 ): continue raise HTTPException ( status_code = exc. code or 500, detail = str ( exc )) raise HTTPException ( status_code = 503, detail = " All Gemini endpoints exhausted " ) Enter fullscreen mode Exit fullscreen mode Bereitstellen des Routers über GKE Gateway API und GCPBackendPolicy Da die Reasoning-Ketten von gemini-4-argon bei großen Kontexten 30 bis 90 Sekunden zur Bearbeitung benötigen können, führen die üblichen 30-Sekunden-Timeouts von HTTP-Loadbalancern zu vorzeitig abgebrochenen Verbindungen und dazu, dass Clients teure Anfragen erneut stellen.

Konfiguriere ein GKE Gateway, eine HTTPRoute und eine GCPBackendPolicy ( networking.gke.io/v1 ), um das Backend-Timeout auf 180 Sekunden zu verlängern und das Connection Draining während Rolling Updates zu aktivieren. Im Gegensatz zum GKE Ingress leitet GKE Gateway die Health Checks des Loadbalancers nicht aus der readinessProbe des Pods ab; standardmäßig wird der Pfad / abgefragt, den der Router mit einem 404 beantwortet. Füge eine HealthCheckPolicy ( networking.gke.io/v1 ) hinzu, die den Loadbalancer auf /healthz verweist:

apiVersion: apps/v1 kind: Deployment metadata: name: ai-model-router namespace: ai-routing spec: replicas: 3 selector: matchLabels: app: ai-model-router template: metadata: labels: app: ai-model-router spec: serviceAccountName: gemini-router-sa containers: - name: router image: us-central1-docker.pkg.dev/production-ai-platform/ai-routing/gemini-4-router:v1.0.0 ports: - containerPort: 8080 env: - name: GOOGLE_CLOUD_PROJECT value: " production-ai-platform" - name: PRIMARY_LOCATION value: " global" - name: SECONDARY_LOCATION value: " us" - name: PRO_MODEL value: " gemini-4-argon" - name: FLASH_MODEL value: " gemini-3.8-flash" readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 resources: requests: cpu: " 500m" memory: " 512Mi" --- apiVersion: v1 kind: Service metadata: name: ai-model-router-svc namespace: ai-routing spec: selector: app: ai-model-router ports: - port: 80 targetPort: 8080 --- apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: gemini-router-backend-policy namespace: ai-routing spec: default: timeoutSec: 180 connectionDraining: drainingTimeoutSec: 60 targetRef: group: " " kind: Service name: ai-model-router-svc --- apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: gemini-router-healthcheck namespace: ai-routing spec: default: checkIntervalSec: 10 timeoutSec: 5 healthyThreshold: 1 unhealthyThreshold: 3 config: type: HTTP httpHealthCheck: port: 8080 requestPath: /healthz targetRef: group: " " kind: Service name: ai-model-router-svc --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: internal-ai-gateway namespace: ai-routing spec: gatewayClassName: gke-l7-rilb listeners: - name: http protocol: HTTP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: gemini-routing-route namespace: ai-routing spec: parentRefs: - name: internal-ai-gateway rules: - matches: - path: type: PathPrefix value: /v1/generate backendRefs: - name: ai-model-router-svc port: 80 Enter fullscreen mode Exit fullscreen mode Wenn zusätzlich ein In-Cluster-vLLM-Pool betrieben wird, der vom GKE Inference Gateway verwaltet wird ( InferencePool in inference.networking.k8s.io/v1 und InferenceObjective in inference.networking.x-k8s.io zur Priorisierung von Workloads), kann auf demselben internal-ai-gateway eine zusätzliche HTTPRoute-Regel angehängt werden (oder intern aus router_app.py heraus dispatcht werden), um datenintensiven Batch-Traffic direkt an group: inference.networking.k8s.io, kind: InferencePool weiterzuleiten.

Wende nach dem Anwenden der Manifeste die Prüfung an, ob der GKE-Gateway-Controller den internen Loadbalancer programmiert und beide Backend-Policies angehängt hat:

# Confirm Gateway programmed status and internal IP address kubectl get gateway internal-ai-gateway -n ai-routing # Verify that both policies are attached to the Service (look for Reason: Attached) kubectl describe gcpbackendpolicy gemini-router-backend-policy -n ai-routing kubectl describe healthcheckpolicy gemini-router-healthcheck -n ai-routing Enter fullscreen mode Exit fullscreen mode Da gke-l7-rilb nur eine interne IP-Adresse bereitstellt, ermittle die Adresse mit kubectl und sende die Testanfragen anschließend von einem Client im selben VPC und in derselben Region aus (zum Beispiel von einem Debug-Pod im Cluster):

export GATEWAY_IP = $( kubectl get gateway internal-ai-gateway -n ai-routing -o jsonpath = '{.status.addresses.value}' ) # 1. Schnelle Klassifizierungsabfrage (wird automatisch an gemini-3.8-flash geroutet) curl -s -X POST "http:// ${ GATEWAY_IP } /v1/generate" \ -H "Content-Type: application/json" \ -d '{"prompt": "Extract the HTTP status code from this log line: GET /checkout 502 Bad Gateway"}' | jq. # 2. Komplexe Architekturabfrage (wird automatisch an gemini-4-argon geroutet) curl -s -X POST "http:// ${ GATEWAY_IP } /v1/generate" \ -H "Content-Type: application/json" \ -d '{"prompt": "Analyze the root cause and trade-offs of etcd leader election timeouts during cross-zone network partitions."}' | jq.

Enter fullscreen mode Exit fullscreen mode Erwartete Antwort, die den gewählten Tier, den Standort, den Fallback-Status und die Token-Bilanzierung zeigt (einschließlich der reasoning thoughts_tokens ):

{ "model_used": "gemini-4-argon", "location": "global", "fallback_triggered": false, "latency_ms": 2840.15, "usage": { "prompt_tokens": 24, "output_tokens": 412, "thoughts_tokens": 186 }, "output": "..." } Enter fullscreen mode Exit fullscreen mode Betriebliche Einschränkungen und Situationen, in denen ein Router nicht sinnvoll ist Bevor ein Modell-Router vor Gemini 4 Argon eingeführt wird, sollten diese betrieblichen Abwägungen berücksichtigt werden:

Wer die Microservices von fest einprogrammierten Modell-Strings entkoppelt, kann Gemini 4 Argon dort einsetzen, wo seine Reasoning-Fähigkeiten am meisten zählen, während Routineabfragen schnell und kosteneffizient auf gemini-3.8-flash oder auf In-Cluster-Beschleunigern laufen bleiben.

Um diese Architektur weiter auszubauen, empfiehlt sich ein Blick in die GKE Gateway API Dokumentation, die Lektüre des GKE Inference Gateway Leitfadens für das Routing zu selbst gehosteten Open-Source-Modellen sowie die Gemini-Plattform-Dokumentation zu Modell-Standorten und Kontingenten für Multi-Region-Verfügbarkeit und Durchsatzkonfiguration.

Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.

Original (Englisch) anzeigen

Routing every incoming user prompt to a frontier reasoning model is the fastest way to blow through your token budget and degrade p99 tail latency. With the release of Gemini 4 Argon on the Gemini platform, engineering teams have access to deep multi-step reasoning in gemini-4-argon alongside high-throughput, low-latency execution in gemini-3.8-flash and open-weights models running directly on cluster accelerators.

In most production applications, workload complexity follows a steep power law. Roughly 70% of requests involve classification, summarization, schema extraction, or straightforward retrieval that a fast tier handles in a few hundred milliseconds. The remaining 30% require multi-hop synthesis, complex code generation, or ambiguous constraint solving where gemini-4-argon shines. Hardcoding a single model identifier in your application containers forces you to either overpay on simple queries or under-deliver on complex ones.

By building a centralized AI routing layer on Google Kubernetes Engine (GKE) using the GKE Gateway API, platform teams can classify prompt complexity at the ingress edge, route requests across Gemini tiers ( gemini-4-argon and gemini-3.8-flash ) and self-hosted GKE Inference Gateway pools, and enforce automatic fallback when rate limits occur.

In this article, I will break down the architecture of a multi-tier Gemini 4 Argon router on GKE, configure GKE Standard and Autopilot infrastructure with Workload Identity Federation for GKE, and walk through the routing, health-check, and observability configurations.

When application teams integrate directly with LLM endpoints inside dozens of individual microservices, three operational problems surface quickly:

Centralizing model routing behind a GKE Gateway and an intelligent router service decouples client microservices from the underlying model tier.

In this architecture, internal microservices send standard requests to a regional internal GKE Gateway ( gke-l7-rilb ). The Gateway forwards traffic to an ai-model-router service that evaluates request metadata or runs a fast complexity check before dispatching the request to one of three model tiers:

Here is how the three tiers compare across production operating dimensions:

The sample router later in this article implements the Tier 1 and Tier 2 location failover and the Tier 1 downgrade. The paths into and out of the in-cluster Tier 3 pool depend on your Inference Gateway setup and are left to your own dispatch logic.

To call the Gemini platform without distributing static service account keys, bind the ai-model-router Kubernetes ServiceAccount directly to an IAM role using Workload Identity Federation for GKE. This works identically across GKE Standard and GKE Autopilot clusters running GKE 1.32 or later with the GKE Gateway controller enabled ( --gateway-api=standard ) and an active regional proxy-only subnet ( --purpose=REGIONAL_MANAGED_PROXY ) in your VPC.

Note on model identifiers and locations: The examples below use gemini-4-argon (Gemini 4 Argon) and gemini-3.8-flash (Gemini 3.8 Flash) configured via environment variables ( PRO_MODEL and FLASH_MODEL ). Both models are served from the global endpoint and the us and eu multi-region endpoints, not from individual regions such as us-central1, so the router fails over from global to us.

export PROJECT_ID = "production-ai-platform" export PROJECT_NUMBER = $( gcloud projects describe " ${ PROJECT_ID } " --format = "value(projectNumber)" ) export LOCATION = "us-central1" export CLUSTER_NAME = "ai-gateway-cluster" # Point kubectl at the cluster gcloud container clusters get-credentials " ${ CLUSTER_NAME } " --location = " ${ LOCATION } " --project = " ${ PROJECT_ID } " # Create the namespace and Kubernetes ServiceAccount kubectl create namespace ai-routing kubectl create serviceaccount gemini-router-sa --namespace = ai-routing # Grant the Kubernetes ServiceAccount permission to invoke Gemini platform models # (the underlying IAM role string is still roles/aiplatform.user) gcloud projects add-iam-policy-binding " ${ PROJECT_ID } " \ --member = "principal://iam.googleapis.com/projects/ ${ PROJECT_NUMBER } /locations/global/workloadIdentityPools/ ${ PROJECT_ID }.svc.id.goog/subject/ns/ai-routing/sa/gemini-router-sa" \ --role = "roles/aiplatform.user" \ --condition = None Enter fullscreen mode Exit fullscreen mode Provisioning capacity on GKE Autopilot vs. Standard For the router Deployment itself, standard CPU compute is sufficient. If you also operate Tier 3 (in-cluster open-weights inference via GKE Inference Gateway for high-volume offload), configure your accelerator capacity according to your cluster mode:

The ai-model-router service inspects incoming requests, estimates task complexity (using explicit client headers, token count thresholds, or keyword triggers), and dispatches the call through the google-genai SDK with cross-location failover and cross-tier fallback. It also exposes a /healthz endpoint that both the Pod readinessProbe and the GKE Gateway load balancer health check use to verify backend readiness.

Save the following implementation as router_app.py:

import os import time from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel from google import genai from google.genai import types from google.genai.errors import APIError app = FastAPI ( title = " GKE Gemini 4 Argon Multi-Tier Router " ) PROJECT_ID = os. environ [ " GOOGLE_CLOUD_PROJECT " ] PRIMARY_LOCATION = os. environ. get ( " PRIMARY_LOCATION ", " global " ) SECONDARY_LOCATION = os. environ. get ( " SECONDARY_LOCATION ", " us " ) PRO_MODEL = os. environ. get ( " PRO_MODEL ", " gemini-4-argon " ) FLASH_MODEL = os. environ. get ( " FLASH_MODEL ", " gemini-3.8-flash " ) # Project-scoped Gemini platform clients authenticated through Workload Identity Federation for GKE. # The vertexai=True flag is the SDK switch for project-scoped IAM auth instead of an API key. primary_client = genai. Client ( vertexai = True, project = PROJECT_ID, location = PRIMARY_LOCATION ) secondary_client = genai. Client ( vertexai = True, project = PROJECT_ID, location = SECONDARY_LOCATION ) REASONING_KEYWORDS = { " architect ", " debug ", " prove ", " multi-step ", " optimize ", " trade-off ", " root cause " } class PromptRequest ( BaseModel ): prompt: str system_instruction: str | None = None require_deep_reasoning: bool = False def select_model_tier ( req: PromptRequest, routing_hint: str | None ) -> str: """ Selects the Gemini 4 Argon (frontier) or Gemini 3.8 Flash tier based on client hints and prompt characteristics.

""" if routing_hint == " pro " or req. require_deep_reasoning: return PRO_MODEL if routing_hint == " flash ": return FLASH_MODEL prompt_lower = req. prompt. lower () word_count = len ( req. prompt. split ()) has_reasoning_trigger = any ( kw in prompt_lower for kw in REASONING_KEYWORDS ) if word_count > 600 or has_reasoning_trigger: return PRO_MODEL return FLASH_MODEL def build_config ( model: str, system_instruction: str | None ) -> types. GenerateContentConfig: """ Gemini 4 Argon ignores sampling parameters and defaults to the MEDIUM thinking level, so temperature is only set on the Flash tier. """ if model == PRO_MODEL: return types.

GenerateContentConfig ( system_instruction = system_instruction ) return types. GenerateContentConfig ( system_instruction = system_instruction, temperature = 0.2 ) @app.get ( " /healthz " ) def health_check (): return { " status ": " ok " } @app.post ( " /v1/generate " ) def generate_response ( req: PromptRequest, x_model_tier: str | None = Header ( default = None ), ): target_model = select_model_tier ( req, x_model_tier ) start_time = time. monotonic () # Attempt the global endpoint, then the us multi-region endpoint, then downgrade to Flash # unless the caller explicitly required deep reasoning attempt_chain = [ ( primary_client, PRIMARY_LOCATION, target_model ), ( secondary_client, SECONDARY_LOCATION, target_model ), ] explicit_pro = x_model_tier == " pro " or req. require_deep_reasoning if target_model == PRO_MODEL and not explicit_pro: attempt_chain. append (( primary_client, PRIMARY_LOCATION, FLASH_MODEL )) for attempt_client, location, candidate_model in attempt_chain: try: response = attempt_client. models. generate_content ( model = candidate_model, contents = req. prompt, config = build_config ( candidate_model, req. system_instruction ), ) latency_ms = round (( time. monotonic () - start_time ) * 1000, 2 ) usage = response. usage_metadata return { " model_used ": candidate_model, " location ": location, " fallback_triggered ": ( location!= PRIMARY_LOCATION or candidate_model!= target_model ), " latency_ms ": latency_ms, " usage ": { " prompt_tokens ": ( usage. prompt_token_count or 0 ) if usage else 0, " output_tokens ": ( usage. candidates_token_count or 0 ) if usage else 0, " thoughts_tokens ": ( usage. thoughts_token_count or 0 ) if usage else 0, }, " output ": response. text, } except APIError as exc: if exc. code in ( 429, 500, 503, 504 ): continue raise HTTPException ( status_code = exc. code or 500, detail = str ( exc )) raise HTTPException ( status_code = 503, detail = " All Gemini endpoints exhausted " ) Enter fullscreen mode Exit fullscreen mode Exposing the router via GKE Gateway API and GCPBackendPolicy Because gemini-4-argon reasoning chains on large contexts can take 30 to 90 seconds to complete, standard 30-second HTTP load balancer timeouts will prematurely drop connections and cause clients to retry expensive requests.

Configure a GKE Gateway, HTTPRoute, and GCPBackendPolicy ( networking.gke.io/v1 ) to extend the backend timeout to 180 seconds and enable connection draining during rolling updates. Unlike GKE Ingress, GKE Gateway does not infer load balancer health checks from the Pod readinessProbe; it probes / by default, which the router answers with a 404. Add a HealthCheckPolicy ( networking.gke.io/v1 ) that points the load balancer at /healthz:

apiVersion: apps/v1 kind: Deployment metadata: name: ai-model-router namespace: ai-routing spec: replicas: 3 selector: matchLabels: app: ai-model-router template: metadata: labels: app: ai-model-router spec: serviceAccountName: gemini-router-sa containers: - name: router image: us-central1-docker.pkg.dev/production-ai-platform/ai-routing/gemini-4-router:v1.0.0 ports: - containerPort: 8080 env: - name: GOOGLE_CLOUD_PROJECT value: " production-ai-platform" - name: PRIMARY_LOCATION value: " global" - name: SECONDARY_LOCATION value: " us" - name: PRO_MODEL value: " gemini-4-argon" - name: FLASH_MODEL value: " gemini-3.8-flash" readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 resources: requests: cpu: " 500m" memory: " 512Mi" --- apiVersion: v1 kind: Service metadata: name: ai-model-router-svc namespace: ai-routing spec: selector: app: ai-model-router ports: - port: 80 targetPort: 8080 --- apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: gemini-router-backend-policy namespace: ai-routing spec: default: timeoutSec: 180 connectionDraining: drainingTimeoutSec: 60 targetRef: group: " " kind: Service name: ai-model-router-svc --- apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: gemini-router-healthcheck namespace: ai-routing spec: default: checkIntervalSec: 10 timeoutSec: 5 healthyThreshold: 1 unhealthyThreshold: 3 config: type: HTTP httpHealthCheck: port: 8080 requestPath: /healthz targetRef: group: " " kind: Service name: ai-model-router-svc --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: internal-ai-gateway namespace: ai-routing spec: gatewayClassName: gke-l7-rilb listeners: - name: http protocol: HTTP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: gemini-routing-route namespace: ai-routing spec: parentRefs: - name: internal-ai-gateway rules: - matches: - path: type: PathPrefix value: /v1/generate backendRefs: - name: ai-model-router-svc port: 80 Enter fullscreen mode Exit fullscreen mode If you also run an in-cluster vLLM pool managed by GKE Inference Gateway ( InferencePool in inference.networking.k8s.io/v1 and InferenceObjective in inference.networking.x-k8s.io for workload prioritization), you can attach an additional HTTPRoute rule on the same internal-ai-gateway (or dispatch internally from router_app.py ) to route high-volume batch traffic directly to group: inference.networking.k8s.io, kind: InferencePool.

After applying the manifests, verify that the GKE Gateway controller has programmed the internal load balancer and attached both backend policies:

# Confirm Gateway programmed status and internal IP address kubectl get gateway internal-ai-gateway -n ai-routing # Verify that both policies are attached to the Service (look for Reason: Attached) kubectl describe gcpbackendpolicy gemini-router-backend-policy -n ai-routing kubectl describe healthcheckpolicy gemini-router-healthcheck -n ai-routing Enter fullscreen mode Exit fullscreen mode Because gke-l7-rilb exposes only an internal IP address, look up the address with kubectl, then send the test requests from a client in the same VPC and region (for example, a debug Pod in the cluster):

export GATEWAY_IP = $( kubectl get gateway internal-ai-gateway -n ai-routing -o jsonpath = '{.status.addresses.value}' ) # 1. Fast classification query (routes automatically to gemini-3.8-flash) curl -s -X POST "http:// ${ GATEWAY_IP } /v1/generate" \ -H "Content-Type: application/json" \ -d '{"prompt": "Extract the HTTP status code from this log line: GET /checkout 502 Bad Gateway"}' | jq. # 2. Complex architectural query (routes automatically to gemini-4-argon) curl -s -X POST "http:// ${ GATEWAY_IP } /v1/generate" \ -H "Content-Type: application/json" \ -d '{"prompt": "Analyze the root cause and trade-offs of etcd leader election timeouts during cross-zone network partitions."}' | jq.

Enter fullscreen mode Exit fullscreen mode Expected response showing the selected tier, location, fallback status, and token accounting (including reasoning thoughts_tokens ):

{ "model_used": "gemini-4-argon", "location": "global", "fallback_triggered": false, "latency_ms": 2840.15, "usage": { "prompt_tokens": 24, "output_tokens": 412, "thoughts_tokens": 186 }, "output": "..." } Enter fullscreen mode Exit fullscreen mode Operational caveats and when not to use a router Before introducing a model router in front of Gemini 4 Argon, weigh these operational trade-offs:

Decoupling your microservices from hardcoded model strings lets you adopt Gemini 4 Argon where its reasoning capabilities matter most while keeping routine queries fast and cost-effective on gemini-3.8-flash or in-cluster accelerators.

To expand this architecture, review the GKE Gateway API documentation, explore the GKE Inference Gateway guide for routing to self-hosted open models, and check the Gemini platform model locations and quota documentation for multi-region availability and throughput configuration.

Originaltitel: Multi-tier model routing on GKE: balancing Gemini 4 Argon reasoning depth with latency and costQuelle: dev.to (dev.to). Original öffnen