Skip to content

AI product · 2026

TaxWiz

A Nigerian tax assistant that does the arithmetic deterministically and lets the language model do only what it is good at: reading.

Role

Sole engineer

Scope

Retrieval-augmented generation · Backend · Product

Year

2026
Wooden blocks spelling TAX on stacks of coins beside a calculator

At a glance

  • 4

    Tax types computed

  • 69

    Tests passing

  • 0

    LLM calls in any calculation

  • 1,536

    Vector dimensions

  • Live

    On Railway

01

The problem

Nigerian tax rules are spread across acts, schedules and rate tables, and the people who need them want two different things: a number they can trust, and an answer they can check. A general-purpose chatbot is bad at both. It hallucinates arithmetic and it cannot show where an answer came from.

02

The insight

Language models are unreliable at arithmetic and reliable at reading. So split the product along exactly that line, and never let the two halves touch.

03

The idea

A tax calculator in plain Python, computing PAYE with its graduated bands and reliefs, company income tax by turnover band, VAT inclusive or exclusive, and withholding tax by transaction type, from fixed rate tables. No model is involved in any number. The results are deterministic, unit-tested and reproducible.

Beside it, a Q&A assistant: the question is embedded, matched against a Pinecone index of Nigerian tax-law passages, and answered by a model that is restricted to the retrieved text. Every answer ships with numbered citations and the passages it was built from, with similarity scores. Below the similarity threshold the model is never called, and the user is told nothing relevant was found.

04

The build

A small Flask application with a deliberately boring shape. Calculation endpoints call pure functions with no network and no model. The ask endpoint runs the retrieval pipeline. A health endpoint never touches Gemini or Pinecone, so it stays green during an outage and the platform does not kill the container. Every endpoint returns either data or a clean error object; stack traces never reach the user.

An offline ingestion script chunks source documents, embeds them and upserts them into the index, and can re-embed an existing namespace with a different model without the original files.

The ask pipeline
  1. 01

    Question

  2. 02

    Embed

    Gemini embedding · retrieval-query task type

  3. 03

    Search

    Pinecone · cosine · 1,536 dimensions

  4. 04

    Threshold

    below similarity cut-off → “nothing relevant found”, no model call

  5. 05

    Cited prompt

    retrieved passages only

  6. 06

    Answer

    numbered citations + source panel with scores

05

The process

The rule that cost the most to learn: embeddings from different models are not comparable. Querying an index built with one model using vectors from another does not fail. It returns confidently wrong passages. TaxWiz keeps one namespace per embedding model and switches between them explicitly.

Two details are kept in sync and must not drift: passages are embedded as retrieval documents and questions as retrieval queries, because the embedding model treats the two asymmetrically; and the model's 3,072-dimensional output is truncated to 1,536 to match the index, then renormalised to unit length, because it only normalises at full width.

06

The result

A live assistant that produces reproducible numbers and checkable answers, with a test suite across the tax maths, the HTTP contract and the retrieval behaviour, including a live check against the index.

07

What I learned

The most important product decision was deciding what the model is not allowed to do. Honest empty results are a feature, and users trust a system more when it shows its sources than when it sounds confident.

Built with

Python · Flask · Pinecone · Gemini · Gunicorn · pytest · Railway