Author: Robina Mirbahar

AI/ML Google Developer Expert (GDE) | Google Cloud Champion Innovator

GitHub Blueprint: RobinaMirbahar/railpulse-gemma-cloudrun

YouTube Walkthrough: @RobinaCodesAI

RailPulse AI Banner

Robina Mirbahar presenting RailPulse AI, Gemma 4, and Cloud Run at DevFest Baku 2026, ADA University

Robina Mirbahar presenting RailPulse AI, Gemma 4, and Cloud Run at DevFest Baku 2026, ADA University.


Most artificial intelligence tutorials show you how to build chatbots that write poems, summarize PDFs, or generate boilerplate code.

Those demos are fun, but they do not reflect the harsh reality of engineering in mission-critical industries.

When you deploy AI to manage physical operations, like freight trains moving across thousands of kilometers, a generic chatbot is not just useless; it can be dangerous. A hallucinated speed limit or a delayed signal alert can lead to catastrophic hardware failure or derailment.

At DevFest Baku 2026 at ADA University, I wanted to show developers how to build an enterprise-grade AI system that solves a real operational problem. We built and deployed RailPulse AI, an autonomous, safety-critical railway dispatch and live-tracking agent powered by Google's open-weights Gemma models, the Google Agent Development Kit (ADK), and Google Cloud Run.

In this article, I will walk you through the complete architecture, how we used function calling with deterministic safety interlocks, and how you can run open-weights agents serverlessly in production.


The Real-World Engineering Problem

Railway corridors run on tight margins. Dispatchers must continuously monitor:

  • Real-Time Telemetry: GPS coordinates, axle bearing temperatures, and locomotive velocity.
  • Corridor Weather Extremes: Sudden crosswinds along coastal or mountain tracks.
  • Schedule Recovery: Balancing delays against passenger connection deadlines and single-track passing sidings.

When an emergency happens, dispatchers do not have time to sift through fragmented SCADA dashboards and thousand-line logs. They need an intelligent system that aggregates live telemetry, cross-references signaling rules, and synthesizes clear, actionable dispatch advisories.

Crucially, the system cannot hallucinate. It must combine the natural reasoning of an LLM with the deterministic predictability of hard-coded safety rules.


The RailPulse AI Architecture

Here is the high-level system design we implemented in RobinaMirbahar/railpulse-gemma-cloudrun:

┌─────────────────────────────────────────────────────────────┐
│                 Streamlit Operator Cockpit                  │
│       Interactive SVG Gauges • Multi-Language (EN/AZ/RU)    │
└──────────────────────────────┬──────────────────────────────┘
                               │ HTTPS / JSON
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                 Google Cloud Run Service                    │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │             Google ADK Agent Orchestrator           │   │
│   │                                                     │   │
│   │  ┌─────────────────┐       ┌─────────────────────┐  │   │
│   │  │   Gemma Model   │ ◄───► │  Tool Declarations  │  │   │
│   │  │  (Open-Weights) │       │   Function Calling  │  │   │
│   │  └─────────────────┘       └──────────┬──────────┘  │   │
│   └───────────────────────────────────────┼─────────────┘   │
│                                           ▼                 │
│   ┌─────────────────────────────────────────────────────┐   │
│   │       Deterministic Safety Interlocks (Python)      │   │
│   │   • Hard Wind Speed Limits (Wind > 65 km/h -> 80)   │   │
│   │   • Absolute Signal Overrides (Red Signal = STOP)   │   │
│   │   └───────────────────────────────────┬─────────────┘   │
│                                           ▼                 │
│   ┌─────────────────────────────────────────────────────┐   │
│   │         Pydantic Structured Advisory Schema         │   │
│   │           RailDispatchAdvisory Validation               │   │
│   └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

1. Grounding the Agent: Real-World Tools via Function Calling

Rather than letting Gemma guess railway conditions, we gave the agent access to dedicated telemetry tools using Google ADK function calling:

def get_live_train_telemetry(train_id: str) -> dict:
    """Fetch live GPS, speed, bearing temperatures, and locomotive health."""
    pass

def check_corridor_signals_and_wind(corridor_id: str) -> dict:
    """Query wayside signal states (Green/Yellow/Red) and track anemometers."""
    pass

def calculate_schedule_recovery(train_id: str, current_delay_min: int) -> dict:
    """Calculate speed profiles needed to recover schedule without exceeding corridor limits."""
    pass
Enter fullscreen mode Exit fullscreen mode

When an operator asks:

"Train 102 is approaching the Absheron corridor 14 minutes behind schedule. Can we accelerate to recover time?"

Gemma does not guess. It autonomously calls check_corridor_signals_and_wind(corridor="Absheron") and get_live_train_telemetry(train_id="102") to gather factual state before generating a response.


2. Deterministic Safety Interlocks: Why the LLM Does Not Make the Final Safety Call

In physical systems, you never give an LLM sole authority over life-safety decisions.

If the model experiences a temporary context confusion, it might suggest maintaining 140 km/h in a 90 km/h windstorm. To prevent this, we built a two-tier architecture:

  1. Tier 1 (Cognitive Reasoning): Gemma analyzes the situation, extracts the context, and proposes a schedule recovery plan.
  2. Tier 2 (Deterministic Guardrails): A hard-coded Python interlock inspects the output against physical invariants before delivering the advisory:
class SafetyInterlock:
    MAX_HIGH_WIND_SPEED_KMH = 80.0
    HIGH_WIND_THRESHOLD_KMH = 65.0

    @classmethod
    def enforce_guardrails(cls, advisory: RailDispatchAdvisory, wind_speed: float, signal_state: str) -> RailDispatchAdvisory:
        # Rule 1: High Wind Speed Clamp
        if wind_speed >= cls.HIGH_WIND_THRESHOLD_KMH:
            if advisory.recommended_speed_kmh > cls.MAX_HIGH_WIND_SPEED_KMH:
                advisory.recommended_speed_kmh = cls.MAX_HIGH_WIND_SPEED_KMH
                advisory.safety_flags.append(
                    f"GUARDRAIL ENFORCED: Wind speed {wind_speed} km/h exceeds threshold. Speed clamped to 80 km/h."
                )

        # Rule 2: Absolute Red Signal Override
        if signal_state == "RED":
            advisory.recommended_speed_kmh = 0.0
            advisory.action_required = "EMERGENCY_STOP"
            advisory.safety_flags.append("CRITICAL: Red signal detected. Immediate stop enforced.")

        return advisory
Enter fullscreen mode Exit fullscreen mode

This guarantees that even if an operator or a prompt edge case attempts to push the model beyond safe boundaries, the mathematical and physical guardrails cannot be bypassed.


3. Strict Output Contracts with Pydantic

To ensure the downstream operator dashboard never crashes due to unstructured freeform text, all agent advisories are validated against a strict schema:

from pydantic import BaseModel, Field
from typing import List, Optional

class RailDispatchAdvisory(BaseModel):
    train_id: str
    recommended_speed_kmh: float = Field(..., ge=0.0, le=160.0)
    delay_delta_minutes: int
    signal_status: str
    action_required: str
    advisory_summary: str
    safety_flags: List[str] = []
    confidence_score: float = Field(..., ge=0.0, le=1.0)
Enter fullscreen mode Exit fullscreen mode

If the agent’s response does not conform to this structure, the ADK pipeline rejects it before it ever reaches the dispatcher cockpit.


4. Packaging and Deploying on Google Cloud Run

To make RailPulse AI truly production-ready, we containerized the application with Docker and deployed it to Google Cloud Run.

Why Cloud Run for AI Agents?

  • Serverless Economics: Rail telematics spikes during train arrivals and yard movements, with quiet periods in between. Cloud Run scales dynamically from zero to handle spikes and scales back down when traffic subsides.
  • Air-Gapped and Sovereign Edge Ready: Because Gemma is an open-weights model, you can run inference entirely inside your own private VPC without sending sensitive operational telemetry to third-party proprietary APIs.
  • One-Command Deployment:
gcloud run deploy railpulse-agent \
    --source . \
    --platform managed \
    --region europe-west1 \
    --allow-unauthenticated \
    --memory 4Gi \
    --cpu 2
Enter fullscreen mode Exit fullscreen mode

5. Localized Operator Experience: Multi-Language Dispatch (EN / AZ / RU)

In international logistics corridors like the Trans-Caspian International Transport Route, operators speak multiple languages.

Because Gemma possesses strong multilingual representations, RailPulse AI seamlessly provides telemetry readouts, safety flags, and advisory summaries in English, Azerbaijani (Azərbaycan dili), and Russian (Русский), allowing local dispatchers to interact with the system in their native language while maintaining uniform safety semantics under the hood.


Key Lessons from Building RailPulse AI

Building this project and presenting it at DevFest Baku reinforced three fundamental principles for building agentic AI:

  1. Agents are More Than Prompts: A production agent is 20% prompt engineering and 80% systems engineering: tool definitions, schema validation, network resilience, and error handling.
  2. Deterministic Guardrails are Mandatory: In physical, industrial, or medical applications, never let an LLM have unchecked authority. Pair cognitive reasoning with deterministic code interlocks.
  3. Open-Weights Models are Production Ready: With models like Gemma and serverless platforms like Google Cloud Run, individual developers and enterprise teams can build custom, private, and fully auditable AI systems without paying thousands of dollars in proprietary API costs.

Explore the Code and Video Walkthrough

The complete codebase, Streamlit operator dashboard, Dockerfile, and Google ADK implementation are open-source and ready to clone:

Special thanks to the GDG Baku team, ADA University, and all the incredible participants at DevFest Baku 2026 for making this hands-on workshop such a rewarding experience!