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) для ограничения генерации токенов на уровне логитов.
Как это работает:
- Преобразование схемы (JSON/Pydantic/regex) в контекстно-свободную грамматику (CFG)
- Преобразование CFG в конечный автомат (FSM)
- Фильтрация недопустимых токенов на каждом шаге генерации
- Ускорение (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] = [] # Пустой список по умолчанию
# Может успешно выполниться, даже если автор/дата отсутствуют
Сравнение с альтернативами
| Функция | Outlines | Instructor | Guidance | LMQL |
|---|---|---|---|---|
| Поддержка Pydantic | ✅ Нативная | ✅ Нативная | ❌ Нет | ❌ Нет |
| JSON-схема | ✅ Да | ✅ Да | ⚠️ Ограниченная | ✅ Да |
| Regex-ограничения | ✅ Да | ❌ Нет | ✅ Да | ✅ Да |
| Локальные модели | ✅ Полная | ⚠️ Ограниченная | ✅ Полная | ✅ Полная |
| API-модели | ⚠️ Ограниченная | ✅ Полная | ✅ Полная | ✅ Полная |
| Нулевые накладные расходы | ✅ Да | ❌ Нет | ⚠️ Частично | ✅ Да |
| Автоматические повторные попытки | ❌ Нет | ✅ Да | ❌ Нет | ❌ Нет |
| Кривая обучения | Низкая | Низкая | Низкая | Высокая |
Когда выбирать Outlines:
- Использование локальных моделей (Transformers, llama.cpp, vLLM)
- Необходима максимальная скорость инференса
- Нужна поддержка моделей Pydantic
- Требуется структурированная генерация с нулевыми накладными расходами
- Контроль процесса семплирования токенов
Когда выбирать альтернативы:
- Instructor: Нужны API-модели с автоматическими повторными попытками
- Guidance: Нужно «исцеление» токенов и сложные рабочие процессы
- LMQL: Предпочтение декларативному синтаксису запросов
Характеристики производительности
Скорость:
- Нулевые накладные расходы: структурированная генерация так же быстра, как и неограниченная
- Оптимизация fast-forward: пропускает детерминированные токены
- В 1.2-2 раза быстрее подходов с валидацией после генерации
Память:
- FSM компилируется один раз на схему (кэшируется)
- Минимальные накладные расходы во время выполнения
- Эффективен с vLLM для высокой пропускной способности
Точность:
- 100% корректных выводов (гарантируется FSM)
- Циклы повторных попыток не нужны
- Детерминированная фильтрация токенов
Ресурсы
- Документация: https://dottxt-ai.github.io/outlines/
- GitHub: https://github.com/outlines-dev/outlines (8k+ звёзд)
- Discord: https://discord.gg/R9DSu34mGd
- Блог: https://blog.dottxt.co
См. также
references/json_generation.md— Комплексные шаблоны JSON и Pydanticreferences/backends.md— Конфигурация, специфичная для бэкендаreferences/examples.md— Примеры, готовые к продакшну