Building the Talent Navigator Agent with Gemini 1.5 & Cloud Run

A Step-by-Step Hands-On Workshop Guide for Google I/O Extended Buea (Silicon Mountain)

Google Cloud
Agentic AI
Gemini 1.5 Flash
FastAPI
Docker
Cloud Run
Silicon Mountain
Workshop
Author
Affiliation

Mbiarrambang Alain

PaveWay Group

Published

August 30, 2026

Note📍 Session Metadata & Quick Access
  • Event: Google I/O Extended Silicon Mountain (Buea, Cameroon)
  • Session Format: 60-Minute Interactive Live Coding & Architecture Workshop
  • Speaker: Mbiarrambang Alain (Founder, PaveWay Group | Cloud & DevOps Engineer)
  • Primary Stack: Python 3.11, Google GenAI SDK (gemini-1.5-flash), FastAPI, Docker, Google Artifact Registry, Google Cloud Run
  • Starter Repository: github.com/mbengchan/talent-navigator-agent (or browse the Code Showcase)

🎯 Workshop Overview & Vision

Designing this 60-minute Google I/O Extended session requires a hyper-focused demonstration that bridges Agentic AI concepts with immediate, deployable utility for the Silicon Mountain ecosystem.

Instead of building a generic chat interface, we are building the Talent Navigator Agent—a purpose-built, API-driven agent that takes an unstructured description of a developer’s current skills and project interests, and dynamically executes deterministic Python tools to generate a concrete final-year project architecture or targeted learning syllabus.

flowchart LR
    A["Unstructured Input:<br/>'Flutter + Tailwind for civic tech'"] --> B["Talent Navigator Agent<br/>(Gemini 1.5 Flash)"]
    B -->|"Tool 1: search_tech_stack()"| C["Domain Knowledge Engine"]
    C -->|"Returns Stack: FastAPI + Cloud Run + Firestore"| B
    B -->|"Tool 2: generate_architecture_doc()"| D["Roadmap Formatter"]
    D -->|"Returns Milestone Plan"| B
    B --> E["Deployable JSON + Markdown Blueprint"]


⏱️ 60-Minute Workshop Timeline

This timeline is engineered to maintain high technical momentum while ensuring attendees leave with working code on their machines and in the cloud.

Timestamp Phase Presenter Strategy & Live Actions Attendee Checkpoint
00:00 – 00:10 The Agentic Paradigm & Harness Engineering Deconstruct LLMs vs. Agents using the Buea Professor vs. Department Head analogy. Introduce Harness Engineering (Engine vs. Chassis). Grasp why tool-augmented models and software harnesses outperform static prompts.
00:10 – 00:30 Building the Core Agent Code walkthrough: Initialize Gemini 1.5 Flash client, write deterministic Python tools, and bind tools to model config. Run the local Python agentic loop in terminal.
00:30 – 00:45 FastAPI & Containerization Wrap agent in FastAPI endpoint (/api/navigate). Walk through the lean Dockerfile for Cloud Run. Test interactive Swagger docs at http://localhost:8080/docs.
00:45 – 00:55 Cloud Run Deployment & Live Test Execute 1-click deploy via Cloud Build & Artifact Registry. Connect GEMINI_API_KEY via Secret Manager. Hit live URL. Send live cURL requests to the public Cloud Run endpoint.
00:55 – 01:00 Q&A & Resource Handoff Open Q&A floor. Share GitHub template QR code and 4 localized final-year project ideas. Clone template repo and bookmark reference guides.

🧠 Part 1: The Agentic Paradigm & Harness Engineering

LLMs vs. Agents: The Localized Analogy

When teaching AI to students and engineers in Buea, the easiest way to clarify the shift from standard LLMs to Agentic AI is through a university analogy:

Tip🏛️ The Buea University Analogy
  • A Standard LLM is like a Brilliant but Isolated Professor: They have read thousands of textbooks and can write eloquent essays from memory. However, they cannot browse today’s live registration records, cannot check database tables, and cannot sign an official course waiver. If asked about something they don’t know, they might guess convincingly (hallucination).
  • An Agent is like a Department Head: They have the intelligence of the professor, but they also have a desk phone, a registry database, and authority to delegate tasks to specialist faculty members (Tools). When a student brings a problem, the Department Head decides: “First, let me check the transcript tool. Second, let me run the prerequisite checker tool. Third, I will write the graduation approval.”

Why Function Calling Matters

Traditional applications rely on rigid, hardcoded if/else logic. Large language models provide fluid reasoning but lack direct system access. Function Calling (Tools) forms the bridge:

  1. Deterministic Execution: The AI model does not execute Python code in the cloud by itself; it returns a structured JSON object specifying which function to call and with what exact arguments.
  2. Local Control & Security: Your Python backend receives the model’s decision, runs the function locally or in your secure database, and feeds the result back to the model.
  3. Structured Outputs: Guarantees valid schemas for downstream frontends (Flutter, React, Mobile Apps).

🏎️ Production Concept: What is Agent Harness Engineering?

In modern software engineering, creating a real-world AI product is not just about sending prompts to an API. It is about Harness Engineering—designing the deterministic software scaffolding, guardrails, state machine, and runtime environment surrounding the model.

Note🔧 The Engine vs. The Harness Metaphor
  • The LLM (Gemini 1.5 Flash) is the Engine: It provides raw probabilistic reasoning, language comprehension, and tool selection capabilities (horsepower).
  • Your Code is the Harness: It provides the chassis, steering wheel, transmission, brakes, dashboard, and seatbelts.
┌─────────────────────────────────────────────────────────────┐
│                    THE AGENT HARNESS                        │
│                                                             │
│   [ Pydantic Schemas ]  ──► Input Validation / Guardrails   │
│   [ Deterministic Tools ] ──► Safe, Verified Python Actions │
│   [ Mock / Fallbacks ]  ──► Circuit Breakers & Offline Mode │
│   [ FastAPI + Cloud Run]──► Containerized Microservice      │
│                                                             │
│                ┌───────────────────────────┐                │
│                │    Gemini 1.5 Flash       │                │
│                │     (The LLM Engine)      │                │
│                └───────────────────────────┘                │
└─────────────────────────────────────────────────────────────┘

Key Pillars of Harness Engineering in This Workshop:

  1. Schema Validation & Guardrails: Pydantic models in FastAPI (main.py) validate user prompts before they reach the model and enforce rigid JSON contracts on responses.
  2. Deterministic Tool Boundaries: Gemini can only choose from strictly typed Python functions in tools.py—preventing arbitrary hallucinated code execution.
  3. Resilience & Circuit Breaking: The offline mock engine (_execute_mock_agent) guarantees uninterrupted service if Wi-Fi or API quotas fail.
  4. Evaluation Harness (For Student Theses & Hackathons): A harness allows writing automated test suites to benchmark your agent against 20+ diverse developer prompts to measure tool selection accuracy and output quality before production deployment.

🛠️ Part 2: Hands-On Code Implementation

Follow these steps to build the complete application from scratch or run it from the starter repository.

Step 1: Environment Setup & Dependencies

Create an isolated virtual environment and install the required packages:

# 1. Create project directory
mkdir talent-navigator-agent && cd talent-navigator-agent

# 2. Initialize virtual environment
python3 -m venv venv
source venv/bin/activate

# 3. Create requirements.txt
cat << 'EOF' > requirements.txt
google-genai>=0.1.1
fastapi>=0.115.0
uvicorn[standard]>=0.30.0
pydantic>=2.8.0
python-dotenv>=1.0.1
EOF

# 4. Install dependencies
pip install -r requirements.txt
# 1. Create project directory
mkdir talent-navigator-agent; cd talent-navigator-agent

# 2. Initialize virtual environment
python -m venv venv
.\venv\Scripts\Activate.ps1

# 3. Install dependencies
pip install google-genai fastapi "uvicorn[standard]" pydantic python-dotenv

Create a .env file to store your Google Gemini API key:

# Get your free key from https://aistudio.google.com/
echo "GEMINI_API_KEY=AIzaSyYourGeminiApiKeyHere" > .env

Step 2: Defining Deterministic Domain Tools (tools.py)

Tools are standard Python functions with clear docstrings and type annotations. Gemini inspects the function signature and docstrings to understand when and how to invoke them.

Create tools.py:

"""
Domain Tools for Talent Navigator Agent.
These functions represent the deterministic capabilities that the Gemini Agent can invoke.
"""

from typing import List, Dict, Any

# Local tech ecosystem knowledge base tailored for Silicon Mountain developers
DOMAIN_RECOMMENDATIONS = {
    "civic tech": {
        "recommended_backend": "FastAPI (Python) or Express (Node.js)",
        "database": "Cloud SQL (PostgreSQL) or Firebase Firestore",
        "cloud_infrastructure": "Google Cloud Run + Secret Manager",
        "auth_and_services": ["Firebase Auth", "Cloud Storage for documents", "SMS/WhatsApp Alerts (Twilio/Infobip)"],
        "recommended_additions": ["OpenStreetMap API", "GeoPandas", "Offline-first sync for low-connectivity regions"],
    },
    "fintech": {
        "recommended_backend": "FastAPI or Go with strict typing",
        "database": "PostgreSQL with ACID transaction compliance",
        "cloud_infrastructure": "Google Cloud Run + Cloud KMS + Secret Manager",
        "auth_and_services": ["MTN MoMo API / Orange Money API", "JWT Auth", "Cloud Audit Logs"],
        "recommended_additions": ["Redis for rate-limiting", "Webhook idempotency handling", "Celery/Cloud Tasks for async payouts"],
    },
    "agritech": {
        "recommended_backend": "FastAPI (Python) with ML inference pipeline",
        "database": "Firebase Firestore (Offline caching) + Cloud Storage",
        "cloud_infrastructure": "Google Cloud Run + Vertex AI / Gemini 1.5 Flash",
        "auth_and_services": ["Firebase Auth", "USSD gateway or SMS notifications"],
        "recommended_additions": ["Plant disease image classification", "Weather forecasting API", "Bilingual French/English UI"],
    },
    "healthtech": {
        "recommended_backend": "FastAPI (Python)",
        "database": "Cloud SQL PostgreSQL (Encrypted at rest)",
        "cloud_infrastructure": "Google Cloud Run + Secret Manager",
        "auth_and_services": ["Firebase Auth with MFA", "Encrypted Cloud Storage"],
        "recommended_additions": ["Triage engine with Gemini", "Offline-first patient syncing"],
    },
    "edtech": {
        "recommended_backend": "FastAPI or Django",
        "database": "Firebase Firestore or Supabase",
        "cloud_infrastructure": "Google Cloud Run + Cloud CDN",
        "auth_and_services": ["Firebase Auth", "Cloud Storage for video/PDF materials"],
        "recommended_additions": ["Gemini Flash AI tutor", "Lightweight bandwidth-saving mode"],
    },
}


def search_tech_stack(interest_domain: str, current_skills: List[str]) -> Dict[str, Any]:
    """
    Search and recommend complementary technologies, infrastructure, and services
    based on the developer's target domain and their current skill set.

    Args:
        interest_domain: The project domain (e.g., 'civic tech', 'fintech', 'agritech', 'healthtech', 'edtech').
        current_skills: List of current technologies known by the developer (e.g. ['Flutter', 'Tailwind CSS']).

    Returns:
        A dictionary containing tailored stack recommendations and infrastructure choices.
    """
    normalized_domain = interest_domain.strip().lower()
    matched_domain = "civic tech"  # default fallback
    for key in DOMAIN_RECOMMENDATIONS:
        if key in normalized_domain:
            matched_domain = key
            break

    profile = DOMAIN_RECOMMENDATIONS[matched_domain]
    
    # Assess frontend vs backend gaps
    has_mobile_or_frontend = any(s.lower() in ["flutter", "react", "vue", "html", "tailwind", "css", "svelte", "android", "ios", "kotlin", "swift"] for s in current_skills)
    has_backend = any(s.lower() in ["python", "fastapi", "django", "node", "express", "go", "java", "spring", "rust", "php", "laravel"] for s in current_skills)

    stack_gaps = []
    if not has_backend:
        stack_gaps.append(f"Backend API layer needed -> Recommend {profile['recommended_backend']}")
    if not has_mobile_or_frontend:
        stack_gaps.append("Client UI needed -> Recommend Flutter (cross-platform mobile) or React (web)")

    return {
        "matched_domain": matched_domain.capitalize(),
        "developer_current_skills": current_skills,
        "recommended_backend": profile["recommended_backend"],
        "recommended_database": profile["database"],
        "recommended_cloud": profile["cloud_infrastructure"],
        "essential_services": profile["auth_and_services"],
        "specialized_additions": profile["recommended_additions"],
        "identified_gaps": stack_gaps,
        "deployment_target": "Google Cloud Run (Containerized Microservice)",
    }


def generate_architecture_doc(
    project_title: str,
    domain: str,
    frontend_stack: str,
    backend_stack: str,
    database_choice: str,
    cloud_services: List[str],
    milestones: List[str],
) -> Dict[str, Any]:
    """
    Generate a concrete, production-grade project architecture specification
    and step-by-step milestone roadmap for a software engineer or student project.

    Args:
        project_title: Name of the proposed application or project.
        domain: Domain of application (e.g. 'Civic Tech in Buea Municipality').
        frontend_stack: Proposed client stack.
        backend_stack: Proposed backend stack.
        database_choice: Selected database engine.
        cloud_services: List of Google Cloud and third-party services.
        milestones: 4-step progressive implementation milestones.

    Returns:
        A structured JSON document containing architecture overview and roadmap.
    """
    services_rendered = "\n".join([f"- {s}" for s in cloud_services])
    milestones_rendered = "\n".join([f"{i+1}. **{m}**" for i, m in enumerate(milestones)])

    markdown_doc = f"""# {project_title} — Technical Architecture Specification

## 1. Executive Summary
- **Domain:** {domain}
- **Deployment Platform:** Google Cloud Run (Serverless Container)
- **Target Scale:** Scales from 0 to N instances on-demand

## 2. System Architecture
- **Client Application:** {frontend_stack}
- **API Microservice:** {backend_stack}
- **Persistence Layer:** {database_choice}
- **Cloud & Auxiliary Services:**
{services_rendered}

## 3. Implementation Roadmap
{milestones_rendered}

## 4. Google Cloud Deployment Checklist
1. Containerize the application using `Dockerfile` (optimized multi-stage build).
2. Authenticate to Google Artifact Registry.
3. Build and submit container image: `gcloud builds submit --tag europe-west1-docker.pkg.dev/$PROJECT_ID/io-extended-buea/{project_title.lower().replace(' ', '-')}:latest`.
4. Deploy to Cloud Run with Secret Manager: `gcloud run deploy --image ... --set-secrets=GEMINI_API_KEY=gemini-api-key:latest`.
"""

    return {
        "status": "success",
        "project_title": project_title,
        "domain": domain,
        "architecture_summary": {
            "frontend": frontend_stack,
            "backend": backend_stack,
            "database": database_choice,
            "cloud_services": cloud_services,
        },
        "milestones": milestones,
        "markdown_specification": markdown_doc.strip(),
    }

Step 3: The Gemini 1.5 Flash Agentic Core (agent.py)

Using the Google GenAI SDK (google-genai), we declare our Python functions directly as tools in GenerateContentConfig. Gemini 1.5 Flash evaluates the developer’s prompt and decides when to trigger the tools.

Create agent.py:

"""
Agent Core: Talent Navigator Agent powered by Gemini 1.5 Flash and Function Calling.
Uses the Google GenAI SDK to autonomously invoke domain tools and generate architectural blueprints.
"""

import os
from typing import Dict, Any, List
from dotenv import load_dotenv
from tools import search_tech_stack, generate_architecture_doc

load_dotenv()

# System prompt defining Persona and Operational Directives
SYSTEM_INSTRUCTION = """
You are the Silicon Mountain Talent Navigator Agent, an expert AI Solution Architect mentor 
assisting software engineering students and early-career developers in Buea, Cameroon.

When a developer shares their current skills and project interests:
1. Always analyze their current skills and target domain.
2. FIRST, call the `search_tech_stack` tool to discover complementary technologies, backend requirements, and cloud infrastructure.
3. SECOND, synthesize the findings and call the `generate_architecture_doc` tool with a concrete, customized 4-milestone plan.
4. Conclude with an inspiring, actionable message tailored to building and deploying on Google Cloud.
"""

def execute_agentic_loop(user_prompt: str) -> Dict[str, Any]:
    """
    Executes the Talent Navigator agentic loop with Gemini 1.5 Flash and Function Calling.
    """
    api_key = os.getenv("GEMINI_API_KEY")
    mock_mode = os.getenv("ENABLE_MOCK_MODE", "false").lower() in ["true", "1", "yes"]
    
    # Wi-Fi / Offline Fallback Contingency
    if mock_mode or not api_key or api_key.startswith("your_"):
        return _execute_mock_agent(user_prompt)

    try:
        from google import genai
        from google.genai import types

        client = genai.Client(
            api_key=api_key,
            http_options=types.HttpOptions(timeout=15000),
        )

        tools_list = [search_tech_stack, generate_architecture_doc]
        tool_map = {
            "search_tech_stack": search_tech_stack,
            "generate_architecture_doc": generate_architecture_doc,
        }

        response = client.models.generate_content(
            model="gemini-1.5-flash",
            contents=user_prompt,
            config=types.GenerateContentConfig(
                system_instruction=SYSTEM_INSTRUCTION,
                tools=tools_list,
                temperature=0.2,
                automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True)
            ),
        )

        tool_calls_record = []
        function_calls = response.function_calls or []
        executed_results = {}

        # If Gemini emitted tool calls, execute them deterministically
        if function_calls:
            for fc in function_calls:
                tool_name = fc.name
                tool_args = dict(fc.args) if fc.args else {}
                
                if tool_name in tool_map:
                    try:
                        tool_result = tool_map[tool_name](**tool_args)
                        executed_results[tool_name] = tool_result
                        tool_calls_record.append({
                            "tool_name": tool_name,
                            "args": tool_args,
                            "result": tool_result,
                        })
                    except Exception as tool_err:
                        tool_calls_record.append({
                            "tool_name": tool_name,
                            "args": tool_args,
                            "error": str(tool_err),
                        })

        # Synthesize final response text
        response_text = None
        if "generate_architecture_doc" in executed_results:
            arch = executed_results["generate_architecture_doc"]
            response_text = (
                f"### Talent Navigator Architecture Generated\n\n"
                f"{arch.get('markdown_specification', '')}"
            )
        elif hasattr(response, "text") and response.text:
            response_text = response.text
        else:
            detected_domain = "civic tech"
            if "search_tech_stack" in executed_results:
                detected_domain = executed_results["search_tech_stack"].get("matched_domain", "Civic tech").lower()
            
            project_title = f"{detected_domain.title()} Solution Portal"
            milestones = [
                "Phase 1: Build FastAPI microservice endpoints on local Docker environment.",
                "Phase 2: Integrate Firebase Auth and Firestore for real-time services.",
                "Phase 3: Connect Google Gemini 1.5 Flash API for automated intelligence.",
                "Phase 4: Deploy to Google Cloud Run via Artifact Registry with Secret Manager."
            ]
            arch_doc = generate_architecture_doc(
                project_title=project_title,
                domain=f"{detected_domain.title()} in Buea Ecosystem",
                frontend_stack="Flutter Mobile App + Tailwind Web",
                backend_stack="FastAPI Microservice (Python)",
                database_choice="Cloud SQL PostgreSQL or Firebase Firestore",
                cloud_services=["Google Cloud Run", "Secret Manager", "Artifact Registry"],
                milestones=milestones,
            )
            response_text = f"### Talent Navigator Architecture Generated\n\n{arch_doc['markdown_specification']}"
            tool_calls_record.append({
                "tool_name": "generate_architecture_doc",
                "args": {"project_title": project_title, "domain": detected_domain},
                "result": arch_doc,
            })

        return {
            "status": "success",
            "model": "gemini-1.5-flash",
            "prompt": user_prompt,
            "tool_calls_executed": tool_calls_record,
            "response_text": response_text,
            "mode": "live_gemini_api"
        }

    except Exception as e:
        return {
            "status": "partial_success",
            "mode": "deterministic_fallback",
            "error_note": f"API call failed ({str(e)}). Switched to deterministic agentic fallback.",
            **_execute_mock_agent(user_prompt)
        }


def _execute_mock_agent(user_prompt: str) -> Dict[str, Any]:
    """Deterministic fallback simulation for offline demos or unit testing."""
    lower_prompt = user_prompt.lower()
    
    detected_skills = []
    for skill in ["flutter", "react", "tailwind", "python", "fastapi", "django", "node", "firebase", "sql"]:
        if skill in lower_prompt:
            detected_skills.append(skill.capitalize())
    if not detected_skills:
        detected_skills = ["Flutter", "Tailwind CSS"]

    detected_domain = "civic tech"
    for domain in ["civic tech", "fintech", "agritech", "healthtech", "edtech"]:
        if domain in lower_prompt:
            detected_domain = domain
            break

    stack_result = search_tech_stack(interest_domain=detected_domain, current_skills=detected_skills)
    project_title = f"{detected_domain.title()} Citizen Portal"
    milestones = [
        "Phase 1: Build FastAPI microservice endpoints on local Docker environment.",
        "Phase 2: Integrate Firebase Auth and Firestore for real-time citizen reports.",
        "Phase 3: Connect Google Gemini 1.5 Flash API for automated issue classification.",
        "Phase 4: Deploy to Google Cloud Run via Artifact Registry with Secret Manager."
    ]

    arch_result = generate_architecture_doc(
        project_title=project_title,
        domain=f"{detected_domain.title()} in Buea Ecosystem",
        frontend_stack=" + ".join(detected_skills) if detected_skills else "Flutter Mobile App",
        backend_stack=stack_result["recommended_backend"],
        database_choice=stack_result["recommended_database"],
        cloud_services=[stack_result["recommended_cloud"]] + stack_result["essential_services"],
        milestones=milestones,
    )

    return {
        "status": "success",
        "model": "gemini-1.5-flash (local agentic simulation)",
        "prompt": user_prompt,
        "tool_calls_executed": [
            {"tool_name": "search_tech_stack", "args": {"interest_domain": detected_domain, "current_skills": detected_skills}, "result": stack_result},
            {"tool_name": "generate_architecture_doc", "args": {"project_title": project_title, "domain": detected_domain}, "result": arch_result}
        ],
        "response_text": (
            f"### Talent Navigator Architecture Generated\n\n"
            f"Based on your skills ({', '.join(detected_skills)}) and passion for **{detected_domain.title()}**, "
            f"here is your complete production roadmap ready to build and deploy to Google Cloud Run.\n\n"
            f"{arch_result['markdown_specification']}"
        ),
        "mode": "deterministic_fallback"
    }

Step 4: Exposing via FastAPI (main.py)

Create main.py with Pydantic request validation, CORS middleware, and automatic Swagger documentation:

"""
FastAPI Server for Talent Navigator Agent.
Provides RESTful APIs for developers and attendees to interact with the Agentic AI.
"""

import os
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from typing import List, Dict, Any, Optional
from agent import execute_agentic_loop

app = FastAPI(
    title="Talent Navigator Agent API",
    description="Google I/O Extended Silicon Mountain — Agentic AI with Gemini 1.5 Flash, FastAPI & Cloud Run",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
)

# Enable CORS for cross-origin browser requests during live demos
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


class NavigateRequest(BaseModel):
    prompt: str = Field(
        ...,
        description="Description of your current skills and project interests.",
        json_schema_extra={"example": "I know a bit of Flutter and Tailwind CSS, but I want to build something for civic tech in Buea."},
    )


class ToolCallRecord(BaseModel):
    tool_name: str
    args: Dict[str, Any]
    result: Optional[Dict[str, Any]] = None


class NavigateResponse(BaseModel):
    status: str
    model: str
    prompt: str
    tool_calls_executed: List[ToolCallRecord]
    response_text: Optional[str] = None
    mode: str


@app.get("/", tags=["Health"])
def root():
    return {
        "event": "Google I/O Extended Silicon Mountain",
        "app": "Talent Navigator Agent",
        "status": "online",
        "docs": "/docs",
        "endpoints": {
            "health": "/health",
            "navigate": "/api/navigate (POST)"
        }
    }


@app.get("/health", tags=["Health"])
def health_check():
    has_api_key = bool(os.getenv("GEMINI_API_KEY"))
    return {
        "status": "healthy",
        "gemini_api_configured": has_api_key,
        "environment": os.getenv("ENVIRONMENT", "production")
    }


@app.post("/api/navigate", response_model=NavigateResponse, tags=["Agent"])
def navigate_talent(request: NavigateRequest):
    if not request.prompt or len(request.prompt.strip()) < 5:
        raise HTTPException(
            status_code=400,
            detail="Please provide a valid prompt describing your skills and domain interest."
        )

    result = execute_agentic_loop(request.prompt)
    return result


if __name__ == "__main__":
    import uvicorn
    port = int(os.environ.get("PORT", 8080))
    host = os.environ.get("HOST", "0.0.0.0")
    print(f"🚀 Starting Talent Navigator Agent on http://{host}:{port}")
    uvicorn.run("main:app", host=host, port=port, reload=True)

Test it locally:

python main.py

Open http://localhost:8080/docs to see the interactive Swagger UI.


Step 5: Containerization with Docker (Dockerfile)

Google Cloud Run is container-native. Create an optimized Dockerfile:

# Use lightweight official Python image
FROM python:3.11-slim

# Prevent Python from writing .pyc files & buffer stdout/stderr
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PORT=8080

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Copy and install python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application source code
COPY . .

# Expose standard Cloud Run port
EXPOSE 8080

# Run FastAPI with Uvicorn bound to Cloud Run PORT environment variable
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port ${PORT:-8080}"]

Create a .dockerignore to keep image builds lean:

__pycache__
*.pyc
env/
venv/
.venv/
.env
.git
.DS_Store

☁️ Part 3: Google Cloud Run Deployment

Google Cloud Run is the premier platform for students and startups in Africa because it scales down to 0 instances when inactive, meaning $0 hosting fees on the Google Cloud Free Tier.

flowchart LR
    A["Local Codebase / Git"] -->|"1. gcloud builds submit"| B["Google Cloud Build"]
    B -->|"2. Stores Image"| C["Google Artifact Registry"]
    C -->|"3. Deploys Container"| D["Google Cloud Run<br/>(Scales 0 → N)"]
    E["Secret Manager<br/>(GEMINI_API_KEY)"] -.->|"Injected securely"| D
    D -->|"HTTPS Endpoint"| F["Mobile & Web Clients"]

The 1-Click Deployment Script (deploy.sh)

#!/bin/bash
set -e

PROJECT_ID=$(gcloud config get-value project 2>/dev/null)
REGION="europe-west1" # Or us-central1
SERVICE_NAME="talent-navigator-agent"
REPO_NAME="io-extended-buea"
IMAGE_NAME="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${SERVICE_NAME}:latest"

echo "🚀 Deploying Talent Navigator Agent to Google Cloud Run..."

# 1. Enable APIs
gcloud services enable \
    run.googleapis.com \
    artifactregistry.googleapis.com \
    cloudbuild.googleapis.com \
    secretmanager.googleapis.com

# 2. Create Artifact Registry Repo
gcloud artifacts repositories create ${REPO_NAME} \
    --repository-format=docker \
    --location=${REGION} \
    --description="Docker repo for I/O Extended" \
    2>/dev/null || echo "Repository exists."

# 3. Build & Submit Container with Cloud Build (Bypasses local Docker & conference Wi-Fi bottlenecks)
gcloud builds submit --tag ${IMAGE_NAME} .

# 4. Ensure Secret Access & Deploy to Cloud Run
if gcloud secrets describe gemini-api-key &>/dev/null; then
    echo "🔒 Ensuring Secret Accessor permission for Cloud Run service account..."
    PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format='value(projectNumber)' 2>/dev/null || echo "")
    if [ -n "$PROJECT_NUMBER" ]; then
        gcloud secrets add-iam-policy-binding gemini-api-key \
            --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
            --role="roles/secretmanager.secretAccessor" &>/dev/null || true
    fi

    gcloud run deploy ${SERVICE_NAME} \
        --image ${IMAGE_NAME} \
        --platform managed \
        --region ${REGION} \
        --allow-unauthenticated \
        --set-secrets=GEMINI_API_KEY=gemini-api-key:latest \
        --min-instances=0 \
        --max-instances=5 \
        --memory=512Mi \
        --cpu=1
else
    echo "⚠️ Secret 'gemini-api-key' not found. Deploying with mock fallback capability."
    gcloud run deploy ${SERVICE_NAME} \
        --image ${IMAGE_NAME} \
        --platform managed \
        --region ${REGION} \
        --allow-unauthenticated \
        --min-instances=0 \
        --max-instances=5 \
        --memory=512Mi \
        --cpu=1
fi

SERVICE_URL=$(gcloud run services describe ${SERVICE_NAME} --platform managed --region ${REGION} --format 'value(status.url)')
echo "🎉 Deployed Successfully! Live URL: ${SERVICE_URL}"
# 1. Set Google Cloud Project & Region Variables
export PROJECT_ID=$(gcloud config get-value project)
export REGION="europe-west1"
export REPO_NAME="io-extended-buea"
export SERVICE_NAME="talent-navigator-agent"

# 2. Enable Required Cloud APIs
gcloud services enable run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com

# 3. Store API Key in Secret Manager & Grant Access
echo -n "YOUR_GEMINI_API_KEY" | gcloud secrets create gemini-api-key --data-file=- 2>/dev/null || \
echo -n "YOUR_GEMINI_API_KEY" | gcloud secrets versions add gemini-api-key --data-file=-

PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format='value(projectNumber)')
gcloud secrets add-iam-policy-binding gemini-api-key \
    --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
    --role="roles/secretmanager.secretAccessor"

# 4. Create Artifact Registry Repository (Modern Docker Registry)
gcloud artifacts repositories create ${REPO_NAME} \
    --repository-format=docker \
    --location=${REGION} \
    --description="Docker repository for I/O Extended Buea" 2>/dev/null || true

# 5. Build & Push via Cloud Build (No local Docker daemon required!)
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${SERVICE_NAME}:latest .

# 6. Deploy Container to Cloud Run (Scales to 0)
gcloud run deploy ${SERVICE_NAME} \
  --image ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${SERVICE_NAME}:latest \
  --platform managed \
  --region ${REGION} \
  --allow-unauthenticated \
  --set-secrets=GEMINI_API_KEY=gemini-api-key:latest \
  --min-instances=0 \
  --memory=512Mi \
  --cpu=1
Tip💰 Google Cloud Free Tier & Budget Safety for Students & Startups
  • Cloud Run Scale-to-Zero: When no requests are arriving, instance count drops to 0. You pay $0.00 for idle time.
  • Monthly Free Tier Allowance: Google Cloud Run includes 2 million free requests and 360,000 GB-seconds of vCPU/memory per month.
  • Google AI Studio (Gemini 1.5 Flash): Generous free RPM quotas allow you to build, test, and demo without entering credit card billing credentials.

🧪 Part 4: Live Testing & Verification

Once deployed, test your live Cloud Run endpoint from terminal, Postman, or Python:

curl -X POST "https://YOUR-CLOUD-RUN-URL.run.app/api/navigate" \
     -H "Content-Type: application/json" \
     -d '{
       "prompt": "I know a bit of Flutter and Tailwind CSS, but I want to build something for civic tech in Buea."
     }'
import requests

url = "https://YOUR-CLOUD-RUN-URL.run.app/api/navigate"
payload = {
    "prompt": "I have experience with Python and SQL, and I want to build an MTN MoMo automated reconciliation engine."
}

res = requests.post(url, json=payload)
print(res.json())
{
  "status": "success",
  "model": "gemini-1.5-flash",
  "prompt": "I know a bit of Flutter and Tailwind CSS, but I want to build something for civic tech in Buea.",
  "tool_calls_executed": [
    {
      "tool_name": "search_tech_stack",
      "args": {
        "interest_domain": "civic tech",
        "current_skills": ["Flutter", "Tailwind CSS"]
      },
      "result": {
        "matched_domain": "Civic tech",
        "recommended_backend": "FastAPI (Python) or Express (Node.js)",
        "recommended_database": "Cloud SQL (PostgreSQL) or Firebase Firestore",
        "recommended_cloud": "Google Cloud Run + Secret Manager",
        "essential_services": ["Firebase Auth", "Cloud Storage for documents", "SMS/WhatsApp Alerts (Twilio/Infobip)"]
      }
    },
    {
      "tool_name": "generate_architecture_doc",
      "args": {
        "project_title": "Civic Tech Citizen Portal",
        "domain": "Civic Tech in Buea"
      },
      "result": {
        "status": "success",
        "project_title": "Civic Tech Citizen Portal"
      }
    }
  ],
  "response_text": "### Talent Navigator Architecture Generated\n\n# Civic Tech Citizen Portal — Technical Architecture Specification...",
  "mode": "live_gemini_api"
}

🛡️ Presenter “Wi-Fi Proof” & Troubleshooting Playbook

In live conference settings where venue Wi-Fi may become congested, keep these strategies ready:

Important📶 3 Contingencies for Live Demo Success
  1. Pre-Deployed Fallback Cloud Run Service: Have your live Cloud Run URL already deployed and open in Postman or browser tabs before stepping on stage.
  2. Use Cloud Build Instead of Local Docker Push: Never push a 400MB Docker image over conference Wi-Fi. Running gcloud builds submit sends only raw source files (~50KB) to Google Cloud, which builds and pushes the image on Google’s gigabit backbone.
  3. Built-In Local Agentic Mock: The codebase automatically falls back to _execute_mock_agent if the API key is not set or network fails, displaying identical tool-calling sequence results without a single dropped beat during the presentation.

🚀 Final-Year Project Ideas for Silicon Mountain Attendees

Encourage attendees to take this exact agentic blueprint and adapt it for their final-year projects, hackathons, or startup MVPs:

  1. MTN/Orange MoMo Agentic Reconciler (FinTech):
    • Tools: Parse PDF/SMS bank statements -> Fetch Mobile Money API transactions -> Detect mismatched balances -> Dispatch WhatsApp alert.
  2. Buea Municipal Citizen Reporting Agent (Civic Tech):
    • Tools: Geocode incident report -> Classify waste/road repair category via Gemini Vision -> Route to municipal council department.
  3. Bilingual Agro-Market Intelligence Agent (AgriTech):
    • Tools: Scrape regional food market prices -> Translate French/English/Pidgin queries -> Provide fertilizer & planting schedules.
  4. Offline-First Health Triage Navigator (HealthTech):
    • Tools: Symptom intake -> Evaluate urgency score -> Locate nearest on-call pharmacy or clinic in Fako Division.

🛠️ Level 2: Next Steps & Agent Architecture Extensions

For attendees aiming to scale this into a full product or submission for Google solution challenges:

  1. Persistent Memory & Session History:
    • Connect Google Cloud Firestore to preserve user context across multi-turn coaching sessions.
  2. Streaming Real-Time Responses:
    • Utilize FastAPI StreamingResponse with Server-Sent Events (SSE) so users see tool execution and markdown generated token-by-token.
  3. Multimodal Inputs:
    • Use Gemini 1.5 Flash’s multimodal vision capabilities to let students take photos of whiteboards, diagrams, or syllabi and generate blueprints directly.
  4. Interactive Client Frontends:
    • Build a cross-platform mobile client with Flutter or web app with React + Tailwind that hits your deployed Cloud Run /api/navigate endpoint.

🎁 Speaker Handoff & Resources

Note🔗 Shareable Links for Attendees