back

how I build with AI

Using an LLM is not a skill. Scoping, building, and measuring an AI system is.

Anyone can call an API. The work that matters is deciding what the model is allowed to say, proving a change made answers better instead of worse, and knowing what a query costs before the invoice arrives. Everything below is drawn from projects that are shipped or in active build, not from a course.

(01)

The 8 AI engineering fundamentals, and where I have shipped each one

01

LLM APIs & prompt design

Prompts are versioned specs with an explicit contract, not strings you tweak in place.

Hive: qa_prompt.yaml, versioned v1/v2, version logged per query

02

RAG

Retrieval is a product decision. What gets chunked, what gets retrieved, and what the model is allowed to say.

Hive: full ingest → embed → retrieve → generate pipeline, shipped

03

Embeddings & vector DBs

Knowing what a vector is, what a similarity score means, and why the store choice matters.

Hive: OpenAI text-embedding-3-small into pgvector on Postgres

04

Agent orchestration

Decomposing a task across model calls, and knowing when a state machine beats a single prompt.

Hani: 7-skill conversational state machine. Hive: query decomposition on the roadmap

05

Evaluation & observability

If you cannot measure whether a change made answers better or worse, you are not engineering, you are guessing.

Hive: live RAGAs faithfulness and relevance scoring on every query, logged with cost

06

Guardrails & output validation

The refusal path is a designed, tested feature. Fabrication is a requirements failure.

Hive: answer-only-from-context contract. Hani: never quiz, never correct, written before the prompt

07

Context-window management

The window the model sees is a known quantity set in config, not whatever the last change produced.

Hive: chunk_size 1000, K=4, enforced. ask-brian-skills: token budget as a product metric

08

Fine-tuning vs prompting

Most problems are prompt and retrieval problems. Knowing when they are not is the skill.

Hive: prompt-only now, decision framework with exit gates on the roadmap

Fundamentals 2, 3, 5, 6, and 7 all show up in one pipeline. Hive, drawn end to end:

IngestPDF → chunksEmbedembedding-3-smallVector storepgvectorRetrieveK = 4Generateclaude-sonnet-4-6Cited answerwith sources
Hive's RAG pipeline. Every stage is a config-enforced contract, not an ad-hoc call.

(02)

The stack, named exactly

Specific model IDs and versions, because “uses LLMs” and “shipped a RAG pipeline on pgvector with a cheap judge model on every query” are not the same claim.

Models

  • Claude claude-sonnet-4-6 (generation)
  • claude-haiku-4-5 (eval judge)
  • OpenAI text-embedding-3-small (embeddings)
  • OpenAI Realtime API (voice-to-voice)

Orchestration & data

  • LangChain 0.3+
  • pgvector / Postgres
  • Supabase
  • Firecrawl
  • WebRTC

Eval & delivery

  • RAGAs
  • Streamlit
  • Docker
  • Next.js
  • Jupyter (as a design-record layer)

(03)

How I evaluate

Two scores on every answer. Faithfulness asks whether the answer stayed inside the retrieved context. Relevance asks whether it actually addressed the question. An answer can be perfectly grounded and still useless, so both matter.

A judge model does the scoring. I use claude-haiku-4-5 because a fast, cheap judge that runs on every single query is worth more than a perfect judge that never gets wired in.

Cost is logged next to the score, not separately. Every query records its token counts and computed USD cost in Postgres, so answer quality and answer cost are always read together.

Prompt versions are logged too. When I test a terser prompt against the current one, I can compare faithfulness and cost across versions after the fact, with real query data, instead of arguing about it up front.

compare versions, then tunePrompt vNqa_prompt.yamlCited answerFaithfulnessjudge: haiku-4-5Relevancejudge: haiku-4-5query_logscore · USD · version
Every answer is scored and priced the moment it is produced. The scores drive prompt iteration.

(04)

How I set guardrails

Guardrails are requirements, written before the prompt. In Hive the contract is: answer only from retrieved context, and if the context does not support an answer, decline. In Hani it is: never quiz, never correct, silence is allowed.

Prompt-level first, hard validation second. The prompt spec carries the contract; a validation layer enforces it where the stakes justify the cost. Both, not one.

The refusal path is a feature. “I don’t have enough information in the knowledge base to answer that” is a tested, designed response, not an edge case the system fell into.

yesnoContexttop-K chunksSupports it?guardrailAnswercite sourcesDecline"not in the KB"
The refusal path is a designed branch, tested like any other feature.

(05)

See it in the work

Hani applies the same discipline to a real-time voice product: a state machine instead of a script, guardrails written first, the hard limits enforced server-side.

spoken replyPersonone buttonWebRTCephemeral tokenRealtime APIvoice ↔ voiceSession capserver-enforcedStory passspeech → cardTimeline cardfamily sees
Voice-to-voice keeps latency conversational. A separate pass turns each told story into a timeline card.

The rest of this site is the same work from the customer’s side. The account. The renewal. The room.