Перейти к основному содержимому

Outlines

Outlines: структурированная генерация JSON/regex/Pydantic для LLM.

Метаданные навыка​

ИсточникОпционально — установка с помощью vibeos skills install official/mlops/outlines
Путьoptional-skills/mlops/inference/outlines
Версия1.0.0
АвторOrchestra Research
ЛицензияMIT
Зависимостиoutlines, transformers, vllm, pydantic
Платформыlinux, macos, windows
ТегиPrompt Engineering, Outlines, Structured Generation, JSON Schema, Pydantic, Local Models, Grammar-Based Generation, vLLM, Transformers, Type Safety

Справочник: полный SKILL.md​

к сведению

Ниже приведено полное определение навыка, которое VibeOS загружает при его активации. Это те инструкции, которые видит агент, когда навык активен.

Outlines: структурированная генерация текста

Когда использовать этот навык​

Используйте Outlines, когда вам нужно:

  • Гарантировать корректную структуру JSON/XML/кода во время генерации
  • Использовать модели Pydantic для типобезопасного вывода
  • Поддерживать локальные модели (Transformers, llama.cpp, vLLM)
  • Максимизировать скорость инференса с помощью структурированной генерации с нулевыми накладными расходами
  • Автоматически генерировать данные по JSON-схемам
  • Контролировать семплирование токенов на уровне грамматики

Звёзды на GitHub: 8000+ | От: dottxt.ai (ранее .txt)

Установка​

# Базовая установка
pip install outlines

# С конкретными бэкендами
pip install outlines transformers # Модели Hugging Face
pip install outlines llama-cpp-python # llama.cpp
pip install outlines vllm # vLLM для высокой пропускной способности

Быстрый старт​

Базовый пример: классификация​

import outlines
from typing import Literal

# Загрузка модели
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")

# Генерация с ограничением типа
prompt = "Тональность отзыва 'Этот продукт потрясающий!': "
generator = outlines.generate.choice(model, ["positive", "negative", "neutral"])
sentiment = generator(prompt)

print(sentiment) # "positive" (гарантированно одно из этих значений)

С моделями Pydantic​

from pydantic import BaseModel
import outlines

class User(BaseModel):
name: str
age: int
email: str

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")

# Генерация структурированного вывода
prompt = "Извлеки пользователя: Иван Иванов, 30 лет, ivan@example.com"
generator = outlines.generate.json(model, User)
user = generator(prompt)

print(user.name) # "Иван Иванов"
print(user.age) # 30
print(user.email) # "ivan@example.com"

Основные концепции​

1. Ограниченный семплинг токенов​

Outlines использует конечные автоматы (FSM) для ограничения генерации токенов на уровне логитов.

Как это работает:

  1. Преобразование схемы (JSON/Pydantic/regex) в контекстно-свободную грамматику (CFG)
  2. Преобразование CFG в конечный автомат (FSM)
  3. Фильтрация недопустимых токенов на каждом шаге генерации
  4. Ускорение (fast-forward) при наличии только одного допустимого токена

Преимущества:

  • Нулевые накладные расходы: фильтрация происходит на уровне токенов
  • Увеличение скорости: ускорение на детерминированных путях
  • Гарантированная корректность: недопустимые выводы невозможны
import outlines

# Модель Pydantic -> JSON-схема -> CFG -> FSM
class Person(BaseModel):
name: str
age: int

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")

# За кулисами:
# 1. Person -> JSON-схема
# 2. JSON-схема -> CFG
# 3. CFG -> FSM
# 4. FSM фильтрует токены во время генерации

generator = outlines.generate.json(model, Person)
result = generator("Сгенерируй человека: Алиса, 25")

2. Структурированные генераторы​

Outlines предоставляет специализированные генераторы для разных типов вывода.

Генератор выбора (Choice)​

# Выбор из нескольких вариантов
generator = outlines.generate.choice(
model,
["positive", "negative", "neutral"]
)

sentiment = generator("Отзыв: Это отлично!")
# Результат: Один из трёх вариантов

JSON-генератор​

from pydantic import BaseModel

class Product(BaseModel):
name: str
price: float
in_stock: bool

# Генерация корректного JSON, соответствующего схеме
generator = outlines.generate.json(model, Product)
product = generator("Извлеки: iPhone 15, $999, в наличии")

# Гарантированно корректный экземпляр Product
print(type(product)) # <class '__main__.Product'>

Regex-генератор​

# Генерация текста, соответствующего регулярному выражению
generator = outlines.generate.regex(
model,
r"[0-9]{3}-[0-9]{3}-[0-9]{4}" # Шаблон номера телефона
)

phone = generator("Сгенерируй номер телефона:")
# Результат: "555-123-4567" (гарантированно соответствует шаблону)

Генераторы целых/вещественных чисел​

# Генерация определённых числовых типов
int_generator = outlines.generate.integer(model)
age = int_generator("Возраст человека:") # Гарантированно целое число

float_generator = outlines.generate.float(model)
price = float_generator("Цена продукта:") # Гарантированно вещественное число

3. Бэкенды моделей​

Outlines поддерживает несколько локальных и API-бэкендов.

Transformers (Hugging Face)​

import outlines

# Загрузка из Hugging Face
model = outlines.models.transformers(
"microsoft/Phi-3-mini-4k-instruct",
device="cuda" # Или "cpu"
)

# Использование с любым генератором
generator = outlines.generate.json(model, YourModel)

llama.cpp​

# Загрузка GGUF-модели
model = outlines.models.llamacpp(
"./models/llama-3.1-8b-instruct.Q4_K_M.gguf",
n_gpu_layers=35
)

generator = outlines.generate.json(model, YourModel)

vLLM (Высокая пропускная способность)​

# Для продакшн-развёртываний
model = outlines.models.vllm(
"meta-llama/Llama-3.1-8B-Instruct",
tensor_parallel_size=2 # Несколько GPU
)

generator = outlines.generate.json(model, YourModel)

OpenAI (Ограниченная поддержка)​

# Базовая поддержка OpenAI
model = outlines.models.openai(
"gpt-4o-mini",
api_key="ваш-api-ключ"
)

# Примечание: некоторые функции ограничены для API-моделей
generator = outlines.generate.json(model, YourModel)

4. Интеграция с Pydantic​

Outlines имеет первоклассную поддержку Pydantic с автоматическим преобразованием схем.

Базовые модели​

from pydantic import BaseModel, Field

class Article(BaseModel):
title: str = Field(description="Заголовок статьи")
author: str = Field(description="Имя автора")
word_count: int = Field(description="Количество слов", gt=0)
tags: list[str] = Field(description="Список тегов")

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, Article)

article = generator("Сгенерируй статью об ИИ")
print(article.title)
print(article.word_count) # Гарантированно > 0

Вложенные модели​

class Address(BaseModel):
street: str
city: str
country: str

class Person(BaseModel):
name: str
age: int
address: Address # Вложенная модель

generator = outlines.generate.json(model, Person)
person = generator("Сгенерируй человека в Нью-Йорке")

print(person.address.city) # "New York"

Перечисления и литералы​

from enum import Enum
from typing import Literal

class Status(str, Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"

class Application(BaseModel):
applicant: str
status: Status # Должно быть одним из значений перечисления
priority: Literal["low", "medium", "high"] # Должно быть одним из литералов

generator = outlines.generate.json(model, Application)
app = generator("Сгенерируй заявку")

print(app.status) # Status.PENDING (или APPROVED/REJECTED)

Типовые шаблоны​

Шаблон 1: Извлечение данных​

from pydantic import BaseModel
import outlines

class CompanyInfo(BaseModel):
name: str
founded_year: int
industry: str
employees: int

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, CompanyInfo)

text = """
Apple Inc. была основана в 1976 году в сфере технологий.
Компания нанимает примерно 164 000 человек по всему миру.
"""

prompt = f"Извлеки информацию о компании:\n{text}\n\nКомпания:"
company = generator(prompt)

print(f"Название: {company.name}")
print(f"Основана: {company.founded_year}")
print(f"Отрасль: {company.industry}")
print(f"Сотрудников: {company.employees}")

Шаблон 2: Классификация​

from typing import Literal
import outlines

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")

# Бинарная классификация
generator = outlines.generate.choice(model, ["spam", "not_spam"])
result = generator("Письмо: Купи сейчас! Скидка 50%!")

# Многоклассовая классификация
categories = ["technology", "business", "sports", "entertainment"]
category_gen = outlines.generate.choice(model, categories)
category = category_gen("Статья: Apple анонсирует новый iPhone...")

# С уверенностью
class Classification(BaseModel):
label: Literal["positive", "negative", "neutral"]
confidence: float

classifier = outlines.generate.json(model, Classification)
result = classifier("Отзыв: Этот продукт нормальный, ничего особенного")

Шаблон 3: Структурированные формы​

class UserProfile(BaseModel):
full_name: str
age: int
email: str
phone: str
country: str
interests: list[str]

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, UserProfile)

prompt = """
Извлеки профиль пользователя из:
Имя: Алиса Джонсон
Возраст: 28
Email: alice@example.com
Телефон: 555-0123
Страна: США
Интересы: пеший туризм, фотография, кулинария
"""

profile = generator(prompt)
print(profile.full_name)
print(profile.interests) # ["hiking", "photography", "cooking"]

Шаблон 4: Извлечение нескольких сущностей​

class Entity(BaseModel):
name: str
type: Literal["PERSON", "ORGANIZATION", "LOCATION"]

class DocumentEntities(BaseModel):
entities: list[Entity]

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, DocumentEntities)

text = "Тим Кук встретился с Сатьей Наделлой в штаб-квартире Microsoft в Редмонде."
prompt = f"Извлеки сущности из: {text}"

result = generator(prompt)
for entity in result.entities:
print(f"{entity.name} ({entity.type})")

Шаблон 5: Генерация кода​

class PythonFunction(BaseModel):
function_name: str
parameters: list[str]
docstring: str
body: str

model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, PythonFunction)

prompt = "Сгенерируй функцию Python для вычисления факториала"
func = generator(prompt)

print(f"def {func.function_name}({', '.join(func.parameters)}):")
print(f' """{func.docstring}"""')
print(f" {func.body}")

Шаблон 6: Пакетная обработка​

def batch_extract(texts: list[str], schema: type[BaseModel]):
"""Извлечение структурированных данных из нескольких текстов."""
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, schema)

results = []
for text in texts:
result = generator(f"Извлеки из: {text}")
results.append(result)

return results

class Person(BaseModel):
name: str
age: int

texts = [
"Ивану 30 лет",
"Алисе 25 лет",
"Бобу 40 лет"
]

people = batch_extract(texts, Person)
for person in people:
print(f"{person.name}: {person.age}")

Конфигурация бэкенда​

Transformers​

import outlines

# Базовое использование
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")

# Конфигурация GPU
model = outlines.models.transformers(
"microsoft/Phi-3-mini-4k-instruct",
device="cuda",
model_kwargs={"torch_dtype": "float16"}
)

# Популярные модели
model = outlines.models.transformers("meta-llama/Llama-3.1-8B-Instruct")
model = outlines.models.transformers("mistralai/Mistral-7B-Instruct-v0.3")
model = outlines.models.transformers("Qwen/Qwen2.5-7B-Instruct")

llama.cpp​

# Загрузка GGUF-модели
model = outlines.models.llamacpp(
"./models/llama-3.1-8b.Q4_K_M.gguf",
n_ctx=4096, # Окно контекста
n_gpu_layers=35, # Слои на GPU
n_threads=8 # Потоки CPU
)

# Полная выгрузка на GPU
model = outlines.models.llamacpp(
"./models/model.gguf",
n_gpu_layers=-1 # Все слои на GPU
)

vLLM (Продакшн)​

# Один GPU
model = outlines.models.vllm("meta-llama/Llama-3.1-8B-Instruct")

# Несколько GPU
model = outlines.models.vllm(
"meta-llama/Llama-3.1-70B-Instruct",
tensor_parallel_size=4 # 4 GPU
)

# С квантизацией
model = outlines.models.vllm(
"meta-llama/Llama-3.1-8B-Instruct",
quantization="awq" # Или "gptq"
)

Лучшие практики​

1. Используйте конкретные типы​

# ✅ Хорошо: Конкретные типы
class Product(BaseModel):
name: str
price: float # Не str
quantity: int # Не str
in_stock: bool # Не str

# ❌ Плохо: Всё как строка
class Product(BaseModel):
name: str
price: str # Должно быть float
quantity: str # Должно быть int

2. Добавляйте ограничения​

from pydantic import Field

# ✅ Хорошо: С ограничениями
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=120)
email: str = Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")

# ❌ Плохо: Без ограничений
class User(BaseModel):
name: str
age: int
email: str

3. Используйте перечисления для категорий​

# ✅ Хорошо: Перечисление для фиксированного набора
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"

class Task(BaseModel):
title: str
priority: Priority

# ❌ Плохо: Свободная строка
class Task(BaseModel):
title: str
priority: str # Может быть чем угодно

4. Предоставляйте контекст в промптах​

# ✅ Хорошо: Чёткий контекст
prompt = """
Извлеки информацию о продукте из следующего текста.
Текст: iPhone 15 Pro стоит $999 и сейчас в наличии.
Продукт:
"""

# ❌ Плохо: Минимальный контекст
prompt = "iPhone 15 Pro стоит $999 и сейчас в наличии."

5. Обрабатывайте опциональные поля​

from typing import Optional

# ✅ Хорошо: Опциональные поля для неполных данных
class Article(BaseModel):
title: str # Обязательно
author: Optional[str] = None # Опционально
date: Optional[str] = None # Опционально
tags: list[str] = [] # Пустой список по умолчанию

# Может успешно выполниться, даже если автор/дата отсутствуют

Сравнение с альтернативами​

ФункцияOutlinesInstructorGuidanceLMQL
Поддержка Pydantic✅ Нативная✅ Нативная❌ Нет❌ Нет
JSON-схема✅ Да✅ Да⚠️ Ограниченная✅ Да
Regex-ограничения✅ Да❌ Нет✅ Да✅ Да
Локальные модели✅ Полная⚠️ Ограниченная✅ Полная✅ Полная
API-модели⚠️ Ограниченная✅ Полная✅ Полная✅ Полная
Нулевые накладные расходы✅ Да❌ Нет⚠️ Частично✅ Да
Автоматические повторные попытки❌ Нет✅ Да❌ Нет❌ Нет
Кривая обученияНизкаяНизкаяНизкаяВысокая

Когда выбирать Outlines:

  • Использование локальных моделей (Transformers, llama.cpp, vLLM)
  • Необходима максимальная скорость инференса
  • Нужна поддержка моделей Pydantic
  • Требуется структурированная генерация с нулевыми накладными расходами
  • Контроль процесса семплирования токенов

Когда выбирать альтернативы:

  • Instructor: Нужны API-модели с автоматическими повторными попытками
  • Guidance: Нужно «исцеление» токенов и сложные рабочие процессы
  • LMQL: Предпочтение декларативному синтаксису запросов

Характеристики производительности​

Скорость:

  • Нулевые накладные расходы: структурированная генерация так же быстра, как и неограниченная
  • Оптимизация fast-forward: пропускает детерминированные токены
  • В 1.2-2 раза быстрее подходов с валидацией после генерации

Память:

  • FSM компилируется один раз на схему (кэшируется)
  • Минимальные накладные расходы во время выполнения
  • Эффективен с vLLM для высокой пропускной способности

Точность:

  • 100% корректных выводов (гарантируется FSM)
  • Циклы повторных попыток не нужны
  • Детерминированная фильтрация токенов

Ресурсы​

См. также​

  • references/json_generation.md — Комплексные шаблоны JSON и Pydantic
  • references/backends.md — Конфигурация, специфичная для бэкенда
  • references/examples.md — Примеры, готовые к продакшну