Генерация кода полезна там, где задача уже понятна: написать черновик функции, тест, SQL-запрос, документацию или план рефакторинга.

Я использую нейросети в разработке почти каждый день, но не как автопилот. Хороший результат получается, когда я даю контекст, ограничения, пример входных данных и критерии проверки. Плохой результат чаще появляется после запроса в духе «напиши мне сервис». Нейросеть уверенно выдаёт код, который выглядит правдоподобно, но может не учитывать версию библиотеки, доменную логику, лимиты базы или внутренние соглашения команды.

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

Какие задачи разработчика реально автоматизируются

Я делю задачи генерации кода на четыре группы.

Задача Что отдавать в промпте Что проверять вручную
Черновик функции Типы данных, пример входа и выхода, крайние случаи Ошибки на пустых данных, сложность, формат результата
Unit-тесты Контракт функции, 3–5 кейсов, ожидаемые исключения Покрытие негативных сценариев, фикстуры, флаки
SQL Схему таблиц, объём данных, индексы, нужную агрегацию План выполнения, дубли, фильтры по датам
Рефакторинг Старый код, цель изменения, запреты Сохранение поведения, совместимость, читаемость
Документация Назначение модуля, примеры запуска, переменные окружения Устаревшие команды, секреты, неверные пути

Моя рабочая норма: нейросеть пишет первый вариант за 30–90 секунд, потом я трачу 5–20 минут на ревью, запуск тестов и правки. Для типовых кусков это быстрее ручного старта с пустого файла. Для кода, который трогает деньги, права доступа или персональные данные, экономия часто исчезает, потому что проверка становится длиннее генерации.

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

Сценарий: Python для обработки заказов

Возьмём задачу из аналитического пайплайна. Есть список заказов из API. Нужно посчитать выручку по дням, исключить отменённые заказы и округлить сумму до двух знаков.

Промпт

Напиши Python-функцию aggregate_revenue_by_day.
Вход: список словарей с полями order_id, created_at, status, amount.
created_at приходит в ISO-формате, amount может быть строкой или числом.
Нужно вернуть список словарей: date и revenue.
Исключи status = cancelled.
Отсортируй результат по дате.
Добавь 3 unit-теста на pytest: обычный случай, пустой список, amount строкой.
Код должен быть без внешних зависимостей, кроме pytest в тестах.

Ответ нейросети

from datetime import datetime
from decimal import Decimal, ROUND_HALF_UP


def aggregate_revenue_by_day(orders):
    # Копим суммы через Decimal, чтобы не ловить ошибки float
    revenue_by_day = {}

    for order in orders:
        if order.get('status') == 'cancelled':
            continue

        created_at = datetime.fromisoformat(order['created_at'])
        day = created_at.date().isoformat()
        amount = Decimal(str(order.get('amount', 0)))
        revenue_by_day[day] = revenue_by_day.get(day, Decimal('0')) + amount

    result = []
    for day in sorted(revenue_by_day):
        rounded = revenue_by_day[day].quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
        result.append({'date': day, 'revenue': float(rounded)})

    return result


def test_aggregate_regular_case():
    orders = [
        {'order_id': 1, 'created_at': '2025-02-01T10:00:00', 'status': 'paid', 'amount': 100},
        {'order_id': 2, 'created_at': '2025-02-01T12:00:00', 'status': 'cancelled', 'amount': 50},
        {'order_id': 3, 'created_at': '2025-02-02T09:00:00', 'status': 'paid', 'amount': 25.555},
    ]

    assert aggregate_revenue_by_day(orders) == [
        {'date': '2025-02-01', 'revenue': 100.0},
        {'date': '2025-02-02', 'revenue': 25.56},
    ]


def test_aggregate_empty_list():
    assert aggregate_revenue_by_day([]) == []


def test_aggregate_amount_as_string():
    orders = [
        {'order_id': 1, 'created_at': '2025-02-01T10:00:00', 'status': 'paid', 'amount': '10.10'},
        {'order_id': 2, 'created_at': '2025-02-01T11:00:00', 'status': 'paid', 'amount': '2.20'},
    ]

    assert aggregate_revenue_by_day(orders) == [
        {'date': '2025-02-01', 'revenue': 12.3},
    ]

Что я сразу проверяю: часовой пояс, формат даты, поведение при amount = None, допустимые статусы, возврат float вместо строки или Decimal. В реальном проекте я бы попросил вторым запросом не менять публичный контракт, но добавить валидацию и отдельный тест на некорректную дату. Для финансовых расчётов я чаще возвращаю строку, например '25.56', чтобы не тащить неточность float дальше по цепочке.

Сценарий: JavaScript/TypeScript для фронтенда

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

Промпт

Напиши TypeScript-хук useRevenueByDay для React.
Он принимает dateFrom и dateTo в формате YYYY-MM-DD.
Делает GET-запрос на /api/revenue?from=...&to=...
Возвращает data, isLoading, error и refetch.
Тип элемента data: { date: string; revenue: number }.
Добавь отмену запроса через AbortController.
Не используй сторонние библиотеки.

Ответ нейросети

import { useCallback, useEffect, useState } from 'react';

type RevenuePoint = {
  date: string;
  revenue: number;
};

type UseRevenueResult = {
  data: RevenuePoint[];
  isLoading: boolean;
  error: string | null;
  refetch: () => void;
};

export function useRevenueByDay(dateFrom: string, dateTo: string): UseRevenueResult {
  const [data, setData] = useState<RevenuePoint[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [reloadIndex, setReloadIndex] = useState(0);

  const refetch = useCallback(() => {
    setReloadIndex((value) => value + 1);
  }, []);

  useEffect(() => {
    const controller = new AbortController();
    const params = new URLSearchParams({ from: dateFrom, to: dateTo });

    async function loadRevenue() {
      setIsLoading(true);
      setError(null);

      try {
        const response = await fetch(`/api/revenue?${params.toString()}`, {
          signal: controller.signal,
        });

        if (!response.ok) {
          throw new Error(`Ошибка API: ${response.status}`);
        }

        const payload = (await response.json()) as RevenuePoint[];
        setData(payload);
      } catch (err) {
        // AbortError не показываем пользователю как ошибку загрузки
        if (err instanceof DOMException && err.name === 'AbortError') {
          return;
        }
        setError(err instanceof Error ? err.message : 'Неизвестная ошибка');
      } finally {
        if (!controller.signal.aborted) {
          setIsLoading(false);
        }
      }
    }

    loadRevenue();

    return () => controller.abort();
  }, [dateFrom, dateTo, reloadIndex]);

  return { data, isLoading, error, refetch };
}

Здесь результат ближе к рабочему коду, но я всё равно смотрю на четыре вещи. Первое, не нарушает ли хук наш способ работы с авторизацией и базовым URL. Второе, нужна ли проверка схемы ответа. Третье, как компонент поведёт себя при быстрой смене диапазона дат. Четвёртое, не стоит ли вынести сообщения об ошибке в слой локализации.

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

Сценарий: SQL для агрегации и проверки гипотез

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

Промпт

Есть PostgreSQL.
Таблица orders: id, user_id, created_at, status, amount.
Нужно посчитать дневную выручку, число оплаченных заказов и скользящую среднюю выручку за 7 дней.
Брать только status = paid.
Период: с 2025-02-01 по 2025-02-28 включительно.
Верни SQL и коротко объясни, какие индексы помогут.

Ответ нейросети

WITH daily_revenue AS (
    SELECT
        created_at::date AS revenue_date,
        COUNT(*) AS paid_orders,
        SUM(amount) AS revenue
    FROM orders
    WHERE status = 'paid'
      AND created_at >= DATE '2025-02-01'
      AND created_at < DATE '2025-03-01'
    GROUP BY created_at::date
)
SELECT
    revenue_date,
    paid_orders,
    revenue,
    AVG(revenue) OVER (
        ORDER BY revenue_date
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS revenue_7d_avg
FROM daily_revenue
ORDER BY revenue_date;

-- Для фильтра по статусу и дате полезен составной индекс:
-- CREATE INDEX idx_orders_status_created_at ON orders (status, created_at);

В таком ответе мне нравится полуоткрытый интервал дат: меньше риска ошибиться на времени внутри последнего дня. Но есть нюанс. Если нужны дни без заказов, запрос их не покажет. Значит, для графика нужен generate_series и левое соединение. Я обычно сразу задаю уточнение: «Добавь строки для дней без заказов, revenue = 0». Это хороший пример диалога, где первый ответ не финальный, а ступень к корректной версии.

Для таблицы на 20 миллионов строк я бы проверил EXPLAIN ANALYZE, селективность status, тип amount, партиционирование по дате и влияние created_at::date на группировку. Нейросеть может подсказать направление, но план выполнения остаётся источником правды.

Ревью и рефакторинг: как просить разбор, а не переписывание ради переписывания

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

Пример промпта для ревью:

Проведи code review функции ниже.
Контекст: функция вызывается в обработчике API 200–500 раз в минуту.
Нужно найти риски по производительности, безопасности и корректности данных.
Не меняй сигнатуру функции.
Ответ дай в формате: критичные проблемы, средние проблемы, косметика, патч.

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

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

Документирование кода: README, комментарии и API-описания

Документация даёт быстрый выигрыш, потому что нейросеть хорошо превращает код и заметки в связный текст. Для README я отдаю структуру проекта, команды запуска, переменные окружения и типовые ошибки. Для комментариев прошу не пересказывать каждую строку, а описывать причины решений.

Хороший промпт для README:

Собери README для сервиса revenue-api.
Разделы: назначение, локальный запуск, переменные окружения, команды тестов, формат ответа /api/revenue, частые ошибки.
Пиши кратко, без рекламного тона.
Не выдумывай переменные окружения. Используй только список: DATABASE_URL, API_TOKEN, LOG_LEVEL.

Последняя строка про запрет на выдумывание особенно полезна. Без неё модель может добавить REDIS_URL, SENTRY_DSN или другие привычные переменные, которых в проекте нет. Для API-документации я добавляю пример запроса и ответа, коды ошибок и ограничения по диапазону дат. Если документация публикуется наружу, я отдельно проверяю, не попали ли туда внутренние URL, токены из примеров или названия закрытых систем.

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

Ограничения: где нейросеть ошибается чаще всего

В моей практике повторяются семь классов ошибок.

  1. Устаревшие API. Модель предлагает метод, который был в старой версии библиотеки или поменял сигнатуру.
  2. Выдуманные поля и параметры. Особенно в SQL, SDK и конфигурациях.
  3. Слабая обработка ошибок. Часто есть happy path, но нет таймаутов, повторов, отмены и понятного сообщения пользователю.
  4. Игнорирование безопасности. Встречаются SQL-инъекции в строковой сборке, лишнее логирование токенов, небезопасные настройки CORS.
  5. Неверные предположения о данных. Пустые списки, null, дубли, часовые пояса и разные валюты ломают красивый пример.
  6. Слишком крупный патч. Чем больше сгенерированный diff, тем сложнее понять, где изменилась логика.
  7. Несовпадение со стилем проекта. Код может быть корректным, но выбиваться из соглашений команды.

Мой чеклист перед принятием сгенерированного кода короткий: запустить тесты, добавить минимум один негативный кейс, проверить типы, посмотреть линтер, оценить сложность, прочитать diff целиком. Для SQL добавляется план запроса. Для фронтенда, ручная проверка состояния загрузки, ошибки и пустого ответа.

Как встроить генерацию кода в командный процесс

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

Практичная схема выглядит так: задача → промпт → черновик → локальный запуск → ревью → маленький коммит. Если какой-то шаг пропущен, риск растёт. Особенно опасен пропуск локального запуска, потому что синтаксически красивый код может падать на первом импорте.

Ещё один рабочий приём, хранить удачные промпты рядом с кодом или во внутренней базе знаний. Через месяц у команды появляется 10–20 проверенных шаблонов: тесты для обработчика API, SQL-агрегация, README для сервиса, ревью миграции, разбор ошибки из логов. Это уже не разовые эксперименты, а повторяемый процесс.

Заключение

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

Я получаю максимальную пользу, когда формулирую задачу как техническое задание на маленький фрагмент: входы, выходы, ограничения, версия стека, критерии проверки. После этого нейросеть экономит время на рутине, а я трачу внимание на архитектуру, крайние случаи и качество изменений. Такой баланс честнее и надёжнее, чем ожидание, что инструмент сам поймёт весь проект по одной фразе.