Перенос кода на другой язык нейросетью: план миграции и проверка

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

5 мин · · разработка · автоматизация

Переписать код на другой язык нейросетью можно за часы вместо недель, но только если вы заранее решили, как докажете, что новый код делает то же самое. Модель переводит синтаксис хорошо, а вот неявное поведение (округления, порядок обхода, обработка пустых значений, кодировки) легко теряется. Ниже план миграции одного модуля: инвентаризация, эталонные тесты, перенос по частям, сверка поведения и оценка стоимости. В качестве примера возьмём утилиту разбора счетов на Python, которую переносим на Go.

Шаг 1. Инвентаризация

Перед первым запросом к модели составьте список того, что переносите. Его можно сделать вместе с моделью, но проверять вам:

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

Последний пункт самый важный. Именно там языки расходятся: деление целых, обработка None и nil, порядок ключей в словаре, поведение при переполнении. Попросите модель найти такие места и перечислить их в виде списка рисков, а затем сами пройдитесь по списку.

Шаг 2. Эталонные тесты до переноса

Правило миграции: тесты пишутся на старом коде и до переноса. Если тестов нет, создайте «золотые» данные: прогоните старую реализацию на репрезентативных входных данных и сохраните результаты.

bash
import json  # make_golden.py: запускается на СТАРОМ коде
from pathlib import Path
from billing.parser import parse_invoice  # старая реализация

cases = []
for path in sorted(Path("samples").glob("*.txt")):
    text = path.read_text(encoding="utf-8")
    cases.append({"name": path.name, "input": text, "output": parse_invoice(text)})

Path("golden.json").write_text(
    json.dumps(cases, ensure_ascii=False, indent=2, sort_keys=True),
    encoding="utf-8",
)

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

Шаг 3. Переносите по частям

Не просите «перепиши весь проект». Двигайтесь снизу вверх по графу зависимостей: сначала чистые функции без побочных эффектов, затем модули с вводом-выводом, в конце точка входа. Для каждой части:

  1. Дайте модели исходный код функции, её тесты и список рисков для неё.
  2. Попросите идиоматичный код на целевом языке, а не построчный перевод: цикл с индексом на Python и на Go пишут по-разному.
  3. Попросите отдельно перечислить места, где поведение может отличаться.
  4. Запустите эталонные тесты. Падение разбирайте с моделью, показывая ей реальный вывод.

Для всего этого удобно использовать агента, который сам запускает тесты: Claude Code или другой инструмент подобного типа. Тогда цикл «правка, запуск, ошибка, правка» не требует вашего участия, а вы читаете итоговый дифф.

Шаг 4. Сверка поведения

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

bash
import json  # compare.py: гоняет старую и новую реализации на одних данных
import subprocess
from pathlib import Path

def run_old(text: str) -> object:
    from billing.parser import parse_invoice
    return parse_invoice(text)

def run_new(text: str) -> object:
    p = subprocess.run(
        ["./invoice-go"], input=text, capture_output=True,
        text=True, encoding="utf-8", timeout=10,
    )
    return json.loads(p.stdout)

bad = 0
for path in sorted(Path("samples").glob("*.txt")):
    text = path.read_text(encoding="utf-8")
    if run_old(text) != run_new(text):
        bad += 1
        print("РАСХОЖДЕНИЕ:", path.name)
print("расхождений:", bad)

Сравнивайте не строки, а разобранные структуры, и отдельно решите, что считать равным: порядок ключей, формат чисел с плавающей точкой, пробелы. Каждое расхождение это либо ошибка переноса, либо ошибка в старом коде, которую вы теперь нашли. Второе тоже бывает, и решение (повторять баг или исправить) принимает человек.

Шаг 5. Чего не доверять без проверки

  • Многопоточность и конкурентность. Модель легко воспроизводит гонки данных, особенно при переносе синхронного кода в асинхронный.
  • Работа с деньгами и временем. Проверьте типы: float вместо десятичных, часовые пояса по умолчанию.
  • Обработка ошибок. В Python исключение, в Go возвращаемое значение, в Rust Result; убедитесь, что ошибка не теряется молча.
  • Зависимости. Модель может «найти» библиотеку, которой нет. Каждую подключаемую зависимость проверьте в реестре пакетов.
  • Производительность. Корректный перенос не гарантирует быстрый; измерьте.

Сколько это стоит

Оценка делается по размеру кода. Допущения (условные, проверьте на своём проекте): модуль в 12 000 строк, около 10 токенов на строку, то есть примерно 0,12 млн токенов. Точное число даёт подсчёт токенов: он не запускает генерацию, но сам запрос платный, токены списываются по цене входа модели.

Один проход (прочитать исходник и написать перевод) без кэша: вход 0,12 млн × цена входа + выход 0,12 млн × цена выхода. Цены Zukko на 18 октября 2026:

  • claude-sonnet-5-5: 0,12 × 0,4 + 0,12 × 2 = 0,048 + 0,24 = $0,288.
  • claude-opus-5-5: 0,12 × 0,8 + 0,12 × 4 = 0,096 + 0,48 = $0,576.
  • gpt-6.1-sol: 0,12 × 0,27 + 0,12 × 1,32 = 0,0324 + 0,1584 = $0,191.

Реальная сумма больше: добавьте тесты, исправления и повторные прогоны. Если принять три-четыре итерации на каждую часть, умножайте на три-четыре. В агентных инструментах добавляется ещё накопленный контекст на каждом шаге, поэтому полезно заранее прикинуть бюджет и поставить ключу лимит. Для переноса большого проекта начните с одного модуля, посмотрите фактический расход в разделе «Использование» кабинета и только потом масштабируйте. Заодно: как сократить расход токенов.

Какая модель лучше справится с вашим стеком, заранее не скажем. Индекс силы в нашем каталоге: Opus 5.5 — 58, GPT-6.1 Sol — 52, Sonnet 5.5 — 48. Возьмите одну функцию средней сложности, прогоните через две-три модели и сравните по эталонным тестам.

Подключение

Для скриптов подойдёт любой SDK: создайте ключ в кабинете, для OpenAI-совместимого клиента используйте base URL https://api.zukko.pro/v1, для Claude Code и Anthropic SDK адрес без /v1. Доступ из России идёт через шлюз, оплата: СБП, карта MasterCard или криптовалюта.

Частые вопросы

Можно ли переписать проект целиком одним запросом?

Технически контекст до 1M токенов у большинства моделей каталога позволяет вместить много кода, но качество проверки это не повышает. Надёжнее переносить по частям и проверять каждую эталонными тестами.

Нейросеть для генерации программного кода сама проверит, что код работает?

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

Что делать, если тестов в проекте нет?

Создайте «золотые» данные по старой реализации (шаг 2). Это не заменяет полноценные тесты, но фиксирует текущее поведение, а миграция и есть задача сохранить его.

Какой язык проще всего переносить?

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

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.