Что такое DSPy в контексте агентов?
Краткий тезис
DSPy — это фреймворк для автоматической оптимизации промптов и few-shot примеров в LLM-пайплайнах, использующий обратное распространение на метриках качества. В контексте агентов DSPy позволяет описывать агента как программу (program) с сигнатурами и модулями, а затем автоматически подбирать промпты для каждого компонента (планировщика, инструментов, рефлексии) без ручного тюнинга. Это избавляет от необходимости вручную настраивать сложные цепочки вызовов LLM и делает агента более устойчивым и адаптивным.
1. Термин: DSPy (Declarative Self-improving Python)
DSPy — это библиотека с открытым исходным кодом (разработана Стэнфордом), которая декларативно описывает LLM-пайплайн в виде программы (program) — последовательности модулей с сигнатурами (signatures). Сигнатура — это спецификация ввода-вывода модуля, например: question: str -> answer: int. Вместо ручного написания промптов DSPy автоматически генерирует, тестирует и оптимизирует промпты и few-shot демонстрации на основе заданной метрики (например, точность, F1, faithfulness).
Ключевая идея: обратное распространение (backpropagation) через LLM-пайплайн. DSPy запускает множество вариантов промптов, измеряет качество на валидационном датасете (validation set) и подбирает конфигурацию (промпты, примеры), максимизирующую метрику. Это похоже на обучение нейросети, но с дискретными LLM.
В контексте агентов DSPy даёт возможность не писать вручную сложные инструкции для планировщика, выбора инструмента и обработки ошибок — эти промпты оптимизируются автоматически под конкретную задачу и домен.
2. Agent как DSPy‑программа
Агент в типичном исполнении — это цикл: планирование, вызов инструментов, наблюдение, рефлексия. Каждый шаг требует LLM-вызова с carefully crafted промптом. DSPy позволяет представить этого агента как композицию модулей:
- Модуль-планировщик (planner): task: str -> plan: List[str]
- Модуль-исполнитель (executor): tool_name: str, args: dict -> observation: str
- Модуль-рефлектор (reflexion): plan: List[str], observations: List[str] -> refined_plan: List[str]
Каждый модуль — это отдельный DSPy Module с сигнатурой. Агент в целом — это dspy.Module, который вызывает эти подмодули в цикле. Вместо того чтобы вручную писать промпт для рефлексии («Учитывая предыдущие шаги, скорректируй план…»), DSPy оптимизирует этот промпт на датасете задач, где известен правильный порядок действий.
3. Оптимизация через обратное распространение на валидации
Процесс оптимизации в DSPy включает:
- Сбор/генерация датасета — набор (вход, ожидаемый выход) для агента, например: запрос пользователя → правильная последовательность действий.
- Определение метрики — например, точность финального ответа, полнота покрытия шагов, среднее количество ретраев.
- Запуск оптимизатора (например, BootstrapFewShot, COPRO, MIPRO) — DSPy генерирует несколько вариантов промптов и few-shot примеров для каждого модуля, прогоняет через пайплайн на валидации и выбирает вариант с лучшей метрикой.
- Итерация — оптимизация может повторяться, постепенно улучшая качество.
Ключевой механизм — bootstrap few-shot. DSPy автоматически создаёт хорошие примеры (демонстрации) из пайплайна, используя правильные решения (если они доступны) или best-effort на метрике.
4. Применение DSPy к компонентам агента
4.1 Планировщик (Planner)
Сигнатура: user_query: str -> plans: List[Вики/step_number|Step, где Вики/step_number|Step содержит tool_name, args, expected_output. Вики/DSPy|DSPy подбирает Вики/prompt|промпт, который учит агента разбивать задачу на шаги, включать проверки, избегать циклов.
4.2 Выбор инструмента (Tool Selector)
Сигнатура: goal: str, available_tools: List[str] -> tool_name: str. Оптимизация помогает агенту корректно выбирать инструмент, даже когда названия похожи.
4.3 Рефлексия (Reflection/Replan)
Сигнатура: history: List[StepResult] -> correction: str (или next_step: Step). DSPy может научить агента распознавать, когда шаг не удался, и предлагать альтернативу.
4.4 Обработка ошибок
Сигнатура: error_message: str, context: str -> fallback_action: str. Автоматически оптимизируется под типичные ошибки (недоступность API, некорректный формат данных).
5. Преимущества DSPy для агентов
| Аспект | Ручной промптинг | DSPy |
|---|---|---|
| Создание промптов | Вручную писать сложные инструкции, учитывать все edge cases | Автоматическая оптимизация на данных |
| Few-shot примеры | Подбирать вручную, поддерживать актуальность | Генерируются через bootstrap, подстраиваются под датасет |
| Адаптация к домену | Дорого, требует много экспериментов | Достаточно собрать датасет из 50–100 примеров |
| Устойчивость к изменениям LLM | Промпты приходится обновлять при смене модели | Переоптимизация на новой модели за несколько запусков |
| Воспроизводимость | Зависит от версии промпта | DSPy-программа — детерминированный код |
6. Пример кода: определение агента через DSPy
import dspy
# Определяем сигнатуры модулей
class Plan(dspy.Signature):
"""Составить поэтапный план для выполнения задачи."""
task = dspy.InputField(desc="Запрос пользователя")
steps = dspy.OutputField(desc="Список шагов в формате: шаг 1: ... \n шаг 2: ...")
class Execute(dspy.Signature):
"""Выполнить один шаг плана с помощью инструмента."""
step = dspy.InputField()
result = dspy.OutputField()
class Reflect(dspy.Signature):
"""Проанализировать результат и скорректировать план."""
original_plan = dspy.InputField()
observation = dspy.InputField()
revised_plan = dspy.OutputField()
# Собираем агента как программу
class SimpleAgent(dspy.Module):
def __init__(self):
super().__init__()
self.planner = dspy.ChainOfThought(Plan)
self.executor = dspy.Predict(Execute)
self.reflector = dspy.ChainOfThought(Reflect)
def forward(self, task: str, max_steps: int = 5):
plan = self.planner(task=task).steps
for i in range(max_steps):
# выполнение шага (упрощённо)
obs = self.executor(step=plan.split('\n')[i]).result
# рефлексия
new_plan = self.reflector(original_plan=plan, observation=obs).revised_plan
plan = new_plan
return dspy.Prediction(final_plan=plan)
# Оптимизация
train_data = [dspy.Example(task="Найти погоду в Москве", final_plan="...").with_inputs("task")]
agent = SimpleAgent()
optimizer = dspy.BootstrapFewShot(metric=lambda x, y: 1.0 if x.final_plan == y.final_plan else 0.0)
optimized_agent = optimizer.compile(agent, trainset=train_data)
7. Сравнение DSPy с другими подходами к оптимизации агентов
| Подход | Суть | Плюсы | Минусы |
|---|---|---|---|
| Ручной промптинг | Человек пишет подсказки для каждого компонента | Полный контроль | Трудоёмко, не масштабируется |
| DSPy (backprop на валидации) | Авто-подбор промптов/примеров по метрике | Не требует ручной настройки | Нужен качественный валидационный датасет |
| RLHF | Обучение через подкрепление на преференциях | Улучшает поведение агента | Требует много вычислительных ресурсов |
| Fine-tuning малой модели | Донастройка LLM на логах агента | Низкая стоимость инференса | Потеря общих знаний, переобучение |
DSPy занимает нишу между ручным промптингом и полноценным RL: даёт автоматизацию без необходимости обучать модель.
8. Интеграция DSPy с существующими фреймворками агентов
DSPy не заменяет такие фреймворки, как LangChain, AutoGPT, или ReAct, а дополняет их. Можно обернуть цепочку вызовов в DSPy-модули и оптимизировать только промпты наиболее критичных компонентов. Например:
- LangChain + DSPy: Заменить обычный LLMChain на dspy.ChainOfThought; сигнатуры позволяют чётко определить вход/выход каждого шага.
- AutoGPT: DSPy может генерировать и оптимизировать промпты для команд управления памятью и планирования.
- ReAct pattern: DSPy автоматически подбирает формат мыслей (Thought/Action/Observation) и количество итераций.
9. Ограничения DSPy
- Требует качественного датасета — метрика должна хорошо коррелировать с реальным качеством агента; плохо размеченные данные снижают эффект.
- Не оптимизирует логику агента — DSPy меняет только промпты и few-shot примеры, архитектуру (например, порядок шагов) нужно задавать вручную.
- Вычислительные затраты — оптимизация требует множества запусков LLM, что может быть дорого (но дешевле RL).
- Совместимость с новыми LLM — оптимизированный пайплайн может плохо переноситься на другую модель без перезапуска.
10. Связь с другими концепциями Agentic RAG
- Self‑RAG (вопрос 10): использует собственный вывод LLM для рефлексии — DSPy может заменить ручную настройку рефлексии.
- Agentic‑RAG (вопрос 895-898): DSPy помогает автоматически настраивать промпты для планирования и выбора чанков.
- Fine‑tuning (вопрос 110): альтернатива DSPy — донастройка модели на логах агента; DSPy дешевле и быстрее для быстрого прототипирования.
- Оценка retrieval (вопрос 5): метрики вроде
faithfulnessмогут быть использованы как цель для DSPy-оптимизации.
Пет-проект для закрепления
Задача: Создать простого агента, который по вопросу пользователя находит информацию в документах (RAG) через несколько инструментов (поиск в векторной БД, суммаризация, проверка достоверности). Использовать DSPy для автоматической оптимизации его промптов.
Инструменты: Python, DSPy, LangChain (для интеграции с инструментами), Chroma (векторная БД), OpenAI API.
Шаги:
- Определить датасет из 50 вопросов и правильных последовательностей шагов (например, вопрос «Какая столица Франции?» → шаги: [«Поиск документа про Францию», «Извлечение строки о столице»]).
- Описать агента как DSPy программу с модулями
Planner,Retriever,AnswerVerifier. - Задать метрику: точность финального ответа + количество лишних шагов (штраф).
- Запустить оптимизатор
BootstrapFewShotWithRandomSearch. - Сравнить качество агента до и после оптимизации на тестовом наборе.
Ожидаемый результат: После оптимизации агент будет реже совершать лишние вызовы инструментов и точнее отвечать на вопросы. Наглядный график точности и количества шагов до/после.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 895 | Как спроектировать Agentic RAG? |
| 898 | Каковы паттерны планирования в Agentic RAG? |
| 10 | Что такое Self-RAG и когда его использовать? |
| 110 | Что такое fine-tuning, как он соотносится с RAG? |
| 5 | Как оцениваете качество retrieval в RAG? |
Навигация
- Предыдущий: 898
- Следующий: 900
- Индекс: 00. Индекс разборов