Guidance

by guidance-ai / Microsoft (open source) · Python 3.8+, transformers, llama.cpp, OpenAI, Azure

Framework AI Assistants Open Source v0.3.2 · 18.03.2026 активный

Guidance — фреймворк для контролируемой генерации текста с языковыми моделями. Позволяет интерливать генерацию и логику: ветвления, циклы, констрейнты — всё как часть одной программы на Python. Возможности: - Гарантированная структура вывода через guidance-программы - `gen(regex=...)` — генерация, ограниченная regexp - `select(options=[...])` — выбор из конкретного набора - Интеграция логики (if/for) прямо в шаблон промпта - Token healing: исправление проблем токенизации на стыках - Работает с llama.cpp, transformers локально - Stateful: модель держит контекст между вызовами

v0.3.2
18.03.2026 current
Добавлен 19.06.2026 · Обновлён 19.06.2026 · AI Assistants
Установка
# pip:
pip install guidance

# С поддержкой llama.cpp:
pip install "guidance[llamacpp]"

# Пример:
import guidance
from guidance import models, gen, select

lm = models.LlamaCpp("model.gguf")

with guidance.system():
    lm += "You are a helpful assistant."

with guidance.user():
    lm += "Is the sky blue? Answer yes or no."

with guidance.assistant():
    lm += select(["yes", "no"], name="answer")

print(lm["answer"])  # "yes"
переведено ИИ

Discord Email Hours

guidance


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

Установка

Guidance доступен через PyPI и поддерживает различные бэкенды (Transformers, llama.cpp, OpenAI и др.). Если у вас уже есть требуемый бэкенд для вашей модели, вы можете просто выполнить

pip install guidance

Возможности

Питоничный интерфейс для языковых моделей

При использовании Guidance вы можете работать с большими языковыми моделями, используя стандартные идиомы Python:

from guidance import system, user, assistant, gen
from guidance.models import Transformers

# Можно также использовать LlamaCpp или множество других моделей
phi_lm = Transformers("microsoft/Phi-4-mini-instruct")

# Объекты моделей неизменяемы, поэтому это копия
lm = phi_lm

with system():
    lm += "You are a helpful assistant"

with user():
    lm += "Hello. What is your name?"

with assistant():
    lm += gen(max_tokens=20)

print(lm)

Если выполнить в командной строке, это выдаст вывод вроде:

<|system|>You are a helpful assistant<|end|><|user|>Hello. What is your name?<|end|><|assistant|>I am Phi, an AI developed by Microsoft. How can I help you today?

Однако при запуске в Jupyter notebook Guidance предоставляет виджет для более богатого пользовательского опыта:

Виджет Guidance, показывающий генерацию HTML

С помощью Guidance очень легко захватить сгенерированный текст:

# Получаем новую копию Модели
lm = phi_lm

with system():
    lm += "You are a helpful assistant"

with user():
    lm += "Hello. What is your name?"

with assistant():
    lm += gen(name="lm_response", max_tokens=20)

print(f"{lm['lm_response']=}")
lm['lm_response']='I am Phi, an AI developed by Microsoft. How can I help you today?'

Гарантия синтаксиса вывода с помощью ограничивающей генерации

Guidance предоставляет простой в использовании, но чрезвычайно мощный синтаксис для ограничения вывода языковой модели. Например, вызов gen() может быть ограничен соответствием регулярному выражению:

lm = phi_lm

with system():
    lm += "You are a teenager"

with user():
    lm += "How old are you?"

with assistant():
    lm += gen("lm_age", regex=r"\d+", temperature=0.8)

print(f"The language model is {lm['lm_age']} years old")
The language model is 13 years old

Часто мы знаем, что вывод должен быть элементом из заранее известного нам списка. Для этого сценария Guidance предоставляет функцию select():

from guidance import select

lm = phi_lm

with system():
    lm += "You are a geography expert"

with user():
    lm += """What is the capital of Sweden? Answer with the correct letter.

    A) Helsinki
    B) Reykjavík 
    C) Stockholm
    D) Oslo
    """

with assistant():
    lm += select(["A", "B", "C", "D"], name="model_selection")

print(f"The model selected {lm['model_selection']}")
The model selected C

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

Отладка грамматик в автономном режиме (без вызовов API модели)

При итерации ограничений вы можете локально проверять предполагаемые строки и тестировать полный прогон с помощью модели Mock.

from guidance import gen
from guidance.models import Mock

grammar = "expr=" + gen(regex=r"\d+([+*]\d+)*", name="expr")

# 1) Напрямую проверяем строки на соответствие грамматике
assert grammar.match("expr=12+7*3") is not None
assert grammar.match("expr=12+*3") is None

# 2) Запускаем ту же грамматику с локальной мок-моделью
lm = Mock(b"<s>expr=12+7*3")
lm += grammar
print(lm["expr"])  # 12+7*3

Создание собственных функций Guidance

С помощью Guidance вы можете создавать собственные функции Guidance, которые могут взаимодействовать с языковыми моделями. Они помечаются с помощью декоратора @guidance. Предположим, мы хотим ответить на множество вопросов с выбором ответа. Мы могли бы сделать что-то вроде следующего:

import guidance

from guidance.models import Model

ASCII_OFFSET = ord("a")

@guidance
def zero_shot_multiple_choice(
    language_model: Model,
    question: str,
    choices: list[str],
):
    with user():
        language_model += question + "\n"
        for i, choice in enumerate(choices):
            language_model += f"{chr(i+ASCII_OFFSET)} : {choice}\n"

    with assistant():
        language_model += select(
            [chr(i + ASCII_OFFSET) for i in range(len(choices))], name="string_choice"
        )

    return language_model

Теперь определим несколько вопросов:

questions = [
    {
        "question" : "Which state has the northernmost capital?",
        "choices" : [
            "New South Wales",
            "Northern Territory",
            "Queensland",
            "South Australia",
            "Tasmania",
            "Victoria",
            "Western Australia",
        ],
        "answer" : 1,
    },
    {
        "question" : "Which of the following is venomous?",
        "choices" : [
            "Kangaroo",
            "Koala Bear",
            "Platypus",
        ],
        "answer" : 2,
    }
]

Мы можем использовать нашу оформленную декоратором функцию как gen() или select(). Аргумент language_model будет автоматически заполнен за нас:

lm = phi_lm

with system():
    lm += "You are a student taking a multiple choice test."

for mcq in questions:
    lm_temp = lm + zero_shot_multiple_choice(question=mcq["question"], choices=mcq["choices"])
    converted_answer = ord(lm_temp["string_choice"]) - ASCII_OFFSET
    print(lm_temp)
    print(f"LM Answer: {converted_answer},  Correct Answer: {mcq['answer']}")
<|system|>You are a student taking a multiple choice test.<|end|><|user|>Which state has the northernmost capital?
a : New South Wales
b : Northern Territory
c : Queensland
d : South Australia
e : Tasmania
f : Victoria
g : Western Australia
<|end|><|assistant|>b
LM Answer: 1,  Correct Answer: 1
<|system|>You are a student taking a multiple choice test.<|end|><|user|>Which of the following is venomous?
a : Kangaroo
b : Koala Bear
c : Platypus
<|end|><|assistant|>c
LM Answer: 2,  Correct Answer: 2

Функции Guidance могут быть скомпонованы для построения полной контекстно-свободной грамматики. Например, мы можем создать функции Guidance для построения простой HTML-страницы (обратите внимание, что это не полная реализация HTML). Мы начинаем с простой функции, которая будет генерировать текст, не содержащий каких-либо HTML-тегов. Функция помечена как stateless, чтобы указать, что мы намереваемся использовать ее для компоновки грамматики:

@guidance(stateless=True)
def _gen_text(lm: Model):
    return lm + gen(regex="[^<>]+") 

Затем мы можем использовать эту функцию для генерации текста внутри произвольного HTML-тега:

@guidance(stateless=True)
def _gen_text_in_tag(lm: Model, tag: str):
    lm += f"<{tag}>"
    lm += _gen_text()
    lm += f"</{tag}>"
    return lm

Теперь создадим заголовок страницы. В рамках этого нам нужно сгенерировать заголовок страницы:

@guidance(stateless=True)
def _gen_header(lm: Model):
    lm += "<head>\n"
    lm += _gen_text_in_tag("title") + "\n"
    lm += "</head>\n"
    return lm

Тело HTML-страницы будет заполнено заголовками и абзацами. Мы можем определить функцию для каждого:

from guidance.library import one_or_more

@guidance(stateless=True)
def _gen_heading(lm: Model):
    lm += select(
        options=[_gen_text_in_tag("h1"), _gen_text_in_tag("h2"), _gen_text_in_tag("h3")]
    )
    lm += "\n"
    return lm

@guidance(stateless=True)
def _gen_para(lm: Model):
    lm += "<p>"
    lm += one_or_more(
        select(
            options=[
                _gen_text(),
                _gen_text_in_tag("em"),
                _gen_text_in_tag("strong"),
                "<br />",
            ],
        )
    )
    lm += "</p>\n"
    return lm

Теперь функция для определения самого тела HTML:

@guidance(stateless=True)
def _gen_body(lm: Model):
    lm += "<body>\n"
    lm += one_or_more(select(options=[_gen_heading(), one_or_more(_gen_para())]))
    lm += "</body>\n"
    return lm

Далее мы переходим к функции, которая генерирует полную HTML-страницу. Мы добавляем открывающий HTML-тег, затем генерируем заголовок, затем тело и приклеиваем закрывающий HTML-тег:

@guidance(stateless=True)
def _gen_html(lm: Model):
    lm += "<html>\n"
    lm += _gen_header()
    lm += _gen_body()
    lm += "</html>\n"
    return lm

Наконец, мы предоставляем удобную обертку, которая позволит нам: - Задавать температуру генерации - Захватывать сгенерированную страницу из объекта Модели

from guidance.library import capture, with_temperature

@guidance(stateless=True)
def make_html(
    lm,
    name: str | None = None,
    *,
    temperature: float = 0.0,
):
    return lm + capture(
        with_temperature(_gen_html(), temperature=temperature),
        name=name,
    )

Теперь используем это для генерации простой веб-страницы:

lm = phi_lm

with system():
    lm += "You are an expert in HTML"

with user():
    lm += "Create a simple and short web page about your life story."

with assistant():
    lm += make_html(name="html_text", temperature=0.7)

При запуске в Jupyter Notebook, где активен виджет, мы получаем следующий вывод:

Виджет Guidance, показывающий генерацию HTML с быстрым пропуском токенов

Обратите внимание на различную подсветку генерации. Это демонстрирует еще одну возможность Guidance: быстрый пропуск токенов. Ограничения, налагаемые грамматикой, часто означают, что некоторые токены известны заранее. Guidance не требует, чтобы модель их генерировала; вместо этого он может вставить их в генерацию. Это экономит прямые проходы через модель и, следовательно, снижает использование GPU. Например, в приведенной выше генерации HTML Guidance всегда знает последний открывающий тег. Если последний открытый тег был <h1> (например), то как только модель генерирует </, Guidance может заполнить h1>, не требуя от модели выполнения прямого прохода.

Генерация JSON

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

import json
from pydantic import BaseModel, Field

from guidance import json as gen_json

class BloodPressure(BaseModel):
    systolic: int = Field(gt=300, le=400)
    diastolic: int = Field(gt=0, le=20)
    location: str = Field(max_length=50)
    model_config = dict(extra="forbid")

lm = phi_lm

with system():
    lm += "You are a doctor taking a patient's blood pressure taken from their arm"

with user():
    lm += "Report the blood pressure"

with assistant():
    lm += gen_json(name="bp", schema=BloodPressure)

print(f"{lm['bp']=}")

# Используем JSON-библиотеку Python
loaded_json = json.loads(lm["bp"])
print(json.dumps(loaded_json, indent=4))

# Используем Pydantic
result = BloodPressure.model_validate_json(lm["bp"])
print(result.model_dump_json(indent=8))
lm['bp']='{"systolic": 301, "diastolic": 15, "location": "arm"}'
{
    "systolic": 301,
    "diastolic": 15,
    "location": "arm"
}
{
        "systolic": 301,
        "diastolic": 15,
        "location": "arm"
}

Обратите внимание, что сгенерированное артериальное давление не является тем, которое модель видела для человека. При генерации JSON значительное количество токенов часто можно быстро пропустить из-за структурных ограничений, налагаемых схемой.

Комментарии
Войдите, чтобы оставить комментарий