Hello, world — and why I'm writing

A first post about what this blog is for, who it's for, and the kind of writing I want to do here. With a few real examples of what the rendering looks like.

I've been meaning to write more for a while. Most engineers I admire have a place where they think out loud — not a polished publication, just a corner of the internet where half-formed ideas are allowed to live until they're worth keeping. This is mine.

What this blog is for

I work on production ML and GenAI systems at Volvo Group — warranty AI, an enterprise GenAI assistant, the kind of work that lives in a monorepo and never tweets itself. A lot of what I learn doesn't fit in a paper or a LinkedIn post, but it's useful to someone. Things like:

  • The unglamorous tradeoffs you make when retrieval, rules, and an LLM all need to agree
  • How a feature pipeline actually fails on a Tuesday
  • Where a "naive RAG" stops being naive
  • Why your text-to-SQL agent works in evals and dies on the first user

Posts will be short when I have something compact to say, and long when I need to draw a diagram.

What it won't be

This isn't a tutorial site. There's no "10 things you must know about LLMs". I'd rather write one honest post about a thing that bit me than ten over-confident posts about a thing I read about.

Quick design tour

Because this is the very first post on a brand-new blog, the rest of this file is mostly here to make sure the rendering pipeline works. If you're here as a human reader: just skim.

Headings, bold, and links

Markdown does the obvious things. Bold is bold, italic is italic, and external links open in a new tab, while internal links stay in the SPA.

Lists

Ordered lists for steps:

  1. Frame the business problem in one sentence.
  2. Inventory the data; profile it before modelling.
  3. Build the dumbest baseline you can defend.
  4. Make the second-dumbest one beat it.

Unordered lists for grab-bags:

  • PySpark + Unity Catalog for batch pipelines
  • MLflow for experiment tracking and the model registry
  • Azure Functions + Service Bus for async inference
  • Caddy + Docker for everything user-facing

Blockquote

Make it work, make it right, make it fast — in that order. Production ML has a fourth step: make it explainable.

A small table

Layer Tool Why
Data Databricks + Unity Catalog Governance, lineage, cheap compute
Training MLflow on Databricks Tracking + registry in one place
Serving Azure Functions Async, scales to zero
Routing FastAPI on App Service One synchronous entry point

Code, inline and fenced

A bit of inline code: if probability > threshold: route_to_human().

A real block, Python:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Claim(BaseModel):
    id: str
    text: str
    vehicle: str

@app.post("/score")
def score(claim: Claim):
    # 1. deterministic rules first — cheap and explainable
    if rule_engine.reject(claim):
        return {"decision": "reject", "by": "rules"}
    # 2. fall back to the GBM
    p = gbm.predict_proba(claim)[1]
    if p < 0.2 or p > 0.8:
        return {"decision": "auto", "score": float(p), "by": "ml"}
    # 3. only the hard ones reach the LLM agent
    return agent.evaluate(claim)

A bit of SQL too:

SELECT date_trunc('day', created_at) AS day,
       count(*) FILTER (WHERE decision = 'auto') AS auto_decisions,
       avg(latency_ms) AS p_avg_latency
FROM warranty_inference
WHERE created_at > now() - interval '7 days'
GROUP BY 1
ORDER BY 1;

That's everything the renderer needs to handle for now. If you're reading this and something looks off — wrong color on a token, awkward spacing around a heading, a heading that doesn't breathe — let me know and I'll fix it before the next post.

— Erfan