Метод: 20 китайских документов об интеграции LLM gateway и 20 соответствующих английских документов,
20 китайских и 20 английских запросов с ответами, размеченными вручную, при этом все три модели запускались
на одном и том же корпусе в один и тот же временной интервал. Корпус небольшой, поэтому различия менее чем
в 5 процентных пунктов не являются убедительными — воспроизведите результаты на своих данных, прежде чем
считать что-либо окончательным.
1. Сначала выберите подходящую модель
Выбирайте bge-m3, когда
- Ваш корпус в основном китайский (или японский / русский): качество retrieval соответствует 3-small,
цена по прайсу вдвое ниже, а тот же текст использует лишь 42% tokens — примерно 1/5 фактических расходов - Вам нужен меньший объём хранилища: 1024 dims — это на 33% меньше, чем 1536, и на 66% меньше, чем 3072
- Вам нужен охват редких языков (поддерживается 100+)
- Вы хотите запускать ту же open-source модель локально, чтобы офлайн- и онлайн-векторы совпадали
Выбирайте OpenAI, когда
- Ваш корпус в основном на английском или код: качество на ступень выше. bge-m3 действительно расходует 15%–50%
больше tokens на таком контенте, но вдвое меньшая цена за единицу всё равно делает его дешевле в целом — поэтому в этом случае
ориентируйтесь на качество, а не на цену - Ваша база знаний содержит материалы на разных языках, и вам нужен только один ответ
- Вам нужен
dimensions, чтобы сократить объём хранилища - У вас уже есть пороговые значения, настроенные по диапазонам оценок OpenAI, и вы не хотите перенастраивать их
2. Всегда разбивайте длинные документы на фрагменты
bge-m3 имеет контекстное окно на 8192 token, поэтому длинное руководство помещается в один вызов. Это не делает такой подход хорошей идеей.
Измерено: 20 разделов, объединённых в одно длинное руководство, при этом 20 коротких документов (каждый соответствовал одному
разделу) были добавлены как сильные отвлекающие варианты, а запросы задавались 20 вопросами —
Для одного и того же вопроса правильный раздел в среднем получает оценку на +0.10 выше, чем весь документ:
Единый вектор длинного документа — это среднее по всему, что в нём есть, поэтому любой короткий
фрагмент с точной формулировкой его превосходит.
3. Пороги нужно калибровать заново для каждой модели
Именно здесь миграция с OpenAI наbge-m3 чаще всего даёт сбой. Два диапазона оценок полностью различаются.
Одинаковые вручную размеченные пары, оценённые всеми тремя моделями:
Лучшие одиночные пороги, измеренные для
bge-m3:
Для сравнения, лучший порог для китайского сценария — 0.45 для
text-embedding-3-small и 0.33 для 3-large.
4. Сходство не может сказать вам, правильно ли что-то
Это верно для любой эмбеддинг-модели — это не недостаток какой-то одной из них, но вам нужно знать об этом заранее:
Все три не срабатывают. Косинусное сходство показывает, об одном ли и том же два текста, а не согласуются ли они.
Отрицание, цены, номера версий и имена сущностей нельзя отделить на этапе поиска. Правильный
запасной вариант:
1
Векторный поиск, Top 50–100
Используйте
bge-m3, чтобы быстро сузить круг. Порог лишь отфильтровывает явно нерелевантное.2
Переранжирование до Top 3–5
Отправьте кандидатов в
bge-reranker-v2-m3. Это cross-encoder,
который пропускает запрос и документ через модель вместе, и это именно тот инструмент, который нужен для таких
тонких различий — и он относится к тому же семейству моделей, что и bge-m3.3
Пусть LLM оценивает во время генерации
Передайте Top 3–5 вместе с исходным вопросом и явно укажите в prompt, что модель должна
сказать, что ничего не найдено, если извлечённый контент не соответствует вопросу.
5. Размер батча и параллельные запросы
Пакетная обработка: точка перегиба — 64–128
После 128 стоимость на элемент почти не улучшается (58ms → 53ms), тогда как один запрос становится в 7 раз дольше.
Длительность запроса напрямую влияет на риск тайм-аута клиента и на то, сколько работы будет потеряно при одном сбое.
Параллельные запросы: 8 для работы в реальном времени, 32–48 для массовой индексации
- Используйте параллельные запросы 8 для получения в реальном времени: 200 requests без единого сбоя
- Для массовой индексации можно поднять до 32–48: максимальная пропускная способность, но 429s начинают появляться, поэтому требуется экспоненциальный backoff
- Не превышайте 64: при 96 уровень сбоев составляет 11.8%, а запросы начинают зависать примерно на 60 seconds
6. Как фактически работает стоимость
Стоимость — это произведение двух вещей: цена за unit и сколько token получается из данного фрагмента текста. Здесь различаются оба параметра.bge-m3 — $0.01 / 1M tokens против $0.02 для text-embedding-3-small — то есть вдвое ниже unit price
еще до всего остального. Дополнительно сказывается эффективность tokenizer: bge-m3 использует XLM-R SentencePiece и дает
около 2.1 Chinese characters per token, тогда как cl100k от OpenAI — около 0.9:
Китайские корпуса стоят примерно одну пятую от
text-embedding-3-small.
Английский текст и code потребляют больше token на bge-m3, но вдвое более низкая unit price все равно делает его дешевле OpenAI по
общим расходам — так что для этих двух корпусов решение зависит от качества retrieval (English Recall@1 70% vs
80%), а не от цены.
Хранение тоже отличается. Векторы уже L2-нормализованы, а возвращаемые значения имеют точность fp16, поэтому
хранение vector bge-m3 в float16 не дает потерь в точности:
7. Режимы отказа, которые остаются незаметными
7.1 Значение по умолчанию в LangChain снижает Recall с 80% до 15%
Измеренные затраты:
Исправление:
7.2 Пустая строка принимается как допустимый input
input: "" возвращает 200 на bge-m3 (OpenAI здесь возвращает 400), формируя вектор размерностью 1024 и
тарифицируя 2 token.
Скрипт chunking, который не отфильтровывает пустые chunks, заполнит ваш index бессмысленными векторами, которые
будут случайно всплывать во время поиска. Фильтруйте пустой текст перед индексацией.
7.3 Параметр dimensions отклоняется
Model "bge-m3" does not support matryoshka representation, changing output dimensions will lead to poor results.
bge-m3 не был обучен с Matryoshka representation, поэтому обрезание вектора заметно ухудшает качество.
Используйте float16, чтобы уменьшить объем хранения, вместо того чтобы самостоятельно обрезать размерности.
7.4 Имя модели чувствительно к регистру, алиасов нет
Работает толькоbge-m3. BAAI/bge-m3 и BGE-M3 оба возвращают 503 «нет доступных каналов».
7.5 8192 — это лимит на один input
Один input длиной более 8192 token возвращает 400 и никогда не обрезается молча — что является более безопасным поведением: вы не получите вектор, который выглядит нормальным, но тихо потерял вторую половину вашего текста. Лимит применяется к каждому item, а не к запросу: один вызов, содержащий 1024 item / 102560 token, в тестировании возвращался нормально. Если любой один item превышает лимит, весь запрос завершается с ошибкой, а число token в ошибке относится именно к этому item, а не к общему итогу.8. Минимальная реализация, которую вы можете скопировать
Связанная документация
API встраивания текста
Параметры, формат ответа, быстрый старт
Переранжирование
bge-reranker-v2-m3, подходящий инструмент для этапа повышения точностиНастройка RAG
Двухэтапное извлечение: сколько кандидатов извлекать
Тарификация моделей
Актуальная тарификация для каждой модели встраивания