The four models
Notice the loop. The ledger feeds the standing and matching models. The matching model’s interactions (applies, approvals, completions) flow back into the ledger. The standing model’s output (the tier) writes to the ledger as a derived signal. The negotiation engine learns inside Redis from every accept and decline. None of this is offline batch ETL. The signal flows continuously.1. The matching model
Fires every time a job is posted. Ranks every plausible Job Seeker. Top candidates get pinged.Shape
A lambdarank learning-to-rank model. Why lambdarank: the underlying problem is ordinal, not classification. We don’t care if the model is 92% confident a particular Job Seeker is a fit — we care that they rank above the people who aren’t a fit. Pairwise ranking objectives optimise for the order, not for the absolute scores. Trained with NDCG@5 as the primary metric. We measure on internal benchmarks against synthetic data calibrated to Nigerian informal-economy patterns. Production retraining cadence: nightly, on the new attendance and review data that arrived in the last 24 hours.Features
Four factor families. Each one maps to one of the four production criteria in the OPay Scholars 2026 challenge.
The model treats these factors as gradient-boosted weak learners — no manual coefficient tuning. The training process finds which combination of features in which ranges produces the best ranking. The same features matter differently for a bricklayer job in Bodija than for a tailor job in Surulere; the model learns this.
Where it fires
A typical inference is under 100ms for a candidate pool of a few thousand.Why not a deep neural network
Three reasons.- Tabular features. Gradient-boosted trees beat deep models on tabular data with our feature shape. This is well-established.
- Interpretability. When a candidate ranks where they do, the gradient-boosted model can explain it (feature contributions). A neural network cannot.
- Training cost. Nightly retraining on commodity hardware is feasible with trees; expensive with deep models.
2. The standing model
Fires every time a dashboard renders, or when the ledger gains material new signal. Outputs the four-tier classification — Building, Emerging, Trusted, Established — plus a raw score 0-1000.Shape
Multi-class softmax classifier on a gradient-boosted tree base. Four output classes match the four tiers. The score is the highest-probability class’s confidence, rescaled.Features
The model trains separately for Job Seeker and trader sub-populations because the most predictive features differ.
Training data and recalibration
Trained on Guild ledger data. Retrained nightly on the new completed-jobs and ratings rows added in the last 24 hours. The model is calibrated continuously — not “trained once and frozen.” A Job Seeker who joined six months ago and has stayed active will have the model’s understanding of them sharpen as more activity arrives.Where the output goes
The tier and score are written back to a derived column on the user row, scoped to the last computation time. Any read of the Job Seeker’s standing returns the cached tier unless a material event has invalidated it (a completed job, a new review, a repayment landed). Materially-invalidated tiers are recomputed lazily on the next dashboard read. The Partner API snapshot endpoint reads from the same cached tier. So lender reads and dashboard reads see identical values.Why a classifier, not a regression
We tried regression first. The issue: a single 0-1000 score doesn’t degrade gracefully. A small ranking change moves a Job Seeker from 599 to 601 — which is the difference between Emerging and Trusted in product terms, even though almost nothing changed in their actual behaviour. A classifier with four discrete output classes is honest about the underlying decision being categorical. It also matches the user’s mental model: people understand “I moved from Emerging to Trusted” better than “my score went from 600 to 604.”3. The negotiation engine
Fires when a Job Seeker is considering a counter-offer. Picks the recommended counter and learns from the outcome.Shape
A Thompson sampling Beta(α, β) bandit. One arm per (segment × bucket).- Segment: a coarse-grained user-context bucket. Examples:
(role=JOB_SEEKER, tier=Emerging, location_band=lagos_metro, skill=bricklayer). - Bucket: the candidate counter-offer. Examples:
accept,counter_+5%,counter_+10%,counter_+15%,decline.
Online learning
When the user takes an action (accepts the recommendation, picks a different bucket, declines entirely), we update the posterior:- Successful negotiation (the bucket led to a closed deal): α += 1.
- Unsuccessful negotiation (the bucket led to a withdrawal or unaccepted counter): β += 1.
ml:bandit:negotiate:{segment}:{bucket}. Persistence is durable enough — losing a recent posterior is recoverable because new outcomes will refill it. Cold-start posteriors are uniform Beta(1, 1).
Why Thompson sampling
We tried epsilon-greedy first. The issue: ε-greedy explores uniformly, even on buckets that are clearly underperforming. Thompson sampling explores in proportion to the posterior’s uncertainty — buckets we’re unsure about get tried often; buckets we’re confident are bad get rarely tried. Faster convergence on real-world signal. We also tried UCB1. It works but is harder to tune. Thompson sampling’s Beta posteriors are interpretable; we can read the (α, β) values and know exactly what the model has learned about each bucket.Where it fires today
The negotiation engine is wired into the application service. When a Job Seeker is presented with a job offer that allows negotiation, the engine selects the recommended counter-offer based on the Job Seeker’s segment. The interaction outcome (accept, decline, counter) flows back as a posterior update. The engine’s posteriors update from every interaction. The longer the platform runs, the better its recommendations get for each segment. This is the data flywheel.4. The transcription model
Fires whenever a voice note arrives in WhatsApp. Returns text.Shape
A speech-to-text model fine-tuned for Nigerian English, Pidgin, Yoruba, Igbo, Hausa. Audio in, text out. Streaming-capable but typically used in batch mode (voice notes are short, completion latency matters more than first-token latency).Where it fires
The user spoke. The system understood. The user didn’t have to type. Same path as a typed message from the intent engine onward.Why a separate transcription model and not delegated to the channel platform
Two reasons.- Quality on Nigerian voices. Generic speech-to-text models trained primarily on American or British English degrade on Nigerian accents and code-switching. A model with Nigerian voice data in its fine-tuning corpus gives materially better transcripts.
- Consistency across channels. When the voice agent (Tola) needs a transcription, when WhatsApp needs a transcription, when SMS-to-voice-note flows need one, they all hit the same model. One consistency surface.
How the four models reinforce each other
The system gets better the more it runs. Not in the marketing sense — in the literal sense. Every interaction either teaches a model (negotiation engine) or feeds a future retraining pass (matching, standing).What we don’t model (and why)
A short list of things judges might ask about.- Fraud detection model. We don’t have one. The webhook reconcile guard + append-only audit + timing-safe HMAC is the defence layer. Fraud detection as a learned model would surface only after the platform has enough signal to be meaningful; we’d want at least 6 months of real production traffic before training one.
- Default-prediction model. Lenders bring their own. Our job is to surface the underlying signals (standing tier, repayment streak, cashflow stability) — the lender’s model decides how to underwrite. This is a deliberate scope choice: we don’t want to be the bank.
- Embedding-based search across job descriptions. Job postings are short and structured. A keyword match on skill tags + a structured filter on location/language outperforms a sentence-embedding search on the size of our corpus. We’d revisit at scale.
- A foundation-scale Nigerian-language model. Tola’s conversational ability comes from her runtime, not from a Guild-trained LLM. We’re not training foundation models.
What’s deployed today
What to read next
Data flow
The ledger as the data substrate. How signal flows in and out.
Resilience & scale
How the inference path is reliable enough to underwrite on.
Standing & the Ledger
The product surface — what users see when the standing model reads them.