DEV Community

xbill for Google Developer Experts

Posted on • Originally published at xbill999.Medium on

Debugging Deployments with Gemma 12B, NVIDIA L4, MCP, Cloud Run, and Antigravity CLI

This article provides a step by step debugging guide for deploying Gemma 4 to a Google Cloud Run hosted GPU enabled system,. A suite of Python MCP tools is built to simplify management of the vLLM hosted Gemma 4 deployment with Antigravity CLI.

What is this project trying to Do?

This project is a DevOps/SRE assistant that uses a Gemma 4 model hosted on Cloud Run with GPU. It provides tools to provision the Docker container and deploy the model, as well as for observability and performance testing.

This project is similar to a previous project that targeted GPU hosted Gemma4 instances on GCP:

Gemma-SRE: Self-Hosted vLLM Infrastructure Agent

Antigravity CLI

Antigravity CLI is the follow-on successor to Gemini CLI- the terminal driven, agent assisted coding tool.

Full details on installing Antigravity CLI are here:

Getting Started with Antigravity CLI

Testing the Antigravity CLI Environment

Once you have all the tools in place- you can test the startup of Antigravity CLI.

You will need to authenticate with a Google Cloud Project or your Google Account:

agy
Enter fullscreen mode Exit fullscreen mode

This will start the interface:

Full Installation Instructions

The detailed installation instructions for Antigravity CLI are here:

Getting Started with Antigravity CLI

Python MCP Documentation

The official GitHub Repo provides samples and documentation for getting started:

GitHub - modelcontextprotocol/python-sdk: The official Python SDK for Model Context Protocol servers and clients

Where do I start?

The strategy for starting MCP development for model management is a incremental step by step approach.

First, the basic development environment is setup with the required system variables, and a working Antigravity CLI configuration.

Then, a minimal Python MCP Server is built with stdio transport. This server is validated with Antigravity CLI in the local environment.

This setup validates the connection from Antigravity CLI to the local server via MCP. The MCP client (Antigravity CLI) and the Python MCP server both run in the same local environment.

Setup the Basic Environment

At this point you should have a working Python environment and a working Antigravity CLI installation. The next step is to clone the GitHub samples repository with support scripts:

cd ~
git clone https://github.com/xbill9/gemma4-tips
Enter fullscreen mode Exit fullscreen mode

Then run init.sh from the cloned directory.

The script will attempt to determine your shell environment and set the correct variables:

gpu-12B-L4-devops-agent
source init.sh
Enter fullscreen mode Exit fullscreen mode

If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:

gpu-12B-L4-devops-agent
source set_env.sh
Enter fullscreen mode Exit fullscreen mode

Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.

Model Management Tool with MCP Stdio Transport

One of the key features that the standard MCP libraries provide is abstracting various transport methods.

The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

The connection over stdio will look similar to this:

# Initialize FastMCP server
mcp = FastMCP("Self-Hosted vLLM DevOps Agent")
Enter fullscreen mode Exit fullscreen mode

Running the Python Code

First- switch the directory with the Python version of the MCP sample code:

~/gemma4-tips/gpu-12B-L4-devops-agent
Enter fullscreen mode Exit fullscreen mode

Run the release version on the local system:

make install
Processing ./.
Enter fullscreen mode Exit fullscreen mode

The project can also be linted:

xbill@penguin:~/gemma4-tips/gpu-12B-L4-devops-agent$ make lint
ruff check .
All checks passed!
ruff format --check .
6 files already formatted
mypy .
Success: no issues found in 6 source files
Enter fullscreen mode Exit fullscreen mode

And a test run:

xbill@penguin:~/gemma4-tips/gpu-12B-L4-devops-agent$ make test
python test_agent.py
2026-05-29 19:07:48,275 - vllm-devops-agent - INFO - Initializing DevOps Agent MCP Server...
.........2026-05-29 19:07:48,318 - vllm-devops-agent - INFO - Querying Cloud Run model with prompt: 'Hello...'
2026-05-29 19:07:48,318 - vllm-devops-agent - INFO - Model response: 'Response from Gemma...'
.2026-05-29 19:07:48,319 - vllm-devops-agent - INFO - Querying model with stats with prompt: 'Hello...'
2026-05-29 19:07:48,320 - vllm-devops-agent - INFO - Model response with stats: TTFT=0.000s, TotalTime=0.000s
.......
----------------------------------------------------------------------
Ran 17 tests in 0.024s
Enter fullscreen mode Exit fullscreen mode

MCP stdio Transport

One of the key features that the MCP protocol provides is abstracting various transport methods.

The high level tool MCP implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

In this project Antigravity CLI is used as the MCP client to interact with the Python MCP server code.

Antigravity CLI mcp_config.json

A sample MCP server file is provided in the .agents directory:

{
  "mcpServers": {
    "gpu-devops-agent": {
      "command": "python3",
      "args": [
        "/home/xbill/gemma4-tips/gpu-12b-L4-devops-agent/server.py"
      ],
      "env": {
        "GOOGLE_CLOUD_PROJECT": "aisprint-491218",
        "GOOGLE_CLOUD_LOCATION": "us-east4",
        "VLLM_BASE_URL": "https://gpu-12b-l4-devops-agent-289270257791.us-east4.run.app",
        "MODEL_NAME": "/mnt/models/gemma-4-12B-it"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Validation with Antigravity CLI

The final connection test uses Antigravity CLI as a MCP client with the Python code providing the MCP server:

MCP Servers
Plugins (~/.gemini/antigravity-cli/plugins)
> ✓ google-dev-knowledge Tools: search_documents, answer_query, get_documents
   ✓ gpu-devops-agent Tools: save_hf_token, get_vllm_endpoint, list_vertex_models, list_bucket_models,
                       analyze_cloud_logging, +21 more
Enter fullscreen mode Exit fullscreen mode

Model Lifecycle Management via MCP

The MCP tools provide a complete suite of agent-oriented operations for managing vLLM deployment on Cloud Run or a TPU.

Overview of MCP tools :

> get_help

  Here is the help documentation and active environment configuration for the GPU vLLM DevOps Agent:

  ### ⚙️ Active Environment Configuration

  • Project ID ( GOOGLE_CLOUD_PROJECT ): aisprint-491218 
  • Region ( GOOGLE_CLOUD_LOCATION ): us-east4 
  • Model Name ( MODEL_NAME ): /mnt/models/gemma-4-26B-A4B-it 
  • GCS Bucket ( BUCKET_NAME ): aisprint-491218-bucket 
  • vLLM Endpoint ( VLLM_BASE_URL ): [https://gpu-26b-l4-devops-agent-289270257791.us-east4.run.app](https://gpu-26b-l4-devops-agent-289270257791.us-east4.run.app) 
  • Active Mode: Running in CLOUD RUN mode targeting NVIDIA L4 GPU in us-east4 .
  ──────
  ### 🧰 Available MCP Tools

  #### 🐳 Infrastructure & Deployment

  • deploy_vllm : Deploys vLLM to Cloud Run GPU (NVIDIA L4 in us-east4 ).
  • destroy_vllm : Deletes the Cloud Run vLLM service.
  • status_vllm : Checks the status of the Cloud Run vLLM service.
  • update_vllm_scaling : Updates min/max instances for scaling.
  • get_vllm_deployment_config : Generates the gcloud deployment command.
  • get_vllm_gpu_deployment_config : Generates a GKE manifest for GPU (NVIDIA L4).
  • check_gpu_quotas : Checks L4 and other GPU quotas for a region.

  #### 📦 Model Management

  • list_vertex_models : Lists models in the Vertex AI Registry.
  • list_bucket_models : Lists model weights in the GCS bucket.
  • save_hf_token : Securely saves a Hugging Face API token to Secret Manager.
  • get_vertex_ai_model_copy_instructions : Instructions to copy a model from Vertex AI Model Garden to GCS.
  • get_huggingface_model_copy_instructions : Instructions to download a model from Hugging Face and upload it to GCS.
  • get_huggingfacehub_download_path : Resolves the local cache path using huggingface_hub .

  #### 📊 Monitoring & Status

  • get_system_status : Provides a high-level status dashboard of the Cloud Run service and health.
  • get_endpoint : Verifies connectivity and returns the active service URL.
  • get_model_details : Retrieves detailed model metadata and engine state from /v1/models .
  • verify_model_health : Deep health check by querying the model with a simple prompt and measuring latency.

  #### 📈 Performance & Benchmarking

  • run_benchmark : Runs performance/concurrency benchmark sweeps against the Cloud Run vLLM GPU endpoint.

  #### 💬 Interaction & Diagnostics

  • query_gemma4 : Primary tool to query the self-hosted model with standard chat message format.
  • query_gemma4_with_stats : Queries the model and returns streaming performance statistics (TTFT, throughput).
  • query_vllm : Direct text completions querying tool.
  • analyze_cloud_logging : Fetches logs from GCP Logging and analyzes them using the model.
  • analyze_gpu_logs : Fetches Cloud Run logs and uses Gemma 4 to analyze them for SRE/DevOps errors.
  • suggest_sre_remediation : Suggests remediation plans for SRE errors using the model.
  ──────
  ### 📂 Key Source Code Reference Files

  • MCP Server Implementation: server.py
  • Project Documentation: README.md
  • Agent Test Suite: test_agent.py
Enter fullscreen mode Exit fullscreen mode

Getting Started with Gemma 4 on GPU

The Official vLLM repo also has Gemma4 specific information:

Releases · vllm-project/vllm

The Gemma 12B model was just released:

Introducing Gemma 4 12B: a unified, encoder-free multimodal model

Attempt to Deploy The Standard 12B Model

The MCP server tools are used to deploy the model to Cloud Run:

deploy the model
Enter fullscreen mode Exit fullscreen mode

But — wait! The unquantized version of the model is larger than you would expect:

The 12B Gemma models (such as the latest Gemma 4 12B Unified) 
possess ≈ 12B parameters. 

The physical raw weight sizes on disk and VRAM requirements depend directly on the quantization level and precision format you choose to deploy:

BF16 / FP16 (Unquantized): ≈ 24 GB to 26.7 GB
Enter fullscreen mode Exit fullscreen mode

The L4 Cloud Run GPU only has 24GB! Can this be done?

  I have created a comprehensive comparison and guide on deployment options for running Gemma 4 12B on a 24GB L4
  GPU. You can view the details in the artifact: deployment_options_l4_12b.md.
  ### 🔑 Key Takeaways:

  1. 🟢 Option 1: QAT ( w4a16-ct ) Model (Highly Recommended)
      • Model: google/gemma-4-12B-it-qat-w4a16-ct 
      • VRAM Footprint: ~6–7 GB, leaving ~17 GB for KV cache.
      • Context Window: Supports large context lengths (32k+) and high concurrency (8+ sequences).
      • Resource Costs: Saves compute on Cloud Run host memory (16GiB RAM / 4 vCPUs).
      • Quality: Negligible quality degradation due to Quantization-Aware Training.
  2. 🔴 Option 2: Unquantized BF16 Model (High Risk of OOM)
      • Model: google/gemma-4-12B-it 
      • VRAM Footprint: ~23.9 GB (occupies 99.5% of the L4 VRAM).
      • Constraints: You must strictly limit the model to a context length of 1024 / 2048 and maximum sequence
      concurrency of 1–2 to avoid GPU Out-Of-Memory (OOM) failures.
      • Resource Costs: Needs a larger host container (32GiB RAM / 8 vCPUs) to copy weights during startup.
Enter fullscreen mode Exit fullscreen mode

Lets try some other options:

> for the google/gemma-4-12B-it are there any options to reduce memory without using the qat model

▸ Thought for 2s, 774 tokens
  Exploring Memory Optimization

● google-dev-knowledge/answer_query(Query vLLM quantization)
● WebSearch(vllm on the fly FP8 quantization OR runtime quantization without prequantized model) (ctrl+o to expand)
▸ Thought Process
  Discovering FP8 Support
  Yes, there are several powerful options to reduce memory usage using the standard, unquantized google/gemma-4-  
  12B-
  it model checkpoint.

  By leveraging runtime / on-the-fly features in vLLM, you can achieve a massive memory reduction without needing a
  pre-quantized QAT or AWQ/GPTQ checkpoint.
  ──────
  ### 1. On-the-Fly FP8 Weight Quantization ( --quantization fp8 )
  vLLM supports dynamic FP8 quantization during model loading:
  • How it works: It loads the standard BF16 weights and quantizes them to 8-bit ( E4M3 format) on the fly as it
  puts them onto the GPU.
  • VRAM Saved: Cuts the weight footprint in half (from ~24 GB to ~12 GB), leaving the remaining ~12 GB of L4 VRAM
  entirely for the KV Cache.
  • L4 Advantage: The NVIDIA L4 has native hardware support for FP8 (Ada Lovelace architecture), meaning you will
  get high execution speeds.
  • Parameter: Add --quantization fp8 to your vLLM args.
  ──────
  ### 2. KV Cache Quantization ( --kv-cache-dtype nvfp4 or fp8 )

  Independent of the weights, you can compress the memory footprint of active context tokens:

  • nvfp4 (4-bit): Compresses the key-value cache to 4-bit precision, saving 4x memory for active context tokens.
  • fp8 (8-bit): Compresses the KV cache to 8-bit precision, saving 2x memory.
  • Parameter: Add --kv-cache-dtype nvfp4 to compress KV cache to the maximum extent.
  ──────
  ### 3. Disable CUDA Graphs ( --enforce-eager )

  By default, vLLM pre-allocates execution buffers (CUDA graphs) for different input shape ranges, which can
  consume
  1–2 GB of VRAM static overhead.

  • Action: Disable CUDA graphs to reclaim this memory.
  • Parameter: Add --enforce-eager .
  ──────
  ### 4. Enable Chunked Prefill ( --enable-chunked-prefill )

  Large prompt inputs can cause sudden spikes in activation memory (prefill memory) which triggers OOMs.

  • Action: Chunk prompt processing into smaller blocks (e.g., 4096 tokens at a time) to flatten the memory spike.
  • Parameter: Add --enable-chunked-prefill --max-num-batched-tokens 4096 .
  ──────
  ### ⚠️ Crucial System RAM Caveat (Cloud Run)

  Because the model is quantized during loading, the container must first fetch the full 24 GB BF16 model. If you
  copy the model to local /tmpfs memory to speed up loading, the container host RAM will spike.

  • Requirement: Keep the Cloud Run configuration at --memory=32Gi and --cpu=8 to ensure the host machine
  doesn't run out of system memory during the initial download/load phase.
  ──────
  ### 🚀 Updated Deployment Command (No QAT, Runtime-Quantized)

  Here is the exact command to deploy the standard google/gemma-4-12B-it model with these runtime memory
  optimizations:

    gcloud beta run deploy gpu-12b-l4-devops-agent \                                                               
      --project=aisprint-491218 \                                                                                  
      --image=vllm/vllm-openai:latest \                                                                            
      --gpu=1 \                                                                                                    
      --add-volume=name=model-volume,type=cloud-storage,bucket=aisprint-491218-bucket,readonly=true \              
      --gpu-type=nvidia-l4 \                                                                                       
      --memory=32Gi \                                                                                              
      --cpu=8 \                                                                                                    
      --execution-environment=gen2 \                                                                               
      --add-volume-mount=volume=model-volume,mount-path=/mnt/models \                                              
      --args=--model=/mnt/models/gemma-4-12B-it,--dtype=bfloat16,--quantization=fp8,--max-model-len=16384,--disable-
  chunked-mm-input,--gpu-memory-utilization=0.90,--kv-cache-dtype=nvfp4,--tensor-parallel-size=1,--max-num-seqs=8,--
  enable-chunked-prefill,--max-num-batched-tokens=4096,--enable-auto-tool-choice,--tool-call-parser=gemma4,--      
  reasoning-parser=gemma4,--async-scheduling,--enforce-eager,--limit-mm-per-prompt={},--host=0.0.0.0,--port=8000 \ 
      --no-allow-unauthenticated \                                                                                 
      --region=us-east4 \                                                                                          
      --no-gpu-zonal-redundancy \                                                                                  
      --timeout=3600                                                                                               

Enter fullscreen mode Exit fullscreen mode

Did that Voodoo Work?

The Cloud Run Deployment was re-started:

  The deployment failed with a CUDA Out-of-Memory (OOM) error.

  ### Why the OOM still occurs with CPU offloading:

  • The vLLM V1 Engine parameter initialization: In recent vLLM versions (where the V0 engine has been fully
  deprecated), the model instantiation phase ( init_parameters ) instantiates the entire structure of the model on
  the active GPU first (allocating 21.61 GB of VRAM for the 12B BF16 weights) before it applies any CPU weight
  offloading or online quantization.
  • Because 21.61 GB is nearly 100% of the usable VRAM on a 24GB L4 GPU, PyTorch runs out of memory during
  parameter initialization before the offloading or runtime FP8 quantization routines can take effect.

  This means it is physically impossible to load the unquantized google/gemma-4-12B-it model checkpoint on a
  single
  24GB L4 GPU using vLLM's dynamic runtime quantization or offloading paths.
  ──────
  ### What are your options now?
  1. Option 1: Deploy using the pre-quantized QAT checkpoint (Recommended & Natively supported in your bucket)
      • The model gemma-4-12B-it-qat-w4a16-ct is already present in your GCS bucket ( gs://aisprint-491218-      
      bucket/gemma-4-12B-it-qat-w4a16-ct/ ). It loads directly as 4-bit weights (~6 GB), completely bypassing VRAM
      loading spikes, and runs with high performance.
      • You can deploy it using the dedicated agent workspace: gpu-12B-qat-L4-devops-agent.
  3. Option 3: Use a smaller model that fits natively in BF16
  2. Option 2: Deploy a pre-quantized Post-Training Quantization (PTQ) FP8 checkpoint
      • If you want to avoid QAT, you can download a pre-quantized FP8 checkpoint (e.g., google/gemma-4-12B-it-ptq-
      fp8 or community AWQ versions) locally, upload it to your GCS bucket, and modify the model path to target it.
      This will load directly in FP8 (12 GB) and bypass the loading spike.
      • You can use a model like gemma-4-E4B-it (which is a 4B parameter model and occupies only ~8 GB of VRAM),
      fitting natively on L4 in full precision without any quantization.
Enter fullscreen mode Exit fullscreen mode

What about the QAT Models?

A deep dive into deploying the 12B QAT model is here:

12B Gemma 4 QAT Deployment with NVIDIA L4, Cloud Run, MCP, and Antigravity CLI

What other Quantization options are there?

I get it. The standard model is too big with unquantized weights- and forget about the KV cache. What else can be done?

> is there a SFP8 / INT8 (8-bit) version of 12b-it?

  Yes, there is indeed a Structured Floating-Point 8-bit (SFP8) version of the Gemma 4 12B-it model. SFP8 is a low-
  precision 8-bit format officially supported by Google for the Gemma 4 family.

  ### 📊 SFP8 Weight Footprint vs. Other Precisions

  For the Gemma 4 12B model, the memory required for the weights drops significantly under SFP8:

  • BF16 (16-bit): 26.7 GB (requires > 32 GB of system VRAM to run comfortably with KV cache).
  • SFP8 (8-bit): 13.4 GB (fits easily on a 24GB L4 GPU, leaving ~10 GB for the KV cache).
  • Q4_0 (4-bit): 6.7 GB.
  ──────
  ### 📦 Where to get SFP8/FP8 versions of 12b-it:

  1. Pre-Quantized FP8 Checkpoints (Hugging Face):
  While Google does not host a standalone repository under the name google/gemma-4-12b-it-sfp8 on Hugging Face,
  several optimized pre-quantized FP8 checkpoints are hosted by the community:
      • vrfai/gemma-4-12B-it-fp8 (Quantized using NVIDIA ModelOpt).
      • AxionML/Gemma-4-12B-FP8 (Uses per-block E4M3 FP8 weight-only quantization to preserve activations).
      • bahadirakdemir/gemma-4-12B-it-text-fp8 (Text-only FP8 optimization).

> which hugging face SFP8/FP8 is the best option?

● WebSearch(AxionML/Gemma-4-12B-FP8 OR vrfai/gemma-4-12B-it-fp8 vllm) (ctrl+o to expand)
▸ Thought for 3s, 555 tokens
  Analyzing FP8 Options
  The best option for your vLLM deployment on the 24GB L4 GPU is:

  ### 🟢 vrfai/gemma-4-12B-it-fp8 

  Here is why this is the optimal choice for your setup:

  1. Instruction-Tuned ( -it ):
  This repository is quantized from the instruction-tuned ( -it ) base. Since your DevOps/SRE assistant relies
  heavily on following system prompts, extracting logs, and formatting tool calls, using the instruction-tuned
  version is mandatory. Other versions (like AxionML/Gemma-4-12B-FP8 ) are based on the pre-trained base model and
  will not follow prompts or formatting instructions reliably.
  2. Native vLLM Compatibility (NVIDIA ModelOpt):
  This model was quantized using NVIDIA ModelOpt to standard FP8 ( E4M3 format). vLLM has native, stable support
  for loading ModelOpt checkpoints directly. You can serve it simply by pointing to this model path and specifying --
  quantization fp8 (or it will auto-detect the configuration).
      • Contrast: AxionML 's version uses a custom per-block weight-only FP8 format ( fp8_pb_wo ) that is
      optimized specifically for SGLang and is prone to compilation/kernel errors in standard vLLM environments.
  3. Bypasses the Loading VRAM Spike:
  Since the weights in this repository are already saved in FP8 format, vLLM will load them directly as 8-bit
  tensors (~13.4 GB) onto the L4 GPU, completely avoiding the 21.61 GB BF16 VRAM instantiation spike that caused
  your previous deployments to crash.
Enter fullscreen mode Exit fullscreen mode

But Will it Blend?

Check the memory usage on the L4 GPU:

  Analyzing KV Cache Usage
  Based on the real-time vLLM engine metrics retrieved from the /metrics endpoint:

  ### 1. VRAM Allocation (NVIDIA L4 GPU - 24 GB Total)

  • Target GPU Memory Utilization: 90% of total VRAM (allocated to vLLM's memory pool, which is approximately 21.6 
  GB).
  • Model Weight Footprint: The 12B parameter model quantized to FP8 ( gemma-4-12B-it-text-fp8 ) consumes
  approximately 12 GB of VRAM for model weights.
  • Pre-allocated KV Cache Blocks: 6,695 blocks are pre-allocated in the remaining VRAM pool for KV cache storage.

  ### 2. Active Cache & Request Usage

  • Current KV Cache Usage ( vllm:kv_cache_usage_perc ): 0.0% (currently idle with no active sessions).
  • Running Requests: 0
  • Waiting Requests: 0
Enter fullscreen mode Exit fullscreen mode

Cross Check The Deployed Model

Once the model starts locally- the MCP tool allows for model verification:

> verify_model_health

  I'll inspect the schema for the verify_model_health tool to understand its required parameters.

● Read(/home/xbill/.gemini/antigravity-cli/mcp/gpu-devops-agent/verify_model_health.json) (ctrl+o to expand)

  I will now run the model health check using the verify_model_health tool.

● gpu-devops-agent/verify_model_health(Model health check) (ctrl+o to expand)

  The health check for the Cloud Run GPU-hosted model has successfully passed:

  • Status: ✅ PASSED
  • Model Path: /tmp/model 
  • Response: 'Yes, I am working correctly! How can I help you to...' 
  • Latency: 1.35 seconds
Enter fullscreen mode Exit fullscreen mode

and model details:

> get_active_models

  I will call get_model_details to check what model is currently active and serving.

● gpu-devops-agent/get_model_details(Get active model details) (ctrl+o to expand)

  The active model currently serving on the Cloud Run GPU endpoint is:

  • Model ID: /tmp/model 
  • Object Type: model 
  • Owner: vllm 
  • Health Status ( /health ): Healthy ✅
  • Base URL: https://gpu-12b-l4-devops-agent-289270257791.us-east4.run.app 

Enter fullscreen mode Exit fullscreen mode

and the endpoint:

> get_endpoint

  I will inspect the schema for the get_endpoint tool.

● Read(/home/xbill/.gemini/antigravity-cli/mcp/gpu-devops-agent/get_endpoint.json) (ctrl+o to expand)

  I will now query the active endpoint using the get_endpoint tool.

● gpu-devops-agent/get_endpoint(Get active endpoint) (ctrl+o to expand)

  The active Cloud Run vLLM service endpoint is:

  • Endpoint URL: https://gpu-12b-l4-devops-agent-289270257791.us-east4.run.app 
  • Status: Online 🟢
Enter fullscreen mode Exit fullscreen mode

and status:

> get_system_details

  I will inspect the schema for the get_system_status tool to see if it is the closest match for
  "get_system_details".

● Read(/home/xbill/.gemini/antigravity-cli/mcp/gpu-devops-agent/get_system_status.json) (ctrl+o to expand)

  I will invoke the get_system_status tool to retrieve the system status details.

● gpu-devops-agent/get_system_status(Get system status) (ctrl+o to expand)

  The system status details for the GPU Cloud Run service are:

  • vLLM Health: Online 🟢 ( https://gpu-12b-l4-devops-agent-289270257791.us-east4.run.app )
  • Cloud Run Service Status: Ready 🟢
  • Recommended Next Action: Use query_gemma4 to interact with the model.
Enter fullscreen mode Exit fullscreen mode

Check the Cloud Run Service

Once Deployed — the model is visible as a standard Cloud Run Service:

Review the Model

Check the model details:

> what are the model details?
  • Model ID / Name: /tmp/model (copied locally to tmpfs from the GCS FUSE bucket directory gemma-4-12B-it-   
  text-fp8 )
  • Underlying Architecture: Gemma4UnifiedForConditionalGeneration (Gemma 4 12B Instruction Model)
  • Maximum Context Length ( max_model_len ): 16384 tokens
  • Weights Quantization: modelopt (ModelOpt FP8 weight quantization format)
  • Data Type ( dtype ): bfloat16 (Activation precision)
  • KV Cache Data Type ( kv_cache_dtype ): fp8 (Pre-allocated into 13,278 GPU cache blocks)
  • Served Engine: vLLM (v1 Engine: v0.22.1rc1.dev288+gd8218b1ee )
  • Endpoint URL: https://gpu-12b-l4-devops-agent-wgcq55zbfq-uk.a.run.app 
  • Status: Healthy ✅

Enter fullscreen mode Exit fullscreen mode

Once everything is online — you can send queries to the Model:

  The model's response along with the performance statistics are detailed below:

  ### 💬 Model Response

  Gemma is a family of lightweight, state-of-the-art open models built by Google DeepMind.

  If you are familiar with Google’s largest AI models (like Gemini), you can think of Gemma as their "smaller,"
  more accessible siblings. While Gemini is designed for massive enterprise tasks, Gemma is designed to run on
  local hardware (like a laptop or a personal workstation) while still maintaining high intelligence.

  Here are the key things to know about Gemma:

  • Open Weights: Google releases the model weights so that developers can download, customize, and run it on their
  own hardware under an open license.
  • Gemini Lineage: It was built using the same research, infrastructure, and technology used to create the Gemini
  models, allowing it to punch above its weight class in reasoning, coding, and math.
  • Efficiency: Because they are relatively small (ranging from 2B to 27B parameters), they run comfortably on
  consumer-grade hardware or serverless GPUs.
  ──────
  ### 📊 Performance Statistics

  • Active Model: /tmp/model (Gemma 4 12B IT)
  • Time to First Token (TTFT): 6.405s 
  • Total Generation Time: 60.426s 
  • Throughput: 12.09 tokens/s 
  • Estimated Tokens Generated: 653 
Enter fullscreen mode Exit fullscreen mode

Benchmark the Local Model

The local model was benchmarked:

The benchmark sweep has completed successfully. Here are the compiled results across all combinations of context
  window sizes and concurrency levels:
Enter fullscreen mode Exit fullscreen mode

This is visualized:

Comparison with QAT Models

 I have generated a comprehensive benchmark comparison between the Standard FP8/BF16 serving configuration and the
  QAT INT4 serving configuration.

  You can view the detailed report here: benchmark_comparison.md.

  ### Summary of Key Findings

  • VRAM Bottleneck: On the 24GB NVIDIA L4 GPU, the unquantized standard model weights consume ~24GB of VRAM,
  leaving 0GB for vLLM's KV cache. The QAT model weights consume only ~6GB, leaving ~18GB of VRAM for the KV cache
  and concurrent user contexts.
  • Throughput Speedup: The QAT model achieves up to a 1.73x throughput speedup at short context sizes (e.g., peak
  throughput of 40.30 req/s vs. 23.38 req/s for standard).
  • Context Capacity: The Standard model crashes (0% success rate) at 16K context size due to out-of-memory errors,
  whereas the QAT model successfully scales to 32K context lengths and maintains active throughput.
  • Concurrency Stability: At extreme concurrency levels (C=2048), QAT sustains significantly higher success rates
  (e.g., 100% vs. 50.9% success at context length 8).
  • Anomaly Note: The high latency observed at Concurrency=1 for both models is caused by vLLM container
  crashes/restarts under the previous maximum load (C=2048), triggering a Cloud Run cold start.


Enter fullscreen mode Exit fullscreen mode

Compare the models:

> is standard qat better

▸ Thought for 2s, 386 tokens
  Analyzing the Best Approach
  QAT (Quantization-Aware Training) is significantly better for serving Gemma 4 12B on a single NVIDIA L4 GPU (24GB
  VRAM).

  Here is why:

  ### 1. The VRAM Cliff (Memory Availability)

  • Standard: Storing unquantized bfloat16 weights consumes ~24GB of VRAM, leaving 0GB for vLLM's KV cache.
  Concurrency drops to 8 users before success rates fall off.
  • QAT: Compressing weights to 4-bit uses only ~6GB, leaving ~18GB of VRAM free for the KV cache. This enables
  scaling to 1024 concurrent users with high success rates.

  ### 2. Context Window Scaling

  • Standard: Fails entirely (0% success rate, Out of Memory) at 16K context lengths.
  • QAT: Serves context lengths up to 32K tokens stably.

  ### 3. Throughput & Latency

  • Throughput: QAT achieves up to 1.73x higher peak throughput (40.30 req/s vs. 23.38 req/s) at low context sizes.
  • Latency: QAT's average latency is consistently 6% to 17% lower across all concurrency levels.

  ### 4. Accuracy Retention

  • Because the model was trained with quantization in the loop (QAT), it retains nearly identical reasoning and   
  coding accuracy as the unquantized 12B Standard model, far outperforming smaller parameter models (like 4B) or
  standard Post-Training Quantization (PTQ).

  ### Conclusion

  For single-GPU (24GB) production workloads, QAT is the optimal choice. The Standard model should only be run if
  you have multi-GPU/TPU setups or require unquantized precision for highly sensitive tasks.
Enter fullscreen mode Exit fullscreen mode

What about the current custom quant model?

 Analyzing Deployment Details
  Here is a direct comparison between the QAT Model and your Current Deployment:

  ### 📋 Technical Comparison

   Metric / Setting | Current Deployment ( gpu-1… | QAT Model ( gpu-12b-qat-l4… | Comparison Advantage
  -----------------------|-----------------------------|-----------------------------|-----------------------------
   Active Model | /tmp/model (Copied from | gemma-4-12B-it-qat-w4a16- | QAT: Trained with
                         | gemma-4-12B-it-text-fp8 ) | ct | quantization in the loop;
                         | | | retains higher accuracy
                         | | | than standard post-training
                         | | | quantization (PTQ).
   Quantization | FP8 Weights & Activations | INT4 Weights & FP16 | QAT: Smaller memory
                         | (PTQ) | Activations (QAT) | footprint per weight.
   Weight VRAM Footprint | ~12 GB | ~6 GB | QAT: Uses 50% less VRAM for
                         | | | weights, freeing up space
                         | | | for user sessions.
   KV Cache Settings | --kv-cache-dtype=auto | --kv-cache-dtype=fp8 (FP8 | QAT: Compresses KV cache
                         | (FP16/BF16 cache) | cache) | memory in half, allowing
                         | | | more tokens to fit.
   Max Context Length | 16384 (16K context - | 32768 (32K context - | QAT: Doubles context
                         | crashes at limit) | stable) | capability (32K vs 16K).
  ──────
  ### ⚡ Performance Comparison (from Sweeps)

  • Throughput (Tokens/Requests per Second): The QAT model achieved up to 40.30 req/s peak throughput compared to
  the current deployment's 23.38 req/s peak (a 1.72x speedup for QAT).
  • Latency: The QAT model exhibits 6% to 17% lower average latency across all concurrent loads.
  • Stability at Scale: At concurrency = 2048 (with context = 8), the current deployment drops to 50.9% success    
  rate due to VRAM starvation, whereas QAT maintains 100% success rate.

  ### 💡 Recommendation

  You should upgrade your current deployment to the QAT model. Doing so will cut your VRAM weight footprint in
  half, double your maximum context window to 32K, and improve serving throughput by up to 72% on the same NVIDIA
  L4 hardware.

Enter fullscreen mode Exit fullscreen mode

One last cross check — what about a kv fp8 quant on a standard model vs standard vs QAT?

> summarize progressive_comparison.md

  Here is a summary of the progressive serving configurations analyzed in progressive_comparison.md:

  • Memory vs. Performance Trade-off: The performance of Gemma 4 on a 24GB L4 GPU is governed by how much VRAM is
  left for the KV cache after storing model weights.
  • Standard Unquantized (BF16): Weights take 24 GB (100% VRAM), leaving 0 GB for cache. It is unusable for
  concurrent workloads.
  • Standard FP8 (Auto KV): Weights take 12 GB, leaving 12 GB for cache. Uncompressed cache memory limits
  concurrency to <= 16 and context window to <= 8K.
  • Standard FP8 + FP8 KV Cache: Weights take 12 GB, and the 12 GB cache is compressed in half. This raises stable
  concurrency to 512 users, but 16K+ context windows still fail due to weight footprint constraints.
  • QAT INT4 + FP8 KV Cache: Weights take only 6 GB, leaving 18 GB for the compressed cache. This enables 16K/32K  
  context windows, high concurrency, and 1.72x higher throughput while retaining nearly 100% unquantized accuracy.

  Verdict: The QAT INT4 + FP8 KV configuration is the optimal setup for DevOps/SRE serving, providing the only
  stable long-context (16K+) execution path on single L4 GPU hardware.

Enter fullscreen mode Exit fullscreen mode

are you sure?!?!

> what is the bottleneck for deployment of 12B on the L4?

▸ Thought for 2s, 354 tokens
  Identifying the Bottleneck
  The primary bottleneck for deploying the Gemma 4 12B model on a single NVIDIA L4 GPU is VRAM Capacity            
  (specifically, the conflict between Model Weight footprint and KV Cache memory space).

  Here is the breakdown of how this bottleneck manifests:

  ### 1. The VRAM Ceiling

  The NVIDIA L4 GPU has exactly 24 GB of VRAM.

  ### 2. Weight Footprint vs. Cache Starvation

  • Weight Footprint: A 12B parameter model stored in bfloat16 precision requires 24 GB of memory just to load
  the model into memory.
  • The Conflict: Loading unquantized weights leaves 0 GB for vLLM's KV cache. The KV cache is required to store
  the attention states of current user sessions. Without VRAM for the KV cache, the engine must drop requests, fail
  with Out-of-Memory (OOM) errors, or offload cache to CPU system memory (which destroys performance).

  ### 3. Concurrency and Context Length Limits

  Every concurrent user and every token in the conversation context increases the KV Cache demand:

  • A single unquantized 1024-token session consumes significant cache space.
  • Scaling to 16K context window or 512 concurrent users requires gigabytes of cache memory.

  ### 4. How the Bottleneck is Resolved

  To run the 12B model successfully on L4, you must reduce both memory footprints:

  1. Weight Quantization: Compressing weights to FP8 (12 GB footprint) or INT4 QAT (6 GB footprint) frees up 12–18 
  GB of VRAM.
  2. KV Cache Quantization: Running --kv-cache-dtype=fp8 halves the VRAM needed per token, doubling the effective
  capacity of the remaining cache buffer.

> how does qat make a difference?

▸ Thought for 2s, 521 tokens
  Defining QAT Advantages
  Quantization-Aware Training (QAT) makes a critical difference in three key areas: Accuracy Retention, VRAM       
  Capacity, and Serving Throughput.

  Here is how it compares to standard Post-Training Quantization (PTQ):
  ──────
  ### 1. Accuracy Retention (Reasoning Capability)

  • The PTQ Problem: Standard Post-Training Quantization simply rounds weights after the model is already trained.
  Rounding weights down to 4-bit (INT4) destroys the model's accuracy, causing it to lose reasoning capabilities,
  hallucinate, and fail at complex SRE tasks or structured tool calling.
  • The QAT Solution: QAT models simulate the precision loss during the training process. The model learns to
  compensate for the lower precision by adjusting its remaining parameters. As a result, the INT4 QAT model retains
  ~99.8% of the accuracy and reasoning capability of the unquantized bfloat16 model.
  ──────
  ### 2. Doubling VRAM Headroom for the KV Cache

  Because QAT compresses the weights to 4-bit (INT4) instead of 8-bit (FP8) or 16-bit (BF16), it drastically
  reduces
  the memory footprint on the GPU:

  • Unquantized (BF16): Weights use 24 GB → Leaves 0 GB for KV cache.
  • Standard Quantized (FP8): Weights use 12 GB → Leaves 12 GB for KV cache.
  • QAT (INT4): Weights use 6 GB → Leaves 18 GB for KV cache.

  This extra 6 GB of free VRAM is the difference between failure and success for long-context applications,
  allowing
  QAT to serve 16K and 32K context windows where FP8 models fail due to memory starvation.
  ──────
  ### 3. Throughput Speedups (Reduced Memory Bandwidth)

  During the token generation phase of LLM serving, the GPU is memory-bandwidth bottlenecked (it spends most of its
  time moving model weights from GPU memory to the processing cores).

  • Because INT4 weights are half the size of FP8 weights, the GPU spends half as much time transferring weights.
  • This results in the 1.72x peak throughput speedup (up to 40.30 req/s vs. 23.38 req/s) observed in our low-
  context benchmarks.
Enter fullscreen mode Exit fullscreen mode

Summary

The strategy for using MCP for Gemma 4 GPU deployment with Antigravity CLI was validated with a incremental step by step approach.

A minimal stdio transport MCP Server was started from Python source code and validated with Antigravity CLI running as a MCP client in the same local environment. This Python server provided all of the management tools to deploy and troubleshoot Cloud Run Model deployments.

Top comments (0)