Содержание
  1. Кому нужен DSPy и какой нужен Python
  2. Вход, выход и ограниченный список меток
  3. Ручные эталоны и разделение train/dev/test
  4. Метрика, которая штрафует реальную ошибку
  5. Модуль и стратегия оптимизации по текущей первичке
  6. Заморозка конфигурации до финальной проверки
  7. Ручной расчёт метрики
  8. Версии модели, программы и данных перед compile
  9. Частые вопросы
Обзоры

DSPy: как оптимизируют программу с языковой моделью

9 ноября 2026 · 8 минут чтения

Разберём DSPy: как оптимизируют программу с языковой моделью через сигнатуры, модули и метрику. Это Python-фреймворк, в котором задача описывается сигнатурой, а оптимизатор подбирает промпты под метрику. Программа с языковой моделью здесь собирается из типизированных входов и выходов. Ниже — рабочий цикл: сигнатура, набор меток, метрика, выбор оптимизатора, заморозка конфигурации и честный ручной расчёт.

Кому нужен DSPy и какой нужен Python

DSPy берёт на себя ту часть работы, где вы уже вызываете модель из кода и правите промпт вручную после каждой ошибки. Документация проекта на dspy.ai описывает фреймворк как способ выразить задачу структурными сигнатурами и получить поддерживаемые, модульные и оптимизируемые программы. Репозиторий stanfordnlp/dspy формулирует ту же мысль: вы пишете композиционный Python-код, а фреймворк учит модель выдавать качественные результаты.

Порог входа — уверенный Python. Официальный сайт указывает требование python ≥ 3.10, установку pip install -U dspy и лицензию MIT. Там же назван автор проекта — Stanford NLP. Для читателя это значит: нужны классы, типы, списки словарей и понимание, как устроен вызов внешнего API. Если вы пока собираете промпт в блокноте, сначала стоит довести до рабочего состояния обычный вызов модели.

Кому фреймворк даёт выигрыш: командам, у которых задача повторяется на потоке данных и качество нужно измерять. Кому он не нужен: разовым экспериментам, где ответ смотрят глазами один раз. Второй группе хватит прямого вызова модели.

Отдельно про версию. Сайт сообщает о релизе DSPy 3.4.1 с улучшениями PythonInterpreter, ускоренным GEPA и совместимостью с MCP v2. Интеграция с моделями сейчас идёт через встроенные движки lm15, без рантайм-зависимости от LiteLLM. Старый пример с dspy.OpenAI из статьи IBM копировать не нужно: актуальная документация использует dspy.LM.

Вход, выход и ограниченный список меток

Сигнатура объявляет задачу типами. Документация dspy.ai показывает класс-наследник dspy.Signature со строкой-описанием, полями dspy.InputField() и dspy.OutputField(). Типы полей проверяются, поэтому выход модели приводится к объявленному виду.

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

PYTHON12 строк
from typing import Literal
import dspy

lm = dspy.LM("openai/gpt-5.4-nano")
dspy.configure(lm=lm)

class Triage(dspy.Signature):
    """Определи категорию обращения в поддержку."""
    ticket: str = dspy.InputField()
    label: Literal["billing", "delivery", "other"] = dspy.OutputField()

classify = dspy.Predict(Triage)

Здесь Triage — сигнатура, dspy.Predict — модуль, который её исполняет. В примере список меток указан в типе Literal; описание сигнатуры дополнительно объясняет смысл категорий. Документация dspy.ai приводит похожий приём с Literal["low", "high"] для поля urgency: тип сужает пространство ответов на уровне объявления.

Практический порядок: сначала выпишите вход одной строкой, затем выход, затем закройте список меток. При открытом списке синонимичные названия одной категории могут считаться разными ответами. Закрытый список делает проверку воспроизводимой.

Ручные эталоны и разделение train/dev/test

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

Набор Обращение Метка
train Верните оплату billing
train Где посылка? delivery
dev В счёте лишняя позиция billing
dev Как поменять пароль? other
test Деньги списались дважды billing
test Трек не обновляется delivery

Правило разделения: train и dev участвуют в подборе, test закрыт до фиксации программы. Это условный учебный журнал; запуск продукта не проводился.

Размер наборов выбирайте по числу классов. Шесть примеров здесь позволяют разобрать разделение наборов. В таблице billing встречается трижды, delivery дважды, other один раз; такое распределение не служит рекомендацией для реальной выборки. Для реальной задачи такого объёма мало: чем больше классов и чем тоньше различия между ними, тем больше эталонов нужно на каждый класс.

Разметку ведите в одном файле с колонками «текст», «метка», «набор». Тогда перенос примера между наборами виден в истории изменений, и случайная утечка теста обнаруживается до проверки.

Метрика, которая штрафует реальную ошибку

Метрика — функция, которая получает пример и предсказание и возвращает число. Документация dspy.ai описывает цикл так: вы даёте примеры и функцию оценки, а оптимизатор подстраивает промпты до сходимости качества.

Для классификации с закрытым списком подходит exact-match: метка совпала — единица, любая другая метка — ноль. Недопустимая метка тоже ошибка, даже если она близка по смыслу к верной.

PYTHON2 строки
def exact_match(example, pred, trace=None):
    return float(example.label == pred.label)

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

Проверьте метрику на бумаге до запуска. Возьмите два тестовых примера и предложите ответы вручную: [label=billing, label=billing]. Первый верен, второй нет, счёт равен 1/2 = 0.5. Это арифметическая проверка самой функции, и она показывает, что метрика считает то, что вы задумали.

Модуль и стратегия оптимизации по текущей первичке

Модуль определяет, как сигнатура исполняется. Документация dspy.ai перечисляет варианты: dspy.Predict для прямого ответа, dspy.ChainOfThought для пошагового рассуждения, dspy.ReAct для работы с инструментами и циклом рассуждения. Интерфейс у них общий, меняется стратегия.

Модуль Когда брать Что добавляет
dspy.Predict Простая классификация Прямой ответ по сигнатуре
dspy.ChainOfThought Нужны промежуточные шаги Рассуждение перед ответом
dspy.ReAct Нужны внешние функции Вызов инструментов и цикл

Оптимизатор компилирует программу против метрики. На dspy.ai приведён пример с dspy.GEPA(metric=..., auto="medium") и вызовом compile(rag, trainset), после которого результат сохраняется через save("rag.v2.json"). Там же показан пример с dspy.MIPROv2 в списке исследовательских работ проекта.

Разделяйте два вида оптимизации. Часть оптимизаторов подбирает инструкции и демонстрации — это работа с промптами. Другая часть может менять веса модели — это обучение. Репозиторий проекта говорит об алгоритмах оптимизации промптов и весов. Для классификации на трёх метках начинайте с подбора промптов: он дешевле и быстрее проверяется.

Выбор делайте по текущей документации проекта. Приёмы из старых статей могут ссылаться на устаревший API.

Заморозка конфигурации до финальной проверки

Заморозка означает: вы фиксируете сигнатуру, модуль, метрику, наборы и параметры оптимизатора, а затем больше их не меняете. До этого момента любые правки допустимы.

Порядок действий:

  1. Записать текущую версию сигнатуры и модуля.
  2. Зафиксировать файл с разметкой и хеш его содержимого.
  3. Записать имя модели и параметры вызова.
  4. Записать выбранный оптимизатор и его настройки.
  5. Прогнать компиляцию на train и dev.
  6. Остановить правки и перейти к тесту.

Смысл в том, что тест показывает качество замороженной конфигурации. Если после теста вы правите промпт и снова показываете результат, это уже другая конфигурация, и прежняя цифра к ней не относится.

Отдельно про бюджет. Вызовы модели стоят денег, и компиляция делает много вызовов. До запуска определите, сколько примеров и сколько проходов вы готовы оплатить. В этой статье вызовов модели не было: все числа учебные.

Ручной расчёт метрики

Ручной расчёт показывает, что метрика работает, и отделяет арифметику от результата оптимизации. Возьмите тестовые примеры и предложите ответы сами.

Для набора из двух тестовых примеров предложение [label=billing, label=billing] даёт 1/2 = 0.5. Первый ответ совпал с эталоном, второй нет. Это ручная проверка функции. Компиляция DSPy в этом примере не выполнялась.

Дальше — отрицательный случай, который ловит утечку. Если после ошибки на тесте добавить этот пример в промпт и снова показать 2/2 как независимую приёмку, проверка провалена: тест перестал быть закрытым. Эталон попал в подбор, и число 2/2 больше ничего не подтверждает.

Практический вывод: держите тест в отдельном файле, который не читается кодом компиляции. Это снижает риск случайной утечки. Отдельно проверьте, какие файлы читает код компиляции.

Версии модели, программы и данных перед compile

Перед фактическим запуском компиляции сохраните три версии и бюджет.

Версия модели: имя модели и провайдер, записанные строкой. Смена модели меняет поведение программы, поэтому имя фиксируется вместе с результатом.

Версия программы: сигнатура, модуль, метрика и настройки оптимизатора в одном файле или в системе контроля версий. Документация dspy.ai показывает сохранение результата через save("extract_v2.json") — этот файл и есть артефакт конкретной компиляции.

Версия данных: файл разметки с разделением на train, dev и test. Хеш содержимого привязывает результат к конкретному набору.

Бюджет: число примеров, число проходов и предел расходов. Записывайте его до запуска, чтобы после не сравнивать несопоставимые прогоны.

Частые вопросы

Что такое DSPy простыми словами?
Это Python-фреймворк, в котором задача описывается типами входа и выхода, а подбор промптов выполняет оптимизатор по заданной метрике. Документация проекта называет такой подход программированием вместо ручного составления промптов. Программа собирается из сигнатур и модулей, как из обычных функций.

Что такое dspy signatures?
Сигнатура — это объявление задачи: класс с описанием, полями dspy.InputField() и dspy.OutputField(). Типы полей проверяются, поэтому выход приводится к объявленному виду. Сигнатура отделяет описание задачи от способа её исполнения.

Как работает dspy optimizer?
Оптимизатор получает программу, набор примеров и функцию оценки, затем подстраивает промпты до сходимости качества. В документации показан вызов compile с последующим сохранением результата в файл. Часть оптимизаторов работает с промптами, часть может менять веса модели.

Какой уровень Python нужен для DSPy?
Официальный сайт указывает требование python ≥ 3.10. Нужны классы, типы, списки и понимание вызова внешнего API. Установка выполняется командой pip install -U dspy.

Сколько примеров нужно для оптимизации?
Для учебного цикла хватает шести примеров на три метки. Для реальной задачи объём зависит от числа классов и тонкости различий между ними. Разметка ведётся руками, а тест закрывается до фиксации программы.

Читайте также

3 материала