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

Переводим проекты с Python на Node.js: на что способна локальная LLM на самом деле

9abdaf405ce25f6e51f62a0971144c1f.webp

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

Всем привет! Меня зовут Максим, и я работаю в ООО РТК ИТ руководителем направления в департаменте разработки и развития систем поддержки бизнеса (ОП ЮГ). В этой статье расскажу, как с помощью локальной языковой модели автоматизировал перевод Python-проектов в Node.js.Опишу технические детали реализации от сборки контекста до генерации файлов с кодом. Подниму вопрос масштабируемости, ограничений LLM при работе с большими проектами и возможных улучшений для повышения точности перевода.

Введение

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

Спустя два года большая часть микросервисов была уже написана, Python-разработчики сменились на новых специалистов. Новые микросервисы на Python создавались уже реже. В основном дорабатывались существующие сервисы. Количество микросеривсов на Node.js со временем тоже увеличивалось. Учитывая, что разработчиков, знающих JavaScript, в команде всегда было больше, и часть из них умели делать бэкенд, в определённый момент было решено, что все новые микросервисы будут создаваться на Node.js.

В таких условиях работы для Python-разработчиков со временем становилось все меньше. Количество разработчиков сократилось до одного, но у него было одно важное преимущество — он знал Python и JavaScript. Получилась ситуация, когда ряд ключевых сервисов, написанных на Python, может доработать только один человек в команде. Чтобы это как-то сбалансировать, руководство приняло решение постепенно переводить старые сервисы с Python на Node.js.

Этим занимался наш единственный Python-разработчик, но мало кто мог ему помочь. Поэтому процесс двигался не очень быстро и местами с трудностями. В это время уже были доступны LLM, и по опыту их использования было ощущение, что они могут помочь с задачей перевода с Python на Node.js.

В 2025 году от нас уходит последний Python-разработчик. Он успел перевести несколько сервисов на Node.js, но их осталось все еще не мало и некоторые из них достаточно важные. Однако еще до ухода из нашей команды последнего Python-разработчика мне поставили задачу — изучить возможность использования LLM для автоматического перевода Python-проектов на Node.js. И вот что из этого вышло.

Требования

Идея перевода заключалась в том, чтобы не просто вручную закидывать Python-код в чат с моделью с просьбой перевести его в Node.js, а дать модели возможность самостоятельно проанализировать папку с исходным кодом Python-проекта и на её основе сгенерировать папку с исходным кодом для Node.js, сохраняя оригинальную бизнес-логику. Таким образом, у модели будет полное представление о проекте и его зависимостях.

Было определенное ограничение: согласно правилам компании, я не могу использовать для целей перевода внешние сервисы, такие как DeepSeek или ChatGPT. Тогда остается вариант запустить языковую модель локально. На моем ПК как раз была подходящая для этого видеокарта GeForce RTX 4070 Ti c 12 ГБ памяти. Но что нужно для запуска LLM на своем ПК?

После небольшого изучения вопроса узнал, что нужны такие программы, как ollma или LM Studio. Выбрал LM Studio прежде всего из-за того, что сразу было понятно, как подружить его с Node.js. На главной странице сайта LM Studio предлагают установить модуль с SDK для Node.js, а также есть ссылка на неплохую документацию с примерами. В документации были примеры, как работать с моделью в агентском режиме с использованием инструментов, что позволяет написать свою функцию, описать ее параметры и передать LLM-модели. Это как раз необходимо для того, чтобы модель могла работать с файлами — это мне и было нужно. Концепция была понятна, осталось ее реализовать.

Реализация

b59c269d10330206210dae03975b4e91.png

Скачал и установил LM Studio, настроил на работу со своей видеокартой. Дальше необходимо было выбрать подходящую открытую LLM-модель. Остановился на модели Qwen2.5 7B Instract Q6K. Эта модель поддерживает работу с инструментами и полностью помещалась в мою видеопамять. Модель была скачана, запущена и протестирована — все было готово к началу разработки. Дальше при помощи модуля @lmstudio/sdk необходимо было написать Node.js-приложение, которое позволяет взаимодействовать с LLM-моделью программным способом, и выполнить процедуру миграции проекта.

Сборка контекста

Первое с чем я столкнулся, как передать содержимое .py-файлов модели? Также модель должна знать путь до файла, чтобы у нее было представление о структуре проекта. Пришел к следующему решению: объединить .py-файлы проекта в одно текстовое сообщение с добавление метаданных.

# File: src/app.py ```python from flask import Flask app = Flask(__name__) ... ``` # Файл: src/models.py ```python from datetime import datetime from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() ... ```

Не все .py-файлы одинаково полезны, некоторые лучше исключить, чтобы сэкономить контекст. К примеру, тесты и миграции БД можно проигнорировать. В результате получилась следующая функция для генерации контекста из .py-файлов проекта.

// Собираем весь Python-проект в один контекст async function buildProjectContext () { const globOptions = { windowsPathsNoEscape: true } if (Array.isArray(CONFIG.IGNORE_DIRS)) { globOptions.ignore = CONFIG.IGNORE_DIRS } const pyFiles = fastGlob.sync([`${CONFIG.PYTHON_DIR}/**/*.py`], globOptions) let context = '# Full project for translation\n\n' for (const file of pyFiles) { const relPath = path.relative(CONFIG.PYTHON_DIR, file) const code = await readFile(file, 'utf-8') context += `## File: ${relPath}\n\`\`\`python\n${code}\n\`\`\`\n\n` } return context }

Данная функция в заданной папке CONFIG.PYTHON_DIR находит все .py-файлы по маске, пропуская файлы и папки, которые находятся в игноре, затем читает содержимое каждого файла и добавляет его в общий контекст.

Инструмент для создания файлов

Чтобы у модели была возможность создавать файлы в проекте Node.js, ей необходимо было предоставить соответствующий инструмент. Этот инструмент создается при помощи @lmstudio/sdk.

import { tool } from '@lmstudio/sdk' import { existsSync, mkdirSync } from 'fs' import { z } from 'zod' // Инструмент для создания файлов Node.js const createNodeFile = tool({ name: 'createNodeFile', description: 'Create a Node.js file with translated code', parameters: { path: z.string(), content: z.string() }, implementation: async ({ path: filePath, content }) => { const normalizedPath = path.win32.normalize(`${CONFIG.OUTPUT_DIR}/${filePath}`) mkdirSync(path.dirname(normalizedPath), { recursive: true }) const isFileExists = existsSync(normalizedPath) await writeFile(normalizedPath, content, 'utf-8') return isFileExists ? `You have already created this file ${filePath} before, now it has been updated` : `File ${filePath} was created successfully` } })

Промнт

У нас есть контекст с бизнес-логикой Python-проекта и инструмент для создания файлов проекта на Node.js. Остается объяснить модели, что со всем этим делать. Для этого нужно модели задать роль, указать ограничения и поставить задачу. В определенный момент своих экспериментов я почему-то решил, что китайской LLM-модели лучше задавать промнт на английском языке, чтобы она его лучше понимала и строже соблюдала, но здесь я приложу русскую версию.

Вы эксперт по переводу Python → Node.js. Пожалуйста, продолжайте до тех пор, пока запрос пользователя не будет полностью выполнен. Завершайте свой ход только тогда, когда будете уверены, что проблема полностью решена. Правила: - Действуйте как старший инженер. - Flask → Express.js, SQLAlchemy → Sequelize, requests → node-fetch, LOG -> winston - Сохраните всю существующую функциональность и создайте правильную структуру проекта для Node.js + Express.js (маршруты в /routes, база данных в /models). - Используйте Standard стиль JavaScript и ESM-модули, не используйте commonjs и TypeScript. - Код должен быть высокого качества. - Используйте "createNodeFile" для создания и обновления каждого файла (правильно передайте параметры!). Не создавайте бессмысленные файлы или файлы без содержимого. - Не объясняйте и не комментируйте код! Ваша главная задача - создать работающий Node.js проект! Пример ответа: <createNodeFile path="src/app.js" content="import fetch from 'node-fetch'..."/>

Это не начальная версия промнта, а ближе к конечной, и по ней можно заметить, что с переводом при помощи LLM моделью были определённые трудности. Например, вместо того чтобы сгенерировать готовый код чат-бот мог подробно объяснить, что он собирается написать. Взамен реализации функции оставить только комментарии с тем какая реализация ожидается.

Инициализация агента

Сначала запуск модели выглядел совсем просто.

async function translateProject () { const model = await client.llm.model() const userPrompt = await buildProjectContext() await model.act(systemPrompt + '\n\n' + userPrompt, [createNodeFile], { temperature: 0.1, topPSampling: 0.9 }) } translateProject().then(() => { console.log('Перевод завершён! Проверьте папку ./node_project') })

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

Запуск

Для тестирования я подготовил небольшой демопроект на Python, состоящий из двух файлов. Его контекст составлял приблизительно 400 токенов. Провел тестовый запуск — агент довольно быстро справился с переводом. Проверил результат — это было вполне рабочее Node.js-приложение. Перевод получился вполне качественный, и я был рад такому результату, но это был всего лишь демопроект.

Пора было попробовать на масштабе побольше и взять уже реальный проект. Нашел небольшой проект, размер контекста которого уже составлял ~2450 токенов. Это в 6 раз больше моего демопроекта. В этот раз агенту понадобилось немного больше времени на перевод, но он справился. Оценил результат перевода, и он уже был хуже. Агент проигнорировал некоторые правила в промнте, местами код содержал ошибки, некоторые файлы были пустые, другие содержали что-то бессмысленное или незаконченное. Сделав несколько запусков, я обнаружил, что результат от запуска к запуску может сильно отличаться как в лучшую, так и в худшую сторону. Стал думать, что можно с этим сделать.

Оптимизация процесса перевода

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

Проект побольше

Настало время для теста на более крупном Python-проекте. В этот раз размер контекста уже составлял ~24660 токенов. С таким большим контекстом мой агент справился уже совсем плохо: то, что он выдавал, сложно было назвать чем-то полезным, и результат не сильно улучшался при повторных запусках. Я начал изучать способы улучшения работы модели с большим контекстом. Единственное, что удалось найти, — возможность включить для LLM-модели опцию Flash Attention. Судя по графику потребления памяти VRAM, этот режим значительно снизил потребление памяти, но на качество перевода скорее повлиял отрицательно.

9cad7147255edf182c5e497fd70e2196.png

Диалоговый режим

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

import { Chat, LMStudioClient, tool } from '@lmstudio/sdk' import { encoding_for_model } from 'tiktoken' import { readFile, writeFile, rm, mkdir } from 'fs/promises' import { createInterface } from 'readline/promises' const encoding = encoding_for_model('gpt-4') async function translateProject () { const model = await client.llm.model() const userPrompt = await buildProjectContext() const tokenNumb = encoding.encode(userPrompt).length const rl = createInterface({ input: process.stdin, output: process.stdout }) console.log('Контекст проекта на Python:', tokenNumb + ' токенов') if (tokenNumb <= MAX_TOKENS_LENGTH) { const normalizedPath = path.win32.normalize(CONFIG.OUTPUT_DIR) await rm(normalizedPath, { recursive: true, force: true }) await mkdir(normalizedPath) const chat = Chat.from([ { role: 'system', content: systemPrompt }, { role: 'user', content: 'Migrate the following Python project to Node.js (DB: PostgreSQL):' + '\n\n' + userPrompt } ]) await model.act(chat, [createNodeFile], { onMessage: (message) => console.info(message.toString()), temperature: 0.3, topPSampling: 0.7 }) while (true) { const input = await rl.question('You: ') // Добавить пользовательский ввод в чат chat.append('user', input) process.stdout.write('Bot: ') await model.act(chat, [createNodeFile], { // Когда модель закончит сообщение, вывести его в чат onMessage: (message) => console.info(message.toString()), temperature: 0.3, topPSampling: 0.7 }) process.stdout.write('\n') } } else { console.warn('Python проект слишком большой для перевода!') } }

Сразу отмечу, что с крупным Python-проектом внедрение диалога все равно не помогло. Размер контекста считается как сумма токенов из сообщения пользователя и ответа модели, а чем больше контекст, тем хуже модель с ним справляется. Если задавать вопрос по крупному проекту, то модели придется анализировать суммарный контекст, с чем ей справиться еще сложней.

Вывод

В итоге полностью автоматизированный перевод проектов с Python на Node.js не удалось реализовать, но получился полезный инструмент. Для небольших проектов он вполне способен выдать базовый каркас приложения, который необходимо будет доработать в определенных деталях. Это может значительно ускорить процесс перевода проекта с одной технологии на другую. Крупные проекты можно переводить частями, исключая часть файлов и сокращая контекст. Если мы хотим получить более качественный результат, то нужны более крупные и специализирующиеся на коде LLM-модели, которые лучше справляются с большим контекстом. Такие модели требуют более мощное оборудование. Наилучшим выбором будет профессиональный серверный ускоритель с большим количеством VRAM. Если такое оборудование недоступно, то можно использовать потребительскую видеокарту, но результат будет хуже, а для большого контекста его может не быть вовсе.

Был ли получившийся инструмент использован для перевода реальных проектов? Если коротко, то да. Для нескольких небольших проектов была получена неплохая основа для быстрого старта. В основном нужно было установить недостающие модули, добавить файлы конфигурации и тщательно все отладить, что занимало большую часть времени. Еще было полезно выполнить автоисправление через ESLint или Prettier. Например, мне удалось перевести проект на ~12700 токенов за две рабочих недели спокойной работы. Если бы я делал вручную, это заняло бы минимум три рабочих недели. Однако, учитывая мои поверхностные знания Python, срок мог бы увеличиться до четырёх недель. Несмотря на это, внутри команды инструмент не стал популярным, так как не у всех есть подходящая для его работы видеокарта и не всем понравился результат, который выдавал агент.

Подобную реализацию можно использовать не только для перевода с Python на Node.js, но и для любых других языков программирования, с которыми знакома используемая LLM. Агент может решать задачи не только, связанные с переводом с одного языка на другой. Это может быть и анализ проекта, и формирование документации, и генерация тестов.

Источник

Возможности рынка
Логотип NODE
NODE Курс (NODE)
$0.02222
$0.02222$0.02222
0.00%
USD
График цены NODE (NODE) в реальном времени
Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу [email protected] для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.