К основному содержанию
скилл CX Codex

dspy-debugging-observability — скилл для Claude Code: отладка DSPy

Скилл для отладки и мониторинга программ на DSPy: история вызовов, трассировка через MLflow, свои колбэки для учёта цены и ошибок.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add OmidZamani/dspy-skills --skill dspy-debugging-observability -a claude-code
Открыть на GitHub

Что делает dspy-debugging-observability

Скилл разбирает четыре подхода к наблюдаемости DSPy. Первый — dspy.inspect_history(n=1), который печатает последний вызов в консоль; сырую историю можно достать из GLOBAL_HISTORY в dspy.clients.base_lm и вытащить оттуда модель, расход токенов и стоимость. Второй — автологирование MLflow: mlflow.dspy.autolog(...) с флагами для трассировки инференса, компиляции и оценки. Для этого нужен запущенный сервер MLflow, например mlflow ui --port 5000, и настроенный retriever перед dspy.Retrieve.

Третий путь — свой колбэк на базе dspy.utils.callback.BaseCallback. В примере скилла ProductionMonitoringCallback считает суммарную стоимость, токены, число вызовов и ошибок, а латентность замеряет по on_lm_start и on_lm_end. Цены моделей зашиты в словарь внутри _estimate_cost, и его надо править под свои тарифы. Четвёртый — сэмплирование: SamplingCallback с sample_rate пропускает через себя долю трасс, чтобы не платить за наблюдаемость на каждом запросе.

Скиллу разрешены только Read, Write, Glob и Grep — он читает и правит код, но не запускает ваши программы. Совместимость заявлена с DSPy 3.2.1, так что на более старых версиях имена колбэков и GLOBAL_HISTORY могут отличаться.

Какие задачи решает

  • понять, почему программа на DSPy выдала неожиданный ответ
  • разложить многошаговый пайплайн по вызовам модели
  • посчитать расход токенов и денег на боевом трафике
  • поймать и посчитать ошибки вызовов LLM
  • включить трассировку MLflow для компиляции и оценки

Примеры запросов агенту

  • Добавь в мой пайплайн колбэк, который считает стоимость и латентность каждого вызова
  • Настрой автологирование MLflow для этого модуля DSPy
  • Покажи, как достать историю последнего вызова через inspect_history

Как установить dspy-debugging-observability

1Через Skills CLI (Vercel)

npx skills add OmidZamani/dspy-skills --skill dspy-debugging-observability -a claude-code

2Вручную: положить файлы

~/.claude/skills/dspy-debugging-observability/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/dspy-debugging-observability/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о dspy-debugging-observability

Как установить dspy-debugging-observability в Claude Code?

Выполните npx skills add OmidZamani/dspy-skills --skill dspy-debugging-observability -a claude-code. Файл скилла появится по пути ~/.claude/skills/dspy-debugging-observability/SKILL.md.

Что делает dspy-debugging-observability?

Помогает отлаживать программы на DSPy: показывает историю вызовов, подключает трассировку MLflow и даёт шаблон своего колбэка для учёта стоимости, токенов, латентности и ошибок.

Что нужно для трассировки через MLflow?

Запущенный сервер MLflow и вызов mlflow.dspy.autolog с нужными флагами. Перед dspy.Retrieve retriever тоже надо настроить через dspy.configure.

Исходный текст

SKILL.md · MIT
---
name: dspy-debugging-observability
version: "1.0.0"
dspy-compatibility: "3.2.1"
tags: ["production"]
requires-extras: []
description: Use for debugging DSPy programs, inspect_history, tracing LLM calls, custom callbacks, observability, monitoring, and cost tracking.
allowed-tools:
  - Read
  - Write
  - Glob
  - Grep
---

# DSPy Debugging & Observability

## Goal

Debug, trace, and monitor DSPy programs using built-in inspection, MLflow tracing, and custom callbacks for production observability.

## When to Use

- Debugging unexpected outputs
- Understanding multi-step program flow
- Production monitoring (cost, latency, errors)
- Analyzing optimizer behavior
- Tracking LLM API usage

## Related Skills

- Optimize programs: [dspy-miprov2-optimizer](../dspy-miprov2-optimizer/SKILL.md)
- Evaluate quality: [dspy-evaluation-suite](../dspy-evaluation-suite/SKILL.md)
- Build agents: [dspy-react-agent-builder](../dspy-react-agent-builder/SKILL.md)

## Inputs

| Input | Type | Description |
|-------|------|-------------|
| `program` | `dspy.Module` | Program to debug/monitor |
| `callback` | `BaseCallback` | Optional custom callback (subclass of `dspy.utils.callback.BaseCallback`) |

## Outputs

| Output | Type | Description |
|--------|------|-------------|
| `GLOBAL_HISTORY` | `list[dict]` | Raw execution trace from `dspy.clients.base_lm` |
| `metrics` | `dict` | Cost, latency, token counts from callbacks |

## Workflow

### Phase 1: Basic Inspection with inspect_history()

The simplest debugging approach:

```python
import dspy

dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))

# Run program
qa = dspy.ChainOfThought("question -> answer")
result = qa(question="What is the capital of France?")

# Inspect last execution (prints to console)
dspy.inspect_history(n=1)

# To access raw history programmatically:
from dspy.clients.base_lm import GLOBAL_HISTORY
for entry in GLOBAL_HISTORY[-1:]:
    print(f"Model: {entry['model']}")
    print(f"Usage: {entry.get('usage', {})}")
    print(f"Cost: {entry.get('cost', 0)}")
```

### Phase 2: MLflow Tracing

MLflow integration requires explicit setup:

```python
import dspy
import mlflow

# Setup MLflow (4 steps required)
# 1. Set tracking URI and experiment
mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("DSPy")

# 2. Enable DSPy autologging
mlflow.dspy.autolog(
    log_traces=True,              # Log traces during inference
    log_traces_from_compile=True, # Log traces when compiling/optimizing
    log_traces_from_eval=True,    # Log traces during evaluation
    log_compiles=True,            # Log optimization process info
    log_evals=True                # Log evaluation call info
)

dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))

# Configure retriever (required before using dspy.Retrieve)
rm = dspy.ColBERTv2(url="http://20.102.90.50:2017/wiki17_abstracts")
dspy.configure(rm=rm)

class RAGPipeline(dspy.Module):
    def __init__(self):
        self.retrieve = dspy.Retrieve(k=3)
        self.generate = dspy.ChainOfThought("context, question -> answer")

    def forward(self, question):
        context = self.retrieve(question).passages
        return self.generate(context=context, question=question)

pipeline = RAGPipeline()
result = pipeline(question="What is machine learning?")

# View traces in MLflow UI (run in terminal): mlflow ui --port 5000
```

MLflow captures LLM calls, token usage, costs, and execution times when autolog is enabled.

### Phase 3: Custom Callbacks for Production

Build custom callbacks for specialized monitoring:

```python
import dspy
from dspy.utils.callback import BaseCallback
import logging
import time
from typing import Any

logger = logging.getLogger(__name__)

class ProductionMonitoringCallback(BaseCallback):
    """Track cost, latency, and errors in production."""

    def __init__(self):
        super().__init__()
        self.total_cost = 0.0
        self.total_tokens = 0
        self.call_count = 0
        self.errors = []
        self.start_times = {}

    def on_lm_start(self, call_id: str, instance: Any, inputs: dict[str, Any]):
        """Called when LM is invoked."""
        self.start_times[call_id] = time.time()

    def on_lm_end(self, call_id: str, outputs: dict[str, Any] | None, exception: Exception | None = None):
        """Called after LM finishes."""
        if exception:
            self.errors.append(str(exception))
            logger.error(f"LLM error: {exception}")
            return

        # Calculate latency
        start = self.start_times.pop(call_id, time.time())
        latency = time.time() - start

        # Extract usage from outputs
        usage = outputs.get('usage', {}) if isinstance(outputs, dict) else {}
        tokens = usage.get('total_tokens', 0)
        model = outputs.get('model', 'unknown') if isinstance(outputs, dict) else 'unknown'
        cost = self._estimate_cost(model, usage)

        self.total_tokens += tokens
        self.total_cost += cost
        self.call_count += 1

        logger.info(f"LLM call: {latency:.2f}s, {tokens} tokens, ${cost:.4f}")

    def _estimate_cost(self, model: str, usage: dict[str, int]) -> float:
        """Estimate cost based on model pricing (update rates for 2026)."""
        pricing = {
            'gpt-4o-mini': {'input': 0.00015 / 1000, 'output': 0.0006 / 1000},
            'gpt-4o': {'input': 0.0025 / 1000, 'output': 0.01 / 1000},
        }
        model_key = next((k for k in pricing if k in model), 'gpt-4o-mini')
        input_cost = usage.get('prompt_tokens', 0) * pricing[model_key]['input']
        output_cost = usage.get('completion_tokens', 0) * pricing[model_key]['output']
        return input_cost + output_cost

    def get_metrics(self) -> dict[str, Any]:
        """Return aggregated metrics."""
        return {
            'total_cost': self.total_cost,
            'total_tokens': self.total_tokens,
            'call_count': self.call_count,
            'avg_cost_per_call': self.total_cost / max(self.call_count, 1),
            'error_count': len(self.errors)
        }

# Usage
monitor = ProductionMonitoringCallback()
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"), callbacks=[monitor])

# Run your program
qa = dspy.ChainOfThought("question -> answer")
for question in questions:
    result = qa(question=question)

# Get metrics
metrics = monitor.get_metrics()
print(f"Total cost: ${metrics['total_cost']:.2f}")
print(f"Total calls: {metrics['call_count']}")
print(f"Errors: {metrics['error_count']}")
```

### Phase 4: Sampling for High-Volume Production

For high-traffic applications, sample traces to reduce overhead:

```python
import random
from dspy.utils.callback import BaseCallback
from typing import Any

class SamplingCallback(BaseCallback):
    """Sample 10% of traces."""

    def __init__(self, sample_rate: float = 0.1):
        super().__init__()
        self.sample_rate = sample_rate
        self.sampled_calls = []

    def on_lm_end(self, call_id: str, outputs: dict[str, Any] | None, exception: Exception | None = None):
        """Sample a subset of LM calls."""
        if random.random() < self.sample_rate:
            self.sampled_calls.append({
                'call_id': call_id,
                'outputs': outputs,
                'exception': exception
            })

# Use with high-volume apps
callback = SamplingCallback(sample_rate=0.1)
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"), callbacks=[callback])
```

## Best Practices

1. **Use inspect_history() for debugging** - Quick inspection during development
2. **MLflow for comprehensive tracing** - Automatic instrumentation in production
3. **Sample high-volume traces** - Reduce overhead with 1-10% sampling
4. **Privacy-aware logging** - Redact PII before logging
5. **Async callbacks** - Non-blocking callbacks for production

## Limitations

- Callbacks are synchronous by default (can block LLM calls)
- MLflow tracing adds ~5-10ms overhead per call
- inspect_history() only stores recent calls (last 100 by default)
- Custom callbacks don't capture internal optimizer steps
- Cost estimation requires manual pricing table updates

## Official Documentation

- **DSPy Documentation**: https://dspy.ai/
- **DSPy GitHub**: https://github.com/stanfordnlp/dspy
- **Observability Guide**: https://dspy.ai/tutorials/observability/

© OmidZamani · MIT · OmidZamani/dspy-skills

Похожие скиллы

Все скиллы по теме «ИИ и ML» →
skill-creator официальный anthropics Помогает создать новый скилл, доработать существующий и проверить результат через тестовые промпты и оценки. 414 180установок writing-for-agents Matt Pocock Помогает писать скиллы и документы с инструкциями для агентов. Пригодится при правках AGENTS.md, CLAUDE.md и связанных справочных файлов. 466 719установок media-use heygen-com Находит и генерирует ассеты для видео в HyperFrames — музыку, дикторский голос, аватары и эффекты. Сохраняет всё локально в assets. CX Codex +1 1 100 000установок mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. 130 949установок subagent-driven-development Jesse Vincent Скилл выполняет план через отдельных субагентов для каждой задачи и проверяет результат после каждого шага. Подходит для независимых задач в одной сессии. CX Codex 237 746установок orchestration stablyai Координирует воркеров Orca через DAG задач, циклы супервизора и цепочки сообщений. Пригодится для распределения сложной работы между агентами. CX Codex +1 350 300установок

Из того же набора7

dspy-signature-designer Помогает описать входы и выходы модуля DSPy через типизированные сигнатуры. Пригодится, когда ответ модели нужно загнать в строгую схему. CX Codex +1 ★ 124звёзд репо dspy-rag-pipeline Строит пайплайны retrieval-augmented generation с ColBERTv2, которые можно систематически улучшать. Пригодится, если вопросы требуют поиска по собственному корпусу документов и факт-чекирования ответов. CX Codex +1 ★ 124звёзд репо dspy-optimizer-selection Помогает выбрать оптимизатор DSPy под данные и бюджет: от LabeledFewShot до GEPA и BetterTogether. Пригодится, когда неясно, с чего начать компиляцию программы. CX Codex +1 ★ 124звёзд репо dspy-mcp-tool-integration Скилл показывает, как подключить MCP-сервер к DSPy: конвертировать его инструменты в dspy.Tool и вызывать их из async-агента. CX Codex +1 ★ 124звёзд репо dspy-finetune-bootstrap Дистиллирует работающую DSPy-программу в веса меньшей модели через BootstrapFinetune, чтобы снизить стоимость инференса и ускорить ответы. CX Codex +1 ★ 124звёзд репо dspy-better-together Скилл помогает собрать цепочку из промпт- и весовых оптимизаторов DSPy, сравнить промежуточные программы и вернуть лучшую. CX Codex +1 ★ 124звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой