AI systems that survive contact with production.

Anyone can call a model. The engineering is in what happens when the call fails, when the quota runs out, when the bill arrives, and when the answer has to be right. This page documents the constraints I've built against and the decisions that came out of them — written for people making the same calls.

7
Systems shipped with LLM components
4
Model providers behind one interface
14,000+
Graph records built from live news
~50%
Inference cost removed by batching

The work.

Four systems, and the constraint that shaped each one.

Rippli

Production Financial Intelligence

A platform that maps how a single news event ripples across global markets — entity extraction, relationship mapping, and sentiment over a live financial knowledge graph. Live at app.rippli.ai.

  • Replaced local models with an LLM, without breaking the system. Entity extraction and sentiment moved off self-hosted FinBERT and spaCy onto Claude Haiku. I kept the original method signatures and dataclasses intact, so every downstream consumer kept working through the migration.
  • Parallelised inference to hold a hard latency budget. Serial per-article calls took ~22s — over the pipeline's 12s Phase 1 timeout. Fanning the batch out across a thread pool brought it to ~7–8s and put the stage back inside budget.
  • RAG grounded in the production database, not a vector store bolt-on. Before the model sees a query, a context service pulls company profiles, persisted relationships, historical mention context, key executives, SEC financial metrics, and category assignments out of PostgreSQL. The context budget is deliberate and measured: ~2–5KB per ticker, ~75KB for a 15-company query.
  • Progressive enhancement so users aren't waiting on the slow path. A fast LLM pass returns a usable answer immediately; an AI-search enrichment pass upgrades the result in place when it lands. The response carries its own analysis tier (fast / hybrid / enhanced) and confidence score.
  • Provider abstraction with a real degradation path. Anthropic, OpenAI, and Gemini sit behind one search-provider interface, auto-selected from environment. When no keys are configured, a no-op fallback provider returns empty results gracefully — a misconfigured deploy degrades instead of crashing.
  • Knowledge graph built from unstructured news. 14,000+ companies, executives, and relationships in Neo4j, discovered from live articles via NLP rather than hand-curated — plus LLM-classified signal duration (SHORT / MEDIUM / STRUCTURAL) so a one-day headline isn't scored like a structural shift.
Claude Gemini Python 3.11 Flask 3 PostgreSQL 15 Neo4j 5.15 Redis 7 Celery Next.js 16 Docker

Impact OS

Production Admissions & Behavioural Scoring

The engine behind Cycle28's participant programmes. It decides who enters a 90-day programme that carries real money — stipends, data support, mentorship — so the scoring has to be defensible, not just clever. Primary KPI: verified income earned before day 90.

  • The problem: everyone now writes like a consultant. Development programmes across the continent screen applicants on written English. Since generative models became universal, that filter selects for access to a chatbot, not readiness. The same profile of applicant kept qualifying, and the people the programme existed for kept missing out.
  • Score readiness, not polish. Intake runs four diagnostic probes — action orientation, market awareness, rejection resilience, and commitment signal — through scenario-based questions with no correct-sounding answer to copy. Each probe scores 0–1 into a composite readiness score with risk flags and an ADMIT / WAITLIST / REJECT recommendation.
  • The Skill Triad. Capability is assessed across three dimensions — technical, commercial, and soft — because each one alone produces a predictable failure: a specialist who can't earn, a hustler with nothing to sell, or someone likeable with nothing to offer. Imbalance is surfaced explicitly, and graduation requires a threshold on all three.
  • Hard limits on what the model may decide. The AI classifies, tags failure types, personalises missions, and flags disengagement. It is explicitly forbidden from motivating emotionally, overriding rules, making exceptions, or deciding graduation — income is the only proof. The model is a referee, not a judge.
  • Degrades to rules, never to nothing. With no API key configured the service logs a warning and falls back to deterministic rule-based scoring. An intake cohort is never blocked because a provider is down.
Claude NestJS Prisma PostgreSQL Next.js Rules engine

Krawl

Production Inference & Extraction Infrastructure

The ingestion and extraction engine underneath Rippli — a resilient content pipeline that pulls full-text articles and filings from primary sources, then runs LLM extraction over them at scale. This is where the cost and quota engineering lives.

  • Self-hosted inference gateway. I built a FastAPI service that fronts Ollama running on a GPU machine, adding API-key auth, per-client rate limiting, request batching, and clean extract / summarize / classify endpoints. Bulk extraction runs against hardware I control instead of metered API tokens.
  • Batch inference for a ~50% cost reduction. I wrote a Gemini Batch Mode client directly against the REST API rather than pulling in another SDK. Batch processing carries no per-minute rate limit, so a universe-scale extraction can't 429 and deplete credits mid-run the way the synchronous lane did.
  • Failure is the default assumption. The batch control plane is rate-limited, so uploads and batch creates retry with exponential backoff on 429 / 500 / 503. Response parsing digs defensively for state and output fields because their location shifts between API revisions.
  • Model fallback chains via litellm. Extraction runs gemini-2.5-flash as primary with flash-lite and Groq behind it. Every call carries a hard timeout ceiling so a hung request can't stall the ingestion loop that awaits it.
  • Vision extraction where text parsing gives up. A minority of congressional disclosure filings are image scans with no extractable text. I render those pages to PNGs with pypdfium2 and ask a vision model for the trade rows — returning the exact dict schema the text parser returns, so nothing downstream can tell which path produced the data.
  • Quota governance across competing workloads. Vision calls and knowledge-graph extraction draw on the same provider quota, so the vision path is gated behind environment flags and per-cycle caps. Every function fails soft — a quota 429 or an unreadable scan logs and returns empty rather than breaking ingestion.
litellm Gemini Batch API Groq Ollama Vision / OCR FastAPI Playwright PostgreSQL Docker Compose

SEO Engine

Production Multi-Tenant LLM Pipeline

A multi-workspace content pipeline where each workspace is a separate site with its own niche, voice, sources, and article store — and content never crosses workspace boundaries.

  • The cheapest token is the one you never send. Topic signals are collected from Reddit, Hacker News, and Google Trends, then filtered by deterministic scoring — engagement plus each workspace's own positive and negative keyword lists — before any LLM spend. The model only ever sees candidates worth paying for.
  • Quality gate with automated remediation. A style firewall scans every generated draft for AI tells and sends failures back for LLM edit retries. Drafts that still fail are held for human review instead of being published — the pipeline degrades to a queue, never to bad output.
  • Provider-agnostic by construction. Anthropic runs on its native SDK; OpenAI, Gemini, Ollama, and any OpenAI-compatible endpoint run through the OpenAI SDK with a base URL override. Each workspace can pin its own provider and model, or inherit the server default. Missing keys fail with an actionable message, naming the workspace and the variable.
  • Multi-tenant isolation as a first-class concern. Per-workspace tone of voice, voice rules, and banned phrases; API keys stored hashed and rotatable; delivery webhooks signed with per-workspace HMAC-SHA256. A worker auto-schedules runs for every active workspace on a 6-hour cycle.
Claude Haiku OpenAI SDK Ollama Next.js Prisma PostgreSQL Docker

Also shipping with LLMs

Dirra

AI-powered learning and mastery platform. Generative models drive content and assessment over a Node service layer.

OfferAlert

Fixed-income opportunity discovery for Nigerian retail investors. FastAPI backend with litellm-based document understanding over prospectuses and filings.

CPD Base

Continuing-education platform with an Anthropic-backed generation layer on Next.js and Prisma.

What production actually taught me.

Latency is a budget, not a hope

A 12-second pipeline ceiling is what forced the parallel fan-out in Rippli. Decide the budget first, then let it dictate the architecture — batching, concurrency, and which calls happen after you've already returned something useful.

Cost is a design constraint

Score before you spend. Batch when the workload is asynchronous. Self-host when volume justifies the hardware. Most LLM cost problems are architecture problems wearing a billing disguise.

Every model call will fail eventually

Rate limits, timeouts, malformed JSON, revised response schemas. Fallback chains, hard timeout ceilings, defensive parsing, and fail-soft returns aren't polish — they're the difference between a degraded feature and a dead pipeline.

Ground the model in your own data

Retrieval from the database you already trust beats a longer prompt and a bigger model. Measure the context you inject — an unbounded context window is an unbounded bill and a slower, less accurate answer.

Schema is the contract

When a vision model replaces a text parser, it should return the identical shape. Downstream code shouldn't know or care which path produced the data — that's what makes an AI component replaceable instead of load-bearing.

Abstract the provider, not the problem

Model providers change pricing, deprecate versions, and go down. One interface, several implementations, and a no-op fallback means switching providers is a config change rather than a refactor.

Advisory & Speaking

I advise teams putting AI into production — particularly where bandwidth, budget, and infrastructure are real constraints rather than footnotes. If you're making these decisions and want a second opinion from someone who has already paid for the mistakes, I'm reachable.