Как собрать переводчик для 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 взято от лезгинского слова "таржумачи", то есть "переводчик")