Case study · Wabel · MVP
Wabel
A supplier-sourcing engine for the food industry. An invoice or a request for quotation is parsed into a typed sourcing brief, matched against the supplier corpus in two phases, vector recall then LLM rerank, and returned as a ranked list with a relevance score and a written reason for every match.
The same stack, a second industry. Nothing in the matching engine is aviation-specific. It is the retrieval and ranking stack that cites manual pages in DocsAI, pointed at a corpus of suppliers instead of a corpus of documents, with the explanation step doing for a buyer what a citation does for an engineer.
The problem
A brief in a buyer's head, a corpus of suppliers
Wabel matches food-industry buyers with suppliers across Europe. A buyer's need arrives as an invoice from a current supplier, a request for quotation, or a few lines of free text. The candidates are a corpus of supplier profiles of uneven completeness, because suppliers describe themselves in their own words and to their own depth.
Matching by keyword misses the supplier who describes the same product in different words. Matching by embedding alone returns a ranked list nobody can argue with, because it gives no reasons. A buyer who is about to pick up the phone needs to know why this supplier and not that one.
The engine had to take an unstructured brief, find the right candidates quickly, and explain each match in a sentence a buyer can read.
The approach
Four decisions
Parse first, match second
Invoices and RFQs are parsed into typed sourcing briefs with structured outputs, so the matcher works from validated fields rather than from a free-text prompt.
Recall fast, rerank behind it
Phase one recalls the top candidates from pgvector and answers within the request. Phase two hands them to an LLM reranker on an async worker, which scores each candidate and streams in behind the first list.
A reason for every match
The reranker writes the reason a buyer can read, not only a score. No black-box ranking.
A corpus that fills itself in
A crawler with a Playwright fallback enriches supplier profiles from their public web presence, so thin records improve without manual data entry.
What shipped
Three screens from the MVP

Brief in, reasons out. A free-text brief becomes a ranked list of suppliers, each with a relevance score and a written reason. The list appears at vector-recall speed; the scores and reasons stream in as the reranker finishes each candidate.

The corpus, browsable. A faceted supplier directory across categories and markets: the same records the matcher searches, enriched by the crawler.

A second product on the same foundations. The clean-label analyzer: an ingredient list matched against EU food-additive grounding data, scored for consumer perception with the worst offenders first, delivered as an audit report.
The engine
Two phases, one explanation
Matching is split so that the cheap, fast phase answers first and the expensive, careful phase improves the answer without making the buyer wait for it.
Blue is where the model reads: the recall phase, and the rerank that streams its scores and reasons back into a list the buyer is already looking at. The corpus is read by both phases and written by the crawler.
Parse
An invoice, an RFQ or free text goes to the model with a schema and comes back as a typed sourcing brief. Structured outputs, not a free-text prompt, so the fields are validated before anything is searched.
Recall
The brief is embedded and pgvector returns the nearest supplier profiles. This is the list the buyer sees first, within the request.
Rerank
The candidates are queued to an Arq worker on Redis. An LLM reranker reads the brief and each profile, assigns a relevance score and writes the reason. Results stream into the list as each one completes.
Enrich
Independently, a crawler visits supplier websites and fills in profiles, falling back to Playwright for pages that need a browser. Better profiles make both phases better.
Clean label
Compliance on the same stack
A follow-on build applies the same foundations to label compliance. An ingredient list is matched against EU food-additive grounding data, each additive is scored for how consumers perceive it, and the worst offenders are surfaced first. The result is delivered as an audit report through an email-gated funnel.
A full domain product stood up in days, because retrieval, ranking and explanation were already there. The domain changed; the engine did not.
Stack
What it is made of
| Layer | Choice |
|---|---|
| Matching | Two phases: pgvector recall, then LLM rerank with a relevance score and a written reason per match |
| Briefs | Invoices and RFQs parsed into typed sourcing briefs with structured outputs |
| Enrichment | Web crawler over supplier sites, Playwright fallback for pages that need a browser |
| Backend | FastAPI; Arq workers on Redis for the rerank queue |
| Data | Postgres 16 with pgvector and pg_trgm |
| Compliance | EU food-additive grounding data for the clean-label analyzer |
| Tests | 51 backend, green CI |