English translation is not available yet. Showing Russian content.

Что такое Assertions в DSPy и зачем они нужны?

Краткий тезис

Assertions в DSPy — это декларативный механизм проверки выходов LLM на соответствие заданным инвариантам (например, «сумма больше нуля» или «ответ содержит цитату»). В отличие от обычного assert в Python, при нарушении условия DSPy не останавливает программу, а пытается автоматически исправить ответ: перегенерировать с изменённым промптом, доопределить вывод, использовать chain-of-thought или другие стратегии. Assertions делают LLM-программы более надёжными, заменяя ручное промпт-инжиниринг программными ограничениями.


1. Термин «Assertion» в контексте DSPy

Assertion (утверждение) — это проверка, которую разработчик встраивает прямо в DSPy-программу. Синтаксически это вызов dspy.Assert(condition, message, feedback) или dspy.Suggest(condition, message, feedback). Главное отличие от обычного Python assert: при ложном условии DSPy не кидает исключение (если только это не настроено специально), а запускает процедуру автоматического исправления.

Термин «feedback» — строка или функция, которая подсказывает оптимизатору DSPy, как изменить промпт или генерацию, чтобы удовлетворить условие в будущем.


2. Зачем нужны Assertions

Обычная LLM-программа (написанная на Python с прямым вызовом API) не гарантирует, что выход соответствует ожидаемым форматам или логике. Например, модель может:

  • Вернуть пустой ответ, хотя обещала всегда отвечать.
  • Нарушить бизнес-правило (отрицательное количество товаров).
  • Не включить необходимую цитату в RAG-ответ.

Традиционный подход — вручную писать постусловия с if ... raise и повторно вызывать модель, что громоздко и не системно. Assertions в DSPy решают эту проблему на уровне программного каркаса:

  • Они декларативны — разработчик только описывает, что правильно, а как исправить, решает сам фреймворк.
  • Они интегрируются с оптимизаторами DSPy — после нескольких нарушений DSPy может автоматически обновить промпт-шаблон, чтобы избежать ошибки в будущем.
  • Они поддерживают мягкие и constraints|жёсткие ограничения: dspy.Assert (остановка с исключением после всех попыток) и dspy.Suggest (только предупреждение, без прерывания).

Таким образом, Assertions — это мост между недетерминированным LLM и строгими требованиями приложения.


3. Как работают Assertions: механизм самокоррекции

Процесс шаг за шагом

  1. Разработчик объявляет DSPy-модуль (например, dspy.ChainOfThought), внутри которого вызывается LLM.
  2. После генерации выхода запускаются все Assertions, приписанные к этому шагу.
  3. Если все условия истинны — результат принимается.
  4. Если условие ложно — DSPy:
    • Увеличивает счётчик попыток.
    • Использует feedback, чтобы модифицировать промпт (например, добавить «Пожалуйста, проверь, что ответ начинается с буквы A»).
    • Повторно вызывает LLM (иногда с другой стратегией, например, chain-of-thought или ReAct).
    • Повторяет проверку. Если после max_retries условие не выполнено — в случае dspy.Assert выбрасывается DSPyAssertionError, а в случае dspy.Suggest — результат принимается, но логируется предупреждение.

Термин «max_retries» — параметр, задающий максимальное количество попыток исправления (по умолчанию 3). Термин «feedback» — текст или функция, которая вставляется в промпт в момент повторной генерации.


4. Типы Assertions: dspy.Assert и dspy.Suggest

ТипПоведение при нарушенииКогда использовать
dspy.AssertПосле max_retries выбрасывает DSPyAssertionError. Программа останавливается.Жёсткие требования: ответ обязательно должен удовлетворять условию (например, в производстве).
dspy.SuggestПосле max_retries выводит предупреждение (лог), но программа продолжается с нарушенным ответом.Мягкие ограничения: желательно, но не критично (например, стиль ответа).

Оба поддерживают параметры:

  • condition — булево выражение (может быть функцией, возвращающей bool).
  • msg — сообщение для лога/исключения.
  • feedback — строка, которая будет добавлена в промпт при повторной попытке (если не указана, DSPy генерирует её по умолчанию).

5. Пример кода с Assertions

import dspy
from dspy import Assert, Suggest

class PositiveSum(dspy.Module):
    def __init__(self):
        self.generate = dspy.ChainOfThought("a: int, b: int -> sum: int")
    
    def forward(self, a, b):
        result = self.generate(a=a, b=b)
        # Жёсткое условие: сумма должна быть положительной
        Assert(result.sum > 0,
               msg=f"Sum {result.sum} is not positive",
               feedback="Пожалуйста, убедись, что сумма положительна.")
        # Мягкое условие: сумма должна быть чётной (если возможно)
        Suggest(result.sum % 2 == 0,
                msg=f"Sum {result.sum} is not even",
                feedback="Постарайся сделать сумму чётной.")
        return result

# Запуск
lm = dspy.OpenAI(model="gpt-4")
dspy.settings.configure(lm=lm)
program = PositiveSum()
try:
    out = program(3, -5)
    print(out.sum)            # после исправления может быть 2 или 8
except dspy.DSPyAssertionError:
    print("Не удалось получить положительную сумму.")

В этом коде:

  • Assert заставляет модель перегенерировать ответ до тех пор, пока сумма не станет положительной (или не закончатся попытки).
  • Suggest просто уведомляет, если сумма нечётная, но не блокирует.
  • feedback подсказывает модели, что нужно исправить.

6. Интеграция с DSPy-программами

Assertions можно встраивать в любые DSPy-модули: ChainOfThought, ReAct, MultiChainComparison, а также в кастомные классы, наследуемые от dspy.Module. Они срабатывают после вызова LLM внутри метода forward.

Важно: Assertions не влияют на этап компиляции (компилятор DSPy использует оптимизатор по умолчанию, не учитывая Assertions напрямую). Однако если вы компилируете модуль с Assertions, feedback может быть использован оптимизатором, если в нём предусмотрена поддержка (например, BootstrapFewShotWithRandomSearch может учитывать сообщения об ошибках при генерации демонстраций).


7. Параметры и конфигурация

Основные глобальные настройки через dspy.settings:

ПараметрТипОписание
assertions_max_retriesintКоличество повторных попыток для каждого Assert/Suggest (по умолчанию 3).
assertions_feedbackstrФраза по умолчанию, если feedback явно не указан.
assertions_handlercallableФункция, вызываемая при нарушении Assert (можно переопределить, чтобы логировать или отправлять метрики).

Пример настройки:

dspy.settings.configure(
    lm=lm,
    assertions_max_retries=5,
    assertions_feedback="Проверь правильность ответа.",
    assertions_handler=lambda x: print(f"Assertion failed: {x}")
)

8. Преимущества и ограничения

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

  • Автоматизация исправлений — не нужно писать циклы повторного вызова вручную.
  • Декларативность — отделение «что должно быть» от «как добиться».
  • Интеграция с DSPy — единый стиль программирования LLM-приложений.
  • Обратная связь для оптимизатора — потенциальное улучшение промптов.

Ограничения

  • Затраты — повторные вызовы LLM увеличивают стоимость и latency.
  • Не поддерживает сложные проверки — условия должны быть вычислимы внутри Python (нельзя, например, попросить модель проверить другую модель).
  • Не заменяет тестирование — Assertions — это механизм рантайм-валидации, а не модульных тестов.
  • Зависимость от качества моделей — если модель систематически не может исправить ошибку, Assertions приведут к исчерпанию retries и исключению.

9. Сравнение с другими подходами

ПодходСутьОтличие от Assertions в DSPy
Ручная валидация после генерацииif not condition: regenerate()Требует вручную писать логику повторов; DSPy делает это автоматически с интеллектуальным feedback.
Guardrails (NVIDIA NeMo Guardrails)Набор правил в формате YAML, перехватывающих вывод до пользователяБолее формализованный, но менее гибкий для динамического программирования.
Chain-of-verification (CoVe)LLM самостоятельно проверяет и исправляет свой ответНе требует явного кода, но менее контролируемо. DSPy даёт чёткое разделение между проверкой и генерацией.
Pydantic + LLMГенерация JSON с последующей валидацией схемыОриентирован на структурированный вывод; Assertions могут проверять и семантические свойства, не только формат.

10. Практические советы

  • Используйте dspy.Suggest для рекомендаций, чтобы не ломать программу на ранних этапах разработки.
  • Для критичных сценариев (финансы, медицина) применяйте dspy.Assert.
  • Нагружайте feedback конкретными инструкциями на естественном языке — это повышает шансы исправления.
  • Комбинируйте Assertions с DSPy-оптимизаторами: после сбора истории нарушений можно обучить модуль реже ошибаться.
  • Помните о затратах — устанавливайте разумное max_retries (обычно 2–3).

Пет-проект для закрепления

Задача Разработать DSPy-модуль для генерации финансового отчёта (например, «прибыль за квартал»), который гарантирует, что:

  • Все числовые суммы положительные.
  • Ответ содержит название валюты (USD, EUR).
  • Ответ не пустой.

Инструменты

  • Python 3.9+, DSPy (установка pip install dspy).
  • LLM-провайдер (OpenAI, Anthropic или любой локальный через HuggingFace).
  • Библиотеки: dspy, re (для проверки валюты).

Шаги:

  1. Создать DSPy-модуль FinancialReport с подписью quarter: str, revenue: float, costs: float -> report: str.
  2. Внутри forward вызвать ChainOfThought, затем добавить три Assertions:
    • dspy.Assert(any(currency in result.report for currency in ("USD", "EUR", "RUB")), "Нет валюты").
    • dspy.Assert(revenue > 0 and costs > 0, "Суммы должны быть положительными").
    • dspy.Assert(len(result.report) > 0, "Пустой ответ").
  3. Запустить на нескольких входных данных, включая проблемные (отрицательные числа).
  4. Вывести количество попыток исправления.

Ожидаемый результат Модуль всегда возвращает отчёт, содержащий валюту и с положительными числами, даже если модель изначально ошибается. В логах будет видно количество ретраев.


Связь с другими вопросами

ВопросТема
101Что такое DSPy и его основные концепции?
102Как работает подпись (Signature) в DSPy?
103Как устроены модули (Modules) в DSPy?
105Как работают оптимизаторы в DSPy?
106Что такое компилятор в DSPy?
107Как написать простую программу на DSPy?

Навигация