TGViewer
Maxim.ML - канал Maxim.ML - канал @ml_maxim · 1.05K subscribers
Post #59 496
Как заставить LLM открыть бутылку пива

Всех с пятницей, у кого какие планы? Может, в бар? А LLM с собой возьмете? Пусть тогда откроет бутылку пива за вас. 🍺

Работая с языковыми моделями, часто требуется не просто получить текстовый ответ, а структурированные данные — например, в формате JSON. Вот самый эффективный способ добиться нужного формата от LLM.

Что мы имеем
С такими данными будем работать - попробуем открыть бутылку пива.

input_data = [
{"номер": 1, "название": "пиво", "характеристика": "светлое", "статус": "закрыто"},
{"номер": 2, "название": "пиво", "характеристика": "светлое", "статус": "закрыто"},
{"номер": 3, "название": "пиво", "характеристика": "светлое", "статус": "закрыто"},
{"номер": 4, "название": "пиво", "характеристика": "светлое", "статус": "закрыто"}
]


Как будем ограничивать LLM: Pydantic + Structured Outputs
Некоторые модели (например в ollama) поддерживают структурированные выходные данные через передачу схемы Pydantic (или JSON Schema). Модель гарантирует, что ответ будет строго соответствовать этой схеме — это самый надёжный способ получить валидный JSON нужной структуры.

Почему это работает
Ограничения на генерацию LLM, такие как JSON Schema или Pydantic, работают как "фильтр" или "направляющая" для модели. Вместо того чтобы выбирать любой следующий токен, LLM вынуждена выбирать только те токены, которые соответствуют заранее определённой структуре (например, число, кавычка, конкретное слово из списка). Этот процесс гарантирует, что итоговый текст будет строго соответствовать заданному формату (например, валидному JSON), исключая ошибки структуры.

Как это применить
from pydantic import BaseModel
from typing import Literal
from ollama import chat

class BeerBottle(BaseModel):
номер: int
название: str
характеристика: str
статус: Literal["открыто", "закрыто"]

class BeerList(BaseModel):
bottles: list[BeerBottle]

prompt = (
"Вот список бутылок пива:\n"
f"{input_data}\n"
"Открой только две бутылки: вторую и четвертую. "
"Первая и третья бутылка должны быть закрыты. "
"Верни результат как список объектов BeerBottle, "
)

response = chat(
model="gemma3:12b",
messages=[{'role': 'user', 'content': prompt}],
format=BeerList.model_json_schema()
)

result = BeerList.model_validate_json(response.message.content)
print(result)


Альтернативные подходы
🟢Можно использовать чистый JSON Schema, минуя Pydantic.
🟢Существуют специальные библиотеки: Outlines, Guidance, JSONFormer — они тоже ограничивают генерацию по схеме.
🟢Можно попробовать добиться нужного формата только промптом, но это менее надёжно.

Важно понимать: большинство "жестких" методов (Pydantic, JSON Schema, грамматики в Guidance/Outlines) основаны на одном и том же принципе — ограничении выбора токенов на этапе генерации.

Так что в следующий раз, когда вам понадобится точный и структурированный ответ от вашей локальной LLM, вспомните про "открытие пивных бутылок" с помощью Pydantic — это действительно работает! Теперь можно и отдохнуть. 🍺
  • 🔥 7
  • ❤ 2
  • 👍 1
More from @ml_maxim
  1. Sep 23, 2026У меня было много образовательных активностей: преподавал школьникам, студентам и олимпиад…
  2. Sep 17, 2026Тут huawei выпустила отчёт intelligent world 2035, там целых 10 смелых прогнозов, советую…
  3. Sep 14, 2026Показательно получилось 🛌 Вчера таки написал на habr про то, как легко теперь копировать…
  4. Sep 11, 2026Сходил за сырниками, а пришлось анализировать данные 📈 В магазине играла знакомая песня.…
  5. Sep 8, 2026Выхожу из декретного творческого отпуска 🛌 и сразу рассказываю свои апдейты и новости, на…
  6. Apr 14, 2026Архитектуру построили. А ML - нет 🤷‍♂️ Завершился наш с Никитой модуль по AI-агентам в ВШ…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →