Guidance
Управляйте выводом LLM через регулярные выражения и грамматики, гарантируйте корректную генерацию JSON/XML/кода, задавайте структурированные форматы и стройте многошаговые сценарии с Guidance — фреймворком ограниченной генерации от Microsoft Research
Метаданные навыка
| Источник | Опциональный — установка командой hermes skills install official/mlops/guidance |
| Путь | optional-skills/mlops/guidance |
| Версия | 1.0.0 |
| Автор | Orchestra Research |
| Лицензия | MIT |
| Зависимости | guidance, transformers |
| Платформы | linux, macos, windows |
| Теги | Prompt Engineering, Guidance, Constrained Generation, Structured Output, JSON Validation, Grammar, Microsoft Research, Format Enforcement, Multi-Step Workflows |
Справочник: полный SKILL.md
Ниже приведено полное определение навыка, которое Hermes загружает при срабатывании навыка. Именно это агент видит как инструкции, когда навык активен.
Guidance: ограниченная генерация LLM
Когда использовать этот навык
Берите Guidance, когда нужно:
- Управлять синтаксисом вывода LLM через регулярные выражения или грамматики
- Гарантировать корректную генерацию JSON/XML/кода
- Сократить задержку по сравнению с обычными подходами к промптингу
- Задавать структурированные форматы (даты, e-mail, идентификаторы и т. п.)
- Строить многошаговые сценарии с управляющими конструкциями в духе Python
- Отсекать некорректный вывод через грамматические ограничения
Звёзд на GitHub: 18 000+ | От: Microsoft Research
Установка
# Base installation
pip install guidance
# With specific backends
pip install guidance[transformers] # Hugging Face models
pip install guidance[llama_cpp] # llama.cpp models
Быстрый старт
Простой пример: структурированная генерация
from guidance import models, gen
# Load model (supports OpenAI, Transformers, llama.cpp)
lm = models.OpenAI("gpt-4")
# Generate with constraints
result = lm + "The capital of France is " + gen("capital", max_tokens=5)
print(result["capital"]) # "Paris"
С Anthropic Claude
from guidance import models, gen, system, user, assistant
# Configure Claude
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# Use context managers for chat format
with system():
lm += "You are a helpful assistant."
with user():
lm += "What is the capital of France?"
with assistant():
lm += gen(max_tokens=20)
Основные понятия
1. Контекстные менеджеры
Guidance использует контекстные менеджеры в стиле Python для работы в формате чата.
from guidance import system, user, assistant, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# System message
with system():
lm += "You are a JSON generation expert."
# User message
with user():
lm += "Generate a person object with name and age."
# Assistant response
with assistant():
lm += gen("response", max_tokens=100)
print(lm["response"])
Плюсы:
- Естественный ход диалога
- Чёткое разделение ролей
- Легко читать и поддерживать
2. Ограниченная генерация
Guidance следит, чтобы вывод соответствовал заданным шаблонам — регулярным выражениям или грамматикам.
Ограничения через регулярные выражения
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# Constrain to valid email format
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# Constrain to date format (YYYY-MM-DD)
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}")
# Constrain to phone number
lm += "Phone: " + gen("phone", regex=r"\d{3}-\d{3}-\d{4}")
print(lm["email"]) # Guaranteed valid email
print(lm["date"]) # Guaranteed YYYY-MM-DD format
Как это работает:
- Регулярное выражение превращается в грамматику на уровне токенов
- Недопустимые токены отсекаются прямо во время генерации
- Модель способна выдать только подходящий вывод
Ограничения через выбор
from guidance import models, gen, select
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# Constrain to specific choices
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
# Multiple-choice selection
lm += "Best answer: " + select(
["A) Paris", "B) London", "C) Berlin", "D) Madrid"],
name="answer"
)
print(lm["sentiment"]) # One of: positive, negative, neutral
print(lm["answer"]) # One of: A, B, C, or D
3. Восстановление токенов (token healing)
Guidance автоматически «залечивает» границы токенов между промптом и генерацией.
Проблема: токенизация создаёт неестественные границы.
# Without token healing
prompt = "The capital of France is "
# Last token: " is "
# First generated token might be " Par" (with leading space)
# Result: "The capital of France is Paris" (double space!)
Решение: Guidance откатывается на один токен назад и генерирует заново.
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# Token healing enabled by default
lm += "The capital of France is " + gen("capital", max_tokens=5)
# Result: "The capital of France is Paris" (correct spacing)
Плюсы:
- Естественные границы текста
- Нет проблем с лишними пробелами
- Модель работает лучше: она видит естественные последовательности токенов
4. Генерация на основе грамматик
Сложные структуры описываются контекстно-свободными грамматиками.
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# JSON grammar (simplified)
json_grammar = """
{
"name": <gen name regex="[A-Za-z ]+" max_tokens=20>,
"age": <gen age regex="[0-9]+" max_tokens=3>,
"email": <gen email regex="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" max_tokens=50>
}
"""
# Generate valid JSON
lm += gen("person", grammar=json_grammar)
print(lm["person"]) # Guaranteed valid JSON structure
Где пригодится:
- Сложный структурированный вывод
- Вложенные структуры данных
- Синтаксис языков программирования
- Предметно-ориентированные языки
5. Функции Guidance
Декоратор @guidance позволяет оформлять шаблоны генерации как переиспользуемые функции.
from guidance import guidance, gen, models
@guidance
def generate_person(lm):
"""Generate a person with name and age."""
lm += "Name: " + gen("name", max_tokens=20, stop="\n")
lm += "\nAge: " + gen("age", regex=r"[0-9]+", max_tokens=3)
return lm
# Use the function
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = generate_person(lm)
print(lm["name"])
print(lm["age"])
Функции с состоянием:
@guidance(stateless=False)
def react_agent(lm, question, tools, max_rounds=5):
"""ReAct agent with tool use."""
lm += f"Question: {question}\n\n"
for i in range(max_rounds):
# Thought
lm += f"Thought {i+1}: " + gen("thought", stop="\n")
# Action
lm += "\nAction: " + select(list(tools.keys()), name="action")
# Execute tool
tool_result = tools[lm["action"]]()
lm += f"\nObservation: {tool_result}\n\n"
# Check if done
lm += "Done? " + select(["Yes", "No"], name="done")
if lm["done"] == "Yes":
break
# Final answer
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
return lm
Настройка бэкендов
Anthropic Claude
from guidance import models
lm = models.Anthropic(
model="claude-sonnet-4-5-20250929",
api_key="your-api-key" # Or set ANTHROPIC_API_KEY env var
)
OpenAI
lm = models.OpenAI(
model="gpt-4o-mini",
api_key="your-api-key" # Or set OPENAI_API_KEY env var
)
Локальные модели (Transformers)
from guidance.models import Transformers
lm = Transformers(
"microsoft/Phi-4-mini-instruct",
device="cuda" # Or "cpu"
)
Локальные модели (llama.cpp)
from guidance.models import LlamaCpp
lm = LlamaCpp(
model_path="/path/to/model.gguf",
n_ctx=4096,
n_gpu_layers=35
)
Типовые приёмы
Приём 1: генерация JSON
from guidance import models, gen, system, user, assistant
lm = models.Anthropic("claude-sonnet-4-5-20250929")
with system():
lm += "You generate valid JSON."
with user():
lm += "Generate a user profile with name, age, and email."
with assistant():
lm += """{
"name": """ + gen("name", regex=r'"[A-Za-z ]+"', max_tokens=30) + """,
"age": """ + gen("age", regex=r"[0-9]+", max_tokens=3) + """,
"email": """ + gen("email", regex=r'"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"', max_tokens=50) + """
}"""
print(lm) # Valid JSON guaranteed
Приём 2: классификация
from guidance import models, gen, select
lm = models.Anthropic("claude-sonnet-4-5-20250929")
text = "This product is amazing! I love it."
lm += f"Text: {text}\n"
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
lm += "\nConfidence: " + gen("confidence", regex=r"[0-9]+", max_tokens=3) + "%"
print(f"Sentiment: {lm['sentiment']}")
print(f"Confidence: {lm['confidence']}%")
Приём 3: многошаговое рассуждение
from guidance import models, gen, guidance
@guidance
def chain_of_thought(lm, question):
"""Generate answer with step-by-step reasoning."""
lm += f"Question: {question}\n\n"
# Generate multiple reasoning steps
for i in range(3):
lm += f"Step {i+1}: " + gen(f"step_{i+1}", stop="\n", max_tokens=100) + "\n"
# Final answer
lm += "\nTherefore, the answer is: " + gen("answer", max_tokens=50)
return lm
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = chain_of_thought(lm, "What is 15% of 200?")
print(lm["answer"])
Приём 4: агент ReAct
from guidance import models, gen, select, guidance
@guidance(stateless=False)
def react_agent(lm, question):
"""ReAct agent with tool use."""
tools = {
"calculator": lambda expr: eval(expr),
"search": lambda query: f"Search results for: {query}",
}
lm += f"Question: {question}\n\n"
for round in range(5):
# Thought
lm += f"Thought: " + gen("thought", stop="\n") + "\n"
# Action selection
lm += "Action: " + select(["calculator", "search", "answer"], name="action")
if lm["action"] == "answer":
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
break
# Action input
lm += "\nAction Input: " + gen("action_input", stop="\n") + "\n"
# Execute tool
if lm["action"] in tools:
result = tools[lm["action"]](lm["action_input"])
lm += f"Observation: {result}\n\n"
return lm
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = react_agent(lm, "What is 25 * 4 + 10?")
print(lm["answer"])
Приём 5: извлечение данных
from guidance import models, gen, guidance
@guidance
def extract_entities(lm, text):
"""Extract structured entities from text."""
lm += f"Text: {text}\n\n"
# Extract person
lm += "Person: " + gen("person", stop="\n", max_tokens=30) + "\n"
# Extract organization
lm += "Organization: " + gen("organization", stop="\n", max_tokens=30) + "\n"
# Extract date
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}", max_tokens=10) + "\n"
# Extract location
lm += "Location: " + gen("location", stop="\n", max_tokens=30) + "\n"
return lm
text = "Tim Cook announced at Apple Park on 2024-09-15 in Cupertino."
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = extract_entities(lm, text)
print(f"Person: {lm['person']}")
print(f"Organization: {lm['organization']}")
print(f"Date: {lm['date']}")
print(f"Location: {lm['location']}")
Рекомендации
1. Проверяйте формат регулярными выражениями
# ✅ Good: Regex ensures valid format
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# ❌ Bad: Free generation may produce invalid emails
lm += "Email: " + gen("email", max_tokens=50)
2. Для фиксированных категорий применяйте select()
# ✅ Good: Guaranteed valid category
lm += "Status: " + select(["pending", "approved", "rejected"], name="status")
# ❌ Bad: May generate typos or invalid values
lm += "Status: " + gen("status", max_tokens=20)
3. Пользуйтесь восстановлением токенов
# Token healing is enabled by default
# No special action needed - just concatenate naturally
lm += "The capital is " + gen("capital") # Automatic healing
4. Задавайте последовательности остановки
# ✅ Good: Stop at newline for single-line outputs
lm += "Name: " + gen("name", stop="\n")
# ❌ Bad: May generate multiple lines
lm += "Name: " + gen("name", max_tokens=50)
5. Выносите повторяемые шаблоны в функции
# ✅ Good: Reusable pattern
@guidance
def generate_person(lm):
lm += "Name: " + gen("name", stop="\n")
lm += "\nAge: " + gen("age", regex=r"[0-9]+")
return lm
# Use multiple times
lm = generate_person(lm)
lm += "\n\n"
lm = generate_person(lm)
6. Соблюдайте баланс в ограничениях
# ✅ Good: Reasonable constraints
lm += gen("name", regex=r"[A-Za-z ]+", max_tokens=30)
# ❌ Too strict: May fail or be very slow
lm += gen("name", regex=r"^(John|Jane)$", max_tokens=10)
Сравнение с альтернативами
| Возможность | Guidance | Instructor | Outlines | LMQL |
|---|---|---|---|---|
| Ограничения через regex | ✅ Да | ❌ Нет | ✅ Да | ✅ Да |
| Поддержка грамматик | ✅ CFG | ❌ Нет | ✅ CFG | ✅ CFG |
| Валидация через Pydantic | ❌ Нет | ✅ Да | ✅ Да | ❌ Нет |
| Восстановление токенов | ✅ Да | ❌ Нет | ✅ Да | ❌ Нет |
| Локальные модели | ✅ Да | ⚠️ Ограниченно | ✅ Да | ✅ Да |
| Модели через API | ✅ Да | ✅ Да | ⚠️ Ограниченно | ✅ Да |
| Синтаксис в стиле Python | ✅ Да | ✅ Да | ✅ Да | ❌ SQL-подобный |
| Порог входа | Низкий | Низкий | Средний | Высокий |
Когда выбрать Guidance:
- Нужны ограничения через regex или грамматику
- Нужно восстановление токенов
- Строите сложные сценарии с управляющими конструкциями
- Работаете с локальными моделями (Transformers, llama.cpp)
- Предпочитаете синтаксис в стиле Python
Когда выбрать альтернативу:
- Instructor: нужна валидация через Pydantic с автоматическими повторами
- Outlines: нужна валидация по JSON-схеме
- LMQL: предпочитаете декларативный синтаксис запросов
Характеристики производительности
Снижение задержки:
- На 30–50 % быстрее обычного промптинга для ограниченного вывода
- Восстановление токенов убирает лишнюю перегенерацию
- Грамматические ограничения не дают сгенерировать недопустимый токен
Расход памяти:
- Накладные расходы минимальны по сравнению с генерацией без ограничений
- Скомпилированная грамматика кэшируется после первого использования
- Эффективная фильтрация токенов во время инференса
Экономия токенов:
- Токены не тратятся на некорректный вывод
- Циклы повторных попыток не нужны
- Прямой путь к корректному результату
Ресурсы
- Документация: https://guidance.readthedocs.io
- GitHub: https://github.com/guidance-ai/guidance (18k+ звёзд)
- Ноутбуки: https://github.com/guidance-ai/guidance/tree/main/notebooks
- Discord: доступна поддержка сообщества
Смотрите также
references/constraints.md— подробные шаблоны regex и грамматикreferences/backends.md— настройка под конкретные бэкендыreferences/examples.md— готовые к продакшену примеры