/
Вопросы и ответы
/
Промт-инжиниринг
/

LLM для миграции между технологиями

LLM для миграции между технологиями

9 часов назад

Никита Вихров

Ответы

0

LLM для миграции между технологиями

Миграция с одного стека на другой — механическая работа. JavaScript → TypeScript, pytest → unittest, REST → GraphQL, один ORM на другой. ИИ делает это быстрее человека и ошибается реже на механических трансформациях.


JavaScript → TypeScript

from anthropic import Anthropic

client = Anthropic()


def js_to_typescript(js_code: str, strict: bool = True) -> str:
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=2048,
        system=f"""Конвертируешь JavaScript в TypeScript.
Режим: {"строгий (strict mode)" if strict else "мягкий (постепенная миграция)"}.

{"Строгий режим:" if strict else "Мягкий режим:"}
{"- Явные типы для всех параметров и возвращаемых значений" if strict else "- Используй any только когда тип реально неизвестен"}
{"- Никаких any без явного обоснования в комментарии" if strict else "- Постепенно добавляй типы, не ломай работающий код"}
- Интерфейсы для объектов вместо object
- Generics где применимо
- Возвращай только TypeScript-код без пояснений""",
        messages=[{
            "role": "user",
            "content": f"```javascript\n{js_code}\n```"
        }]
    )
    return response.content[0].text


js_code = """
async function fetchUserOrders(userId, options = {}) {
    const { limit = 10, status } = options;
    const response = await fetch(`/api/users/${userId}/orders?limit=${limit}`);
    
    if (!response.ok) {
        throw new Error(`HTTP error: ${response.status}`);
    }
    
    const data = await response.json();
    return status ? data.filter(order => order.status === status) : data;
}
"""

print(js_to_typescript(js_code))

Миграция SQL между диалектами

def migrate_sql(query: str, from_db: str, to_db: str) -> str:
    dialect_notes = {
        ("postgresql", "mysql"): "SERIAL → AUTO_INCREMENT, ILIKE → LIKE, :: casting → CAST()",
        ("mysql", "postgresql"): "AUTO_INCREMENT → SERIAL, LIMIT x,y → LIMIT y OFFSET x",
        ("sqlite", "postgresql"): "AUTOINCREMENT → SERIAL, datetime() → NOW(), || → CONCAT()",
    }

    notes = dialect_notes.get((from_db.lower(), to_db.lower()), "")

    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system=f"""Конвертируешь SQL-запросы с {from_db} на {to_db}.
{f"Ключевые отличия: {notes}" if notes else ""}
Сохраняй логику запроса, меняй только синтаксис.
Если функция не поддерживается — добавь комментарий с альтернативой.
Возвращай только SQL без пояснений.""",
        messages=[{
            "role": "user",
            "content": f"```sql\n{query}\n```"
        }]
    )
    return response.content[0].text


# MySQL → PostgreSQL
mysql_query = """
SELECT u.id, u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY u.id
HAVING order_count > 5
ORDER BY order_count DESC
LIMIT 0, 20;
"""

print(migrate_sql(mysql_query, "mysql", "postgresql"))

Миграция ORM: SQLAlchemy 1.x → 2.0

def migrate_sqlalchemy(code: str) -> str:
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=2048,
        system="""Мигрируешь код с SQLAlchemy 1.x на SQLAlchemy 2.0.

Ключевые изменения:
- session.execute(query) вместо session.query()
- select(Model) вместо session.query(Model)
- scalars().all() вместо .all() после execute
- Mapped[type] для аннотаций колонок
- mapped_column() вместо Column()
- relationship() с back_populates вместо backref
- Async: AsyncSession, async with, await session.execute()

Возвращай только мигрированный код.""",
        messages=[{
            "role": "user",
            "content": f"```python\n{code}\n```"
        }]
    )
    return response.content[0].text

Пакетная миграция файлов

import os
from pathlib import Path


def migrate_directory(
    source_dir: str,
    file_pattern: str,
    migrator_fn,
    dry_run: bool = True
) -> dict:
    results = {"migrated": [], "errors": [], "skipped": []}

    for filepath in Path(source_dir).rglob(file_pattern):
        try:
            with open(filepath) as f:
                original = f.read()

            migrated = migrator_fn(original)

            if original == migrated:
                results["skipped"].append(str(filepath))
                continue

            if dry_run:
                print(f"[DRY RUN] Будет мигрирован: {filepath}")
                print(f"Первые 200 символов изменений:\n{migrated[:200]}\n")
            else:
                # Бэкап оригинала
                backup_path = str(filepath) + ".bak"
                open(backup_path, "w").write(original)

                # Записываем мигрированный код
                open(filepath, "w").write(migrated)
                print(f"✅ Мигрирован: {filepath}")

            results["migrated"].append(str(filepath))

        except Exception as e:
            results["errors"].append({"file": str(filepath), "error": str(e)})
            print(f"❌ Ошибка в {filepath}: {e}")

    return results


# Пример: мигрируем все JS-файлы в TypeScript
results = migrate_directory(
    source_dir="./src",
    file_pattern="*.js",
    migrator_fn=lambda code: js_to_typescript(code, strict=False),
    dry_run=True  # сначала смотрим что изменится
)

print(f"\nИтог: {len(results['migrated'])} файлов будет мигрировано")
print(f"Ошибок: {len(results['errors'])}")

Важно: ИИ не заменяет ревью

Механические трансформации ИИ делает хорошо. Но после миграции — обязательно:

  1. Запусти тесты
  2. Сделай ревью diff перед коммитом
  3. Проверь граничные случаи специфичные для бизнес-логики

ИИ может не знать о специфических особенностях твоей версии библиотеки или нестандартном использовании.


На курсе «ИИ для разработчиков» на Хекслете разбирают как выстраивать AI-workflow для реальных инженерных задач: рефакторинг, миграции, работа с кодовой базой через агентов.

9 часов назад

Никита Вихров

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845