Код-ревью Middle LLM в проде спрашивают часто обновлено

Код-ревью: клиент к LLM-провайдеру

Вопрос

Это обёртка, через которую все сервисы команды вызывают модель. Найдите проблемы надёжности, стоимости и безопасности.

import time, requests, logging

API_KEY = "sk-live-8f3a..."

def ask(prompt, user_text):
    body = {"model": "big-model", "messages": [
        {"role": "system", "content": prompt},
        {"role": "user", "content": user_text}]}
    for attempt in range(10):
        r = requests.post(URL, json=body, headers={"Authorization": API_KEY})
        if r.status_code == 200:
            logging.info("prompt=%s answer=%s", user_text, r.text)
            return r.json()["choices"][0]["message"]["content"]
        time.sleep(1)
    return ""

Коротко

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

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

  1. Безопасностьстрока 3
    Ключ API в исходном коде: утечёт через репозиторий. Ключ берётся из хранилища секретов или переменных окружения.
  2. Ошибкастрока 10
    Нет таймаута у requests.post: зависший запрос заблокирует поток навсегда.
  3. Ошибкастрока 9
    Повтор на любую ошибку, включая 400 и 401: десять бесполезных запросов. Повторять только 429, 5xx и сетевые ошибки.
  4. Производительностьстрока 14
    Фиксированная пауза 1 секунда без экспоненты, джиттера и учёта Retry-After: при сбое провайдера все клиенты долбят его синхронно.
  5. Безопасностьстрока 12
    В лог пишется полный текст пользователя и ответ: персональные данные в логах без маскирования.
  6. Ошибкастрока 15
    После всех попыток возвращается пустая строка: вызывающий код не отличит ошибку от пустого ответа. Нужно исключение или явный результат ошибки и фолбэк.
  7. Производительностьстрока 6
    Модель зашита в код, нет max_tokens и учёта токенов и стоимости в ответе: бюджет не контролируется, переключить модель без деплоя нельзя.

Разбор

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

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

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