RAG for the fuzzy questions, a deterministic CLI for the exact ones
A telecom's operational memory lives in its ticketing system. Ours is IBM Maximo: every trouble ticket, every fibre cut, every site visit. The questions people ask of it fall into two very different shapes — and the interesting engineering decision was to answer them with two different tools.
Two kinds of question
- "Were there similar outages on this route last winter? What usually causes flapping at that PoP?" — fuzzy, semantic, judgement questions.
- "How many trouble tickets in March? List the open ones for Ukraine." — exact, countable questions.
The mistake would be to throw both at a language model. An LLM is great at the first kind and quietly unreliable at the second — ask it to count and it will confidently give you a number that's almost right. So the toolkit splits them:
- RAG (Onyx).
maximo_sync.pylogs into Maximo (read-only), pages the ticket object structure, turns each ticket into a text document plus aggregate "digest" docs, and upserts them into a local Onyx index. Now the fuzzy questions can be asked in natural language. The sync is idempotent (hash manifest) so it's safe under cron. - A deterministic CLI.
maximo_stats.pyanswers the countable questions by querying Maximo directly —--year,--month,--type,--status,--list,--json. No model in the loop, no hallucinated totals. It's the boring, correct counterpart to the RAG.
That separation — LLM for meaning, code for arithmetic — is the whole idea.
Around the edges
- A status dashboard. An hourly snapshot is built per country and rsynced to a web host; a small PHP dashboard renders it, including a PoP map (Leaflet) and a heuristic analytics block — MTTR/SLA proxies, equipment mentions, fibre-cut hotspots. The analytics are deliberately approximate and labelled as such.
- A Telegram watcher. It tails active trouble tickets for a location and pings me on new/closed events, with an hourly consolidated digest of what's still open.
Built to be safe and portable
Everything is read-only against Maximo — GET requests only, a read-only
account, nothing that can change a ticket. The Python tools use the standard
library only, no third-party packages, so they drop onto any box with Python
and run. And nothing deployment-specific is baked in: endpoints, credentials and
scope all come from env files (chmod 600, outside the repo), while the
reference data shipped in the repo is small synthetic samples — real exports,
credentials and snapshots are gitignored.
It's a small toolkit, but it captures a principle I keep coming back to: a language model is a fantastic interface to your data and a terrible source of truth. Let it handle the questions that are really about meaning, and keep a deterministic path for everything that has to be correct.
Transparency: most posts here are drafted with AI assistance, and the non-English versions are machine-translated by a local LLM and then reviewed. Spotted an error? Please let me know.