Fine-Tuning Embedding Models for Your Domain
Imagine you've deployed a RAG pipeline with a state-of-the-art embedding model—BAAI/bge-m3 or OpenAI text-embedding-3. It works well for general queries, but when it comes to domain-specific documents—medical protocols, court rulings, or technical standards—search accuracy drops. The model confuses domain terms, context recall stagnates at 0.6-0.7, and top-K results are filled with semantically similar but thematically irrelevant documents. We solve this by fine-tuning the model on your data. No infrastructure changes required. Our approach: synthetic pair generation via LLM, fine-tuning with MultipleNegativesRankingLoss, and thorough evaluation. The result: NDCG improvement of 15-30%. Over 5 years, we've completed more than 30 projects customizing NLP models.
"Domain-specific fine-tuning of embedding models can improve retrieval metrics by 15-30% without changing infrastructure" — from a project report
When Is Fine-Tuning Necessary?
Symptoms that indicate the need for fine-tuning:
- The general model confuses specific terms: MeSH terms in medicine, legal constructs in law, technical abbreviations.
- Context recall of the RAG system is stuck below 0.75, even after optimizing chunking and search index.
- High false positive rate—semantically similar but topically irrelevant documents appear in top-K.
If you notice these signs, fine-tuning will boost metrics by 15-30% without changing architecture.
Why Fine-Tuning Is Better Than Model Replacement
Switching to a larger model (e.g., from 768 to 1536 dimensions) increases latency and vector storage costs. Fine-tuning the same model on domain data is cheaper and faster. We use MultipleNegativesRankingLoss—it's more effective than triplet loss for retrieval tasks. Infrastructure savings can reach 30%, and API costs for data generation are offset by accuracy gains.
How We Fine-Tune: Stack and Configuration
We use sentence-transformers, PyTorch, Hugging Face Transformers. Base models: BAAI/bge-m3 or intfloat/multilingual-e5-large. We train on A100 (80GB) with batch size 32, learning rate 2e-5, warmup 10%.
Generating Training Pairs with LLM
To create a dataset without manual labeling, we use GPT-4o-mini. Example generation:
from openai import OpenAI
import json
client = OpenAI()
def generate_queries_for_document(doc_text: str, n: int = 5) -> list[str]:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": f"""Generate {n} search queries..."""
}],
response_format={"type": "json_object"},
)
return json.loads(response.choices[0].message.content)["queries"]
Typically: 1000 documents × 5 queries = 5000 pairs in ~2 hours and $5-15 on API.
Step-by-Step Fine-Tuning Process
- Domain analysis and collection of representative documents. Identify key topics and query types.
- Generation of synthetic query-document pairs. Use LLM (GPT-4o-mini) to create up to 5000 pairs.
- Manual review and correction (optional). Engage domain experts to improve quality.
- Fine-tuning. Run training on A100 with MultipleNegativesRankingLoss.
- Evaluation. Compare metrics on test set before and after.
- Deployment. Replace weights file—infrastructure unchanged.
Data Volume: Minimum and Optimal
| Dataset Type | Number of Pairs (query-document) | Expected NDCG@10 Improvement |
|---|---|---|
| Minimum | 300–500 | 5–10% |
| Optimal | 2000–5000 | 15–30% |
From Our Practice: Legal Documents
We worked with a large law firm. Their task was searching through court rulings and regulations. The baseline model BAAI/bge-m3 gave NDCG@10 = 0.68. We fine-tuned on 8000 pairs (6500 synthetic via GPT-4o-mini, 1500 manual from experts). Results:
| Metric | Before FT | After FT |
|---|---|---|
| NDCG@10 | 0.68 | 0.84 |
| Recall@5 | 0.61 | 0.79 |
| MRR@5 | 0.65 | 0.82 |
| Latency | unchanged | unchanged |
+24% NDCG without infrastructure changes—just a weight update. The client got a search system that finds relevant documents twice as accurately.
What’s Included
- Analysis of your data and identification of retrieval issues.
- Preparation of training dataset (synthetic + manual labeling if needed).
- Fine-tuning the model on the chosen stack.
- Evaluation on your test queries.
- Deployment of the fine-tuned model in your infrastructure (Docker, SageMaker, Triton).
- Documentation and team training.
Request an evaluation of your project—we'll design the optimal fine-tuning strategy.
Timeline
- Dataset generation: 3-7 days.
- Fine-tuning: 2-4 hours (on A100) up to a day for large volume.
- Evaluation and comparison: 2-3 days.
- Total: 1 to 3 weeks depending on complexity.
How to Evaluate Quality After Fine-Tuning?
We use InformationRetrievalEvaluator from sentence-transformers:
evaluator = InformationRetrievalEvaluator(
queries=test_queries,
corpus=test_corpus,
relevant_docs=relevance_labels,
precision_recall_at_k=[1,5,10],
ndcg_at_k=[10],
)
Compare baseline and fine-tuned model. Visualize results and deliver to client.
To avoid common pitfalls, we use sufficient data volume, separate test sets, and normalize embeddings at inference. With 5 years of NLP experience and over 30 successful fine-tuning projects, we guarantee results.
Contact us—we'll evaluate your project and propose the best solution. We work end-to-end: from data analysis to deployment. Get a consultation—it's free.







