Inspiration

Modern fintech needs AI that can be added safely and incrementally—without risky rewrites. Our goal was to evolve Bank of Anthos into a proactive system by adding an agentic AI layer strictly via APIs, keeping the core microservices untouched. GKE provides the platform; Vertex AI Gemini provides reasoning and explanation.

Why Pivot?

The transactionhistory controller exposes GET /transactions/{accountId} and requires a valid JWT authorising that specific account. There is no endpoint to fetch all users’ transactions. A global fraud bot isn’t possible without modifying BoA (against hackathon rules). Solution: a scoped Personal Financial Advisor that acts on behalf of one user (the demo user) with a valid JWT.

What it does

  • Spending Analyst — categorises and summarises transaction patterns and trends
  • Fraud Scout(scoped) — flags anomalies for the demo user with transparent rationales and confidence
  • Budget Coach — generates personalised budgets and savings nudges for the demo user
  • Multi-agent orchestration — agents cross-review and reach consensus before user-visible actions

How we built it

  • Base: Bank of Anthos deployed unchanged on GKE (Autopilot)
  • PFA agents: containerised Python/FastAPI services calling BoA public APIs only
  • MCP Server: the only bridge to BoA; it manages JWT + calls per-account endpoints (/transactions/{accountId}, balances, etc.)
  • AI: Vertex AI Gemini for reasoning, summarisation, and explanations
  • Orchestration: ADK/MCP/A2A for agent tasking, debate, and consensus
  • Data path: async event consumers for transaction streams; idempotent jobs; backpressure controls
  • Infra/IaC: Terraform for cluster add-ons; Cloud Build → Artifact Registry → GKE
  • Security: Workload Identity, least-privilege service accounts, Secrets/ConfigMaps
  • Reliability: HPA, readiness/liveness probes, target SLO p95 insight latency ≤ 300 ms @ 10 rps; error-budget alerts
  • Observability: OpenTelemetry/Prometheus metrics, structured logs, trace IDs, dashboards & alerts

Challenges we ran into

  • BoA APIs are per-account + JWT-protected; no global “read everything” feed
  • Designing narrow agent roles that remain explainable and safe within a single user’s scope
  • Delivering meaningful features while remaining API-only (no core code changes)
  • Balancing latency when combining BoA calls and LLM reasoning

Accomplishments that we're proud of

  • A drop-in agentic layer that cleanly extends BoA via APIs (no risky rewrites)
  • Consensus workflows that reduce false positives and improve trust
  • Reproducible GKE manifests + CI path, service-mesh-friendly if needed later

What we learned

  • Guardrails and role clarity keep agents safe, predictable, and explainable
  • API-first integration is the lowest-risk path for modernising microservices with AI
  • Practical cost/latency trade-offs for Gemini in near-real-time workflows

What's next for Agentic Anthos: AI Advisor for Bank of Anthos

  • Add Investment Advisor and Credit Optimiser agents
  • Real-time anomaly detection over streams; goal tracking
  • Publish a deep-dive blog and open-source a Helm chart

Architecture diagram


flowchart LR
  subgraph GKE[Google Kubernetes Engine (Autopilot)]
    subgraph BoA[Bank of Anthos (unchanged)]
      UI[Web UI]
      ACC[Accounts Service]
      TXN[Transaction History Service]
      LED[Ledger Service]
      NOTIF[Notifier Service]
      USR[User Service (JWT login)]
    end

    subgraph Agentic[Agentic Layer (new, per-demo-user scope)]
      MCP[MCP Server (JWT manager + BoA proxy)]
      PFA[Personal Financial Advisor (FastAPI)]
      SA[Spending Analyst]
      FS[Fraud Scout]
      BC[Budget Coach]
    end
  end

  VTX[Vertex AI Gemini]

  %% Flows
  PFA -->|internal HTTP| SA
  PFA -->|internal HTTP| FS
  PFA -->|internal HTTP| BC
  SA --> VTX
  FS --> VTX
  BC --> VTX

  %% MCP ↔ BoA
  PFA -->|GET /mcp/transactions?accountId=...| MCP
  MCP -->|GET /transactions/{accountId} + JWT| TXN
  PFA -->|GET /mcp/balance?accountId=...| MCP
  MCP --> ACC
  MCP --> LED
  MCP --> USR

  %% Optional notify path (no core changes)
  PFA -->|POST /notify (existing endpoint)| NOTIF

  %% UI remains unchanged
  UI <-->|existing routes| BoA

Built With

  • a2a
  • adk
  • artifact-registry
  • bank-of-anthos-apis
  • cloud-build
  • configmaps
  • docker
  • fastapi
  • gke
  • kubernetes-yaml
  • mcp
  • opentelemetry
  • prometheus
  • python
  • secret
  • terraform
  • vertex-ai-gemini
  • workload-identity
Share this project:

Updates

Private user

Private user posted an update

Highlights

  • AI backend migrated from Flask + deprecated vertexai.generative_modelsFastAPI + google-genai SDK (Gemini 2.5 Pro).
  • Reliability/Throughput: per-pod RPM throttle, semaphore concurrency, truncated exponential backoff with jitter + Retry-After.
  • K8s hardening: clean base/overlays, proper probes, WI bootstrap for Vertex, and FinOps autoscaling.
  • UI fixed: rebuilt/published budget-coach-ui v0.1.1, corrected in-cluster service ports, and aligned with new /api/* backend.
  • Smokes green end-to-end: core, data, e2e, fraud, spending, coach all pass.

What changed

Backend (insight-agent)

  • New FastAPI app (src/ai/insight-agent/main_vertex.py) with endpoints:

    • POST /api/budget/coach
    • POST /api/spending/analyze
    • POST /api/fraud/detect
    • GET /api/healthz
  • Switched to google-genai client (Vertex mode), model: gemini-2.5-pro.

  • JSON-schema responses + ThinkingConfig budgets; deterministic (temperature=0.0).

  • DSQ-friendly controls via env:

    • GENAI_CONCURRENCY, GENAI_RPM, GENAI_MAX_TOKENS, GENAI_THINK_TOKENS.

Kubernetes

  • Service ports standardized: cluster port 80 → container 8080 (both mcp-server and insight-agent).
  • Dev overlay sets Vertex/env knobs; Vertex Dockerfile runs uvicorn.
  • Added HPA/VPA (Autopilot) manifests under kubernetes-manifests/finops/.

FinOps

  • Cloud Logging cost cut via exclusion filter on _Default sink.
  • Enabled Vertical Pod Autoscaling on cluster.
  • Added HPA/VPA for all app agents (userservice, transactionhistory, frontend, mcp-server, agent-gateway, insight-agent, etc.).
  • Insight-agent HPA set to minReplicas: 1 (keeps latency predictable for demos).

UI (Streamlit)

  • Image rebuilt & pushed: .../budget-coach-ui:v0.1.1.
  • Fixed stale deployment (judges overlay) & set envs:

    • INSIGHT=http://insight-agent/api
    • USERSVC=http://userservice:8080
    • Port fix: MCPSVC=http://mcp-server (service on 80; no :8080).
  • UI now transforms BoA txns to {date,label,amount} before POSTing to the new FastAPI APIs.

Validation

  • make smoke-fast and make smoke-e2e passed:

    • Fraud: high-quality structured findings with SAR recommendations.
    • Spending: top categories + unusual count.
    • Coach: budget summary + buckets + tips.
  • Manual UI checks confirm end-to-end flow after env + port fix.

Notables / Footguns avoided

  • 422 Unprocessable Entity earlier was due to stale UI posting old timestamp shape; fixed by deploying v0.1.1 UI.
  • ConnectTimeout came from calling http://mcp-server:8080 (service listens on 80). Env corrected.

Paths you’ll see in the repo

  • Backend: src/ai/insight-agent/* (FastAPI, prompts, Dockerfiles, k8s overlays)
  • UI: ui/* (Streamlit app, Dockerfile, overlays)
  • FinOps: kubernetes-manifests/finops/* (HPA/VPA)
  • Make targets: deploy, smoke, WI bootstrap, image pinning.

Quick commands (for reference)

# Update UI env to correct ports/paths
kubectl -n default set env deploy/budget-coach-ui \
  INSIGHT=http://insight-agent/api \
  USERSVC=http://userservice:8080 \
  MCPSVC=http://mcp-server

# Re-deploy judges UI overlay
make ui-judges-apply

Log in or sign up for Devpost to join the conversation.

Private user

Private user posted an update

Submission Updates — Budget Coach UI (Dev / Judges / Prod)

What changed (and why)

  • Single image placeholder in base ui/k8s/base/deployment.yaml uses image: REPLACE_ME_UI_IMAGE. Overlays swap this to a concrete image (tag for Dev/Judges, digest for Prod). Why: avoids “InvalidImageName” races and makes overlays deterministic.

  • Environment variables standardized UI reads in-cluster endpoints via env:

    • USERSVC=http://userservice.default.svc.cluster.local:8080
    • MCPSVC=http://mcp-server.default.svc.cluster.local:80
    • INSIGHT=http://insight-agent.default.svc.cluster.local:80/api
    • ACCOUNT=1011226111
    • WINDOW_DAYS=30 Why: names match the Streamlit app, kills 404s from wrong base paths.
  • Overlays by purpose

    • Development: tag-based image for quick iteration.
    • Judges: same tag + a LoadBalancer service for external access.
    • Production: digest-pinned image for immutability & rollbacks.

Tag vs Digest (quick guide)

  • Tag (:v0.1.0) – mutable pointer; great for Dev/Judges. Pros: fast swaps, simple mental model. Cons: can drift; rollouts may pick unexpected bits if tag is moved.

  • Digest (@sha256:…) – immutable; the exact bytes you tested. Pros: reproducible, safe, audit-friendly, ideal for Prod. Cons: one more step to resolve the digest.

How to deploy

0) Set shared env once (terminal)

export PROJECT=<PROJECT-ID>
export REGION=us-central1
export REG="${REGION}-docker.pkg.dev/${PROJECT}/bank-of-anthos-repo"

1) Development (tag-based)

# Pin the dev overlay to a tag (already in repo, but repeatable)
(cd ui/k8s/overlays/development && \
  kustomize edit set image REPLACE_ME_UI_IMAGE=${REG}/budget-coach-ui:v0.1.0)

# Apply + verify
make ui-dev-apply
make ui-dev-status
make ui-dev-smoke   # quick POST to /api/budget/coach (expects 200/400 JSON)

2) Judges (public LB + tag-based)

# Apply + get the external IP + tail logs
make ui-judges-apply
make ui-judges-ip
make ui-judges-logs
# Open:  http://$(make ui-judges-ip)

3) Production (digest-pinned)

A. Resolve digest for a tag (or skip if you already have it):

UI_TAG=v0.1.0
UI_IMAGE_DIGEST=$(gcloud artifacts docker images describe \
  "$REG/budget-coach-ui:${UI_TAG}" \
  --project "$PROJECT" --format='value(image_summary.digest)')
echo "$UI_IMAGE_DIGEST"

B. Bake the digest into the prod overlay and apply:

make ui-prod-set-digest   # writes @sha256:… into ui/k8s/overlays/production
make ui-prod-apply
make ui-prod-verify

Expected verification output includes:

  • Deployment image like:
  .../budget-coach-ui@sha256:059630b47e...
  • Pod env snapshot showing USERSVC, MCPSVC, INSIGHT, ACCOUNT, WINDOW_DAYS.

Smoke tests (what “good” looks like)

  • UI logs show endpoints and Streamlit URL
  URL: http://0.0.0.0:8501
  INFO:budget-coach:USERSVC=...
  INFO:budget-coach:MCPSVC=...
  INFO:budget-coach:INSIGHT=.../api
  • Agent POST returns JSON (400 is fine with minimal body):
  kubectl run curl --rm -it --restart=Never --image=curlimages/curl:8.7.1 -- \
    sh -lc "curl -sS -D- -X POST -H 'Content-Type: application/json' \
    -d '{\"transactions\":[]}' \
    http://insight-agent.default.svc.cluster.local/api/budget/coach | head -n 20"

Troubleshooting quick checks

  • Wrong image picked up / duplicate RS
  kubectl get rs -l app=budget-coach-ui \
    -o 'custom-columns=NAME:.metadata.name,IMAGE:.spec.template.spec.containers[0].image'
  # delete old RS if needed
  kubectl delete rs <old-rs>
  • Env not updated after patch
  kubectl rollout restart deploy/budget-coach-ui
  POD=$(kubectl get pods -l app=budget-coach-ui -o jsonpath='{.items[-1:].metadata.name}')
  kubectl exec "$POD" -- printenv | egrep '^(USERSVC|MCPSVC|INSIGHT|ACCOUNT|WINDOW_DAYS)='
  • LB IP shows but UI blank

    • Ensure budget-coach-ui-lb targets port:80 -> targetPort:8501
    • Endpoints point at the Running UI pod IP on port 8501.

Log in or sign up for Devpost to join the conversation.