
Serverless platforms like Google Cloud Run are fundamentally designed to be stateless: containers can spin up, restart, or scale down to zero at any moment. But how do you run a long-running, stateful autonomous AI Agent that maintains persistent conversation history, chat database files, and a live Telegram bot connection?
In this article, I share the architecture behind deploying Hermes Agent on Cloud Run with persistent state backed by Google Cloud Storage and a dual-engine LLM backend.
High-Level Architecture
|
|
1. Stateful Persistence on Serverless (GCS State Bridge)
Hermes Agent maintains SQLite databases (state.db) for conversation memory, user sessions, and tool states. To survive container revisions and deployments without losing a single chat:
- Startup Hook: When the container initializes, a lightweight Python wrapper runs GCS API sync to restore
/app/data/state.dbfromgs://wojciech-genai-hermes-state/. - Periodic Daemon & SIGTERM Catch: A background thread flushes SQLite WAL checkpoints and uploads snapshots to GCS every 5 minutes and on graceful container shutdown.
2. Secure Secret Management (GCP Secret Manager)
Hardcoding tokens or passwords in container environment variables is an anti-pattern. We integrate GCP Secret Manager with native Cloud Run references:
|
|
3. Dual-Engine LLM Fallback (vLLM + Vertex AI)
To maximize reasoning power while keeping GPU FinOps tightly controlled:
- Daytime (vLLM GPU): Between 08:00 and 23:00, when our dedicated NVIDIA RTX PRO 6000 (96 GB VRAM) instance is active, Hermes routes primary inference and tool-calling requests to our private BF16 model with custom Jinja tool-calling templates.
- Nighttime & Failover (Vertex AI): At 23:00, Cloud Scheduler scales the GPU service down to
min-instances=0(cutting monthly GPU spend from $944/month down to ~$550/month). Whenever the GPU instance is scaled to zero or undergoing maintenance, Hermes transparently falls back togoogle/gemini-3.7-flashon Vertex AI with zero downtime.
In the next post, we will look at how we route and sanitize tool-calling payloads using a custom Python middleware proxy!