Одно дело — использовать AI-агента, чтобы писать код. Другое — встроить AI прямо в продукт: чат-поддержку, умный поиск, автозаполнение, разбор документов. Это уже не «помощник разработчика», а часть самого приложения, которую пишете вы. Разберём, из каких кирпичиков собирается такая функциональность и чем она отличается от обычного кода.

Четыре части любой LLM-фичи

Почти любая функциональность на основе языковой модели складывается из одного и того же:

  1. Промпт — инструкция модели: что сделать и в каком виде ответить.
  2. Контекст — данные, которые вы подмешиваете в запрос: сообщение пользователя, куски документов, история диалога.
  3. Вызов модели — отправка промпта с контекстом и получение ответа.
  4. Обработка ответа — разбор того, что вернула модель, и действие: показать пользователю, сохранить, вызвать функцию.

Вся инженерия LLM-фичи — это про то, как хорошо собрать эти четыре части. Модель — готовый «двигатель»; ваша работа — грамотно подать ей вход и аккуратно принять выход.

Промпт: инструкция, а не магия

Промпт обычно делят на две части: системную (кто модель и по каким правилам работает — «ты — ассистент поддержки, отвечай кратко и только по фактам из контекста») и пользовательскую (конкретный запрос). Хороший промпт конкретен: задаёт роль, формат ответа, границы («не выдумывай, если данных нет»). Плохой — расплывчат, и модель заполняет пробелы догадками.

Важно понять: промпт — это не заклинание, а спецификация. Чем яснее вы описали задачу, тем предсказуемее ответ. Значительная часть работы над LLM-фичей — это итеративная доводка промпта на реальных примерах.

Контекст: модель знает только то, что вы дали

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

  • окно контекста конечно — влезает ограниченный объём (см. контекст), поэтому нельзя просто «загрузить всю базу»; нужные куски отбирают;
  • лишний контекст вредит — мусор в запросе путает модель и повышает стоимость (см. токены и стоимость).

Как отбирать нужные куски данных из большого корпуса — отдельная большая тема; её решает RAG и эмбеддинги.

Структурированный вывод

Если ответ модели идёт прямо пользователю — достаточно текста. Но если фича встроена в программу (модель классифицирует обращение, извлекает поля из письма, решает, что делать дальше), ответ нужен машиночитаемый — обычно JSON по заданной схеме. Современные модели умеют возвращать структурированный вывод по описанию схемы; это превращает модель из «собеседника» в компонент, чей результат можно надёжно разобрать и использовать в коде. Механику вызова функций по схеме разбирает вызов инструментов.

Чем это отличается от обычного кода

Ключевое, к чему надо привыкнуть: вывод модели недетерминирован. Один и тот же вход может дать разные ответы, а модель иногда ошибается уверенно — выдаёт правдоподобную неправду. Обычная функция при одном входе всегда даёт один выход; LLM — нет.

Отсюда другой подход к качеству:

  • не «тест прошёл / не прошёл», а оценка (evaluation). LLM-фичу проверяют на наборе примеров, измеряя, в какой доле случаев ответ приемлем, — а не ждут точного совпадения.
  • защита на выходе. Раз модель может ошибиться, ответ проверяют: валидируют структуру, отсекают недопустимое, подставляют запасной вариант при сбое.
  • заземление на данные. Чтобы модель не выдумывала, ей дают факты в контексте и просят отвечать только по ним — это резко снижает выдумки.

Тот же принцип приёмки, что и для AI-написанного кода: доверяй, но проверяй машиной.

Коротко

  • LLM-фича = промпт + контекст + вызов модели + обработка ответа. Модель — двигатель, ваша работа — вход и выход.
  • Промпт — это спецификация (роль, формат, границы), а не магия; его доводят на примерах.
  • Контекст ограничен и должен быть релевантным; отбор нужных данных решает RAG.
  • Для встроенных фич нужен структурированный вывод (JSON по схеме), а не просто текст.
  • Вывод модели недетерминирован: качество меряют оценкой на примерах, а ответ защищают валидацией и заземлением на данные.

Дальше — LangChain: как оркестрировать эти части, когда фича становится сложнее одного вызова.