Код-ревью Middle ИИ-фичи в продукте обновлено

Код-ревью: обработчик вызова LLM, написанный ИИ

Вопрос

Ассистент сгенерировал эндпоинт, который извлекает из письма клиента поля заявки через LLM API. Найдите проблемы.

const OPENAI_KEY = "sk-live-4f9a...";

app.post("/api/extract", async (req, res) => {
  const { email } = req.body;
  const r = await fetch(LLM_URL, {
    method: "POST",
    headers: { Authorization: `Bearer ${OPENAI_KEY}` },
    body: JSON.stringify({
      model: MODEL,
      messages: [
        { role: "system", content: "Верни JSON: name, phone, product" },
        { role: "user", content: email },
      ],
    }),
  });
  const data = await r.json();
  const order = JSON.parse(data.choices[0].message.content);
  await db.orders.insert(order);
  res.json(order);
});

Коротко

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

Что должен найти ревьюер

  1. Безопасностьстрока 1
    Ключ API захардкожен в коде и попадёт в репозиторий. Его место в секретах окружения, а утёкший ключ надо отозвать.
  2. Безопасностьстрока 3
    Нет проверки аутентификации и лимитов: любой может вызывать эндпоинт и тратить бюджет.
  3. Ошибкастрока 5
    fetch без таймаута и без повторов на 429 и 5xx: зависший провайдер повесит запросы, временный сбой сразу станет ошибкой.
  4. Ошибкастрока 5
    Не проверяется r.ok: при ошибке провайдера data.choices не будет, и обработчик упадёт с непонятным исключением.
  5. Производительностьстрока 9
    Нет max_tokens и ограничения длины письма: огромное письмо или длинный ответ дадут дорогой и медленный запрос.
  6. Ошибкастрока 17
    JSON.parse без проверки схемы: невалидный JSON уронит обработчик, а выдуманные или пустые поля попадут в базу. Нужна валидация (например, Zod) и фолбэк.
  7. Безопасностьстрока 18
    Ответ модели пишется в базу целиком: модель могла вернуть лишние поля, включая служебные. Сохранять только проверенные поля.

Разбор

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

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.