КЛАСТЕР 01 · ОСНОВЫ ВЗАИМОДЕЙСТВИЕ С LLM ~15 МИНУТ
День 01 · из 35

Первый запрос
к LLM

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

Суть урока

LLM — это stateless-функция: ты передаёшь ей массив сообщений с ролями (system, user, assistant), она возвращает следующее сообщение. Она не помнит ничего. Память, контекст, диалог — это иллюзии, которые создаёт твой код, каждый раз пересобирая историю заново. Эта мысль — фундамент всего курса.

Правильная ментальная модель

Когда ты пользуешься ChatGPT через сайт, есть ощущение, что ты разговариваешь с моделью. Она «помнит» предыдущее сообщение, «следует» за разговором, «развивает» мысль. Это — главная иллюзия, которую интерфейс создаёт за тебя.

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

LLM — это не собеседник. Это функция: (массив сообщений) → следующее сообщение. Всё ощущение «памяти» — работа кода вокруг неё.

Из этого следует практический вывод, который мы будем разворачивать весь курс: что попадёт в массив сообщений — то модель и «знает». Управление этим массивом и есть AI-инжиниринг.

Анатомия запроса

На уровне сети взаимодействие с LLM — это обычный HTTP-запрос. Никакой магии: тот же протокол, что у любого другого API.

Поток одного запроса
Твой код собирает запрос JSON + ключ
API провайдера принимает HTTP POST /chat
Модель генерирует ответ токен за токеном
Твой код получает JSON с ответом + usage

В минимальном запросе у тебя есть три обязательных элемента:

Что

Модель

Какую именно версию вызываешь. У каждого провайдера свой список: gpt-4o-mini, claude-sonnet-4-5, llama-3.1-70b и т.д.

Контент

Messages

Массив объектов, каждый с ролью и текстом. Это и есть «разговор», который модель прочитает целиком.

Кто

API-ключ

В заголовке Authorization. Идентифицирует тебя для биллинга и квот провайдера.

Три роли и зачем они

Внутри массива messages каждое сообщение помечено ролью. Это не просто метка — она меняет то, как модель его воспринимает. Понимание ролей — это понимание того, как ты можешь управлять моделью.

Кликни по табу, чтобы увидеть смысл каждой роли:

Кто ты и как себя ведёшь

Это инструкция-конституция. Задаётся один раз, в начале массива. Модель воспринимает её как свод правил, которые нельзя нарушать: личность, тон, формат ответов, ограничения.

Пример рычага: один и тот же user-запрос с разными system'ами даст принципиально разные ответы. «Отвечай как юрист с 20-летним стажем» и «Отвечай как друг в баре» — две разные модели на одном и том же запросе.

Это самый дешёвый рычаг качества в AI-инжиниринге. Если результат плохой — первое, на что смотрят, это system prompt.

То, на что модель должна ответить

Сообщение от тебя или твоего конечного пользователя. Именно на user-сообщение модель отвечает; system только задаёт рамки.

В сложных системах user-сообщение часто конструируется автоматически: пользователь написал короткий вопрос, а твой код перед отправкой обогащает его контекстом, найденными документами (RAG), результатами инструментов. Это и есть «промпт-инжиниринг под капотом».

Главное правило: user — это вход, доверенный или нет в зависимости от того, кто его прислал. На этом построены атаки prompt injection (см. День 0).

Что модель уже говорила

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

Технически — это способ показать модели её собственную «историю». Она увидит «я уже говорила X» и продолжит логически. Без этой роли модель каждый раз начинала бы с нуля.

Тонкий момент: ты сам решаешь, что класть в assistant-роль. Можешь подсунуть «фальшивую» историю — модель примет её за свои прошлые слова. Это используется для few-shot prompting и направления стиля.

Что приходит в ответе

В ответ модель возвращает JSON. В нём — не только текст ответа, но и несколько критических полей, которые AI-инженер обязан читать всегда, не только в проде.

Минимальная структура ответа выглядит так:

Ответ от API · упрощённо
// ↓ собственно текст ответа "choices": [{ "message": { "content": "..." },
              "finish_reason": "stop" }],

// ↓ счётчики токенов — это деньги "usage": { "prompt_tokens": 24,
            "completion_tokens": 87,
            "total_tokens": 111 }

В нём три вещи, на которые ты смотришь каждый раз:

То, что ты показываешь пользователю или передаёшь дальше по пайплайну. Очевидное поле — но обрати внимание: оно может быть пустым или обрезанным, и об этом тебе подскажет finish_reason, а не само поле.

Возможные значения:

  • stop — модель закончила сама, всё хорошо.
  • length — упёрлась в max_tokens, ответ обрезан. Если ты ждал JSON — он невалидный.
  • content_filter — модерация заблокировала ответ.
  • tool_calls — модель решила вызвать инструмент (увидим в Дне 17+).

Это поле — главный сигнал «что-то пошло не так». Игнорируешь — получаешь баги вида «иногда JSON не парсится».

prompt_tokens — сколько токенов ушло в запросе. completion_tokens — сколько модель сгенерировала. Биллинг считается по обоим, обычно по разным ставкам (input дешевле, output дороже).

Это поле — твой главный метрик-сигнал. Когда диалог растёт, токены растут квадратично (см. День 8). Когда вылезает счёт на $200 вместо $20 — ответ всегда находится в usage.

Привычка с первого дня: логируй usage в каждом запросе.

Решения, которые ты принимаешь как AI-инженер

Программист пишет код. AI-инженер принимает решения о том, как должна вести себя система с LLM внутри. Уже на этапе первого запроса у тебя есть несколько развилок, на которых легко свернуть не туда.

Развилка 1. Какую модель выбрать

У каждой задачи свой оптимум — не «самая мощная», а «достаточная при адекватной цене и скорости».

Маленькая модель

Когда брать

Простые задачи (классификация, извлечение, переписать в формат), массовые вызовы, чувствительность к стоимости и latency. Качество — 80% от топовой при 5–10% цены.

Большая модель

Когда брать

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

Развилка 2. Свой провайдер или маршрутизатор

Можно работать напрямую с одним провайдером (OpenAI, Anthropic), а можно — через прослойку типа OpenRouter или LiteLLM, которая даёт доступ к десяткам моделей через один API.

Для обучения — бери прямой API одного провайдера, не усложняй. В проде — маршрутизатор полезен, когда хочешь fallback'и и A/B-тесты между моделями.

Развилка 3. Что класть в system, а что в user

Частая ошибка новичка — пихать всё в user: и инструкции, и данные, и вопрос. Модель путается, что главное.

Правильная привычка: system — это правила игры (роль, тон, формат, ограничения), которые ты задал один раз. user — это конкретный запрос с данными для этого конкретного раза. Эта разница станет особенно важной в Дне 14, когда мы будем разбирать инварианты.

i
Концептуально важное
system prompt — это политика, user — событие. Политика стабильна, события меняются. Не смешивай.

Концептуальные грабли первой недели

Самый частый и самый дорогой когнитивный баг. Модель не помнит ничего. Если в её ответе появилась преемственность — значит, твой код подложил историю в массив. Если её там нет — модель отвечает как впервые, даже если ты только что ей это писал.

Эта ошибка лечится тем, что ты с самого начала задаёшь себе вопрос: «что именно сейчас находится в массиве messages?».

Видишь поле content, копируешь его дальше — и теряешь сигнал о том, что ответ был обрезан, заблокирован или модель захотела вызвать инструмент. В обучении это терпимо, в проде — приводит к самым странным багам.

Привычка: всегда проверяй finish_reason === "stop" перед тем, как использовать ответ.

«Я не дал system — значит модель работает как есть». Это не так. Без явного system модель работает с дефолтным system'ом провайдера, который ты не видишь и не контролируешь. Он не нейтральный — он усреднённый под широкую аудиторию.

Для любой серьёзной задачи ты пишешь свой system. Это сразу повышает качество в разы — без всякой смены модели.

Практика

Поскольку курс про AI-инжиниринг, практика тут — про мышление и наблюдение, а не написание кода. Сделай эти три эксперимента — они займут полчаса в плейграунде провайдера (например, platform.openai.com/playground или console.anthropic.com).

Эксперимент 01 · Сила system'a

Один вопрос — четыре личности

В плейграунде задай один и тот же user-вопрос («Объясни мне, почему небо голубое»). Прогони четыре раза с разными system: «ты учёный-физик», «ты ребёнок 5 лет», «ты программист, объясняй через аналогии с кодом», «ты циничный философ». Сравни ответы и обрати внимание: сам факт, тон, длина, выбор слов — всё меняется. Это даст тебе интуицию про силу system.

Эксперимент 02 · Stateless на практике

Покажи модели её «беспамятство»

Открой два отдельных запроса (не диалог, а именно два разных). В первом скажи: «Меня зовут Алекс». Во втором, новом, спроси: «Как меня зовут?». Модель не знает. Теперь сделай один запрос с массивом messages, где первое сообщение — твоё представление, второе — вопрос. Модель ответит правильно. Это и есть демонстрация того, что памяти нет — есть только массив.

Эксперимент 03 · Заглянуть в usage

Посмотри, как растёт счёт

В плейграунде или через любой UI, который показывает usage — отправь короткий запрос, посмотри prompt_tokens и completion_tokens. Потом скопируй большой кусок текста (5-10 параграфов) и попроси его пересказать. Сравни. Это даст тебе физическое ощущение того, что токены = деньги, и зачем мы будем учиться сжимать историю в Днях 8–10.

Что в Дне 02
Возьмём этот же базовый запрос и начнём управлять формой ответа: ограничивать длину, требовать конкретный формат, ставить условия остановки. От «модель что-то ответила» — к «модель ответила так, как мне нужно».