Как собрать переводчик для low-resource языка с помощью LLM и синтетических данных

Как собрать переводчик для low-resource языка с помощью LLM и синтетических данных

Лезгинский язык относится к low-resource языкам: для него мало открытых параллельных корпусов, мало готовых датасетов для машинного перевода и мало инструментов, с которыми можно просто взять и начать обучение модели. Если для английского, русского, немецкого или французского почти всегда можно найти миллионы готовых пар предложений, то для лезгинского такой роскоши нет.

В этой статье я покажу, как можно собрать переводчик для low-resource языка с помощью LLM и синтетических данных, на примере лезгинского языка. Речь не про абстрактную схему для любой пары языков, а про вполне конкретный кейс: как из ограниченного набора ресурсов, словаря, реальных текстов и LLM-подсказок собрать первую обучающую выборку и получить рабочую модель машинного перевода.

Я хотел собрать первую рабочую версию переводчика лезгинский ↔ русский на базе NLLB. Не академически идеальную систему, а практический MVP, который уже умеет переводить длинные предложения на среднем качестве и может служить основой для следующих итераций.

Главная проблема была очевидной: чтобы обучить переводчик, нужен параллельный корпус, а для лезгинского его почти нет.Поэтому дальше я буду разбирать подход именно на примере лезгинского языка: где брался исходный материал, как LLM использовались для генерации синтетических пар, почему этого оказалось достаточно для первой версии модели и какие ограничения у такого подхода проявились на практике.

Почему вообще понадобились LLM

Когда речь идет о low-resource языке, обычно есть несколько вариантов:

- искать готовые параллельные тексты;
- собирать их вручную;
- строить систему через словарь и правила;
- использовать LLM для ускорения разметки и синтетической генерации.

Первые два варианта хорошие, но медленные. Третий полезен как база, но сам по себе редко дает естественный перевод на уровне предложения. Поэтому я пошел по комбинированному пути:

1. Собрать словарь и инструменты нормализации.
2. Взять реальные тексты на лезгинском.
3. Написать скрипт, который умеет искать переводы слов в словаре.
4. Дать LLM исходные предложения и возможность использовать этот словарный поиск для понимания текста.
5. На получившемся синтетическом корпусе дообучить NLLB.

То есть LLM здесь не заменяет переводчик, а помогает его обучить.

Почему именно такой подход

Если сразу пытаться использовать LLM как production-переводчик для low-resource языка, быстро всплывают ограничения:

- нестабильность качества от запроса к запросу;
- галлюцинации;
- высокая стоимость при больших объемах;
- трудности с массовой пакетной обработкой;
- для low-resource языка перевод в обратном направлении, например русский -> лезгинский, может работать значительно хуже или вообще не работать;
- зависимость от внешнего API.

А вот в роли инструмента генерации корпуса LLM чувствует себя заметно лучше. Даже если в синтетических данных есть ошибки, они все равно могут оказаться полезными, если:

- текстов достаточно много;
- есть базовый словарь или опорные подсказки;
- есть фильтрация плохих примеров;
- итоговая модель потом обучается на большом количестве пар, а не на единичных ручных примерах.

Именно это я и хотел проверить на практике.

Исходная задача

Цель была достаточно приземленной:

- получить первую версию переводчика для лезгинского языка;
- взять NLLB как базовую multilingual-модель и добавить в нее лезгинский язык;
- дообучить ее на доменно-близких парах лезгинский <-> русский;
- научить модель переводить не только короткие фразы, но и длинные предложения.

Важно: на старте у меня не было большого качественного параллельного корпуса, который можно было бы просто подать в обучение. Зато были:

- лезгинско-русский словарь;
- тексты на лезгинском;
- пайплайн токенизации и нормализации;
- возможность использовать LLM для генерации переводов;
- Codex/LLM-агенты для полуавтоматической пакетной обработки.

Этого уже оказалось достаточно, чтобы собрать рабочий цикл.

Общая схема пайплайна

Схема получилась такой:

1. Берем тексты на лезгинском.
2. Разбиваем их на абзацы, предложения и токены.
3. Пишем скрипт, который нормализует словоформы и ищет переводы слов в словаре.
4. В промпте явно указываем LLM использовать этот скрипт при работе с предложением.
5. Получаем более естественный русский перевод.
6. Сохраняем пару `лезгинское предложение -> русский перевод`.
7. Фильтруем и чистим пары.
8. Обучаем NLLB на синтетическом корпусе.

На практике самое важное в этой схеме не просто "дать LLM перевести текст", а дать ей вместе с текстом инструменты, которыми она сможет пользоваться для более качественного перевода, и точный промпт, который удерживает модель в нужном сценарии и не дает ей сбиваться.

Почему нельзя просто попросить LLM перевести low-resource язык

Если язык редкий, LLM часто:

- неуверенно распознает морфологию;
- путает близкие словоформы;
- додумывает значения из контекста;
- слишком смело "нормализует" непонятные места;
- может перепутать имена собственные, грамматические роли и даже направление перевода.

Поэтому я не использовал режим "вот предложение, переведи как умеешь". Вместо этого я давал модели дополнительные опоры:

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

Идея простая: чем меньше свободы у LLM там, где ей не хватает знаний, тем полезнее ее результат как обучающего примера.

Роль словаря

Словарь в этом проекте оказался критически важен. Он выполнял сразу несколько функций:

- давал переводы отдельных слов для LLM;
- уменьшал пространство ошибок для LLM;
- позволял находить неизвестные слова;
- давал возможность постепенно расширять покрытие;
- служил источником контроля качества.

Даже если словарные переводы слов были неполными или неоднозначными, они все равно были очень полезны как промежуточная опора. LLM уже не начинала "с пустого места", а получала набор смысловых сигналов по предложению. Для low-resource сценария это намного надежнее, чем полностью свободный перевод без опор.

Как использовались LLM и Codex-агенты

Я использовал LLM как инструмент массовой генерации пар предложений. Важно, что задача была не в "идеальном переводе каждого предложения", а в создании достаточно хорошего синтетического корпуса.

Практически это выглядело так:

- готовился TSV с предложениями;
- для каждого предложения добавлялись словарные подсказки;
- агент получал строгий формат вывода;
- результаты сохранялись построчно;
- уже обработанные записи пропускались при возобновлении;
- при необходимости можно было делать повторные проходы и правки.

Codex-агент оказался удобен именно как исполнитель пайплайна:

- последовательно обрабатывать большие массивы;
- работать по заданному шаблону;
- писать результат в нужный формат;
- не терять прогресс при длинных сериях;
- помогать в чистке данных и служебной автоматизации.

Фактически LLM здесь выступала частью data-engineering процесса.

Генерация синтетических пар

Ключевой рабочий сценарий в моем случае был не русский -> лезгинский, а именно лезгинский -> русский. LLM заметно лучше справлялась с переводом из лезгинского в русский, потому что русский язык для нее гораздо лучше покрыт обучающими данными. Лезгинских текстов модель, очевидно, видела значительно меньше, поэтому в обратном направлении качество резко падало.

Именно поэтому синтетические пары я строил вокруг направления лезгинский -> русский: брал реальные лезгинские предложения, давал модели доступ к словарному инструменту и на этой основе получал русский перевод, который потом использовался как часть параллельного корпуса.

Для low-resource языков это особенно важно. Когда данных мало, выбор часто не между "идеальным корпусом" и "синтетическим корпусом", а между "каким-то корпусом" и "никаким".

Что в итоге получилось

Главный практический результат: LLM действительно помогли обучить первую рабочую версию переводчика.

Я дообучал NLLB поверх существующей модели и получил систему, которая уже умеет переводить длинные предложения на среднем качестве. Это не production-идеал и не человеческий уровень перевода, но это уже не игрушка и не демо на пяти фразах. Модель можно использовать как базовую точку для дальнейшего улучшения.

Для меня это важный вывод: даже корпус с заметным числом ошибок может быть полезен, если он:

- достаточно большой;
- тематически релевантный;
- согласован по формату;
- построен на реальных текстах;

Какие были проблемы

Разумеется, синтетические данные не бывают бесплатными. Ошибок было много. Основные типы проблем:

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

Отдельная проблема состоит в том, что LLM умеет звучать уверенно даже там, где фактически ошибается. Из-за этого синтетический корпус нужно воспринимать не как "истину", а как сырье, которое еще требует фильтрации и следующих итераций.

Кому еще может подойти этот подход

Этот подход можно попробовать не только для лезгинского языка. Если вы работаете с другим low-resource языком, вполне возможно, что у вас тоже получится собрать первую версию переводчика через LLM и синтетические данные.

Но здесь есть важная практическая проверка, которую нужно сделать заранее: может ли выбранная LLM достаточно вменяемо переводить с вашего языка на русский или другой популярный язык. Именно от этого во многом зависит, подойдет вам метод или нет.

Проверять это лучше не на одном-двух примерах, а на небольшом наборе реальных предложений:

- простые бытовые фразы;
- предложения средней длины;
- длинные предложения;
- предложения с именами собственными;
- предложения с морфологией и синтаксисом, характерными именно для вашего языка.

Важно и то, что нужно пробовать разные LLM. Одни модели могут неожиданно хорошо справляться с конкретным low-resource языком, а другие на тех же примерах будут давать почти бесполезный результат.
В моем случае я использовал codex-gpt-5.4 с уровнем рассуждения medium. Для моей задачи этого оказалось достаточно, чтобы генерировать полезные синтетические пары, хотя, конечно, без ошибок не обошлось.

Где можно попробовать результат

В итоге я собрал не только обучающий пайплайн, но и первые пользовательские интерфейсы для тестирования переводчика.

Попробовать текущую версию можно здесь:

- В telegram-боте: @LezgiTranslatorBot
- На сайте: https://tarzhumachi.ru (название сайта tarzhumachi взято от лезгинского слова "таржумачи", то есть "переводчик")