32 мин чтенияAI

LLM: Как это работает, где взять и как приручить

LLM: Как это работает, где взять и как приручить

1. Введение. Развенчание мифов

Большие языковые модели — LLM. Начнем с того, что развеем главный миф: LLM — это не волшебный шар, который читает ваши мысли и знает все ответы.

Когда мы впервые сталкиваемся с ChatGPT или аналогичными системами, возникает ощущение магии. Мы пишем вопрос — получаем ответ. Кажется, что перед нами разумная сущность, которая всё понимает. Но на самом деле LLM — это очень сложный, но предсказуемый статистический калькулятор слов.

Что это значит на практике? Это значит, что модель не «понимает» смысл ваших слов в человеческом смысле. Она не знает ваших внутренних бизнес-процессов, если вы ей о них не рассказали. Она не может прочитать ваши мысли.

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

Наша задача как инженеров, менеджеров и всех, кто работает с LLM — научиться управлять этой вероятностью. Разберемся, как это делать.


2. Анатомия «мышления»: Токены и Температура

Начнем с базовых понятий. Когда вы пишете текст модели, она видит его не как слова, а как токены.

Токен — это базовая единица обработки. Это может быть целое слово, часть слова или даже отдельный символ. Например, фраза «Clean Architecture» разбивается на три токена: «Clean», « Arch» и «itecture». Обратите внимание: токенов больше, чем слов, потому что модель работает с частями слов.

Как тратятся токены

Когда вы отправляете запрос к модели, токены тратятся в двух направлениях:

Input токены — это всё, что вы отправляете модели: ваш промпт, системные инструкции, история диалога, контекст из RAG. Это то, что модель должна «прочитать» и понять.

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

Важно для менеджеров: Стоимость API обычно считается так: $X за 1M input токенов + $Y за 1M output токенов. При этом output токены часто стоят в 2-4 раза дороже. Поэтому длинные ответы модели — это дорого.

Важно для разработчиков: Лимит контекстного окна (например, 8K, 32K, 128K токенов) включает и input, и output. Если у вас история диалога на 7000 токенов, а лимит 8000, то на ответ остается всего 1000 токенов. Это примерно 750 слов — модель может оборвать ответ на полуслове.

Лимит токенов: max_tokens

Параметр max_tokens ограничивает длину ответа модели. Что произойдет, если модель достигнет этого лимита?

Сценарий 1: Ответ оборвался. Модель генерировала длинный код, но достигла лимита. Вы получите обрезанный, нерабочий код. В ответе API будет флаг finish_reason: "length" вместо "stop".

Сценарий 2: Модель не успела закончить мысль. Например, вы попросили объяснить концепцию, но модель остановилась на середине предложения.

Как избежать: Всегда проверяйте finish_reason в ответе API. Если это "length", значит ответ обрезан, и нужно либо увеличить max_tokens, либо попросить модель продолжить. Для генерации кода ставьте max_tokens с запасом — 2000-4000 токенов, чтобы модель могла написать полный класс без обрезания.

Температура и другие параметры контроля

Температура — это не единственный параметр, который управляет «креативностью» модели. Давайте разберем весь набор.

Temperature (0.0 — 2.0) — основной параметр. На температуре 0.0 модель максимально строгая и детерминированная. Если вы попросите её сгенерировать PHP-код, SQL-запрос или извлечь данные в JSON — ставьте температуру 0.0 или 0.1. Вы получите предсказуемый, стабильный результат. На температуре 0.7–0.9 модель становится креативной, хаотичной. Это идеально для брейншторма идей, написания маркетингового текста. Но для кода или точных данных такая температура опасна.

Top_p (nucleus sampling, 0.0 — 1.0) — альтернатива температуре. Модель рассматривает только токены, которые в сумме дают вероятность p. Например, top_p=0.9 означает, что модель выбирает из токенов, которые покрывают 90% вероятности. Чем ниже значение, тем более предсказуемый ответ. Обычно используется либо temperature, либо top_p, но не оба сразу. Для кода ставьте top_p=0.1-0.3.

Top_k (1 — бесконечность) — модель рассматривает только k наиболее вероятных следующих токенов. top_k=1 означает, что модель всегда выбирает самый вероятный токен (жадный поиск, greedy decoding). Это максимально детерминированный режим. Для PHP-кода и JSON top_k=1-10 дает очень стабильные результаты.

Frequency penalty (-2.0 — 2.0) — штрафует токены, которые уже часто встречались в ответе. Чем выше значение, тем меньше модель повторяется. Полезно для генерации длинных текстов, чтобы избежать зацикливания. Для кода ставьте 0.0 — повторения в коде (например, использование одних и тех же переменных) — это нормально.

Presence penalty (-2.0 — 2.0) — штрафует токены, которые уже появлялись в ответе, независимо от частоты. Это заставляет модель переходить к новым темам. Для креативного письма ставьте 0.5-1.0. Для кода — 0.0.

Stop sequences — список строк, при появлении которых модель останавливается. Например, если вы генерируете JSON и не хотите, чтобы модель добавляла пояснения после JSON, добавьте stop=["\n\n"] или stop=["```"]. Это гарантирует, что ответ закончится ровно там, где вам нужно.

Практические рекомендации для разных задач

Для генерации PHP-кода:

temperature: 0.0-0.1
top_p: 0.1-0.3
top_k: 1-10
frequency_penalty: 0.0
presence_penalty: 0.0
max_tokens: 2000-4000

Для извлечения данных в JSON:

temperature: 0.0
top_p: 0.1
top_k: 1
max_tokens: 500-1000 (зависит от сложности JSON)

Для брейншторма идей:

temperature: 0.7-0.9
top_p: 0.9
frequency_penalty: 0.5
presence_penalty: 0.5
max_tokens: 1000-2000

Для суммаризации текста:

temperature: 0.3-0.5
top_p: 0.5
max_tokens: 200-500 (зависит от желаемой длины саммари)

Галлюцинации

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

Как бороться:

  1. Используйте temperature=0.0 для фактических вопросов
  2. Применяйте RAG — давайте модели реальные данные в контексте
  3. В промпте явно указывайте: «Если не знаешь ответа, скажи "Я не знаю"»
  4. Всегда проверяйте факты в критичных задачах

3. Анатомия модели: Где брать и что значат цифры

Теперь разберемся, что такое модель и как выбирать подходящую.

У модели есть три ключевых параметра, которые нужно понимать.

Первый — размер в параметрах. Вы видите обозначения вроде 7B, 8B, 70B. B — это миллиард параметров. Условно говоря, это «размер мозга» модели. Модели на 7-8 миллиардов параметров (например, Llama 3 8B или Mistral 7B) достаточно для большинства задач: суммаризация текста, простые чаты, написание кода, извлечение данных. Модели на 70B и больше нужны для сложной логики, глубоких рассуждений, работы с большими контекстами. Но они требуют гораздо больше ресурсов.

Второй — квантование. Это сжатие модели. Вы видите обозначения вроде Q4_K_M, Q8, FP16. Квантование уменьшает размер модели и потребление оперативной памяти с минимальной потерей качества. Например, модель 8B в квантовании Q4 занимает около 5 ГБ оперативной памяти и спокойно запускается на хорошем ноутбуке. В полном качестве (FP16) она заняла бы 16 ГБ. Для большинства задач разница в качестве между Q4 и FP16 минимальна, а разница в ресурсах — колоссальная.

Третий — где брать модели. Мы не тренируем модели с нуля. Мы берем готовые open-source решения. Основные источники: Hugging Face — это как GitHub для ML-моделей, там лежат тысячи моделей с документацией. И официальный реестр Ollama — там модели уже оптимизированы для локального запуска.

Но есть еще один критически важный аспект — семейство моделей.

Семейства моделей: кто есть кто

На рынке open-source моделей доминирует несколько ключевых семейств. Каждый имеет свою специализацию.

Meta Llama (3.3, 4) — самое популярное семейство. Llama 4, представленная в 2025 году, перевела флагманские модели на MoE-архитектуру.

  • Llama 4 Scout: 109B параметров (17B активных), нативная мультимодальность (изображения, видео), контекстное окно до 10M токенов.
  • Llama 4 Maverick: 402B параметров (17B активных), 1M контекст.

Обе отлично справляются с чатами, суммаризацией, сложной логикой и генерацией кода. Llama 3.3 70B остаётся мощной плотной моделью для тех, кому нужна стабильность и меньший объём VRAM. Для локального запуска в условиях ограниченных ресурсов всё ещё актуальны Llama 3.1 8B и Llama 3.2 (мультимодальные 11B / 90B).

Mistral — французское семейство, славящееся эффективностью.

  • Mistral Large 3 (123B) — флагман 2025 года, 256K контекст, мультимодальность, лучший выбор для сложных задач.
  • Mistral Small 3 (24B) — «рабочая лошадка» для локального запуска: при квантовании помещается в 16 ГБ RAM и превосходит многих конкурентов в кодировании и рассуждениях.

Qwen 3 — семейство от Alibaba. Вышло весной 2025 года. Поддержка 119 языков, включая превосходную работу с русским и китайским.

  • Qwen 3 Coder (специализированные версии 8B, 32B) — лидеры в бенчмарках кода, обходят GPT-4o в задачах генерации и отладки.
  • Qwen 3 8B / 32B — универсальные мультиязычные модели с контекстом до 1M токенов.

DeepSeek — китайское семейство, флагман эффективности и рассуждений.

  • DeepSeek V3.1 (март 2025): 671B MoE (37B активных), 128K контекст, выдающееся качество в коде и математике.
  • DeepSeek R1 — модель с продвинутой цепочкой рассуждений, решает задачи, требующие пошаговой логики.
  • DeepSeek Coder V3 — узкая специализация на программировании, стабильно в топе бенчмарков.

Microsoft Phi-4 — маленькие, но мощные модели (конец 2024 – 2025).

  • Phi-4-mini (3.3B) — удивительно сильна в рассуждениях, математике и следовании инструкциям. Идеальна для edge-устройств и мобильных приложений.
  • Phi-4 (14B) — более крупная версия, контекст 128K, хороша для аналитики и длинных документов.

Google Gemma 3 — открытое семейство на базе технологий Gemini (2025). Модели от 1B до 27B, все с контекстом 128K и мультимодальностью. Gemma 3 27B сравнима с Llama 3.3 70B по качеству, но значительно легче.

Как выбирать модель: бенчмарки и специализация

Ни одна модель не решает все задачи одинаково хорошо. Ориентируйтесь на ключевые тесты.

  • MMLU (Massive Multitask Language Understanding) — общие знания и рассуждения. DeepSeek V3.1 и Llama 4 Maverick показывают ≈88‑89%, Qwen 3 235B — около 87%. Хороший уровень для прикладной системы — от 80%.
  • HumanEval / MBPP — генерация и понимание кода (Python, JavaScript, PHP и др.). Здесь лидируют Qwen 3 Coder 32B и DeepSeek Coder V3, набирая выше 90% pass@1.
  • MT-Bench / AlpacaEval — качество диалога и следования инструкциям. Важно для чат-ботов и ассистентов. Лидеры — Llama 4 Maverick, Mistral Large 3 и Qwen 3 235B.
  • GSM8K / MATH — математические и логические рассуждения. DeepSeek R1 и Qwen 3 Coder решают почти 100% задач GSM8K и сложные олимпиадные примеры.
  • Мультиязычность — если работаете с русским, обязательно проверяйте. Llama 4, Qwen 3, Mistral Large 3 и DeepSeek V3 прекрасно понимают кириллицу, генерируют текст и код с комментариями на русском. Маленькие модели (Phi-4-mini, Gemma 3 1B) могут «спотыкаться» на сложных конструкциях.

Контекстное окно: сколько текста модель может «увидеть»

Лимит токенов (input + output) критичен для RAG, обработки длинных документов и многошаговых диалогов.

  • Llama 4 Scout — до 10 000 000 токенов (беспрецедентный объём, ~7 млн слов). Позволяет загружать целые книги и большие кодовые базы.
  • Llama 4 Maverick / Qwen 3 (крупные) — 1 000 000 токенов.
  • Mistral Large 3 — 256K токенов.
  • DeepSeek V3.1 / R1, Phi-4, Gemma 3 — 128K токенов.

Практический совет: если ваш RAG-пайплайн подгружает десятки чанков из векторной БД, выбирайте модель с окном от 128K, чтобы избежать лишней суммаризации.

Практические рекомендации по выбору

Для локального чат-бота на ноутбуке (8–16 ГБ RAM):

  • Qwen 3 8B Q4 (~5 ГБ) — универсальный мультиязычный выбор.
  • Mistral Small 3 24B Q4_K_M (~14 ГБ) — если есть 16 ГБ и нужен упор на код и логику.
  • Phi-4-mini Q4 (~2 ГБ) — для очень ограниченных ресурсов.

Для корпоративного RAG с большими документами:

  • Llama 4 Scout Q4 на GPU с ≥24 ГБ VRAM (RTX 4090/5090 или A6000) — контекст 10M, экономично.
  • Облачный API DeepSeek V3.1 или Mistral Large 3 — если нужна максимальная точность без собственного парка GPU.

Для генерации кода (PHP, Python, JavaScript):

  • Qwen 3 Coder 32B (локально или в облаке).
  • DeepSeek Coder V3.
  • Mistral Large 3 (облачный API) — мощный универсал с сильным кодом.

Для edge-устройств и мобильных приложений:

  • Phi-4-mini (3.3B).
  • Gemma 3 1B / 4B.
  • Qwen 3 3B.

Мультиязычность и русский язык

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

Отличная поддержка: Llama 4, Qwen 3, Mistral Large 3 / Small 3, DeepSeek V3.

Хорошая поддержка: Gemma 3 27B, Phi-4 (базовая).

Как проверить: дайте модели инструкцию на русском с требованием написать код с комментариями на русском и оцените качество. Модели вроде Qwen 3 или Llama 4 справятся без нареканий.

Где брать модели: детализация источников

  • Hugging Face — главный репозиторий. Все модели доступны в различных форматах: GGUF для Ollama, safetensors для vLLM, PyTorch для дообучения. Множество community-сборок под медицинские, юридические, финансовые задачи.
  • Ollama — по-прежнему самый простой способ локального запуска. Одна команда ollama run llama4:scout — и модель готова к работе. Поддерживает все популярные кванты.
  • LM Studio — графический интерфейс с поиском по Hugging Face, авто-квантованием и чатом. Удобен для быстрого прототипирования.
  • vLLM — движок для продакшен-инференса. PagedAttention, continuous batching, поддержка квантов FP8/FP4. Требует настройки, но даёт максимальный throughput.

Проприетарные облачные модели

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

Anthropic Claude (Opus 4, Sonnet 4, Haiku 4)

Флагманское семейство 2025–2026 годов. Claude считается эталоном для сложных инженерных и аналитических задач.

  • Opus 4 — самая мощная модель для глубоких рассуждений, анализа многотысячестраничных документов и комплексной разработки. Контекст до 500K токенов, отлично держит детали из начала.
  • Sonnet 4 — оптимальный баланс скорости и качества, лучший выбор для генерации кода, рефакторинга и RAG. Контекст 200K, отличное следование инструкциям.
  • Haiku 4 — быстрая и недорогая, подходит для простых чат-ботов, классификации и рутинной обработки.

Сильные стороны: минимальный уровень галлюцинаций, феноменальная точность в «needle in a haystack», строгие корпоративные политики безопасности (включая опцию нулевого удержания данных).

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

OpenAI GPT (GPT-4o, GPT-4.1, GPT-5 mini)

Базовый ориентир для большинства разработчиков.

  • GPT-4o (2024) — мультимодальный универсал, понимает текст, изображения и аудио.
  • GPT-4.1 (2025) — улучшенная логика и следование инструкциям, особенно в коде.
  • GPT-5 mini (2026) — сверхбыстрая и крайне дешёвая модель, унаследовавшая качество старших версий для простых задач вроде суммаризации, извлечения JSON и диалогов.

Особенность для разработчиков: у OpenAI одни из самых надёжных Structured Outputs и JSON Mode, что критично при интеграции с PHP/Python-бэкендами.

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

Google Gemini (2.5 Pro, 2.5 Flash)

Проприетарные модели с самым большим контекстным окном на рынке — до 2 миллионов токенов у Gemini 2.5 Pro.

  • Gemini 2.5 Pro — флагман, отлично проявляет себя в аналитике, мультимодальных задачах и поиске по гигантским массивам документов.
  • Gemini 2.5 Flash — быстрая и экономичная версия для повседневных задач, контекст до 1M токенов.

Обе модели глубоко интегрированы с экосистемой Google Cloud, что удобно, если инфраструктура уже там. Качество мультиязычной работы (включая русский) на высоком уровне.

Как это меняет выбор (Обновленная матрица)

Теперь, когда мы видим полную картину, выбор модели становится осознанным компромиссом:

  • Нужна максимальная приватность и работа без интернета? → Только open-source: Llama 3.1 8B/70B, Qwen 2.5, Mistral (запуск через Ollama/vLLM).
  • Нужно анализировать 100-страничный технический документ или писать сложный рефакторинг, и данные можно отправлять в облако? → Claude 3.5 Sonnet (лучшее качество рассуждений и работы с большим контекстом).
  • Нужно надежно извлекать данные в JSON для PHP-приложения с минимальными затратами? → GPT-4o mini (дешево, быстро, отличный Structured Output) или локальный Qwen 2.5 Coder 7B (если данные чувствительные).
  • Нужно встроить модель в мобильное приложение или IoT-устройство? → Phi 3.5 Mini или Gemma 2 2B (работают прямо на устройстве).

Экономика: сколько это стоит

Облачные API (цены ориентировочные на середину 2026):

  • OpenAI GPT-4o: ~$1.0 за 1M входящих токенов, ~$4.0 за 1M исходящих.
  • Anthropic Claude 4 Sonnet: ~$3/$15.
  • Mistral Large 3: ~$2/$6.
  • DeepSeek V3.1: ~$0.27/$1.1 — одно из лучших соотношений цена/качество.

Для приложения с 1 000 запросов в день (500 входных + 200 выходных токенов) ежемесячные расходы на GPT-4o составят около $60, на DeepSeek V3.1 — менее $10.

Локальный запуск:

Стоимость GPU RTX 5090 (32 ГБ) — около $2 000. Модель Llama 4 Scout Q4 занимает ~20 ГБ VRAM и потребляет порядка 250 Вт. При круглосуточной работе и цене $0.1 за кВт·ч расходы на электричество — около $18/мес. Окупаемость железа по сравнению с GPT-4o наступает примерно через 9–12 месяцев при нагрузке от 5 000 запросов в день. Для стартапов с высоким трафиком локальный инференс становится выгодным очень быстро.

Вывод для менеджеров

Если у вас регулярный поток >10 000 запросов в день и доступен GPU — вложения в локальный запуск Llama 4 Scout или Qwen 3 32B окупаются за год и далее приносят чистую экономию. При низком или нестабильном трафике облачные API DeepSeek V3.1 или Mistral Large 3 дают максимальную гибкость и минимальный порог входа. Для кодовых задач лучшими помощниками остаются Qwen 3 Coder и DeepSeek Coder, а для русского языка уверенно лидируют Qwen 3 и Llama 4.


4. Где и как запускать: Облако vs Локально

Теперь вопрос инфраструктуры. Где запускать модель?

Есть два основных пути: облако и локально.

Облачные API — это OpenAI, Anthropic, YandexGPT и другие. Плюсы: не нужно своё железо, доступны самые мощные модели (GPT-4, Claude 3), не нужно разбираться в инфраструктуре. Минусы: ваши данные уходят наружу (для многих компаний это критично), оплата за каждый токен, зависимость от интернета и доступности сервиса.

Локальный запуск — это LM Studio, Ollama, vLLM. Плюсы: полная приватность данных (всё остается у вас), бесплатно после покупки железа, работа без интернета. Минусы: нужна оперативная память (от 8-16 ГБ для небольших моделей), модели чуть менее мощные, чем топовые облачные.

Для прототипирования, личных задач и тестирования идеально подходит LM Studio — это красивый графический интерфейс, скачал модель, нажал кнопку Run, и всё работает. Или Ollama — работает через терминал, легко интегрируется в скрипты и автоматизацию.

Для корпоративного продакшена, где нужны чувствительные данные и высокая нагрузка, мы поднимаем свои инстансы Ollama или vLLM внутри нашего периметра, обычно в Docker-контейнерах. vLLM особенно хорош для высоконагруженных систем, где нужна максимальная скорость отдачи.


5. Форматы промптов: Как правильно «разговаривать»

Теперь самое интересное — как писать промпты, чтобы получать предсказуемый результат. Это не просто "напиши текст", это целая дисциплина — промпт-инжиниринг.

Базовые форматы промптов

1. Простой текст

Напиши функцию на PHP, которая сортирует массив пользователей по дате регистрации.

Это работает для простых задач, но для сложных может быть недостаточно. Модель может интерпретировать запрос по-разному каждый раз.

2. XML / Markdown разметка

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

<role>
Ты опытный PHP-разработчик с 10-летним стажем.
Ты всегда используешь строгую типизацию и PSR-12.
</role>

<rules>
1. Используй только PHP 8.5+
2. Добавляй PHPDoc для всех публичных методов
3. Обрабатывай все возможные ошибки
4. Пиши код в стиле Clean Architecture
</rules>

<context>
Вот текущий код, который нужно рефакторить:
```php
class UserService {
    public function saveUser($data) {
        mysql_query("INSERT INTO users...");
    }
}
</context>

<task>
Примени паттерн Repository к этому коду.
Выдели интерфейс UserRepository и реализацию MysqlUserRepository.
</task>

<output_format>
Верни результат в виде двух блоков кода:
1. Интерфейс UserRepository
2. Класс MysqlUserRepository
</output_format>

Модель гораздо лучше понимает структуру. Она не перепутает инструкцию с данными. XML-теги работают как "разделители контекста" для внимания модели (attention mechanism).

3. JSON Mode / Structured Output

Это критически важно для разработчиков. Если вам нужно, чтобы модель вернула структурированные данные для обработки в коде, всегда используйте JSON Mode:

{
  "prompt": "Извлеки из текста имя пользователя и email",
  "text": "Меня зовут Иван Петров, мой email ivan@example.com",
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "user_extraction",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "email": {"type": "string", "format": "email"}
        },
        "required": ["name", "email"],
        "additionalProperties": false
      }
    }
  }
}

Это гарантирует, что вы получите валидный JSON, который можно распарсить через json_decode($response, true) без ошибок. Иначе модель может ответить текстом вроде "Конечно, вот ваш JSON:" и добавить пояснения, которые сломают парсинг.

Пример на PHP:

$response = $llm->generate($prompt, [
    'response_format' => ['type' => 'json_object']
]);

$data = json_decode($response, true);
if (json_last_error() === JSON_ERROR_NONE) {
    // Успешно распарсили
    $user = new User($data['name'], $data['email']);
} else {
    // Обработка ошибки
    throw new \Exception('Invalid JSON response');
}
JSON Mode: ограничения и альтернативы

Важно: JSON Mode (особенно Structured Outputs с гарантированной валидацией схемы) доступен не для всех моделей и фреймворков.

Где JSON Mode работает надёжно

Облачные API

  • OpenAI GPT-4.1, GPT-5 mini. Полная поддержка response_format: { "type": "json_object" } и Structured Outputs — режим, в котором модель строго соблюдает переданную JSON-схему (100% гарантия валидности ответа). GPT-4.1 также позволяет совмещать Structured Outputs с вызовом функций, что удобно для сложных конвейеров на PHP‑бэкенде.
  • Anthropic Claude (Opus 4, Sonnet 4). Гарантированный JSON достигается через tool use (function calling) — модель возвращает данные в полях аргументов функции, соответствующих заранее заданной схеме. В расширенном режиме (extended tool use) можно явно указать, что ответ всегда должен быть валидным JSON. Sonnet 4 при этом отлично держит структуру даже для вложенных объектов, а Opus 4 незаменим, когда схема сложная и требует многошаговых рассуждений.
  • Google Gemini 2.5 Pro, 2.5 Flash. Нативная поддержка JSON Mode через параметр response_mime_type: "application/json". В сочетании с system instruction, описывающей желаемую структуру, Gemini 2.5 даёт очень стабильный JSON. Модель также поддерживает Controlled Generation — указание схемы напрямую, что исключает невалидные ответы.

Open-source / локальный запуск

Современные движки позволяют получить надёжный JSON Mode за счёт принудительного ограничения генерации грамматикой (guided/constrained decoding). Ключевые инструменты:

  • llama.cpp / Ollama — встроенная поддержка JSON grammar (формат GBNF). Достаточно передать описание схемы, и модель сгенерирует токены строго по ней. Проверенные модели: Qwen 3, Llama 4 (обе конвертируются в GGUF), Mistral Small 3, Phi‑4‑mini.
  • vLLM — режим guided_decoding_backend с опорой на outlines или lm-format-enforcer. Позволяет передать Pydantic-модель или JSON Schema прямо в API. Рекомендуемые модели: Qwen 3 Coder 32B, DeepSeek V3.1 (при развёртывании через vLLM).
  • Outlines (библиотека) — строит FSM, гарантирующий генерацию токенов по регулярному выражению или JSON-схеме. Работает поверх transformers, vLLM, llama.cpp. Идеален, если нужна максимальная скорость и строгость.

Таким образом, если раньше JSON Mode считался вотчиной проприетарных API, то сейчас любая open-source модель, запущенная через llama.cpp с грамматикой или vLLM с guided decoding, гарантирует 100% валидный JSON. Это полностью снимает проблему «сломанного» вывода при интеграции с PHP-приложениями — можно смело выбирать локальную Qwen 3 8B для извлечения данных и быть уверенным в структуре ответа.

Где JSON Mode НЕ работает или работает плохо:

  • Старые модели (Llama 2, Mistral v1) — не обучались на JSON-формате, часто генерируют невалидный JSON
  • Маленькие модели (< 7B параметров) — могут "ломаться" на сложных JSON-схемах
  • Модели без fine-tuning на JSON — некоторые специализированные модели (например, для кода) могут не понимать JSON-структуру

Альтернативы, если JSON Mode недоступен

Если ваша модель не поддерживает JSON Mode или генерирует невалидный JSON, есть несколько рабочих паттернов:

Паттерн 1: Явная инструкция + пример (Few-shot)

Верни результат СТРОГО в формате JSON. Никаких пояснений, никакого текста до или после JSON.

Пример правильного ответа:
{"name": "Иван", "email": "ivan@example.com"}

Текст для обработки:
"Меня зовут Петр, мой email petr@test.com"

Паттерн 2: Обертка в XML-теги + парсинг

Верни результат в тегах <json>...</json>.

Пример:
<json>
{"name": "Иван", "email": "ivan@example.com"}
</json>

На PHP:

$response = $llm->generate($prompt);

// Извлекаем JSON из тегов
if (preg_match('/<json>(.*?)<\/json>/s', $response, $matches)) {
    $jsonString = trim($matches[1]);
    $data = json_decode($jsonString, true);
    
    if (json_last_error() === JSON_ERROR_NONE) {
        // Успешно
    } else {
        // Попытка восстановить JSON
        $data = attemptJsonRepair($jsonString);
    }
}

Паттерн 3: Retry с валидацией

$maxRetries = 3;
$lastError = null;

for ($i = 0; $i < $maxRetries; $i++) {
    $response = $llm->generate($prompt);
    $data = json_decode($response, true);
    
    if (json_last_error() === JSON_ERROR_NONE) {
        // Валидный JSON
        break;
    }
    
    $lastError = json_last_error_msg();
    
    // Добавляем ошибку в промпт для следующей попытки
    $prompt = $originalPrompt . "\n\nПредыдущий ответ был невалидным JSON: $lastError. Попробуй снова.";
}

if (json_last_error() !== JSON_ERROR_NONE) {
    throw new \Exception("Failed to get valid JSON after $maxRetries retries: $lastError");
}

Паттерн 4: Function Calling (Tool Use)

Вместо JSON Mode используйте function calling — многие модели лучше справляются с вызовом функций, чем с генерацией JSON:

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "extract_user",
        "description": "Извлекает имя и email из текста",
        "parameters": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"}
          },
          "required": ["name", "email"]
        }
      }
    }
  ]
}

Модель вернет:

{
  "tool_calls": [
    {
      "function": {
        "name": "extract_user",
        "arguments": "{\"name\": \"Иван\", \"email\": \"ivan@example.com\"}"
      }
    }
  ]
}

На PHP:

$response = $llm->generate($prompt, ['tools' => $tools]);

if (isset($response['tool_calls'])) {
    $args = json_decode($response['tool_calls'][0]['function']['arguments'], true);
    // $args['name'], $args['email']
}

Паттерн 5: Post-processing с LLM

Если модель сгенерировала "грязный" JSON, используйте вторую (более дешевую) модель для очистки:

$dirtyResponse = $llm->generate($extractionPrompt);

$cleanupPrompt = "Исправь этот JSON, чтобы он был валидным. Верни ТОЛЬКО исправленный JSON:\n" . $dirtyResponse;
$cleanJson = $cheapLlm->generate($cleanupPrompt);

$data = json_decode($cleanJson, true);

Практические рекомендации

Для продакшена с критичными данными:

  • Облако:
    • OpenAI GPT-4.1 или GPT-5 mini — Structured Outputs со строгим соблюдением переданной JSON-схемы.
    • Anthropic Claude Sonnet 4 или Opus 4 — JSON через tool use, гарантированно валидный и идеально подходящий для сложных многошаговых сценариев.
    • Google Gemini 2.5 Pro или Flash — нативный JSON Mode + Controlled Generation с явным указанием схемы.
  • Локально:
    • vLLM с guided decoding + сильная модель: Qwen 3 32B, DeepSeek V3.1 (развёрнутая через vLLM), Mistral Small 3 24B. Это даёт 100% валидный JSON на собственной инфраструктуре без компромиссов по приватности.

Для локального запуска с Ollama:

  • Используйте встроенную поддержку JSON Schema: передайте желаемую структуру через параметр format (с версии Ollama 0.5.0+). Модель будет сгенерирована с грамматикой, гарантирующей точное соответствие схеме.
  • Рекомендуемые модели: Qwen 3 8B (универсальная), Mistral Small 3 24B (с упором на код и логику), Llama 4 Scout (если хватает памяти). Для простых задач отлично работают Phi-4-mini или Gemma 3 4B.
  • Паттерны с XML-тегами и повторными попытками (retry) больше не обязательны — грамматика исключает невалидный вывод на корню.

Для маленьких моделей (< 7B):

  • Принудительная JSON-грамматика гарантирует валидность даже на скромных моделях, однако смысловое наполнение может уступать старшим собратьям.
  • Чтобы повысить точность, обязательно добавляйте few-shot примеры в промпт — это помогает модели лучше понять, какие данные ожидаются в полях.
  • Для критичных приложений придерживайтесь простых схем (один–два уровня вложенности) и всегда проверяйте смысловую корректность ответа.

4. Специальные токены (Chat Templates)

У разных моделей есть свои особенности разметки диалога:

  • Mistral: [INST] Инструкция [/INST] Ответ
  • Llama 3: <|start_header_id|>user<|end_header_id|> Сообщение <|eot_id|>
  • ChatML (OpenAI): <|im_start|>Предоставьте контекст и/или инструкции для модели.<|im_end|>

6. Почему «сделай мне хорошо» не работает: Сила детализации

А теперь главный практический вывод. Почему запрос «сделай мне хорошо» не работает?

Потому что LLM не может прочитать ваши мысли. Если вы не описали требование в промпте, его для модели не существует. Модель работает по принципу близости токенов — она сильнее всего связывает слова, которые стоят рядом в вашем запросе. Чем детальнее запрос, тем точнее результат.

Давайте посмотрим на конкретный кейс с PHP.

Плохой запрос: «Напиши скрипт на PHP для сохранения пользователя». Что вы получите? Скорее всего, устаревший код с mysql_query (который давно deprecated) или спагетти-код без валидации, без обработки ошибок, без типизации. Модель сделала то, что вы попросили — написала скрипт. Но она не знает, что вам нужен production-ready код.

Хороший запрос: «Напиши класс на PHP 8.5 для сохранения пользователя. Используй Clean Architecture, строгую типизацию (declare(strict_types=1)), паттерн Repository, PDO для работы с базой данных и кастомные исключения. Добавь PHPDoc для всех методов». Что вы получите? Готовый к использованию код, который соответствует современным стандартам, с правильной архитектурой, типизацией и документацией.

Разница колоссальная. И эта разница — в детализации запроса.

Еще один важный инструмент — System Prompt. Это инструкция, которая действует на протяжении всего диалога. Например: «Ты опытный PHP-разработчик с 10-летним стажем. Ты всегда проверяешь входные данные. Ты используешь PSR-12. Ты пишешь PHPDoc для всех публичных методов». Этот промпт задает контекст и роль модели для всего разговора.

Паттерны промпт-инжиниринга

Паттерн 1: Chain of Thought (CoT) — "Думай шаг за шагом"

Модели гораздо лучше решают сложные задачи, если явно попросить их рассуждать вслух. Это особенно важно для рефакторинга, анализа кода, отладки.

Плохой промпт:

Найди баг в этом PHP-коде и исправь его.

Модель может пропустить тонкую ошибку или предложить неверное решение.

Хороший промпт с CoT:

Проанализируй этот PHP-код шаг за шагом:

1. Сначала опиши, что делает каждая функция
2. Затем найди потенциальные баги (учти race conditions, SQL injection, 
   проблемы с типами)
3. Для каждого бага объясни, почему он опасен
4. Предложи исправление с примером кода

<code>
<?php
function getUserById($id) {
    global $db;
    $result = $db->query("SELECT * FROM users WHERE id = $id");
    return $result->fetch();
}
</code>

Почему это работает: Модель вынуждена "пройтись" по коду логически, а не угадывать ответ. Качество исправлений вырастает на 30-50% по бенчмаркам.

Паттерн 2: Few-shot — примеры в промпте

Модель учится "на лету" из примеров, которые вы даете в промпте. Это критически важно для задач классификации, извлечения данных, форматирования.

Пример для извлечения сущностей из логов:

Извлеки из текста лога уровень, сообщение и контекст.

Пример 1:
Текст: "[ERROR] Connection failed: timeout after 30s (db=primary)"
Ответ: {"level": "ERROR", "message": "Connection failed: timeout after 30s", "context": {"db": "primary"}}

Пример 2:
Текст: "[INFO] User logged in successfully (user_id=123, ip=192.168.1.1)"
Ответ: {"level": "INFO", "message": "User logged in successfully", "context": {"user_id": "123", "ip": "192.168.1.1"}}

Текст для обработки:
"[WARNING] Disk space low: 5% remaining (server=web-01, path=/var/log)"

Почему это работает: Модель видит паттерн и воспроизводит его. Без примеров она может вернуть JSON в другом формате, с другими ключами или вообще текстом.

На PHP:

$examples = [
    ['input' => '[ERROR] ...', 'output' => ['level' => 'ERROR', ...]],
    ['input' => '[INFO] ...', 'output' => ['level' => 'INFO', ...]],
];

$prompt = buildFewShotPrompt($examples, $newLogEntry);
$response = $llm->generate($prompt, ['response_format' => ['type' => 'json_object']]);

Паттерн 3: Decomposition — разбиение сложной задачи

Если задача слишком сложная для одного промпта, разбейте её на подзадачи. Это особенно полезно для генерации сложной архитектуры.

Плохой промпт:

Создай систему аутентификации на PHP с JWT, refresh tokens, 
rate limiting и двухфакторной аутентификацией.

Модель выдаст поверхностный код, не покрывающий все аспекты.

Хороший промпт с декомпозицией:

Мы строим систему аутентификации. Реализуй ТОЛЬКО первый компонент:

Задача: Создать класс JwtTokenService на PHP 8.5

Требования:
- Использование HMAC SHA256 для подписи
- Поддержка access и refresh токенов с разными TTL
- Методы: generateAccessToken(), generateRefreshToken(), validateToken()
- Обработка истекших токенов через кастомное исключение TokenExpiredException
- Строгая типизация, PHPDoc для всех методов

Не пиши остальные компоненты (контроллеры, middleware) — только этот сервис.

Затем в следующем запросе:

Теперь создай AuthMiddleware, который использует JwtTokenService...

Почему это работает: Модель фокусируется на одной задаче и выдает production-ready код. Каждый компонент можно протестировать отдельно.

Паттерн 4: Generated Knowledge — модель генерирует контекст

Попросите модель сначала сгенерировать релевантные знания, а потом использовать их для ответа.

Пример:

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

Шаг 2: Используя эти практики, проверь этот код и предложи улучшения:
<code>...</code>

Почему это работает: Модель "вспоминает" релевантные знания перед анализом, что повышает качество рекомендаций.

Паттерн 5: ReAct (Reason + Act) — мостик к агентам

Это основа работы агентов. Модель чередует рассуждения и действия.

Пример промпта для агента:

Ты PHP-разработчик с доступом к инструментам:
- read_file(path) — читает файл
- run_tests() — запускает PHPUnit
- search_codebase(query) — ищет по коду

Задача: Исправь падающий тест UserServiceTest::testCreateUser

Думай вслух:
1. Какие файлы нужно прочитать?
2. Какой инструмент вызвать?
3. Что показал результат?
4. Что делать дальше?

Формат ответа:
Thought: [твои рассуждения]
Action: [инструмент(аргументы)]

Почему это работает: Модель получает возможность "исследовать" кодовую базу, а не гадать.

Антипаттерны промпт-инжиниринга (чего НЕ делать)

Антипаттерн 1: Негативные инструкции

Плохо:

Не используй устаревшие функции.
Не забывай про обработку ошибок.

Хорошо:

Используй только функции PHP 8.5+.
Для каждой операции с БД добавляй try-catch с логированием.

Почему: Модель плохо понимает отрицания. Она может сфокусироваться на "устаревших функциях" и начать их использовать. Позитивные инструкции работают надежнее.

Антипаттерн 2: Перегрузка промпта

Плохо:

Ты эксперт. Используй PSR-12. Пиши PHPDoc. Обрабатывай ошибки. 
Используй Clean Architecture. Добавь тесты. Оптимизируй производительность. 
Следуй SOLID. Используй dependency injection. Пиши комментарии. 
Проверяй входные данные. Логируй все действия. Используй кэширование.
... 
(20+ требований в одном промпте)

Хорошо:

Главные приоритеты (в порядке важности):
1. Строгая типизация PHP 8.5
2. Обработка ошибок через try-catch
3. PHPDoc для публичных методов

Остальное — по возможности.

Почему: Модель теряет фокус при слишком длинных инструкциях. Приоритизация помогает ей понять, что критично, а что — опционально.

Антипаттерн 3: Отсутствие примеров

Плохо:

Верни результат в формате JSON.

Хорошо:

Верни результат в формате JSON. Пример:
{
  "status": "success",
  "data": {
    "user_id": 123,
    "action": "created"
  }
}

Почему: Без примера модель может интерпретировать "формат JSON" по-своему (другие ключи, другая структура, вложенность).

Антипаттерн 4: Противоречивые инструкции

Плохо:

Напиши максимально короткий код.
Добавь подробные комментарии к каждой строке.

Хорошо:

Напиши лаконичный код (без избыточных абстракций).
Добавь PHPDoc только для публичных методов.

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

Антипаттерн 5: "Ты эксперт" без конкретики

Плохо:

Ты эксперт по PHP.

Хорошо:

Ты senior PHP-разработчик с 10-летним опытом в:
- Laravel и Symfony
- Clean Architecture и DDD
- Оптимизации производительности
- Безопасности веб-приложений

Ты следуешь принципам:
- PSR-12 для стиля кода
- SOLID для архитектуры
- TDD для тестирования

Почему: "Эксперт" — это размытое понятие. Конкретные навыки и принципы дают модели четкий контекст.

Антипаттерн 6: Игнорирование формата вывода

Плохо:

Проанализируй этот код и скажи, есть ли баги.

Модель вернет текст на 500 слов, который сложно распарсить.

Хорошо:

Проанализируй этот код. Верни результат СТРОГО в формате:
{
  "has_bugs": true/false,
  "bugs": [
    {
      "line": номер_строки,
      "severity": "critical|warning|info",
      "description": "описание",
      "fix": "предложение по исправлению"
    }
  ]
}

Почему: Без четкого формата вывод придется парсить вручную или писать сложный regex.

Чек-лист хорошего промпта

Перед отправкой запроса проверьте:

  1. Роль и контекст
    • Указана роль модели (кто она, какой опыт)
    • Описан контекст задачи (зачем мы это делаем)
  2. Четкая задача
    • Сформулирована одна конкретная задача (не "сделай всё")
    • Использованы позитивные инструкции ("делай X", а не "не делай Y")
  3. Требования
    • Приоритизированы (что критично, что опционально)
    • Конкретны (PHP 8.5, а не "современный PHP")
  4. Формат вывода
    • Указан точный формат (JSON, XML, Markdown)
    • Дан пример ожидаемого ответа
  5. Ограничения
    • Указаны лимиты (длина ответа, используемые библиотеки)
    • Указано, что делать, если задача невыполнима ("скажи 'не знаю'")
  6. Контекстные данные
    • Данные отделены от инструкций (XML-теги)
    • Нет противоречий между инструкциями и данными

Практический пример: от плохого к идеальному промпту

Задача: Нужно написать PHP-класс для работы с кэшем.

Уровень 1 — Плохо:

Напиши класс для кэша на PHP.

Результат: Простой класс с file_put_contents, без интерфейсов, без обработки ошибок.

Уровень 2 — Лучше:

Напиши класс Cache на PHP 8.5 для работы с файловым кэшем.
Используй строгую типизацию. Добавь методы get, set, delete.

Результат: Базовый класс с типизацией, но без интерфейсов, без TTL, без сериализации.

Уровень 3 — Хорошо:

Напиши систему кэширования на PHP 8.5:

1. Интерфейс CacheInterface с методами:
   - get(string $key, mixed $default = null): mixed
   - set(string $key, mixed $value, int $ttl = 3600): bool
   - delete(string $key): bool
   - has(string $key): bool

2. Реализация FileCache:
   - Хранение в директории /tmp/cache
   - Сериализация через serialize/unserialize
   - Автоматическая очистка истекших ключей при get()
   - Обработка ошибок через CacheException

3. Требования:
   - declare(strict_types=1)
   - PHPDoc для всех методов
   - PSR-12
   - Без внешних зависимостей

Результат: Production-ready код с интерфейсом, реализацией, обработкой ошибок, документацией.

Уровень 4 — Идеально (с CoT и примерами):

Ты senior PHP-разработчик, специализирующийся на инфраструктурном коде.

Задача: Создать систему кэширования на PHP 8.5.

Шаг 1: Опиши, какие проблемы решает кэш (контекст)
Шаг 2: Спроектируй интерфейс CacheInterface
Шаг 3: Реализуй FileCache с учетом:
  - Race conditions (два процесса пишут одновременно)
  - Сериализации сложных объектов
  - Атомарности операций
  - Очистки истекших ключей

Требования:
- declare(strict_types=1)
- PHPDoc для всех методов
- PSR-12
- Обработка ошибок через кастомные исключения

Пример использования:
```php
$cache = new FileCache('/tmp/cache');
$cache->set('user:123', ['name' => 'Иван'], 3600);
$user = $cache->get('user:123'); // ['name' => 'Иван']
``

Верни результат в виде двух блоков кода: интерфейс и реализация.

Результат: Архитектурно грамотный код с учетом edge cases, готовый к продакшену.

Для менеджеров: как формулировать требования для LLM-задач

Если вы ставите задачу разработчику, который будет использовать LLM, включите в ТЗ:

  1. Входные данные: Что именно будет подаваться на вход модели? (текст, JSON, код, логи)
  2. Ожидаемый выход: В каком формате должен быть результат? (JSON с конкретной схемой, Markdown, PHP-код)
  3. Критерии качества: Что значит "хороший результат"? (валидный JSON, код без багов, ответ до 100 слов)
  4. Edge cases: Что делать, если задача невыполнима? (вернуть ошибку, сказать "не знаю", использовать fallback)
  5. Примеры: Дайте 2-3 примера "вход → выход".

Это сэкономит десятки итераций промптинга и ускорит разработку в разы.


7. Эволюция: Почему простых промптов иногда недостаточно (Агенты и Инструменты)

Но даже самые детальные промпты имеют ограничение. Модель видит только то, что вы написали в запросе. Она не видит ваш код, вашу базу данных, ваши файлы.

И здесь на сцену выходят агенты.

В чем разница между простой LLM и агентом? Простая LLM — это мозг в банке. Она знает только свои веса и то, что вы написали в промпте. Она не видит ваш код, если вы его не скопировали (а скопировать весь проект невозможно — не влезет в контекст).

Агент — это LLM плюс инструменты. Это мозг с руками. Агент может принять решение вызвать функцию: прочитать файл, сделать запрос к базе данных, выполнить bash-команду. Он получает реальный результат и на его основе дает точный ответ.

Как это работает? Модель работает по циклу: видит задачу, понимает, что ей не хватает данных, и сама запрашивает инструмент. Например: «Мне нужно прочитать src/Config.php, чтобы дать совет». Она возвращает структурированный запрос: «Вызови функцию read_file с аргументом src/Config.php». Ваш PHP-код перехватывает этот запрос, выполняет реальное чтение файла, возвращает результат обратно в модель. И модель генерирует ответ на основе реального кода.

Эффект для разработчиков: Качество результата вырастает на порядок. Вместо абстрактных советов по PHP вы получаете анализ вашего конкретного кода, потому что агент реально прочитал локальный файл через предоставленный ему инструмент.


8. Заключение

Подведем итоги.

LLM — это не магия, а управляемый вероятностный движок. Успех работы с ним зависит от трех факторов:

  1. Выбор модели: правильный размер и квантование под вашу задачу и ресурсы.
  2. Среда запуска: облако для скорости и мощности, локально для приватности и контроля.
  3. Структурированный промпт: использование XML-тегов, JSON Mode, детализация требований.

Чем лучше вы понимаете, как работает модель, тем предсказуемее результат. И чем детальнее вы описываете задачу, тем точнее модель её решает.