Skip to main content

Reduce AI application latency spikes by offloading embeddings to Foundry Local 1.2, improving edge performance, responsiveness, scalability, and cost efficiency.

Performance FixFoundry Local 1.2Linux ARM64EmbeddingsOffline ASR

The Edge Latency Drop: Fixing Latency Spikes by Offloading Embeddings to Foundry Local 1.2

You are paying a full cloud round trip — network, TLS, queue, throttle risk — to turn a twelve-word search query into a vector. That is the most expensive way possible to do one of the cheapest computations in your stack. Foundry Local 1.2 now runs on Linux ARM64, which means embeddings and speech recognition can happen on a Raspberry Pi, a Jetson, or a Graviton instance — offline, unmetered, and in single-digit milliseconds.

The failure signature this guide resolves
# Application Insights — the embedding call, not the LLM, is your tail latency:
name                              p50      p95       p99        calls/day
POST /embeddings  (cloud)         89 ms   412 ms   3,847 ms      1,240,000
POST /chat/completions (cloud)   940 ms  1,720 ms  2,910 ms         38,000
                                                   ^^^^^^^^
                     A 12-word query embedding is your SLOWEST operation at p99.

# And under load, the same tiny call starts failing outright:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{"error":{"code":"429","message":"Requests to the Embeddings_Create Operation
 under Azure OpenAI API version 2024-02-01 have exceeded call rate limit."}}

# Or, on an edge device with intermittent connectivity, it simply dies:
requests.exceptions.ConnectionError: HTTPSConnectionPool(
  host='my-aoai.openai.azure.com', port=443): Max retries exceeded
  (Caused by NewConnectionError: Failed to establish a new connection:
   [Errno -3] Temporary failure in name resolution)

Symptom: Embedding and transcription calls dominate p99 latency and throttle budget, despite being computationally trivial.  Failure point: Client → network → TLS → cloud queue → a 0.6B-parameter model that could run locally in milliseconds.  Default platform behaviour: Every embedding, however small, pays the full round trip and consumes shared quota. The compute is cheap; the journey is the cost.

0.6B
qwen3-0.6b-embedding — the model doing the work you are currently sending across the internet
ARM64
Foundry Local 1.2 runs on Raspberry Pi 5, NVIDIA Jetson, AWS Graviton, and Ampere — the edge is now a first-class target
40+ langs
Multilingual streaming ASR on-device via Nemotron 3.5, at roughly 8% WER and low single-digit % CPU
$0 / token
No per-token cost, no quota, no throttle — and no network. The whole point of moving the work, not just speeding it up

There is a quiet absurdity at the heart of most RAG architectures. To answer a question, you send the user's twelve-word query across the public internet, terminate TLS, wait in a shared queue, and consume metered quota — all so that a model can perform a computation that a Raspberry Pi could complete in a few milliseconds without ever touching a network. The generation step genuinely needs a frontier model in the cloud. The embedding step does not, and never really did. It was in the cloud because that was the only place it could be. As of Foundry Local 1.2, with Linux ARM64 support, that is no longer true — and the latency you get back is not marginal, because you are not making the call faster. You are deleting it.

Figure 1 — Where the milliseconds actually go: a cloud embedding call vs a local one
ONE EMBEDDING CALL — WHERE THE TIME IS SPENT✗ CLOUD ROUND TRIPDNS+TCPTLSNETWORK RTTQUEUE / THROTTLEINF.NETWORK RTTp99 ≈ 3,800 msActual model compute:this sliverEverything else is transport, queueing, and waiting.✓ FOUNDRY LOCAL — ON-DEVICEINFERsingle-digit ms · no network · no queue · no quotaThe model is the same class of work. The DIFFERENCE is that you deleted the journey —not that you made the model faster. This is why the win is disproportionate at p99.The tail is the point. A cloud embedding's p50 looks fine — it is the p99, driven by queueing and throttling under load,that wrecks your UX. Local inference has no queue to wait in, so the tail collapses toward the median.
A cloud embedding call spends the overwhelming majority of its wall-clock time on transport and queueing, not on the inference itself. Moving the model on-device does not optimise those stages — it removes them entirely, which is why the p99 improvement is far larger than the p50 improvement.
01The Latency Math: Why Embeddings Don't Belong in the CloudRoot Cause

The instinct is that AI work belongs in the cloud because AI work is heavy. That is true of a frontier chat model. It is emphatically not true of an embedding model, and the mismatch is where your latency budget is being burned.

Consider the asymmetry. A chat completion runs tens of billions of parameters, streams hundreds of tokens, and takes a second or more — the network round trip is a rounding error against the compute. An embedding runs a 0.6-billion-parameter model over a dozen words and returns a single fixed-length vector. The compute is trivial. The round trip is not. You have inverted the ratio: for embeddings, the transport is the workload.

PropertyChat completionText embedding
Model sizeTens to hundreds of billions of params~0.6B (qwen3-0.6b-embedding)
OutputHundreds of streamed tokensOne fixed-length vector
Compute vs transportCompute dominates — cloud is correctTransport dominates — cloud is wrong
Call volumeLow (one per user turn)Very high (every query + every document chunk)
Quota pressureExpected and budgetedSilently consumes the same shared quota
Offline capable?No — needs a frontier modelYes — trivially

Now add volume. Embeddings are called on every query and on every document chunk during indexing — often by orders of magnitude more often than your chat endpoint. Each one competes for the same tenant quota. This is why teams see the embedding endpoint throttle first and hardest, and why a 429 on a trivial vector call can take down a feature that has nothing to do with generation.

The tail is what your users feel

A cloud embedding at p50 looks perfectly healthy — 89ms, nobody complains. The damage is at p99, where queueing and throttling stretch the same trivial call into multiple seconds. Because local inference has no queue to sit in and no quota to exceed, moving the work on-device does not just shift the median down — it collapses the tail toward the median. That is the real prize, and it is invisible if you only look at averages.

02What Foundry Local 1.2 Actually ShipsCapability

Foundry Local is Microsoft's cross-platform local AI runtime — models execute on the user's own hardware with no cloud dependency, no network latency, and no per-token cost. It auto-detects available hardware and selects the best execution provider (NPU, GPU, or CPU). The two releases that make this article possible are 1.1 and 1.2.

CapabilityReleaseWhat it means for you
Text embeddings1.1On-device embedding generation via a dedicated embedding client. Ships with qwen3-0.6b-embedding. Single and batch input, configurable dimensions, and OpenAI-format responses for cloud-to-edge portability
Live transcription1.1Real-time streaming speech-to-text from a microphone, with an OpenAI Realtime-compatible surface. Model: nemotron-speech-streaming-en-0.6b
Linux ARM641.2The unlock. Runs on Raspberry Pi 5, NVIDIA Jetson, AWS Graviton, and Ampere — extending local AI to genuine edge and embedded scenarios
Multilingual ASR1.240+ languages via the Nemotron 3.5 ASR Streaming Multilingual model — no longer English-only
Inference cancellation1.2Cancel in-flight chat completions and transcription sessions cleanly when the user moves on — no wasted compute or orphaned streams
Faster model downloads1.2The catalog is fronted by Azure Traffic Manager, routing to the best-performing region. No code change — just move to the 1.2.0 SDK
File transcriptionWhisper models (e.g. whisper-tiny) for transcribing audio files, across all SDKs

Five SDKs are available — Python, JavaScript, C#, Rust, and C++ — plus a CLI and an optional OpenAI-compatible local server.

The ASR numbers are better than you'd expect

The streaming ASR model was not chosen casually. Microsoft benchmarked over 50 configurations across encoder-decoder, transducer, and LLM-based architectures — including Whisper, Nemotron, Parakeet, Canary, and Qwen3-ASR — before selecting NVIDIA's Nemotron Speech Streaming for resource-constrained hardware. They then re-implemented the pipeline in ONNX Runtime with aggressive quantisation, taking the model from 2.47GB down to as little as 0.67GB while holding word error rate within 1% of the full-precision baseline. In their testing it delivers roughly 8% WER using low single-digit percent CPU. That is genuinely deployable on a Pi.

03The Hybrid Split: What Moves to the Edge, What StaysArchitecture

Going hybrid is not "move AI to the edge." It is a deliberate split along a single axis: does this workload's value come from model scale, or from proximity? Get the split right and you keep frontier quality where it matters while deleting the network from everything else.

WorkloadWhere it belongsWhy
Text embeddingsEdgeTiny model, enormous call volume, transport-dominated. The textbook case
Speech-to-textEdgeStreaming audio to the cloud is expensive, laggy, and a privacy exposure. Runs at ~8% WER locally
Intent / classificationEdgeSmall models, high frequency, latency-sensitive
Vector search (local corpus)EdgePair local embeddings with a local vector store for a fully offline retrieval pipeline
Final answer generationCloudGenuinely needs a frontier model. Compute dominates, so the round trip is a rounding error
Complex reasoning / agentsCloudModel scale is the product here
Enterprise-wide vector indexCloudShared, large, centrally governed — not an edge concern
The privacy dividend is not a footnote

Local ASR means raw audio — customer voices, clinical dictation, shop-floor conversation — never leaves the device. For a regulated workload, that is often a more compelling argument than the latency, because it changes what data crosses a boundary at all rather than merely how fast it gets there. If you are currently streaming microphone audio to a cloud speech endpoint, the compliance case for this migration may be stronger than the performance one.

04⚠ The Embedding-Space Trap (Read Before You Migrate)Critical

This is the section that will save you a production incident, and it is the one most "move embeddings to the edge" write-ups skip entirely. If you take nothing else from this article, take this.

You cannot swap the embedding model on one side of a vector search. An embedding is only meaningful relative to the model that produced it. Vectors from text-embedding-3-large and vectors from qwen3-0.6b-embedding live in different geometric spaces. They are not compatible, not convertible, and not comparable — even if you force the dimensions to match.

So if your Azure AI Search index was built in the cloud with text-embedding-3-large, and you now start embedding queries locally with qwen3-0.6b-embedding, one of two things happens:

Outcome A — you get lucky and it fails loudly (dimension mismatch)
HTTP/1.1 400 Bad Request

{
  "error": {
    "code": "InvalidRequestParameter",
    "message": "The vector field 'contentVector' has dimension 3072, but the
                query vector has dimension 1024. Vector dimensions must match."
  }
}
Outcome B — the dimensions happen to match, and it fails SILENTLY
HTTP/1.1 200 OK

# No error. No warning. Retrieval "works".
# It just returns semantically irrelevant documents, because you are
# measuring cosine distance between vectors from two unrelated spaces.
# Your RAG answers quietly degrade into confident nonsense.

# This is the dangerous one. There is NO error string to search for.

Outcome B is the nightmare. There is no exception, no 400, no alert — retrieval quality simply collapses, and because LLMs are fluent even on bad context, your application keeps producing confident, well-written, wrong answers. Teams have shipped this and discovered it weeks later through user complaints about "the AI getting dumber."

The rule, stated plainly

The model that embeds your documents and the model that embeds your queries must be the same model. Full stop. This is not a Foundry Local limitation — it is how vector spaces work. Moving query embedding to the edge therefore means one of the two paths below, and there is no third option.

Your two legitimate migration paths

PathWhat you doCost / caveat
Re-indexRe-embed your entire corpus with qwen3-0.6b-embedding, then use the local model for both indexing and queryingA full re-index — expensive and slow for a large corpus, but a one-time cost. Retrieval quality may differ from the larger cloud model; evaluate before you commit
Local-corpus-onlyUse local embeddings only for a new, edge-resident index (device documents, local cache, on-device history). Leave the cloud index untouched and cloud-embeddedClean, safe, no re-index. You now maintain two indexes with two embedding models — never query across them
Evaluate retrieval quality, don't assume it

A 0.6B embedding model is not automatically as good at retrieval as a large cloud one. It may be perfectly adequate for your corpus — often it is — but that is an empirical question, not an article of faith. Before you re-index a production corpus, build a small golden set of query/expected-document pairs and measure recall@k with both models. Trading 20ms of latency for a measurable drop in retrieval accuracy is a bad deal, and you will only know which way it went if you measure.

Figure 2 — Two vector spaces, one index: why swapping only the query model corrupts retrieval
✗ BROKEN — documents and queries embedded by DIFFERENT modelsDOCUMENTStext-embedding-3-large3072 dims · SPACE AVECTOR INDEXholds SPACE A vectorsQUERY (edge)qwen3-0.6b-embedding1024 dims · SPACE BTWO OUTCOMESA) dims differ → HTTP 400(you got lucky — it failed loud)B) dims match → SILENT GARBAGECONFIDENT NONSENSERetrieval returns irrelevantdocs. The LLM is fluent anyway.No error to alert on.✓ CORRECT — the SAME model embeds both sidesDOCUMENTSqwen3-0.6b-embeddingVECTOR INDEXone space, one modelQUERY (edge)SAME MODEL BOTH SIDES → RETRIEVAL IS VALIDEither RE-INDEX the corpus with the local model, or keep local embeddingsto a SEPARATE edge-resident index. Never query across two spaces.
Vectors are only comparable within the space of the model that produced them. Swapping the query-side model against a cloud-embedded index either fails with a dimension mismatch (the lucky case) or, worse, succeeds and returns semantically meaningless neighbours with no error at all.

Architectural Topology: Failing vs Remediated

ComponentFailing configuration (current)Remediated configuration (fix)
Query embeddingCloud round trip per query — transport-dominatedOn-device via Foundry Local, single-digit ms
Speech-to-textRaw audio streamed to a cloud endpointOn-device ASR — audio never leaves the device
Embedding model parityUnconsidered — the trapSame model both sides, enforced and tested
Quota exposureEmbeddings consume shared tenant quota; throttle firstZero quota consumption — no 429 possible
Offline behaviourTotal failure — DNS resolution errorFully functional; cloud used only for generation
Answer generationCloud (correct)Cloud (unchanged — this belongs there)
Failure modeHard dependency on connectivityEdge-first with a cloud fallback path
06Fix 1 — Deploy Foundry Local on Linux ARM64Remediation

This is the capability that makes the whole architecture viable. Before 1.2.0, the Python SDK simply had no aarch64 wheel — installing on a Jetson failed outright with a platform resolution error. Foundry Local 1.2.0 ships linux-arm64, covering Raspberry Pi 5, NVIDIA Jetson, AWS Graviton, and Ampere.

What this used to fail with (pre-1.2, on aarch64)
error: Distribution `foundry-local-core==1.0.0 @ registry+https://pypi.org/simple`
can't be installed because it doesn't have a source distribution or wheel
for the current platform

hint: You're on Linux (`manylinux_2_35_aarch64`), but `foundry-local-core`
(v1.0.0) only has wheels for the following platforms:
`manylinux_2_28_x86_64`, `macosx_11_0_arm64`, `win_amd64`, `win_arm64`
Linux ARM64 — install the runtime and verify hardware detection# Grab the linux-arm64 build from the v1.2.0 release, extract, and verify. tar xzf foundry-linux-arm64.tar.gz ./foundry/foundry --version # Confirm the service is up and see what hardware it detected. # Foundry Local auto-selects the best execution provider (NPU / GPU / CPU). foundry status # Browse the curated catalog foundry model list # Pull the embedding model and load it into memory foundry model load qwen3-0.6b-embedding # Most commands accept --output json, which makes them scriptable foundry status --output json
Install the SDK (Python) — now resolves on aarch64# 1.2.0+ publishes aarch64 wheels. Pin the version explicitly. pip install "foundry-local-sdk>=1.2.0" # Verify the wheel resolved for your platform python -c "import foundry_local; print(foundry_local.__version__)"
Pick the device for the workload, not the brochure

A Raspberry Pi 5 is genuinely sufficient for text embeddings and streaming ASR — recall the ASR model uses low single-digit percent CPU. A Jetson earns its price only if you also need on-device vision or a local chat model where the GPU matters. Graviton or Ampere make sense when the "edge" is actually a regional cloud VM and you are chasing cost and quota isolation rather than physical proximity. Don't buy a Jetson to run a 0.6B embedding model.

07Fix 2 — Run Text Embeddings LocallyRemediation

The embedding client is a first-class surface across all SDKs. The lifecycle is always the same: get the model from the catalog, download it, load it, then get an embedding client. Responses follow the OpenAI embeddings format, which is deliberate — it makes cloud-to-edge portability nearly mechanical.

Python — single and batch embeddings, fully on-devicefrom foundry_local import FoundryLocalManager manager = FoundryLocalManager(app_name="edge-rag") # Download + load the embedding model. Cached after first run. model = manager.catalog.get_model("qwen3-0.6b-embedding") model.download() model.load() client = model.get_embedding_client() # Single embedding — this is the call you just deleted from the network response = client.generate_embedding("The quick brown fox jumps over the lazy dog") embedding = response.data[0].embedding print(f"Dimensions: {len(embedding)}") # Batch — use this for indexing. Far more efficient than looping. batch_response = client.generate_embeddings([ "Machine learning is a subset of artificial intelligence", "The capital of France is Paris", "Rust is a systems programming language", ])
C# — the same lifecyclevar model = await catalog.GetModelAsync("qwen3-0.6b-embedding"); await model.DownloadAsync(); await model.LoadAsync(); var embeddingClient = await model.GetEmbeddingClientAsync(); // Single embedding var response = await embeddingClient.GenerateEmbeddingAsync( "The quick brown fox jumps over the lazy dog"); var embedding = response.Data[0].Embedding; Console.WriteLine($"Dimensions: {embedding.Count}"); // Batch embeddings var batchResponse = await embeddingClient.GenerateEmbeddingsAsync([ "Machine learning is a subset of artificial intelligence", "The capital of France is Paris", "Rust is a systems programming language" ]);

A fully local retrieval pipeline

Pair local embeddings with a local vector store and the entire retrieval path leaves the network. Note that both the indexing and the query call use the same model — that is not an accident, it is the rule from Section 4 being obeyed.

Python — local embed + local vector store, zero network callsimport chromadb from foundry_local import FoundryLocalManager manager = FoundryLocalManager(app_name="edge-rag") model = manager.catalog.get_model("qwen3-0.6b-embedding") model.download(); model.load() embed = model.get_embedding_client() store = chromadb.Client().create_collection("local-docs") # INDEX — embed documents with the LOCAL model (batch) docs = ["Turbine 4 vibration exceeded threshold at 14:02.", "Scheduled maintenance for pump B is due Friday.", "Coolant pressure nominal across all units."] vectors = [d.embedding for d in embed.generate_embeddings(docs).data] store.add(ids=[f"d{i}" for i in range(len(docs))], documents=docs, embeddings=vectors) # QUERY — embed with the SAME local model. Same space. Valid retrieval. q = embed.generate_embedding("why did the turbine alarm?").data[0].embedding hits = store.query(query_embeddings=[q], n_results=2) # Retrieval complete. Nothing has touched the network. # Only the final generation call (optional) goes to the cloud.
08Fix 3 — Offline and Streaming Speech RecognitionRemediation

There are two distinct ASR paths, and they solve different problems. File transcription (Whisper) processes recorded audio. Live streaming (Nemotron) pushes raw PCM chunks and returns results as they arrive, with is_final markers distinguishing interim text from finalised text — which is what you need for captioning, voice UIs, and meeting transcription.

CLI — the fastest possible smoke test# Transcribe a local audio file. No account, no key, no network. foundry transcribe -m whisper-tiny -f audio.wav
JavaScript — file transcription and real-time streamingimport { FoundryLocalManager } from 'foundry-local-sdk'; const manager = FoundryLocalManager.create({ appName: 'edge-asr' }); const whisperModel = await manager.catalog.getModel('whisper-tiny'); await whisperModel.download(); await whisperModel.load(); const audioClient = whisperModel.createAudioClient(); audioClient.settings.language = 'en'; // One-shot: transcribe a file const result = await audioClient.transcribe('recording.wav'); console.log('Transcription:', result.text); // Streaming: emit text as it is recognised for await (const chunk of audioClient.transcribeStreaming('recording.wav')) { process.stdout.write(chunk.text); } // Free the memory when you're done — important on a Pi. await whisperModel.unload();
Choose the right ASR model for the job

Use whisper-tiny for transcribing files. For live microphone streaming, use the purpose-built streaming model — nemotron-speech-streaming-en-0.6b for English, or the Nemotron 3.5 multilingual variant in 1.2 if you need any of the 40+ supported languages. Whisper is not designed for low-latency streaming; using it for a live voice UI is the most common mistake here and it will feel sluggish.

Cancel in-flight work — new in 1.2

Foundry Local 1.2 added inference cancellation: you can cleanly cancel in-flight chat completions and transcription sessions when the user moves on, with no wasted compute or orphaned streams. On a constrained edge device this matters more than it does on a server — an abandoned transcription session holding CPU on a Pi is a real cost, not a rounding error. Wire cancellation into your UI's "stop" affordance from day one.

09Fix 4 — Hybrid Fallback (and Where This Is the Wrong Tool)Honest Limits

A hybrid architecture needs a defined behaviour when the local model is unavailable — the device is still downloading it, the model failed to load, or you are running on hardware that cannot host it. The pattern is edge-first with a cloud fallback, and it comes with a sharp caveat.

Python — edge-first embedding with a guarded cloud fallbackclass HybridEmbedder: """Edge-first. Falls back to cloud ONLY if the vector spaces match. CRITICAL: falling back to a DIFFERENT embedding model silently corrupts retrieval (see Section 4). If the local and cloud models differ, a fallback is NOT safe — failing the request is the correct behaviour. """ def __init__(self, local_client, cloud_client, *, spaces_match: bool): self.local = local_client self.cloud = cloud_client self.spaces_match = spaces_match # must be explicitly asserted def embed(self, text: str) -> list[float]: try: return self.local.generate_embedding(text).data[0].embedding except LocalModelUnavailable: if not self.spaces_match: # Fail LOUDLY. A wrong vector is worse than no vector. raise RuntimeError( "Local embedding model unavailable and cloud model uses a " "different vector space — refusing to corrupt retrieval." ) logger.warning("edge_embed_unavailable: falling back to cloud") return self.cloud.embeddings.create( model="text-embedding-3-large", input=text ).data[0].embedding
⚠ Foundry Local is NOT a server inference stack

This is the misuse to avoid, and Microsoft is explicit about it. Foundry Local is optimised for hardware-constrained devices where a single user accesses the model at a time. You can technically run it on server hardware, but it is not designed as a shared inference backend. It does not do concurrent request queuing, continuous batching, or efficient GPU sharing across many simultaneous clients.

So: do not stand up one Foundry Local box and point your whole fleet at it as a shared "embedding microservice." That is exactly the workload it is not built for, and you will rediscover every queueing problem you were trying to escape. If you need a multi-user local inference server, use a server-oriented runtime such as vLLM or Triton. Foundry Local's model is one runtime per device.

Prefer the SDK over the local server

Foundry Local ships an optional OpenAI-compatible local web server, which is genuinely useful for experimenting via REST or integrating with tools that expect an HTTP endpoint. But for an embedded application, use the SDK directly — it runs inference in-process, without the overhead of a separate server process. Reaching for the HTTP server inside your own app reintroduces a network hop you just spent this entire article removing.

One more limit worth stating: the model catalog is deliberately curated, not a general-purpose model zoo. It exists so that every model in it is quantised, tested across consumer hardware, and small enough to ship inside an application. If your plan depends on running an arbitrary Hugging Face checkpoint, Foundry Local is the wrong runtime and you want ONNX Runtime or llama.cpp directly.

Validation & Verification: Confirm the Fix

Two things must be proven, and the second is the one people skip. One: the latency actually dropped. Two: retrieval quality did not silently degrade. A migration that halves latency while quietly wrecking recall is not a win — it is a regression with good telemetry.

Step 1 — Benchmark local vs cloud on the target device (run it ON the Pi)import time, statistics from foundry_local import FoundryLocalManager manager = FoundryLocalManager(app_name="bench") model = manager.catalog.get_model("qwen3-0.6b-embedding") model.download(); model.load() local = model.get_embedding_client() query = "why did the turbine alarm at 14:02?" # WARM UP first — the first call includes model warm-up, not steady state. local.generate_embedding(query) def bench(fn, n=100): times = [] for _ in range(n): t = time.perf_counter() fn() times.append((time.perf_counter() - t) * 1000) times.sort() return { "p50": round(statistics.median(times), 1), "p95": round(times[int(n * 0.95)], 1), "p99": round(times[int(n * 0.99)], 1), } print("LOCAL:", bench(lambda: local.generate_embedding(query))) print("CLOUD:", bench(lambda: cloud.embeddings.create( model="text-embedding-3-large", input=query))) # PASS: local p99 collapses toward local p50 — no queue, no throttle. # The p99 delta should be far larger than the p50 delta. That is the tail win.
Step 2 — THE important one: prove retrieval quality did not regress# A golden set of (query -> document that SHOULD be retrieved) pairs. # Build this from real user queries. 50 pairs is enough to catch a regression. GOLDEN = [ ("why did the turbine alarm?", "d0"), ("when is pump maintenance due?", "d1"), ("is coolant pressure ok?", "d2"), ] def recall_at_k(embed_client, store, k=3) -> float: hits = 0 for query, expected_id in GOLDEN: v = embed_client.generate_embedding(query).data[0].embedding result = store.query(query_embeddings=[v], n_results=k) if expected_id in result["ids"][0]: hits += 1 return hits / len(GOLDEN) print("recall@3 (cloud model):", recall_at_k(cloud_embed, cloud_store)) print("recall@3 (local model):", recall_at_k(local_embed, local_store)) # PASS: local recall is within an acceptable margin of cloud recall. # FAIL: a meaningful drop means the 0.6B model is not good enough for your # corpus. DO NOT ship the latency win at the cost of retrieval accuracy.
Step 3 — Prove it is genuinely offline (the negative test)# The decisive test. Sever the network and confirm the edge path still works. # If embedding/ASR still succeed with no route to the internet, they are # truly local. If they fail, something is still calling out. sudo ip link set eth0 down # or: sudo nmcli networking off foundry transcribe -m whisper-tiny -f audio.wav python -c " from foundry_local import FoundryLocalManager m = FoundryLocalManager(app_name='offline-test') model = m.catalog.get_model('qwen3-0.6b-embedding'); model.load() print('dims:', len(model.get_embedding_client() .generate_embedding('offline check').data[0].embedding)) " sudo ip link set eth0 up # PASS: both succeed with the network down. (Model must be cached already — # the FIRST download obviously needs connectivity.)
What "fixed" actually means here

Success is three conditions met together, not one. First, the embedding p99 collapses — because you removed the queue, not because you found a faster model. Second, recall@k holds against your golden set; if the smaller model retrieves worse, you have traded correctness for speed and that is a bad trade. Third, the edge path genuinely works with the network severed. A migration that satisfies the first condition but not the second is the single most common way this goes wrong, and it produces an application that is fast, confident, and subtly incorrect.

Key Takeaways

For embeddings, the transport is the workload. A 0.6B model over twelve words is trivial compute wrapped in a full internet round trip. You are not making the call faster by moving it local — you are deleting the call.
Linux ARM64 in Foundry Local 1.2 is the unlock. Raspberry Pi 5, Jetson, Graviton, and Ampere are now first-class targets. Before 1.2 there was no aarch64 wheel at all.
The embedding-space trap is the real danger, not latency. Documents and queries must be embedded by the same model. Swap only the query side and you either get a 400 — or, far worse, silently meaningless retrieval with no error at all.
Split by proximity vs scale. Embeddings, ASR, and classification go to the edge. Final answer generation stays in the cloud, where model scale genuinely is the product.
Local ASR is a privacy migration disguised as a performance one. Raw audio never leaves the device — often a stronger argument for a regulated workload than the latency win.
Foundry Local is not a server inference stack. It is built for one user per device. Do not turn it into a shared embedding microservice — that is what vLLM and Triton are for.
Measure recall, not just milliseconds. A smaller embedding model may retrieve worse on your corpus. Prove it doesn't, with a golden set, before you re-index production.

Frequently Asked Questions

Can I just point my existing Azure AI Search index at local embeddings?
No — and this is the most dangerous mistake in the whole migration. Embeddings are only meaningful within the vector space of the model that produced them, so if your index was built with text-embedding-3-large and you start embedding queries with qwen3-0.6b-embedding, the vectors are not comparable. If the dimensions differ you will get a clean HTTP 400 dimension-mismatch error, which is actually the lucky outcome. If the dimensions happen to match, the query succeeds and returns semantically irrelevant documents with no error at all — and because the LLM stays fluent on bad context, you ship confident nonsense. You have exactly two safe options: re-embed the entire corpus with the local model, or use local embeddings only for a separate, edge-resident index.
Will a 0.6B embedding model retrieve as well as a large cloud model?
Maybe — and "maybe" is not good enough to ship on. It is frequently adequate, especially for a narrow domain corpus, but it is an empirical question about your data, not a general truth. Before re-indexing anything in production, build a golden set of query-to-expected-document pairs drawn from real user queries and measure recall@k with both models. If local recall holds, take the latency win. If it drops meaningfully, you are trading correctness for speed, which is a bad deal no matter how good the p99 chart looks. The validation section of this guide includes a script for exactly this measurement.
Can I run Foundry Local as a shared embedding server for my whole fleet?
You shouldn't. Microsoft is explicit that Foundry Local is optimised for hardware-constrained devices where a single user accesses the model at a time, and that while you can technically install it on server hardware, it isn't designed as a server inference stack. It does not handle concurrent request queuing, continuous batching, or efficient GPU sharing across many simultaneous clients. Standing up one box as a shared "embedding microservice" reintroduces exactly the queueing and contention you moved to the edge to escape. If you need multi-user local inference, use a server-oriented runtime such as vLLM or Triton. The Foundry Local model is one runtime per device.
Is a Raspberry Pi 5 really enough for this?
For text embeddings and speech recognition, yes. The embedding model is only 0.6B parameters, and the streaming ASR model was aggressively optimised for exactly this class of hardware — Microsoft re-implemented the pipeline in ONNX Runtime and quantised it from 2.47GB down to as little as 0.67GB while keeping word error rate within 1% of the full-precision baseline, reporting roughly 8% WER at low single-digit percent CPU usage. Foundry Local also auto-detects available hardware and picks the best execution provider. Where a Pi is not enough is if you also want to run a local chat model or on-device vision — that is when a Jetson starts to earn its cost. Don't buy accelerator hardware to run a 0.6B embedding model.

Related FAVRITE Articles

Popular posts from this blog

Learn how to use Azure Chaos Studio to simulate data center outages, test Azure OpenAI failover, and validate AI app resiliency using KQL and CLI workflows

Resiliency Testing Chaos Studio Zone Down Azure OpenAI Failover Testing AI Resiliency: Using Azure Chaos Studio to Simulate Data Center Outages on Your LLM Every multi-region Azure OpenAI architecture diagram has a failover arrow drawn on it. Almost none of them have ever actually been triggered. The arrow is a hypothesis, confirmed only by a real outage — unless you deliberately cause a controlled one first, on your own schedule, with a rollback plan, instead of finding out during an incident that the failover you designed never quite worked the way the diagram promised. The failure signature this guide resolves # The gap this article closes — a real architecture review finding: Design doc, page 4: "In the event of a regional outage, Azure Front Door automatically routes traffic to the secondary Azure OpenAI deployment in West Europe, with an expected failover time under 60 seconds." Verification performed to support this claim: NONE. Last time this path was ac...

Explore Amazon’s AI strategy: how AWS Bedrock hosts frontier models like Claude, uses Trainium silicon, and bets on cloud neutrality.

The Cloud Incumbent: AWS Bedrock Hosts Every Frontier Model and Amazon Is Betting on Neutrality AWS at $37.6 billion quarterly revenue, growing 28%. $13 billion invested in Anthropic. A $100 billion Anthropic-to-AWS commitment. Trainium with $225 billion in customer revenue commitments. The most quietly powerful AI strategy in the race. By Francis Avorgbedor | Azure Engineer  ·  July 4, 2026  ·  14 min read  ·  Amazon · AWS · Cloud AI 74 SEVENAI Momentum Score — Rank #5 $37.6B AWS Q1 2026 revenue — 28% YoY growth ▲ Fastest in 15 quarters $13B Total Amazon investment in Anthropic to date ▲ Strategic anchor 100K+ Customers running Claude on AWS Bedrock ▲ Distribution moat Amazon's AI strategy is built on a thesis that every other Magnificent Seven company is testing against — and that Amazon is uniquely positioned to win regardless of the outcome. The thesis is neutrality. In a race where Microsoft has bet on OpenAI, Google has bet on Gemini, and Meta has bet...

Find the hidden Windows 10 system files consuming up to 500GB, including hibernation, shadow copies, backups, and WinSxS, with safe cleanup steps.

  The 500GB System File That Eats Your Hard Drive Something on your Windows 10 drive is consuming hundreds of gigabytes and the normal tools cannot find it. This guide identifies every known culprit — from hibernation files and shadow copies to runaway backups and the Windows component store — and tells you exactly what is safe to delete, what to leave alone, and what the commands actually do.
How to Reset an Azure Virtual Machine to Factory Settings Using a Managed Disk Azure does not have a single "factory reset" button. What it does have is something better: the OS Disk Swap — a method that swaps out the corrupted or misconfigured OS disk for a clean Windows Server managed disk without deleting the VM, its NICs, its IP addresses, or any attached data disks. Here is how it works, when to use it, and the exact steps to execute it safely. FA Francis Avorgbedor Azure Engineer July 16, 2026 15 min read Azure VMs · Windows Server · Real-World Fix 3 Methods to achieve a clean Windows Server installation on an existing Azure VM ~15min Typical OS Disk Swap duration — VM retains its NICs, IPs, and data disks throughout 0 Data disks affected by an OS Disk Swap — data disks remain attached and untouched 1 Snapshot of the original OS disk you must take before starting — no exceptions Introduction Why Azure Does Not Have a Simple Factory Reset — and What to Do Instead On a ph...

Learn how to select Azure Files and Blob storage tiers, avoid early deletion fees, model costs, and automate lifecycle management for large file migrations.

Choosing the Right Azure Storage Tier for Large File Migrations The complete decision framework for storage tier selection during large file migrations — Azure Files tiers, Blob tiers, cost modelling, early deletion traps, lifecycle automation, and the 2026 changes that affect every migration running today. By Francis Avorgbedor | Azure Engineer  ·  July 14, 2026  ·  18 min read  ·  Storage Tiers · Cost Optimisation · Migration FA Francis Avorgbedor Azure Engineer  ·  SEVENAI  ·  Azure Field Notes 9 Distinct Azure storage tiers across Files and Blob — most engineers know only 3 15hrs Archive tier rehydration time at standard priority — the delay teams forget to plan for 128KB Minimum billable object size for Cool/Cold/Archive from July 2026 — a 32× trap for small files 70% How much retrieval and transaction fees add to a theoretical Archive storage bill The most expensive mistake I see on large Azure file migrations is not choosing the w...
Incident Playbook AKS Kubernetes kubectl 2026 AKS CrashLoopBackOff, Pending Pods, and NotReady Nodes — The Real Fixes Engineers Use Every AKS engineer eventually faces the same nightmare: CrashLoopBackOff at 2am, pods stuck Pending for no clear reason, or nodes flipping to NotReady mid-deployment. The difference between panic and control is knowing the exact diagnostic sequence — and the real fixes that work in production. This guide gives you both. 3 commands get pods, describe pod, and logs diagnose roughly 90% of AKS incidents before you touch anything else Exit 137 The code that means OOMKilled — the container hit its memory limit and was killed by the kernel (128 + SIGKILL 9) Events The bottom of kubectl describe is where the real cause lives — Pending, FailedScheduling, and image errors all surface there CoreDNS The single component behind most "intermittent" production failures — service discovery breaks quietly and looks like an app bug Table of Contents 01 The 3 Comm...
Can I Update My Old Computer to Windows 11 — and How Much Will It Cost? Your i7, 16GB RAM, 512GB SSD machine is powerful enough to run Windows 11 comfortably. The TPM 2.0 and Secure Boot wall is a security checkbox, not a performance ceiling. Here are two proven ways to get past it, what each one costs, and what you are trading away by doing so. $0 Cost of the Windows 11 licence if your existing Windows 10 is genuine — the upgrade remains free in 2026 2 Proven methods to bypass TPM 2.0 and Secure Boot — Rufus (easy) and Registry edit (manual) 25H2 Current Windows 11 version — all known bypass methods tested and confirmed working as of July 2026 Oct 2025 Windows 10 end of life — no more security updates. Staying on Windows 10 now carries real risk. First — Check Your BIOS Before Anything Else You Might Not Actually Need a Bypass Before running any bypass, open your BIOS and look at two settings. Many computers that fail the Windows 11 compatibility check have TPM 2.0 present in the hard...
Troubleshooting Guide AKS Kubernetes Real Solutions kubectl Azure Kubernetes Service (AKS) Troubleshooting Guide: Real Solutions to Common Problems CrashLoopBackOff at 2am. Pods stuck Pending with no obvious cause. Nodes going NotReady mid-deployment. DNS resolution silently failing in production. Every AKS engineer encounters these — the difference between engineers who panic and engineers who stay calm is knowing the exact sequence of diagnostic commands to run. This guide gives you that sequence, the root cause analysis for each failure mode, and the fix. 3 commands 90% of AKS problems are diagnosed with the same three kubectl commands: describe pod, logs --previous, and get events — in that order, every time Exit 137 The exit code that tells you everything: container killed by SIGKILL — either the Linux OOM killer (memory limit exceeded) or kubelet after grace period expired 5 min The CrashLoopBackOff ceiling: Kubernetes applies exponential backoff (10s → 20s → 40s → 80s → 160s → 3...
2026 Edition 100 Tools Software Engineering DevOps AIOps Top 100 Best AI Tools for Azure  Engineers and DevOps Professionals in 2026 85% of developers now regularly use AI tools. Fully AI-generated code accounts for nearly 28% of all pull requests. The question is no longer whether to use AI tools — it is which ones, in which combination, for which part of the lifecycle. This guide cuts through the noise: 100 tools, 10 categories, honest pricing, real use cases, and a selection framework for building your stack without redundancy. 85% Percentage of developers who now regularly use AI tools, per JetBrains' 2025 State of Developer Ecosystem report — up from near zero three years ago 28% Share of all pull requests containing primarily AI-generated code in 2026 — the metric that signals AI coding assistants have moved from experiment to workflow $50B Cursor's reported valuation in April 2026 Series D talks — the number that signals investor confidence in the AI developer tools mark...