[{"data":1,"prerenderedAt":744},["ShallowReactive",2],{"blog-embedding-fine-tuning-domain-en":3},{"slug":4,"published":5,"updated":6,"minutes":7,"category":8,"tags":9,"keywords":15,"about":26,"sources":36,"cover":73,"og":74,"expertise":75,"locales":76,"lang":77,"title":80,"description":81,"coverAlt":82,"metaTitle":83,"takeaways":84,"faq":90,"toc":106,"blocks":140,"others":497},"embedding-fine-tuning-domain","2026-09-28","2026-10-17",8,"rag",[10,11,12,13,14],"Embeddings","Fine-tuning","RAG","Evaluation","Sentence Transformers",[16,17,18,19,20,21,22,23,24,25],"fine-tuning embedding models","domain adaptation embeddings","hard negative mining retrieval","MultipleNegativesRankingLoss","GISTEmbed vs MNRL","Matryoshka embedding dimensions","Qwen3-Embedding fine-tune","BGE-M3 vs EmbeddingGemma","embedding evaluation recall@k","catastrophic forgetting dense retrieval",[27,30,33],{"name":28,"url":29},"Word embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWord_embedding",{"name":31,"url":32},"Fine-tuning (deep learning)","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFine-tuning_%28deep_learning%29",{"name":34,"url":35},"Information retrieval","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInformation_retrieval",[37,40,43,46,49,52,55,58,61,64,67,70],{"title":38,"url":39},"Sentence Transformers: training overview","https:\u002F\u002Fsbert.net\u002Fdocs\u002Fsentence_transformer\u002Ftraining_overview.html",{"title":41,"url":42},"Sentence Transformers: loss overview","https:\u002F\u002Fsbert.net\u002Fdocs\u002Fsentence_transformer\u002Floss_overview.html",{"title":44,"url":45},"Sentence Transformers: hard negative mining","https:\u002F\u002Fsbert.net\u002Fdocs\u002Fpackage_reference\u002Futil\u002Fhard_negatives.html",{"title":47,"url":48},"RocketQA (arXiv 2010.08191)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2010.08191",{"title":50,"url":51},"InPars (arXiv 2202.05144)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2202.05144",{"title":53,"url":54},"Promptagator (arXiv 2209.11755)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2209.11755",{"title":56,"url":57},"Qwen blog: Qwen3-Embedding (Jun 2025)","https:\u002F\u002Fqwenlm.github.io\u002Fblog\u002Fqwen3-embedding\u002F",{"title":59,"url":60},"BAAI\u002Fbge-m3 model card","https:\u002F\u002Fhuggingface.co\u002FBAAI\u002Fbge-m3",{"title":62,"url":63},"Google: EmbeddingGemma docs (Oct 2026)","https:\u002F\u002Fai.google.dev\u002Fgemma\u002Fdocs\u002Fembeddinggemma",{"title":65,"url":66},"Sentence Transformers: Matryoshka embeddings","https:\u002F\u002Fsbert.net\u002Fexamples\u002Fsentence_transformer\u002Ftraining\u002Fmatryoshka\u002FREADME.html",{"title":68,"url":69},"MMTEB (arXiv 2502.13595)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2502.13595",{"title":71,"url":72},"ANCE-Tele (arXiv 2210.17167)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2210.17167","\u002Fimages\u002Fblog\u002Fembedding-fine-tuning-domain\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fembedding-fine-tuning-domain\u002Fog.jpg","ai-engineer",[77,78,79],"en","de","hu","Fine-tuning embedding models for your domain: hard negatives, losses and evals","Fine-tuning embeddings for a domain: when it beats a reranker, training pairs, hard negatives, losses in sentence-transformers v6, Matryoshka, evals and cost.","Loose dots on the left become tight clusters on the right after training.","Fine-tuning embedding models · Balázs Csorba",[85,86,87,88,89],"Fine-tune the retriever when the right document is not retrieved at all; add a reranker when it is retrieved but ranked too low. Many teams need the reranker first.","Training pairs can come from logs, tickets or LLM-generated queries; InPars and Promptagator show synthetic queries work when they are filtered, and the test split must be by document, not by pair.","Hard negatives give the strongest signal and the worst mistakes: mine them with a fixed model, keep a margin band, and rescore with a cross-encoder to drop false negatives.","In sentence-transformers v6, start with MultipleNegativesRankingLoss or its cached variant, try GISTEmbed when false negatives hurt, and wrap the loss in MatryoshkaLoss if you will serve smaller dimensions.","Evaluate recall@k and nDCG on a frozen query set of your own before and after, check unrelated traffic for forgetting, and expect a small model iterated quickly to beat one expensive large run.",[91,94,97,100,103],{"q":92,"a":93},"When should I fine-tune an embedding model instead of adding a reranker?","Fine-tune when the relevant document is not in the retrieved candidates at all, which usually means the base model’s idea of similarity does not match your domain. If the right document is retrieved but ranked low, a cross-encoder reranker is cheaper and often enough. Measure which case you have before training anything.",{"q":95,"a":96},"How do I get training data for embedding fine-tuning?","Use real query-document pairs from search logs or support tickets where you have them, and generate queries per chunk with an LLM where you do not, filtering out unanswerable and duplicate ones. Split train, dev and test by document or query cluster so the test set does not leak.",{"q":98,"a":99},"What are hard negatives and why do they matter?","Hard negatives are documents that look similar to the query but do not answer it. They teach the model fine distinctions, which in-batch negatives alone cannot. The risk is false negatives, documents that do answer the query but are unlabeled, so mine with a margin and rescore with a cross-encoder.",{"q":101,"a":102},"Which loss should I use in sentence-transformers?","For query-document pairs, start with MultipleNegativesRankingLoss and a no-duplicates batch sampler. Use the cached variant for larger effective batches on limited memory, GISTEmbedLoss when false negatives are common, and MatryoshkaLoss as a wrapper when you plan to serve truncated embeddings.",{"q":104,"a":105},"How much does fine-tuning an embedding model cost?","As of October 2026 an A100 80GB rents for about $1.79 to $2.79 an hour on common GPU clouds. By that arithmetic, a six-hour run costs roughly $11 to $17 and a 24-hour LoRA run on a 7B to 8B model about $43 to $67; small models usually train in less time.",[107,110,113,116,119,122,125,128,131,134,137],{"id":108,"title":109},"when-fine-tuning-beats-a-reranker","When fine-tuning beats a reranker",{"id":111,"title":112},"where-training-pairs-come-from","Where training pairs come from",{"id":114,"title":115},"hard-negatives","Hard negatives",{"id":117,"title":118},"losses-in-sentence-transformers-v6","Choosing a loss in sentence-transformers v6",{"id":120,"title":121},"base-models-worth-adapting-2026","Base models worth adapting in 2026",{"id":123,"title":124},"matryoshka-and-dimension-reduction","Matryoshka: train once, serve smaller",{"id":126,"title":127},"evaluation-that-predicts-production","Evaluation that predicts production",{"id":129,"title":130},"cost-and-gpu-hours","Cost in GPU hours",{"id":132,"title":133},"pitfalls-forgetting-and-languages","Pitfalls: forgetting and languages",{"id":135,"title":136},"checklist","A checklist before you swap the index",{"id":138,"title":139},"sources","Sources",[141,149,158,161,168,174,185,186,197,201,204,207,208,214,234,240,241,250,315,333,335,336,349,356,357,368,371,372,378,389,390,403,406,407,419,431,432,451,458,459],{"type":142,"content":143},"paragraph",[144,148],{"tag":145,"children":146},"strong",[147],"Fine-tuning an embedding model"," means training a general retriever on query-document pairs from your own domain, so that your users’ questions land near the documents that answer them. It is worth doing when the base model’s idea of similarity does not match yours: product codes that look alike but mean different things, regulatory language, internal jargon. It is not worth doing when the right document is already retrieved and only ranked too low, because a reranker fixes that more cheaply.",{"type":142,"content":150},[151,152,157],"This article covers the training loop rather than the model menu: the decision between fine-tuning and reranking, where training pairs come from, hard negatives, losses in sentence-transformers v6, base models worth adapting as of October 2026, Matryoshka dimensions, evaluation that predicts production, GPU cost and the failure modes. Choosing a base model in the first place is covered in ",{"tag":153,"to":154,"children":155},"link","\u002Fblog\u002Fembedding-model-selection-2026",[156],"embedding model selection",".",{"type":159,"level":160,"id":108,"text":109},"heading",2,{"type":142,"content":162},[163,164,167],"Fine-tuning beats a reranker when the failure is in retrieval, not in ranking. The sentence-transformers documentation puts the reason simply: fine-tuning “often heavily improves the performance of the model on your use case, because each task requires a different notion of similarity” (",{"tag":165,"href":39,"children":166},"a",[14],"). A reranker reads query and document together and is more accurate per pair, but it can only reorder what the first stage found. If the answer is not in the top 50, no reranker will rescue it.",{"type":169,"src":170,"alt":171,"wide":172,"caption":173},"image","\u002Fimages\u002Fblog\u002Fembedding-fine-tuning-domain\u002Fdiagram-4.webp","Fine-tune or rerank: the decision Three rows. First: do you have a query-to-document relevance signal from logs, tickets or generated queries? If not, start with hybrid retrieval and a reranker. Second: is the right document in the top 50 but ranked low? Then add a reranker. Third: is the right document not retrieved at all? Then fine-tune the retriever, and ship it only after the eval gate on a frozen query set passes.",true,"Measure first where the right document ends up; only a retrieval miss justifies training the retriever.",{"type":142,"content":175},[176,177,180,181,157],"In practice the two combine. The BGE-M3 model card itself recommends hybrid retrieval followed by a cross-encoder reranker (",{"tag":165,"href":60,"children":178},[179],"BGE-M3","), and a fine-tuned retriever with a reranker on top is the usual end state. The order matters for cost: add the reranker first, measure what is still missing, and train only if retrieval misses remain. How rerankers compare is covered in ",{"tag":153,"to":182,"children":183},"\u002Fblog\u002Freranking-models-compared",[184],"cross-encoder rerankers compared",{"type":159,"level":160,"id":111,"text":112},{"type":142,"content":187},[188,189,192,193,196],"The best pairs are real ones: a search query and the document the user opened and kept, a support ticket and the article that resolved it. Where those do not exist, generate them. InPars uses few-shot LLM prompts to generate queries per document and reports retrievers fine-tuned only on that data outperforming BM25 (",{"tag":165,"href":51,"children":190},[191],"InPars","); Promptagator generates task-specific queries from a short task description and at most eight examples and reports dual encoders beating an MS MARCO-trained ColBERT v2 by more than 1.2 nDCG on average across 11 datasets (",{"tag":165,"href":54,"children":194},[195],"Promptagator",").",{"type":169,"src":198,"alt":199,"wide":172,"caption":200},"\u002Fimages\u002Fblog\u002Fembedding-fine-tuning-domain\u002Fdiagram-8.webp","Assembling training data Five steps from left to right: corpus chunks; an LLM generates queries per chunk; filters drop unanswerable, duplicate and wrong-language queries; hard negatives are mined with a fixed model inside a margin band and rescored by a cross-encoder; and the pairs are split into train, dev and test by document.","Every filter removes noise the model would otherwise learn; the split by document keeps the test honest.",{"type":142,"content":202},[203],"Synthetic data works only after filtering. Drop queries the chunk cannot answer, near-duplicates, queries in the wrong language and questions that copy whole phrases from the chunk, because those teach the model to match surface words rather than meaning. No published number says how many pairs you need; in practice a few thousand clean pairs per domain is a common starting point, and quality beats quantity.",{"type":142,"content":205},[206],"Split train, dev and test by document or by query cluster, never by pair. If two generated queries about the same chunk land on both sides of the split, the test measures memorisation. Freeze the test set before the first experiment and do not look at it while tuning; use the dev set for that.",{"type":159,"level":160,"id":114,"text":115},{"type":142,"content":209},[210,211,196],"Contrastive losses such as MultipleNegativesRankingLoss treat every other positive in the batch as a negative. Those in-batch negatives are mostly easy, so the model learns coarse distinctions quickly and fine ones slowly. Hard negatives, documents that look relevant but are not, carry the strongest signal. RocketQA built the recipe most fine-tunes still copy, with cross-batch negatives and denoised hard negatives, because unlabeled positives otherwise poison training (",{"tag":165,"href":48,"children":212},[213],"RocketQA",{"type":142,"content":215},[216,217,221,222,225,226,229,230,233],"sentence-transformers now includes the tooling. ",{"tag":218,"children":219},"code",[220],"mine_hard_negatives()"," embeds your pairs, finds the nearest documents for each query, can rescore candidates with a cross-encoder, and samples negatives inside a band set by ",{"tag":218,"children":223},[224],"range_min",", ",{"tag":218,"children":227},[228],"range_max"," and an absolute or relative margin (",{"tag":165,"href":45,"children":231},[232],"hard negatives","). Skip the top few results, because those are the likeliest false negatives, and keep a margin below the positive’s score. Mine with a fixed copy of the base model, not the model you are training, or the negatives shift under you.",{"type":142,"content":235},[236,237,239],"A useful sanity check after mining is to read twenty random triplets by hand. If several negatives actually answer the query, raise ",{"tag":218,"children":238},[224]," or tighten the margin; if the negatives are obviously unrelated, they are too easy and the band is too wide. Ten minutes of reading here saves a training run that teaches the model the wrong boundary.",{"type":159,"level":160,"id":117,"text":118},{"type":142,"content":242},[243,244,247,248,196],"For query-document pairs the documented choices are MultipleNegativesRankingLoss, its cached variant, MegaBatchMarginLoss and the two GISTEmbed losses; MatryoshkaLoss, Matryoshka2dLoss and AdaptiveLayerLoss wrap any of them (",{"tag":165,"href":42,"children":245},[246],"loss overview","). The training overview’s own example uses one epoch, a batch size of 16, a learning rate of 2e-5 and a no-duplicates batch sampler, because in-batch-negative losses suffer when a batch contains the same text twice (",{"tag":165,"href":39,"children":249},[14],{"type":251,"head":252,"rows":263},"table",[253,255,257,259,261],[254],"Loss",[256],"Inputs",[258],"Needs",[260],"When to use",[262],"Pitfall",[264,274,284,294,304],[265,266,268,270,272],[19],[267],"pairs or triplets",[269],"large batches help",[271],"default starting point",[273],"duplicates in a batch become false negatives",[275,277,278,280,282],[276],"CachedMultipleNegativesRankingLoss",[267],[279],"gradient caching",[281],"big effective batch on small GPU",[283],"slightly slower; not with Matryoshka2d",[285,287,288,290,292],[286],"GISTEmbedLoss",[267],[289],"a guide model",[291],"many false negatives",[293],"training overhead",[295,297,298,300,302],[296],"CachedGISTEmbedLoss",[267],[299],"guide model, caching",[301],"GIST with large batches",[303],"set mini_batch_size to fit memory",[305,307,309,311,313],[306],"MatryoshkaLoss",[308],"wraps another loss",[310],"list of dims",[312],"serving truncated vectors",[314],"evaluate every dim you serve",{"type":142,"content":316},[317,318,322,323,327,328,332],"CachedMultipleNegativesRankingLoss uses gradient caching to reach much larger batches without extra memory, at a small speed cost (",{"tag":165,"href":319,"children":320},"https:\u002F\u002Fsbert.net\u002Fdocs\u002Fpackage_reference\u002Fsentence_transformer\u002Flosses.html",[321],"losses","), based on the GradCache technique (",{"tag":165,"href":324,"children":325},"https:\u002F\u002Farxiv.org\u002Fabs\u002F2101.06983",[326],"GradCache","). GISTEmbedLoss takes a guide model and uses it to drop in-batch negatives that the guide considers too similar to the positive, which addresses false negatives directly (",{"tag":165,"href":329,"children":330},"https:\u002F\u002Farxiv.org\u002Fabs\u002F2402.16829",[331],"GISTEmbed","). One restriction to know: Matryoshka2dLoss cannot wrap the cached, hook-based losses.",{"type":218,"code":334},"# Sketch for sentence-transformers v6: mine negatives with a fixed model, train with a cached loss\nfrom sentence_transformers import SentenceTransformer, SentenceTransformerTrainer, SentenceTransformerTrainingArguments\nfrom sentence_transformers.cross_encoder import CrossEncoder\nfrom sentence_transformers.sentence_transformer.losses import CachedMultipleNegativesRankingLoss, MatryoshkaLoss\nfrom sentence_transformers.util import mine_hard_negatives\n\nbase = SentenceTransformer(\"BAAI\u002Fbge-m3\")\nminer = SentenceTransformer(\"BAAI\u002Fbge-m3\")             # fixed copy, never the model being trained\ntrain = mine_hard_negatives(\n    pairs_train, miner, cross_encoder=CrossEncoder(\"BAAI\u002Fbge-reranker-v2-m3\"),\n    range_min=10, range_max=50, relative_margin=0.05, num_negatives=3, output_format=\"triplet\",\n)\n\nloss = MatryoshkaLoss(base, CachedMultipleNegativesRankingLoss(base, mini_batch_size=32),\n                      matryoshka_dims=[1024, 512, 256])\nargs = SentenceTransformerTrainingArguments(\n    output_dir=\"out\u002Fbge-m3-domain\", num_train_epochs=1, per_device_train_batch_size=128,\n    learning_rate=2e-5, warmup_ratio=0.1, bf16=True, batch_sampler=\"no_duplicates\",\n)\nSentenceTransformerTrainer(model=base, args=args, train_dataset=train, loss=loss).train()",{"type":159,"level":160,"id":120,"text":121},{"type":142,"content":337},[338,339,341,342,345,346,196],"As of October 2026, three open families cover most needs. BGE-M3 is MIT-licensed, does dense, sparse and multi-vector retrieval from one model, handles 8,192-token inputs and covers more than 100 languages (",{"tag":165,"href":60,"children":340},[179],"). Qwen3-Embedding comes in 0.6B, 4B and 8B under Apache-2.0, with 32K context, instruction-aware inputs and Matryoshka dimensions; its own training used LoRA and a three-stage pipeline in which the LLM also synthesized training data (",{"tag":165,"href":57,"children":343},[344],"Qwen","). EmbeddingGemma 2 is a 740M multimodal model with Matryoshka truncation from 768 down to 128 dimensions and Apache-2.0 weights (",{"tag":165,"href":63,"children":347},[348],"Google",{"type":142,"content":350},[351,352,355],"Smaller usually wins the first round. A 0.6B model trains in hours on one GPU, so you can run ten experiments on data and negatives in the time one 8B run takes, and most of the gain comes from data quality, not parameters. The MMTEB paper reported multilingual-e5-large-instruct, at 560M parameters, as the best publicly available model on its multilingual benchmark (",{"tag":165,"href":69,"children":353},[354],"MMTEB","); that is a statement about the paper’s snapshot, but it shows how far a mid-sized model can go.",{"type":159,"level":160,"id":123,"text":124},{"type":142,"content":358},[359,360,363,364,157],"MatryoshkaLoss applies the base loss to truncated slices of the embedding, so the first 512, 256 or 128 dimensions remain useful on their own. In the library’s own experiment, a Matryoshka-trained model kept 98.37 percent of its full-size performance at 8.3 percent of the embedding size, against 96.46 percent for a standard model (",{"tag":165,"href":66,"children":361},[362],"Matryoshka","). That matters at serving time, where smaller vectors mean less memory and faster search; quantization and truncation combine, as described in ",{"tag":153,"to":365,"children":366},"\u002Fblog\u002Fembedding-quantization-binary-matryoshka",[367],"embedding quantization with binary and Matryoshka",{"type":142,"content":369},[370],"The caveat is evaluation: Matryoshka only pays off if the slice you serve is the slice you measured. Evaluate recall at every dimension you plan to deploy, not only at full size.",{"type":159,"level":160,"id":126,"text":127},{"type":142,"content":373},[374,375,377],"Measure recall@k, nDCG@10 and MRR on your frozen test set before and after training, at the k you actually retrieve. Public benchmarks are a weak proxy here by design: MMTEB spans more than 500 tasks in more than 250 languages, and its English benchmark is meant to be zero-shot, excluding datasets such as MS MARCO that are commonly used for fine-tuning (",{"tag":165,"href":69,"children":376},[354],"). A fine-tune can raise your domain score and lower a leaderboard score at the same time, and only the first one matters.",{"type":142,"content":379},[380,381,384,385,157],"Then re-run the full RAG evaluation, not just retrieval, because better recall can still produce worse answers if the new top chunks are longer or noisier. Treat the comparison as a decision with a confidence attached: in my ",{"tag":218,"children":382},[383],"jev-decide"," skill, a decision with low confidence goes to a person instead of being applied, and a fine-tune that wins by less than the dev-set noise belongs in that category. Generating evaluation data for whole answers is covered in ",{"tag":153,"to":386,"children":387},"\u002Fblog\u002Fsynthetic-test-data-rag-evals",[388],"synthetic test data for RAG evals",{"type":159,"level":160,"id":129,"text":130},{"type":142,"content":391},[392,393,397,398,402],"The arithmetic is short. As of October 2026 an A100 80GB costs about $1.79 an hour on demand at RunPod (",{"tag":165,"href":394,"children":395},"https:\u002F\u002Fwww.runpod.io\u002Fpricing",[396],"RunPod",") and $2.79 at Lambda (",{"tag":165,"href":399,"children":400},"https:\u002F\u002Flambda.ai\u002Fpricing",[401],"Lambda","). A six-hour run on one card is therefore about $11 to $17, and a 24-hour LoRA run on a 7B to 8B model about $43 to $67; these are estimates from the hourly rates, not benchmarks. Small models fit a full fine-tune on one card; 7B to 8B models usually need LoRA and gradient caching.",{"type":142,"content":404},[405],"The expensive part is not the GPU but the iteration loop. Three days of quick runs on a 0.5B model, each changing one thing in the data or the negatives, usually beat one heroic run on an 8B model you cannot afford to repeat.",{"type":159,"level":160,"id":132,"text":133},{"type":142,"content":408},[409,410,413,414,418],"Catastrophic forgetting is documented in dense retrieval, not hypothetical. ANCE-Tele traced training instability in iterative mine-and-train loops to models learning and forgetting different groups of negatives (",{"tag":165,"href":72,"children":411},[412],"ANCE-Tele","), and a 2025 study found systems tuned for temporal queries losing accuracy on ordinary ones (",{"tag":165,"href":415,"children":416},"https:\u002F\u002Farxiv.org\u002Fabs\u002F2507.06782",[417],"temporal IR","). Keep the learning rate low, train one epoch first, mix some general-domain pairs back in, and test a sample of unrelated queries alongside your domain set.",{"type":420,"variant":421,"title":422,"body":423},"callout","warn","Build your own eval set per language",[424],[425,426,430],"Language coverage claims are broader than benchmark coverage. MTEB’s retrieval suite includes German sets such as GermanDPR, but Hungarian retrieval is represented by only a couple of contributed tasks (",{"tag":165,"href":427,"children":428},"https:\u002F\u002Fembeddings-benchmark.github.io\u002Fmteb\u002Foverview\u002Favailable_tasks\u002Fretrieval\u002F",[429],"MTEB","). If your users ask in German and Hungarian, as on my own site, which I translated with an LLM pipeline, generate and judge test queries in each language yourself.",{"type":159,"level":160,"id":135,"text":136},{"type":433,"ordered":172,"items":434},"list",[435,437,439,441,443,445,447,449],[436],"Freeze a baseline and log recall@k, nDCG@10 and MRR on a frozen test set.",[438],"Confirm it is a retrieval miss, not a ranking problem a reranker would fix.",[440],"Build filtered pairs per language and split by document.",[442],"Mine negatives with a fixed model and a cross-encoder filter.",[444],"Start with MNRL or its cached variant, 2e-5 and one epoch.",[446],"Evaluate every Matryoshka dimension you plan to serve.",[448],"Check unrelated queries for forgetting, then re-run the full RAG eval.",[450],"Re-embed the corpus and swap the index only after all of the above pass.",{"type":142,"content":452},[453,454,157],"If your retrieval misses domain-specific questions and you want to know whether fine-tuning or a reranker is the cheaper fix, see my ",{"tag":153,"to":455,"children":456},"\u002Fexpertise\u002Fai-engineer",[457],"AI engineering work",{"type":159,"level":160,"id":138,"text":139},{"type":433,"ordered":172,"items":460},[461,464,467,470,473,476,479,482,485,488,491,494],[462],{"tag":165,"href":39,"children":463},[38],[465],{"tag":165,"href":42,"children":466},[41],[468],{"tag":165,"href":45,"children":469},[44],[471],{"tag":165,"href":48,"children":472},[47],[474],{"tag":165,"href":51,"children":475},[50],[477],{"tag":165,"href":54,"children":478},[53],[480],{"tag":165,"href":57,"children":481},[56],[483],{"tag":165,"href":60,"children":484},[59],[486],{"tag":165,"href":63,"children":487},[62],[489],{"tag":165,"href":66,"children":490},[65],[492],{"tag":165,"href":69,"children":493},[68],[495],{"tag":165,"href":72,"children":496},[71],[498,565,625,683],{"slug":499,"published":6,"minutes":500,"category":8,"tags":501,"keywords":504,"about":517,"sources":523,"cover":559,"og":560,"expertise":75,"locales":561,"lang":77,"title":562,"description":563,"coverAlt":564},"embedding-model-selection-2026",9,[10,12,429,502,503],"Vector search","Model selection",[505,506,507,508,509,510,511,512,513,514,515,516],"best embedding model 2026","how to choose an embedding model","embedding model comparison","MTEB leaderboard explained","RTEB benchmark","open source embedding model","multilingual embedding model","voyage-4 vs openai embeddings","Qwen3-Embedding","EmbeddingGemma","embedding model for RAG","switching embedding models re-embed",[518,519,520],{"name":28,"url":29},{"name":34,"url":35},{"name":521,"url":522},"Discounted cumulative gain","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDiscounted_cumulative_gain",[524,526,529,532,535,538,541,544,547,550,553,556],{"title":525,"url":69},"Enevoldsen et al.: MMTEB, Massive Multilingual Text Embedding Benchmark (2025)",{"title":527,"url":528},"Hugging Face: Introducing RTEB, a new standard for retrieval evaluation (Oct 2025)","https:\u002F\u002Fhuggingface.co\u002Fblog\u002Frteb",{"title":530,"url":531},"OpenAI: Vector embeddings guide","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings",{"title":533,"url":534},"OpenAI: API pricing","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fpricing",{"title":536,"url":537},"Voyage AI: The Voyage 4 model family, shared embedding space with MoE architecture (Jan 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F01\u002F15\u002Fvoyage-4\u002F",{"title":539,"url":540},"Voyage AI: Text embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fembeddings",{"title":542,"url":543},"Voyage AI: Pricing","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fpricing",{"title":545,"url":546},"Google: Gemini API embeddings documentation","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fembeddings",{"title":548,"url":549},"Google: Gemini API pricing","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fpricing",{"title":551,"url":552},"Cohere: Embed models documentation","https:\u002F\u002Fdocs.cohere.com\u002Fdocs\u002Fcohere-embed",{"title":554,"url":555},"Qwen: Qwen3-Embedding-8B model card","https:\u002F\u002Fhuggingface.co\u002FQwen\u002FQwen3-Embedding-8B",{"title":557,"url":558},"Google Developers Blog: Introducing EmbeddingGemma (Sep 2025)","https:\u002F\u002Fdevelopers.googleblog.com\u002Fen\u002Fintroducing-embeddinggemma\u002F","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fog.jpg",[77,78,79],"Choosing an embedding model in 2026: leaderboards, costs and a bake-off on your own data","How to pick an embedding model for RAG in 2026: what MTEB and RTEB tell you, hosted vs open weights, prices, dimensions, and a one-week bake-off.","Three columns of stacked blocks, the middle tallest, each measured by a short bar and a wide bracket.",{"slug":566,"published":6,"minutes":567,"category":8,"tags":568,"keywords":572,"about":584,"sources":594,"cover":619,"og":620,"expertise":75,"locales":621,"lang":77,"title":622,"description":623,"coverAlt":624},"contextual-retrieval-late-chunking",10,[12,569,10,570,571],"Chunking","Contextual retrieval","Late chunking",[573,574,575,576,577,578,579,580,581,582,583],"contextual retrieval","anthropic contextual retrieval","late chunking","contextual chunk embeddings","contextual embeddings rag","contextual bm25","chunk context rag","voyage-context-3","voyage-context-4","late chunking vs contextual retrieval","rag chunking context loss",[585,588,591],{"name":586,"url":587},"Retrieval-augmented generation","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRetrieval-augmented_generation",{"name":589,"url":590},"Okapi BM25","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOkapi_BM25",{"name":592,"url":593},"Sentence embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSentence_embedding",[595,598,601,604,607,610,613,616],{"title":596,"url":597},"Anthropic: Introducing Contextual Retrieval (Sep 2024)","https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fcontextual-retrieval",{"title":599,"url":600},"Günther et al.: Late Chunking, Contextual Chunk Embeddings Using Long-Context Embedding Models (2024, rev. 2025)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2409.04701",{"title":602,"url":603},"Jina AI: Late Chunking in Long-Context Embedding Models (Aug 2024)","https:\u002F\u002Fjina.ai\u002Fnews\u002Flate-chunking-in-long-context-embedding-models\u002F",{"title":605,"url":606},"Voyage AI: Introducing voyage-context-3 (Jul 2025)","https:\u002F\u002Fblog.voyageai.com\u002F2025\u002F07\u002F23\u002Fvoyage-context-3\u002F",{"title":608,"url":609},"Voyage AI: voyage-context-4 (Jun 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F06\u002F29\u002Fvoyage-context-4\u002F",{"title":611,"url":612},"Voyage AI: Contextualized chunk embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fcontextualized-chunk-embeddings",{"title":614,"url":615},"Anthropic: Claude API pricing","https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fabout-claude\u002Fpricing",{"title":617,"url":618},"Qu, Tu and Bao: Is Semantic Chunking Worth the Computational Cost? (2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2410.13070","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fog.jpg",[77,78,79],"Contextual retrieval and late chunking: giving RAG chunks back their context","Chunks lose their document. How contextual retrieval, late chunking and contextualized embedding models fix that, what each costs, and when to skip it.","Four loose square pieces gathered by a wide bracket below, each joined upward to a large sheet.",{"slug":626,"published":6,"minutes":500,"category":8,"tags":627,"keywords":631,"about":644,"sources":652,"cover":677,"og":678,"expertise":75,"locales":679,"lang":77,"title":680,"description":681,"coverAlt":682},"rag-access-control-permissions",[12,628,629,630,502],"Access control","Security","Multi-tenancy",[632,633,634,635,636,637,638,639,640,641,642,643],"rag access control","permission aware rag","document level security rag","rag multi tenancy","vector database access control","pgvector row level security","security trimming azure ai search","openfga rag authorization","qdrant multitenancy","pinecone namespaces multitenancy","owasp llm08 vector and embedding weaknesses","rag data leakage",[645,648,651],{"name":646,"url":647},"Access-control list","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAccess-control_list",{"name":649,"url":650},"Multitenancy","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitenancy",{"name":586,"url":587},[653,656,659,662,665,668,671,674],{"title":654,"url":655},"OWASP GenAI Security Project: LLM08:2025 Vector and Embedding Weaknesses","https:\u002F\u002Fgenai.owasp.org\u002Fllmrisk\u002Fllm082025-vector-and-embedding-weaknesses\u002F",{"title":657,"url":658},"PostgreSQL documentation: Row Security Policies","https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-rowsecurity.html",{"title":660,"url":661},"pgvector README: filtering and iterative index scans","https:\u002F\u002Fgithub.com\u002Fpgvector\u002Fpgvector",{"title":663,"url":664},"Qdrant: Multitenancy and partitions guide","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fguides\u002Fmultiple-partitions\u002F",{"title":666,"url":667},"Pinecone: Implement multitenancy using namespaces","https:\u002F\u002Fdocs.pinecone.io\u002Fguides\u002Findex-data\u002Fimplement-multitenancy",{"title":669,"url":670},"Microsoft Learn: Document-level access control in Azure AI Search","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-document-level-access-overview",{"title":672,"url":673},"OpenFGA: RAG authorization use case","https:\u002F\u002Fopenfga.dev\u002Fdocs\u002Fuse-cases\u002Frag-authorization",{"title":675,"url":676},"Morris et al.: Text Embeddings Reveal (Almost) As Much As Text (EMNLP 2023)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2310.06816","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fog.jpg",[77,78,79],"Access control for RAG: permission-aware retrieval without leaking documents","How RAG assistants leak documents and how to stop it: ACLs on every chunk, pre-filtering, row-level security in pgvector, permission sync and leak tests.","Seven cards in a row, six with a lock badge, one bare card sending an arrow outward.",{"slug":684,"published":6,"minutes":567,"category":8,"tags":685,"keywords":690,"about":702,"sources":710,"cover":737,"og":738,"expertise":739,"locales":740,"lang":77,"title":741,"description":742,"coverAlt":743},"rag-product-catalog-pim-data",[12,686,687,688,689],"PIM","Product data","B2B e-commerce","Metadata filtering",[691,692,693,694,695,696,697,698,699,700,701],"rag product catalog","rag pim data","llm product data","product catalog chatbot","akeneo rag","pimcore ai search","rag structured data","metadata filtering rag","product attributes embeddings","b2b product assistant","etim classification ai",[703,706,707],{"name":704,"url":705},"Product information management","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FProduct_information_management",{"name":586,"url":587},{"name":708,"url":709},"ETIM (standard)","https:\u002F\u002Fwww.etim-international.com\u002Fclassification\u002F",[711,714,717,720,722,725,728,731,734],{"title":712,"url":713},"Akeneo API: Products, product values, metric values and product models","https:\u002F\u002Fapi.akeneo.com\u002Fconcepts\u002Fproducts.html",{"title":715,"url":716},"Akeneo Help Center: What about products with variants?","https:\u002F\u002Fhelp.akeneo.com\u002Fserenity-take-the-power-over-your-products\u002Fserenity-what-about-products-with-variants",{"title":718,"url":719},"Pimcore documentation: Classification Store","https:\u002F\u002Fdocs.pimcore.com\u002Fplatform\u002FPimcore\u002FObjects\u002FObject_Classes\u002FData_Types\u002FClassification_Store\u002F",{"title":721,"url":709},"ETIM International: Classification",{"title":723,"url":724},"ETIM International: ETIM releases and the IXF format","https:\u002F\u002Fetim-international.com\u002F?p=754",{"title":726,"url":727},"Reddy et al.: Shopping Queries Dataset, a large-scale ESCI benchmark for improving product search (2022)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2206.06588",{"title":729,"url":730},"Amazon Science: esci-data repository","https:\u002F\u002Fgithub.com\u002Famazon-science\u002Fesci-data",{"title":732,"url":733},"Qdrant documentation: Filtering","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fconcepts\u002Ffiltering\u002F",{"title":735,"url":736},"Sui et al.: Table Meets LLM, can large language models understand structured table data? (WSDM 2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2305.13062","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fog.jpg","b2b-ecommerce-developer",[77,78,79],"RAG over product catalogues: turning PIM data into answers that hold","Product data is structured, so chunking it like PDFs fails. How to serialize PIM attributes, route spec questions to filters and keep answers exact.","A frame of nine squares with tiny symbols, funnelling down to one card.",1792342719194]