By Hakim Research9 min read

Research preview to Fast v1.0: what we rewrote

A retrospective on the nine weeks of decoder surgery, the Beirut-Cairo-Riyadh corpus collection, and the boring infra work that separated a notebook demo from a production API.

EngineeringModels

Today we're shipping Hakim Fast v1.0, the first deployable member of the Hakim family, to three design-partner teams under private alpha.

This is a retrospective on how we got here. The short version: taking a research preview to a deployable model is mostly the work of getting all the boring things right, in a particular order.

Where we started

The research previewHakim Fast v0.9, was five months of work by two researchers. It could synthesize Arabic audibly. It was not ready to ship by a long stretch. Specifically, the failures we identified in internal review were:

  1. Prosody degraded on sentences longer than ~25 tokens. The acoustic decoder was fine on short utterances and started drifting on long ones. The model was learning sentence-level rhythm from a corpus that over-indexed on short sentences.
  2. Dialect bleed in conditioning. Two of the conditioning heads (MSA and Gulf) were not cleanly separated in the decoder latent space. Asking for Gulf with strong enough prompting got you Gulf. Asking for MSA sometimes got you a slightly Gulf-tinted MSA, which is the kind of thing a native Saudi listener will tell you about in the first ten seconds.
  3. Inference was too slow. End-to-end latency on a single-GPU preview rig was around 400 ms p95 for short sentences, climbing over a second for longer ones. Not a production number.
  4. No serving story at all. The preview ran in a research notebook. There was no inference server, no batching, no health checks, no anything.

"We can fix these" is true. "We can fix these without breaking anything else" was the actual question.

The decoder rewrite

The prosody drift turned out to be load-bearing. Fixing it required going deeper than we'd hoped into the decoder.

The original acoustic decoder was a mostly-conventional transformer-over-mel-frames architecture with a duration predictor hanging off the side. That architecture is fine for short utterances; it's structurally prone to drift on long ones because the duration predictor operates locally and doesn't have a strong prior on what sentence-level rhythm should look like.

We replaced it with a two-stage model: a phrase-rhythm planner that produces a coarse prosody contour for the full sentence, followed by a local decoder that attends both to the phonemes and to the planner's contour. The planner is tiny (~30M params) but structurally gives the decoder the long-range information it was missing.

This wasn't a minor refactor. It was a nine-week delay on the v1.0 ship date. But it fixed the prosody problem, and, unexpectedly, cleaned up the dialect bleed: with a better rhythm prior conditioned on the dialect head, the decoder had less reason to smuggle one dialect's cadence into another.

The corpus

The research preview was trained on what we had, which was a lot of scraped podcasts and public-domain audio. To get from preview quality to production quality, we needed native-read studio corpora, speakers reading curated text, in a proper recording environment, with phonetic coverage verified against our eval set.

This is a logistics problem, not an ML problem. We partnered with three recording studios, one in Beirut, one in Cairo, one in Riyadh, and ran a corpus collection program from October 2024 through January 2025. The output was roughly 300 hours of MSA + dialect audio with confirmed phonetic coverage and matched transcripts.

The corpus was what made v1.0 production-viable. The model architecture was the hero; the corpus was the pit crew.

Inference work

Getting latency from 400 ms to something shippable required a pass through the inference stack that was 90% "remove unnecessary work" and 10% "do anything clever."

Unnecessary work, in decreasing order of payoff:

  1. Batching. The preview ran one sentence at a time. Shipping a batched inference server with request coalescing dropped per-request latency on the serving side by ~40% at low load and much more at steady state.
  2. Avoiding redundant encoder passes. The phoneme encoder's output is deterministic given the input text. Caching it per (text, dialect) tuple saved a measurable chunk on repeat calls, and repeat calls are the common case in production.
  3. Lower-precision inference. The acoustic decoder tolerated FP16 cleanly. Quantizing to INT8 on the rhythm planner was fine; INT8 on the decoder cost us MOS quality we didn't want to give back, so we didn't.
  4. Co-locating models. Moving the phoneme encoder, rhythm planner, and acoustic decoder into a single process (rather than three pods with network calls between them) killed a surprising amount of latency that was hiding in HTTP overhead.

None of this is clever. It's the kind of engineering that earns zero citations and a lot of shipped product.

The serving story

We built a Fastify-backed inference gateway that sits in front of the model pods. The gateway does the things the model shouldn't know about: rate limits, auth, billing integration, routing to the right regional pods, request logging for audit, and response caching for identical calls. The model pods do inference, full stop.

This split mattered for speed, inference pods got simpler and more tightly optimized, and for safety: the security-critical logic lives in the gateway, which we can iterate on without touching the model runtime.

What we didn't do

A few choices we made deliberately:

  • We didn't ship all dialects. v1.0 shipped with MSA only plus limited preview-quality Levantine. The full 15-dialect tree waited for Hakim Arab v2 in 2026. Shipping a dialect we hadn't cleared the MOS bar on would have invalidated the quality claim for the ones we had.
  • We didn't ship streaming. v1.0 was one-shot synthesis only. Streaming was a v1.2 feature, we wanted the serving path to be stable first.
  • We didn't ship a public SDK. v1.0 went to three design partners with hand-built client libraries. The public SDK family. Node, Python, came in v1.2. Releasing SDKs for a private API would have created a public surface we weren't ready to support.

Each of those "didn't" decisions added a quarter to the roadmap. Each was the right call.

What this became

Hakim Fast v1.0 shipped to private alpha in February 2025. v1.1, the prosody pass, followed in May. v1.2, streaming + the first SDKs, in July. v1.3, the 113 ms end-to-end p95 we publish today, arrived in February 2026.

The through-line from the preview to the current model is surprisingly straight. The decoder architecture in v1.3 is an evolution of the one we put in for v1.0. The rhythm planner is the same shape; it's just trained on ten times more data. The inference stack still looks structurally like what shipped in v1.0; the optimizations accreted on top.

The hardest engineering work on this model wasn't the latest version. It was the gap between v0.9 and v1.0, getting from "it works in a notebook" to "it serves a production call."

Everything since then has been compounding.

Read next