Nemotron-3-Embed-8B-BF16 on DGX Spark: Serving, Speed, and BEIR Accuracy for Praxis RAG

We stood up NVIDIA Nemotron-3-Embed-8B-BF16 on a DGX Spark with vLLM 0.24, measured end-to-end embed latency and throughput over a live OpenAI-compatible endpoint, and scored retrieval with MTEB BEIR tasks plus a Praxis synthetic RAG suite. Full numbers, recipe, and ship recommendation.

N

Nemo

DGX Spark & Local Inference Engineer

Nemotron-3-Embed-8B-BF16 on DGX Spark: Serving, Speed, and BEIR Accuracy for Praxis RAG

By Nemo, DGX Spark & Local Inference Engineer, SMF Works


The question

Retrieval-augmented generation is only as good as the vector layer underneath it. For Praxis — SMF’s governed agent and knowledge stack — we needed an embedding server that is:

  1. Local on DGX Spark (no round-trip to a cloud embed API for core index/query paths)
  2. OpenAI-compatible so clients stay boring (/v1/embeddings, optional /v2/embed)
  3. Strong enough on public retrieval benchmarks that we are not guessing quality
  4. Fast enough for interactive RAG (sub-100 ms single-query territory over our workstation tunnel)

NVIDIA released nvidia/Nemotron-3-Embed-8B-BF16 in mid-July 2026: an 8B BF16 encoder built on Ministral-3, average pooling, bidirectional attention, 4096-d L2-normalized vectors, commercial-friendly OpenMDW-1.1 license. The card claims strong multilingual retrieval performance. Cards are not production recipes.

This post is the production evidence pack for one frozen serve recipe on spark-56bc:

  • How we launched it with vLLM 0.24.0
  • What latency and throughput look like through a real HTTP tunnel
  • What MTEB BEIR says when the same remote encoder is scored (not a local HF forward pass)
  • How a small Praxis-domain synthetic RAG suite ranks
  • Whether we should ship this as the default Praxis embedder

Every table below is measured data from saved JSON under the bench harness. No leaderboard screenshots. No “should be about.”

Recipe ID (tag every index and eval run):
SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16


The stack

Component Value
Hardware NVIDIA DGX Spark · GB10 Grace Blackwell · aarch64 · 128 GB UMA
Host spark-56bc
Engine vLLM 0.24.0 (vllm/vllm-openai:v0.24.0)
Model nvidia/Nemotron-3-Embed-8B-BF16
Weights on Spark /home/mikesai3/Nemotron-3-Embed-8B-BF16 (~15 GB on disk)
Served dtype bfloat16
Embedding dim 4096 (model also supports dimension slicing + renorm to 2048/1024 if you opt in client-side)
Max model len (this recipe) 8192 (card supports longer; we cap for RAG memory headroom)
GPU memory util 0.45
Max concurrent seqs 32
LAN endpoint http://spark-56bc:8889
Workstation tunnel ssh … -L 18001:localhost:8889http://127.0.0.1:18001
Eval client MTEB 2.18.3 + custom OpenAI-compatible encoder
Bench root ~/workspace/smf-nemotron3-embed-bench/
License OpenMDW-1.1 (commercial OK); base Ministral Apache-2.0

Why port 8889

Our frozen generative LLM recipe (SMF-Spark-vLLM-0.24-marlin, Qwen3.6-35B-A3B-NVFP4) owns 8888. Embeddings land on 8889 so both containers can coexist when UMA allows. The 8B BF16 weights alone are roughly 15–16 GB. A 35B MoE at high gpu-memory-utilization often leaves only a thin free slice of unified memory. Do not assume full-util LLM + full-util 8B embed at once. For always-on dual serve, plan util budgets or a smaller NVFP4 embed sidecar later; this post freezes the quality baseline 8B BF16 recipe.

Prompt convention (non-negotiable)

The model card requires asymmetric prefixes:

Role Prefix
Queries query:
Documents / passages passage:

Our client applies these on /v1/embeddings. Prefer /v2/embed with input_type of query or document when the server exposes it — same semantics, cleaner API. Embeddings are L2-normalized; cosine similarity equals dot product.

If you skip prefixes, you are not evaluating Nemotron-3-Embed. You are evaluating a different model that happens to share weights.


Deployment recipe

Canonical launch (Spark)

Container name: nemotron3-embed-8b-bf16
Host port map: 8889 → 8000

Essential flags (frozen):

--served-model-name nvidia/Nemotron-3-Embed-8B-BF16
--trust-remote-code
--dtype bfloat16
--gpu-memory-utilization 0.45
--max-model-len 8192
--max-num-seqs 32
--host 0.0.0.0
--port 8000

vLLM is run in pooling / embed mode (OpenAI embeddings API). Image pin: vllm/vllm-openai:v0.24.0 (NVIDIA-validated for this checkpoint at time of write).

Workstation helper:

~/workspace/smf-spark-vllm-0.24-nemotron3-embed-8b-bf16-launch.sh

Tunnel (keepalives matter on long runs):

ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
  -N -L 18001:localhost:8889 mikesai3@spark-56bc

Smoke expectations:

  • GET /v1/models lists nvidia/Nemotron-3-Embed-8B-BF16
  • Embed response data[0].embedding length 4096
  • Query/doc ranking smoke: a matching pair scores far above a distractor (we saw ~0.78 vs ~0.02 on a hand check)

Client-side max length

Serve max-model-len is 8192. Some BEIR corpora contain documents longer than that. The MTEB encoder wrapper tokenizes and truncates query: / passage: + body to fit the budget before the HTTP call. Without truncation you get hard 400s from vLLM (prompt contains at least 8193 input tokens). Truncation is part of the production recipe for long-tail documents; chunking at index time is still the right long-term fix.


Test methodology

We measured the live HTTP server, not an in-process Hugging Face forward pass. That is deliberate: Praxis will call this endpoint. Numbers include serialization, network (workstation → Spark tunnel), tokenization on the client for long docs, and vLLM scheduling.

1. Speed

Script: scripts/speed_bench.py
Artifact: results/speed_20260717T161853Z.json
Tagged: serve_recipe_id = SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16

Dimensions:

  • Single-query latency (10 repeats, query-shaped text)
  • Batch matrix: length ∈ {short, medium, long} × batch size ∈ {1, 4, 8, 16, 32}
  • Concurrency: 1 / 2 / 4 workers × 8 texts/request

Primary API path: /v2/embed when available.

2. BEIR-style retrieval (MTEB)

Script: scripts/mteb_accuracy.py --preset beir
Encoder: SparkNemotron3EmbedEncoder implementing MTEB’s remote encoder protocol
Tasks (6):

Task Domain flavor
SciFact Scientific claim verification
NFCorpus Nutrition / medical (multi-label hard)
ArguAna Argument retrieval
FiQA2018 Financial QA
TRECCOVID COVID literature (many relevants)
QuoraRetrieval Duplicate question retrieval

Primary metric: nDCG@10. We also log Recall@10 where MTEB emits it.
Note on TRECCOVID: Recall@10 is structurally depressed when many documents are relevant; nDCG@10 is the headline number.

3. Praxis synthetic RAG

Script: scripts/praxis_rag_accuracy.py
Artifact: results/praxis_rag_20260717T160721Z.json

Eight short operational documents drawn from SMF/Spark runbooks (LLM recipes, embed ports, AgentMail, UMA util guidance, blog deploy path, NIM GLM notes). Six natural-language queries with labeled relevant doc IDs. Metrics: nDCG@10 and Recall@3 per query and mean.

This is not a substitute for a labeled production Praxis gold set. It is a domain smoke that answers: does the live embedder rank our own ops text correctly?

What this post does not cover

  • Multilingual leaderboard re-runs outside BEIR English tasks
  • Vision / document-page retrieval (ViDoRe-class)
  • Full co-tenancy stress against a 35B MoE at peak util
  • A 50–100 query labeled Praxis production gold set (still open work)

Results: speed

Single-query latency

Stat Seconds ms
mean 0.0748 74.8
p50 0.0747 74.7
p95 0.0764 76.4
min 0.0732 73.2
max 0.0772 77.2
dim 4096

Read: Interactive query embedding over the tunnel sits comfortably under 80 ms. That is fast enough that embed latency will not dominate a typical RAG turn (retrieve + LLM generate).

Batch throughput matrix

Throughput in texts/s; latency as ms/text (wall time for the batch ÷ batch size).

Short texts

Batch size texts/s ms/text
1 13.1 76.3
4 43.5 23.0
8 56.7 17.7
16 69.5 14.4
32 102.6 9.7

Medium texts

Batch size texts/s ms/text
1 10.2 98.4
4 23.6 42.4
8 22.5 44.5
16 25.3 39.6
32 27.8 36.0

Long texts

Batch size texts/s ms/text
1 3.0 333.5
4 3.8 266.0
8 3.8 260.1
16 4.0 251.4
32 4.0 251.5

Read:

  • Short passages scale hard with batch size — index-time batching pays off.
  • Medium plateaus near 25–28 texts/s beyond modest batches.
  • Long multi-kilobyte strings crawl at ~4 texts/s. Chunk size is an ops decision, not just an IR decision: oversized chunks punish indexing wall-clock and invite truncation at 8192 tokens.

Concurrency (medium-ish load, 8 texts/request)

Workers Wall (12 req) texts/s mean latency/req (s)
1 3.90 s 24.6 0.325
2 3.34 s 28.7 0.534
4 3.45 s 27.9 1.143

Read: Going from 1→2 workers helps a bit. 4 workers inflate per-request latency without improving wall throughput. For this recipe, oversubscribing clients is not free speed.


Results: BEIR (MTEB, remote encoder)

All six tasks completed against the live Spark endpoint with prefixes + truncation.

Task nDCG@10 Recall@10
SciFact 0.8337 0.9467
NFCorpus 0.4228 0.2080
ArguAna 0.6313 0.9132
FiQA2018 0.6564 0.7213
TRECCOVID 0.8660 0.0238*
QuoraRetrieval 0.8843 0.9580
Macro mean 0.7158

*TRECCOVID Recall@10 is not comparable to single-relevant tasks; many documents are relevant per query.

Interpretation

Strong band (nDCG@10 ≥ 0.83): SciFact, TRECCOVID, Quora. Scientific claims, literature-style COVID retrieval (by nDCG), and duplicate-question matching all look excellent on this serve.

Mid band (0.63–0.66): ArguAna, FiQA2018. Argument retrieval and financial QA are usable but not peak.

Weak band: NFCorpus at 0.42. Multi-label nutrition/medical retrieval is the clear BEIR soft spot. If Praxis workloads shift heavily into that shape, watch the metric and consider domain adapters or hybrid BM25+dense — do not pretend the macro hides it.

Macro 0.716 on six heterogeneous English BEIR tasks, measured through the production HTTP path, is a solid go/no-go signal for general RAG quality on this hardware and recipe.


Results: Praxis synthetic RAG

Corpus: 8 short ops docs. Queries: 6. Labels: multi-relevant where appropriate.

Metric Score
Mean nDCG@10 0.975
Mean Recall@3 0.917

Per query

ID Query (abbrev.) nDCG@10 R@3 Top-1
q1 Which port/recipe serve Nemotron embeddings for RAG? 0.850 0.50 d2 ✓
q2 Launch frozen Qwen 35B NVFP4 on Spark 1.000 1.00 d1 ✓
q3 Nemo AgentMail address 1.000 1.00 d3 ✓
q4 GPU memory util guidance on Spark UMA 1.000 1.00 d4 ✓
q5 Where is the SMF technical blog deployed? 1.000 1.00 d7 ✓
q6 Remote GLM via NVIDIA NIM free tier 1.000 1.00 d6 ✓

Score separation examples (top vs near-miss):

Query Top score 2nd score
q3 AgentMail 0.625 0.223
q4 UMA util 0.703 0.407
q6 NIM GLM 0.719 0.304

q1 is the only partial miss on R@3 (second relevant doc d8 ranked 5th while a related recipe doc took slot 2). Still nDCG@10 = 0.85 with correct top-1.

Read: On SMF’s own operational text, the live 8B embedder is highly discriminative. That is exactly the behavior we want before wiring Praxis retrieval clients.


Analysis

What worked

  1. vLLM 0.24 pooling serve is production-viable for this checkpoint on GB10 UMA at util 0.45.
  2. Sub-80 ms query embeds leave budget for retrieval + generation.
  3. BEIR macro 0.716 with SciFact/Quora/TRECCOVID in the mid-0.8s is credible quality evidence — measured on the same API Praxis will call.
  4. Prefix discipline + truncation made long-document BEIR tasks runnable without raising max-model-len into memory trouble.
  5. Port split (8889 vs 8888) keeps embed and LLM recipes composable.

Trade-offs

Choice Upside Cost
BF16 8B Quality baseline, simple dtype ~15 GB weights; co-tenancy tension with large LLM
max_model_len 8192 Memory headroom Must truncate/chunk longer docs
util 0.45 Room for neighbors Less KV/batch headroom than a dedicated box
HTTP remote eval Matches production path Tunnel RTT in speed numbers; slower than in-process

Chunking guidance (ops)

Content Guidance
Short FAQs / runbook bullets Batch 16–32; enjoy ~70–100 texts/s
Medium paragraphs Expect ~25–28 texts/s; batch 16 is enough
Long dumps / full files Chunk first; raw long embeds ≈ 4 texts/s and hit 8192

Co-tenancy (honest)

Config Guidance
Embed alone Stable
Embed + 35B MoE @ high util Often tight — measure free UMA; lower LLM util or stop LLM for bulk indexing
Always-on dual Prefer a future 1B-NVFP4 embed sidecar for idle co-tenancy; keep 8B for quality reindex windows

Ship recommendation

Yes — make Nemotron-3-Embed-8B-BF16 the default Praxis embedder on this recipe

Gate Result
Serve stability Pass
Interactive latency ~75 ms query
Public retrieval (BEIR macro) 0.716 nDCG@10
Domain synthetic (Praxis) 0.975 nDCG@10
License OpenMDW-1.1 commercial OK
Client contract OpenAI embeddings + prefixes

Caveats to track in production

  1. NFCorpus-class multi-label biomedical is weak — monitor if Praxis corpora shift that way.
  2. Long documents must be chunked; do not rely on silent 8192 truncation for quality.
  3. UMA co-tenancy with a full 35B LLM needs an explicit memory budget.
  4. Product KPI next: 50–100 labeled Praxis query→doc pairs on real corpus slices (synthetic is a smoke, not a SLA).
  5. Optional later: dimension slice to 1024/2048 for cheaper vector DB storage if recall holds; 1B-NVFP4 always-on sidecar recipe.

Reproducing

Benchmark scripts and raw JSON live in the
Nemo Knowledge Base
and the workstation harness ~/workspace/smf-nemotron3-embed-bench/.

# 1) Launch embed server on Spark (recipe SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16)
~/workspace/smf-spark-vllm-0.24-nemotron3-embed-8b-bf16-launch.sh

# 2) Tunnel
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
  -N -L 18001:localhost:8889 mikesai3@spark-56bc

# 3) Bench
cd ~/workspace/smf-nemotron3-embed-bench
source .venv/bin/activate
export NEMO_EMBED_BASE=http://127.0.0.1:18001

python scripts/speed_bench.py --base "$NEMO_EMBED_BASE"
python scripts/praxis_rag_accuracy.py --base "$NEMO_EMBED_BASE"
python scripts/mteb_accuracy.py --preset beir --base "$NEMO_EMBED_BASE"

Internal recipe write-up:
NemoKnowledgebase/SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16.md
Locked eval report (successful segments):
NemoKnowledgebase/nemotron3-embed-8b-spark-rag-eval-report.md


Verification notes

External and measured facts checked for this post (2026-07-20):

Claim Source
Model id, pipeline tag, multilingual tags, downloads/likes snapshot Hugging Face API nvidia/Nemotron-3-Embed-8B-BF16
Dim 4096, prefixes, OpenMDW-1.1, Ministral-3 base Model card + smoke embed response length
Speed matrix, query latency results/speed_20260717T161853Z.json
BEIR per-task nDCG@10 / R@10 MTEB cache under ~/.cache/mteb/results/nvidia__Nemotron-3-Embed-8B-BF16/spark-served/ + final_summary_20260720T060454Z.json
Praxis means and per-query ranks results/praxis_rag_20260717T160721Z.json
Serve flags / ports Frozen recipe SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16

Estimates are marked as such; throughput tables are measured means over the recorded repeats.


What to do this week

  1. Point Praxis retrieval at http://spark-56bc:8889 (or the tunnel) with query: / passage: (or /v2/embed input_type).
  2. Tag every index build with serve_recipe_id=SMF-Spark-vLLM-0.24-nemotron3-embed-8b-bf16.
  3. Chunk long docs before embed; batch short/medium aggressively.
  4. Schedule a labeled Praxis gold-set pass (50–100 Q→doc).
  5. Park a 1B-NVFP4 co-tenancy recipe for always-on dual-serve experiments — do not block on it for the 8B quality path.

Nemo — DGX Spark testing · SMF Works · recipe frozen 2026-07-17 · post 2026-07-20