Дообчання Embedding-моделі під домен замовника

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
Дообчання Embedding-моделі під домен замовника
Середній
від 1 тижня до 3 місяців
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

Дообучення Embedding-моделі під домен замовника

Стандартні embedding-моделі навчені на загальному веб-тексті та академічних корпусах. У спеціалізованих доменах (медицина, право, фінанси, технічні стандарти) вони погано розрізняють специфічну термінологію і показують зменшений retrieval recall. Fine-tuning embedding-моделі під конкретний домен підвищує якість пошуку без зміни всієї RAG-інфраструктури.

Коли необхідне дообучення embedding-моделі

Ознаки, які вказують на необхідність fine-tuning:

  • Загальна embedding-модель погано розрізняє специфічні терміни домену (MeSH терміни, юридичні конструкції, технічні абревіатури)
  • Context recall RAG-системи застряг нижче 0.75 незважаючи на оптимізацію чункінгу та пошуку
  • Висока частка «хибних спрацьовань» — семантично подібні, але тематично нерелевантні документи потрапляють у top-K

Підготовка навчальних даних: Triplet vs Contrastive

Triplet Loss: якір (anchor), позитив (релевантний документ), негатив (нерелевантний документ).

Contrastive / Multi Negative Ranking Loss: пари (запит, релевантний документ). Негативи беруться з інших документів у батчі.

from sentence_transformers import SentenceTransformer, InputExample, losses
from torch.utils.data import DataLoader

# Навчальні дані: пари (query, relevant_document)
train_examples = [
    InputExample(texts=["якій тривалості запиту щодо трудових спорів",
                        "Строк позивності по індивідуальним трудовим спорам складає 3 місяці..."]),
    InputExample(texts=["розрахунок допомоги з тимчасової непрацездатності",
                        "Розмір допомоги з тимчасової непрацездатності визначається..."]),
    # ... ще приклади
]

# Завантаження базової моделі
model = SentenceTransformer("BAAI/bge-m3")

# Multi Negative Ranking Loss (ефективніше triplet для retrieval)
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=32)
train_loss = losses.MultipleNegativesRankingLoss(model)

# Навчання
model.fit(
    train_objectives=[(train_dataloader, train_loss)],
    epochs=3,
    warmup_steps=100,
    output_path="./bge-m3-legal-finetuned",
    show_progress_bar=True,
)

Генерація навчальних пар з LLM

Для створення навчального датасету без ручної розмітки:

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"""Згенеруй {n} пошукових запитів, які користувач міг би задати,
щоб знайти наступний документ. Запити мають бути різними за формулюванням,
але все вони мають бути відповідені цим документом.
Верни JSON-список строк.

Документ:
{doc_text[:1000]}"""
        }],
        response_format={"type": "json_object"},
    )
    return json.loads(response.choices[0].message.content)["queries"]

# Генерація датасету з 1000 документів
training_pairs = []
for doc in domain_documents:
    queries = generate_queries_for_document(doc.text)
    for query in queries:
        training_pairs.append(InputExample(texts=[query, doc.text]))

print(f"Згенеровано {len(training_pairs)} навчальних пар")
# Типово: 1000 документів × 5 запитів = 5000 пар за ~2 години та $5-15

Оцінка покращення retrieval

from sentence_transformers.evaluation import InformationRetrievalEvaluator

# Тестовий набір: {query_id: query, corpus_id: doc, relevant_docs: {query_id: [doc_ids]}}
evaluator = InformationRetrievalEvaluator(
    queries=test_queries,
    corpus=test_corpus,
    relevant_docs=relevance_labels,
    precision_recall_at_k=[1, 5, 10],
    ndcg_at_k=[10],
    show_progress_bar=True,
)

# Порівняння базової та дообученої моделі
base_model = SentenceTransformer("BAAI/bge-m3")
finetuned_model = SentenceTransformer("./bge-m3-legal-finetuned")

base_results = evaluator(base_model, output_path="./eval_base")
ft_results = evaluator(finetuned_model, output_path="./eval_finetuned")

Практичний кейс: юридичні документи

Базова модель: BAAI/bge-m3. Датасет: 8000 пар (синтетичних: 6500 через GPT-4o-mini + 1500 ручних). Домен: російське трудове та цивільне право.

Метрика До FT Після FT
NDCG@10 0.68 0.84
Recall@5 0.61 0.79
MRR@5 0.65 0.82
Latency (inference) без змін без змін

+24% до NDCG без змін інфраструктури — лише оновлення ваг моделі.

Терміни

  • Генерація навчального датасету: 3–7 днів
  • Fine-tuning (bge-m3, 5000 пар): 2–4 години (A100)
  • Evaluation та порівняння: 2–3 дні
  • Всього: 1–2 тижні