DEV Community

Cover image for Как построить RAG-базу знаний на text-embedding-3-large: chunking, embeddings и rerank
Jenny Met
Jenny Met

Posted on

Как построить RAG-базу знаний на text-embedding-3-large: chunking, embeddings и rerank

Как построить RAG-базу знаний на text-embedding-3-large: chunking, embeddings и rerank

Многие демо RAG выглядят просто: загрузил PDF, задал вопрос — AI ответил.

Но когда доходит до реального продакшна, сразу появляются проблемы:

  • Документ слишком длинный — не помещается в контекст
  • Поиск по ключевым словам не находит похожие по смыслу фрагменты
  • Пользователь спрашивает разговорно, а документация написана официально
  • Найденные куски не по теме — модель начинает “галлюцинировать”
  • Чем больше данных, тем выше задержки и стоимость поиска

text-embedding-3-large решает одну из ключевых задач: преобразует вопросы и документы в сравнимые семантические векторы.

RAG knowledge base architecture with embeddings

В этой статье — никакой воды, только практический разбор рабочего RAG-процесса с инженерной точки зрения.

Базовая архитектура RAG-системы

Типовая база знаний на RAG делится на два основных контура.

Первый — оффлайн-индексация:

  1. Сбор документов
  2. Очистка текста
  3. Разделение на чанки (chunking)
  4. Генерация векторов через embedding-модель
  5. Сохранение в векторную базу данных

Второй — онлайн-ответы на вопросы:

  1. Пользователь задаёт вопрос
  2. Преобразование вопроса в embedding
  3. Поиск похожих чанков в векторной базе
  4. (Опционально) rerank — уточняющая сортировка
  5. Сборка контекста
  6. Генерация ответа через чат-модель

text-embedding-3-large используется на шаге 4 (оффлайн) и шаге 2 (онлайн).

Он не отвечает на вопросы напрямую, но определяет, получит ли модель нужную информацию.

Шаг 1: Подготовка документов и разбиение на чанки

Качество RAG во многом зависит от того, как вы режете текст на чанки.

Слишком крупные чанки — много “шума”, модель видит лишнее.

Слишком мелкие — не хватает контекста, информации мало.

Рекомендации для старта:

Тип документа Рекомендуемый размер чанка overlap
FAQ / Справка 200-500 токенов 30-80
Техническая дока 400-800 токенов 80-120
Длинные отчёты 600-1000 токенов 100-150
Документация кода По функции/классу/заголовку По ситуации

Пример кода для разбиения:

def chunk_text(text, chunk_size=600, overlap=100):
    words = text.split()
    chunks = []
    start = 0

    while start < len(words):
        end = start + chunk_size
        chunk = " ".join(words[start:end])
        chunks.append(chunk)
        start = end - overlap

    return chunks
Enter fullscreen mode Exit fullscreen mode

В продакшне не режьте только по пробелам. Лучше разбивать по заголовкам, абзацам, спискам, границам кода.

Шаг 2: Генерация векторов через text-embedding-3-large

Пример на OpenAI-совместимом API. Можно использовать тот же SDK для вызова /v1/embeddings.

from openai import OpenAI

client = OpenAI(
    api_key="your-api-key",
    base_url="https://crazyrouter.com/v1"
)

def get_embedding(text: str):
    text = text.replace("\n", " ")
    response = client.embeddings.create(
        model="text-embedding-3-large",
        input=text,
        encoding_format="float"
    )
    return response.data[0].embedding
Enter fullscreen mode Exit fullscreen mode

Если нужно контролировать размерность вектора, добавьте параметр dimensions:

response = client.embeddings.create(
    model="text-embedding-3-large",
    input=text,
    dimensions=1536,
    encoding_format="float"
)
Enter fullscreen mode Exit fullscreen mode

Чем меньше размерность, тем дешевле хранение и поиск, но качество может упасть. Тестируйте на реальных вопросах.

Шаг 3: Сохранение в векторную базу данных

Для прототипа можно использовать файлы или SQLite, но для продакшна лучше выбрать специализированную векторную БД.

Популярные варианты:

Инструмент Когда использовать
pgvector Уже используете PostgreSQL, не хотите новых сервисов
Qdrant Отдельная векторная БД, простая установка, мощная фильтрация
Milvus Масштабируемый поиск по большим данным
Pinecone Облачный сервис, не требует поддержки
Weaviate Есть схема и гибридный поиск

В любом случае, для каждого чанка сохраняйте минимум такие поля:

{
  "id": "doc_001_chunk_003",
  "text": "chunk content here",
  "embedding": [0.0123, -0.0456],
  "metadata": {
    "source": "billing-guide.md",
    "title": "Billing Guide",
    "section": "Token pricing",
    "updated_at": "2026-05-18"
  }
}
Enter fullscreen mode Exit fullscreen mode

Метаданные важны — они позволяют фильтровать по продукту, языку, времени, правам доступа.

Шаг 4: Семантический поиск при запросе

Когда пользователь задаёт вопрос, сначала превращаем его в вектор, затем ищем похожие чанки в базе.

def retrieve(query: str, vector_db, top_k=5):
    query_vector = get_embedding(query)
    results = vector_db.search(
        vector=query_vector,
        top_k=top_k,
        filter={"language": "ru"}
    )
    return results
Enter fullscreen mode Exit fullscreen mode

Если нет векторной базы, можно показать cosine similarity на numpy:

import numpy as np

def cosine_similarity(a, b):
    a = np.array(a)
    b = np.array(b)
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
Enter fullscreen mode Exit fullscreen mode

Но если данных больше нескольких тысяч, переходите на специализированную векторную БД.

Шаг 5: Добавляем rerank — меньше “мимо кассы”

Embedding-поиск — это “грубый” отбор: быстро, но не всегда точно.

Rerank — “точная” сортировка: оценивает релевантность вопроса и каждого кандидата.

Рекомендованный пайплайн:

  1. Embedding-поиск — top 20 кандидатов
  2. Rerank — сортировка по релевантности
  3. В чат-модель идут top 5

Это надёжнее, чем просто брать top 5 по embedding, особенно если:

  • Много технической документации
  • База знаний для поддержки
  • Юридические/финансовые документы
  • Мультиязычные базы
  • Много похожих по названию документов

Crazyrouter поддерживает endpoint /v1/rerank — его можно встроить в RAG-процесс для точной сортировки после поиска.

Шаг 6: Передаём найденные чанки в чат-модель

После поиска собираем prompt:

def build_prompt(question, chunks):
    context = "\n\n".join(
        f"Source: {c['metadata']['source']}\n{c['text']}"
        for c in chunks
    )

    return f"""
Вы — строгий помощник базы знаний.
Отвечайте только на основе приведённых материалов.
Если ответа нет — скажите “В предоставленных данных ответа нет”.

Материалы:
{context}

Вопрос: {question}
"""
Enter fullscreen mode Exit fullscreen mode

Далее вызываем чат-модель:

answer = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[{"role": "user", "content": build_prompt(question, chunks)}]
)

print(answer.choices[0].message.content)
Enter fullscreen mode Exit fullscreen mode

Embedding-модель и чат-модель работают вместе:

  • text-embedding-3-large: ищет релевантные материалы
  • gpt-5-mini / Claude / Gemini: формирует ответ на основе найденного

Преимущества text-embedding-3-large для мультиязычного RAG

Во многих компаниях документация на разных языках:

  • Английская API-дока
  • Русский справочный центр
  • Японские мануалы
  • Корейские статьи сообщества
  • Вьетнамские туториалы

Проблема мультиязычного RAG: пользователь спрашивает на одном языке, а ответ — в документации на другом.

text-embedding-3-large официально позиционируется как embedding-модель высокого качества для английского и других языков. Для кросс-языкового поиска стоит протестировать её в первую очередь.

Но не полагайтесь только на официальные метрики — соберите свой набор тестовых запросов:

Вопрос Верный документ Язык Найден?
Почему быстро списываются средства? billing-token-cost.md ru да/нет
how to set API base URL quickstart.md en да/нет
Как настроить Claude Code? integrations/claude-code.md ru да/нет

Оценивайте recall в top 3 / top 5.

Рекомендации для продакшна

1. Индексируйте только изменённые чанки

При обновлении документа пересчитывайте embedding только для новых/изменённых чанков.

Сохраняйте hash каждого чанка:

import hashlib

def content_hash(text):
    return hashlib.sha256(text.encode("utf-8")).hexdigest()
Enter fullscreen mode Exit fullscreen mode

Если hash не изменился — пропускайте.

2. Используйте batch-embedding

Не вызывайте API по одному чанку. Обычно Embeddings API поддерживает пакетную обработку.

response = client.embeddings.create(
    model="text-embedding-3-large",
    input=[chunk1, chunk2, chunk3],
    encoding_format="float"
)
Enter fullscreen mode Exit fullscreen mode

Так быстрее и проще контролировать лимиты.

3. Гибридный поиск

Чисто векторный поиск может пропустить точные совпадения по ключевым словам: коды ошибок, номера заказов, имена функций.

Надёжнее комбинировать:

  • BM25 / поиск по ключевым словам
  • Векторный поиск
  • Объединение результатов
  • Rerank

4. Добавляйте ссылки на источник в ответах

Не ограничивайтесь только текстом ответа. Лучше указывать заголовок и ссылку на документ.

Это повышает доверие пользователя и облегчает отладку.

5. Фильтрация по правам доступа

В корпоративных базах знаний обязательно фильтруйте по правам.

Не фильтруйте после поиска — добавляйте условия доступа прямо в запрос к векторной базе.

Частые проблемы и их решения

Проблема Причина Как исправить
Не находится нужный документ Чанк слишком большой/маленький, короткий запрос Подберите размер чанка, перепишите запрос
Ответ ссылается не на тот документ Мало кандидатов, нет rerank Брать top 20 + rerank
Высокая задержка Каждый раз пересчитывается embedding документа Индексируйте документы оффлайн, запросы embedding — онлайн
Растёт стоимость Дублирующая индексация, слишком большая размерность Удаляйте дубли по hash, тестируйте меньшую размерность
Плохо ищет по разным языкам Модель не подходит для мультиязыка Тестируйте large, соберите мультиязычный тестовый набор

Когда НЕ стоит использовать text-embedding-3-large?

Не всегда нужен embedding максимального качества.

Можно обойтись без него, если:

  • Данных мало, хватает поиска по ключевым словам
  • Это внутренний инструмент, требования к качеству невысокие
  • Очень ограниченный бюджет, а база — одноязычный FAQ
  • Проект на стадии MVP, нет реальных пользовательских запросов

Лучше сначала протестировать small и large на реальных вопросах и только потом решать, стоит ли переходить на более дорогую модель.

Вывод: успех RAG наполовину зависит от поиска

Какой бы ни был мощный чат-модель, если в контексте не те данные — ответ будет ошибочным.

text-embedding-3-large позволяет находить информацию по смыслу, а не только по ключевым словам.

Если строите продакшн RAG, рекомендую такой порядок:

  1. Соберите реальные документы
  2. Разбейте их на адекватные чанки
  3. Постройте векторный индекс на text-embedding-3-large
  4. Оцените recall top 5 на реальных вопросах
  5. Добавьте rerank
  6. Оптимизируйте prompt и чат-модель

Вы можете подключить Crazyrouter embeddings API через OpenAI-совместимый SDK и использовать один base_url для embedding, rerank и чат-модели — удобно для построения полного RAG-процесса.

FAQ

Обязательно ли использовать text-embedding-3-large для RAG-базы знаний?

Нет. Он оптимален для продакшн, мультиязыка и задач с высокими требованиями к качеству. Для небольших проектов можно начать с более дешёвых embedding-моделей.

Какой размер чанка оптимален?

Нет универсального ответа. Для технической документации — 400-800 токенов, для FAQ — короче. Ориентируйтесь на качество поиска по реальным вопросам.

Можно ли использовать text-embedding-3-large с pgvector?

Да. Вектор можно сохранять в поле pgvector в PostgreSQL и искать по схожести.

Почему embedding находит нужный материал, а модель всё равно ошибается?

Возможно, среди найденных чанков есть “шум”, prompt не ограничивает модель, нет ссылок на источник или вопрос требует объединения нескольких документов. Добавьте rerank и контроль ссылок.

Нужно ли добавлять rerank в RAG?

В продакшне — да. Embedding быстро отбирает кандидатов, rerank точно сортирует. Вместе — надёжнее.

Top comments (0)