Architecture, data, and what it took to ship — from the four-agent SequentialAgent down to the partition keys on the BigQuery table.
NetPulse AI is a multi-agent telecom operations assistant built for the APAC GenAI Academy 2026 hackathon. A natural-language complaint goes in; a structured incident ticket comes out — complete with the related network events the operator should know about, the CDR findings that back up the customer’s account of what happened, and a recommended NOC action plan.
The core ADK package telecom_ops exposes a
SequentialAgent that runs four LlmAgent sub-agents
in order: classifier, network investigator, CDR analyzer, response
formatter. Each one reads the shared session state, queries its data
store through the MCP toolbox, and enriches the state for the next.
The fourth writes a structured ticket to AlloyDB and the run ends.
The four steps have strict data dependencies — the network
investigator can’t run until the classifier has tagged a region; the CDR
analyzer joins on the time window the network investigator returned;
the formatter needs all three to write a coherent ticket. A
SequentialAgent models this as code rather than encoding it
into a prompt, so the dependency stays correct under prompt churn.
Direct BigQuery MCP endpoints returned 403 / connection-closed on Cloud Run during early integration. The toolbox-as-intermediary pattern works reliably and gives one place to evolve tool definitions without redeploying the agent service.
All-BigQuery makes ticket writes/updates painful — no transactions, latency wrong for an interactive UI. All-AlloyDB makes event scans expensive, forces scaling decisions for telemetry that doesn’t need a relational store, and loses the cheap historical depth. Showing two services used for the right reasons mirrors how telecom ops actually splits analytical investigation from operational record-keeping.
open → investigating → resolved). BigQuery is the wrong tool for mutable rows.The complete list of moving parts. Everything is Google Cloud (the hackathon track requires it); the LLM-side work is Vertex AI Gemini.
output_key handoffs.gemini-3.1-flash-lite-preview at the global endpoint, with a 4-attempt model ladder failing over via gemini-3-flash-preview to gemini-2.5-flash under quota pressure.network_events table — DAY-partitioned on started_at, clustered by (region, severity). 50,000 events across 10 metros, 6-month rolling window.call_records served in two tiers: parameterized SQL primary (query_cdr_summary, query_cdr_worst_towers) executes in <2s; query_cdr_nl is the AlloyDB AI NL2SQL fallback for off-script free-form prompts. A structurally read-only role executes either path.incident_tickets — append-only writes via the native ADK tool save_incident_ticket. Connection pool refreshed every 5 minutes to dodge silent-death sockets.telecom_network_toolset) plus three CDR tools on AlloyDB (cdr_toolset: 2 parameterized SQL + 1 NL2SQL fallback) live in a separate Cloud Run service. Agents reach the data via the toolbox; the toolbox reaches the warehouses via service accounts.netpulse-ui wraps the same root_agent in a hero landing + workspace timeline. Each request runs its own asyncio loop in a worker thread; events stream out incrementally via Server-Sent Events.netpulse-ui serves the chat surface; network-toolbox hosts the MCP toolbox. Both built from a Dockerfile in the project root, deployed from main.Three data surfaces feed the run. Each viewer page describes its schema and filter dimensions in detail.
NetPulse AI ships with seed data for ten Indonesian metros. Adapting to a different telecom dataset is a three-step exercise:
docs/seed-data/ with your own network_events.csv and call_records.csv. Keep the column shapes intact — see network events schema and call records schema for column-by-column descriptions.scripts/setup_bigquery.py --seed --recreate to drop and rebuild the BQ table with your data, then scripts/setup_alloydb.py --seed to load CDRs into AlloyDB. The --recreate flag is destructive but is the only way to reapply the partition + cluster spec.telecom_ops/tools.py (VALID_REGIONS) and the toolbox config in tools.yaml if your cities diverge from the Indonesian-metro defaults. The agents will pick up the new vocabulary on next deploy.The agents themselves are dataset-agnostic — what changes is the
data, the region whitelist, and the natural-language prompt examples in
tools.yaml that ground AlloyDB AI’s NL-to-SQL translation.
NetPulse AI was built through a series of timeboxed phases. Each phase landed in a single PR (in most cases) and was visually verified end-to-end before the next began.
The hackathon scope is a refined prototype, not a product. These are the next directions if the project continues past 2026-04-30.