Skip to main content
skill CX Codex

dspy-output-refinement-constraints — Claude Code skill for validation

This skill shows how to validate DSPy outputs, refine them with dspy.Refine, and choose among candidates with dspy.BestOfN. Use it when generated results must meet format or content rules.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add OmidZamani/dspy-skills --skill dspy-output-refinement-constraints -a claude-code
Open on GitHub

What dspy-output-refinement-constraints does

The skill walks through wrapping a DSPy module with dspy.Refine. A reward function scores its output against checks such as length limits and required terms, then the module can try again. dspy.BestOfN generates candidates and selects one by score. Examples cover JSON validation and structured data extraction.

You need a DSPy module and a reward function that defines your checks. The skill also explains replacing dspy.Assert and dspy.Suggest with dspy.Refine. Each attempt makes an additional LLM call; BestOfN costs scale with the number of candidates.

What it helps with

  • validate required fields in generated JSON
  • enforce a word-count or length limit
  • score an answer against several conditions
  • select a candidate from multiple generations
  • replace checks built with dspy.Assert and dspy.Suggest

Example prompts for the agent

  • Show me how to use dspy.Refine to enforce a length limit and check for a required term.
  • Set up dspy.BestOfN to select a valid JSON result from several candidates.
  • Replace this dspy.Assert check with a reward function and dspy.Refine.

How to install dspy-output-refinement-constraints

1Skills CLI (Vercel)

npx skills add OmidZamani/dspy-skills --skill dspy-output-refinement-constraints -a claude-code

2Manually: put the files in place

~/.claude/skills/dspy-output-refinement-constraints/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/dspy-output-refinement-constraints/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about dspy-output-refinement-constraints

How do I install dspy-output-refinement-constraints in Claude Code?

Run npx skills add OmidZamani/dspy-skills --skill dspy-output-refinement-constraints -a claude-code. The skill file is at ~/.claude/skills/dspy-output-refinement-constraints/SKILL.md.

What does dspy-output-refinement-constraints do?

It explains how to validate DSPy outputs against custom conditions, refine them with dspy.Refine, and select a high-scoring candidate with dspy.BestOfN.

Does each refinement attempt make another LLM call?

Yes. Every attempt adds an LLM call, and dspy.BestOfN costs increase with the number of candidates.

Source text

SKILL.md · MIT
---
name: dspy-output-refinement-constraints
version: "1.0.0"
dspy-compatibility: "3.2.1"
tags: ["evaluation", "reasoning"]
requires-extras: []
description: Use for dspy.Refine, dspy.BestOfN, output constraints, validation, reward functions, and iterative output refinement.
allowed-tools:
  - Read
  - Write
  - Glob
  - Grep
---

# DSPy Output Refinement & Constraints

## Goal

Improve output quality using iterative refinement (dspy.Refine) and best-of-N selection (dspy.BestOfN) with custom constraint validation.

## When to Use

- Outputs need format validation (JSON, specific structure)
- Length constraints (max tokens, word count)
- Content requirements (must include X, avoid Y)
- Quality improvement through multiple attempts
- Replacing deprecated Assert/Suggest patterns

## Related Skills

- Design signatures: [dspy-signature-designer](../dspy-signature-designer/SKILL.md)
- Optimize programs: [dspy-miprov2-optimizer](../dspy-miprov2-optimizer/SKILL.md)
- Evaluate quality: [dspy-evaluation-suite](../dspy-evaluation-suite/SKILL.md)

## Inputs

| Input | Type | Description |
|-------|------|-------------|
| `module` | `dspy.Module` | Module to refine |
| `reward_fn` | `callable` | Constraint validation function |
| `N` | `int` | Number of attempts |
| `threshold` | `float` | Minimum reward to accept |

## Outputs

| Output | Type | Description |
|--------|------|-------------|
| `refined_output` | `dspy.Prediction` | Validated, refined result |

## Workflow

### Phase 1: dspy.Refine for Iterative Improvement

Refine iteratively improves outputs across multiple attempts:

```python
import dspy

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

# Base module
summarizer = dspy.ChainOfThought("document -> summary: str")

# Reward function: checks constraints
def summary_reward(args, pred):
    summary = pred.summary
    word_count = len(summary.split())

    if word_count > 100 or len(summary) < 50:
        return 0.0
    if "important" not in summary.lower():
        return 0.5
    return 1.0

# Refine module
refined_summarizer = dspy.Refine(
    module=summarizer,
    reward_fn=summary_reward,
    N=3,
    threshold=1.0
)

# Use it
result = refined_summarizer(document="Long document text here...")
print(result.summary)
```

### Phase 2: dspy.BestOfN for Selection

Generate N outputs and pick the best:

```python
import dspy

def json_reward(args, pred):
    """Validate JSON format and fields."""
    import json
    try:
        data = json.loads(pred.output)
        if not {'name', 'age', 'email'}.issubset(data.keys()):
            return 0.3
        if '@' not in data.get('email', ''):
            return 0.5
        return 1.0
    except json.JSONDecodeError:
        return 0.0

# BestOfN: try 5 times, pick best
extractor = dspy.Predict("text -> output: str")
best_extractor = dspy.BestOfN(module=extractor, reward_fn=json_reward, N=5, threshold=1.0)

result = best_extractor(text="John Doe, 30 years old, [email protected]")
print(result.output)  # Best valid JSON
```

### Phase 3: Multi-Constraint Reward Functions

Complex validation with scoring:

```python
import dspy
import re

def comprehensive_reward(args, pred):
    """Validate format, length, and content."""
    text = pred.answer
    score = 0.0

    # Length: 50-150 words (33%)
    word_count = len(text.split())
    if 50 <= word_count <= 150:
        score += 0.33

    # Format: capitalized, ends with period (33%)
    if re.match(r'^[A-Z]', text) and text.endswith('.'):
        score += 0.33

    # Content: required terms present (34%)
    if all(term in text.lower() for term in ['data', 'analysis']):
        score += 0.34

    return score

# Use with Refine
qa = dspy.ChainOfThought("question -> answer: str")
refined_qa = dspy.Refine(module=qa, reward_fn=comprehensive_reward, N=4, threshold=0.9)

result = refined_qa(question="What is data science?")
```

## Production Example

```python
import dspy
import json
import logging

logger = logging.getLogger(__name__)

class StructuredExtractor(dspy.Module):
    """Extract structured data with validation."""

    def __init__(self):
        self.extractor = dspy.Predict(
            "text -> json_output: str"
        )
        self.refined = dspy.Refine(
            module=self.extractor,
            reward_fn=self.validation_reward,
            N=3,
            threshold=0.9
        )

    def validation_reward(self, args, pred):
        """Validate JSON structure and business logic."""
        try:
            data = json.loads(pred.json_output)
            score = 0.0

            # Required fields
            if {'product', 'price', 'quantity'}.issubset(data.keys()):
                score += 0.4

            # Type validation
            if isinstance(data.get('price'), (int, float)) and data['price'] > 0:
                score += 0.3
            if isinstance(data.get('quantity'), int) and data['quantity'] > 0:
                score += 0.3

            return score
        except (json.JSONDecodeError, TypeError) as e:
            logger.warning(f"Validation failed: {e}")
            return 0.0

    def forward(self, text: str):
        try:
            return self.refined(text=text)
        except Exception as e:
            logger.error(f"Extraction failed: {e}")
            return dspy.Prediction(json_output='{}')

# Usage
extractor = StructuredExtractor()
result = extractor(text="iPhone 15, $999, quantity: 50")
print(result.json_output)
```

## Migration from Assert/Suggest

DSPy 2.6+ deprecates `dspy.Assert`/`dspy.Suggest`. Use Refine with reward functions:

```python
# Old: dspy.Assert(len(output) < 100, "Too long")
# New:
def reward(args, pred):
    return 1.0 if len(pred.output) < 100 else 0.0

refined = dspy.Refine(module=module, reward_fn=reward, N=3, threshold=1.0)
```

## Best Practices

1. **Score gradually** - Use 0.0-1.0 range, not binary pass/fail
2. **Multiple constraints** - Weight each constraint (e.g., 25% each for 4 checks)
3. **Handle exceptions** - Reward functions should never raise, return 0.0 on error
4. **Limit attempts** - 3-5 attempts for Refine, 5-10 for BestOfN
5. **Log failures** - Track which constraints fail most often

## Limitations

- Each attempt costs an additional LLM call
- Reward functions don't receive feedback prompts (unlike GEPA)
- BestOfN is expensive (N × cost)
- No automatic constraint learning (manual reward design)
- Refine may not improve if base module is fundamentally wrong

## Official Documentation

- **DSPy Documentation**: https://dspy.ai/
- **DSPy GitHub**: https://github.com/stanfordnlp/dspy
- **Refine Module**: https://dspy.ai/api/modules/Refine/

© OmidZamani · MIT · OmidZamani/dspy-skills

Similar skills

All skills for AI and ML →

From the same set23

dspy-reasoning-modules Guides configuration of DSPy 3.2.1 reasoning modules including RLM, ProgramOfThought, CodeAct, and Parallel. Useful for sandboxed code and long documents. CX Codex +1 ★ 124repo stars dspy-react-agent-builder This skill guides you through building DSPy ReAct agents that call tools to handle multi-step tasks. Use it for workflows involving retrieval, calculations, or answers based on external data. CX Codex +1 ★ 124repo stars dspy-rag-pipeline Builds retrieval-augmented generation pipelines powered by ColBERTv2 that can be systematically optimized. Use when questions require searching across your own document corpus and grounding answers in retrieved facts. CX Codex +1 ★ 124repo stars dspy-production-deployment Prepares DSPy 3.2.1 pipelines for production by configuring safe caching, state-only JSON persistence, async calls, and output streaming. CX Codex +1 ★ 124repo stars dspy-optimizer-selection Helps you pick a DSPy optimizer that fits your data and budget, from LabeledFewShot up to GEPA and BetterTogether. Useful when you don't know where to start compiling. CX Codex +1 ★ 124repo stars dspy-optimize-anything Guides AI agents through GEPA reflective evolutionary search for code, prompts, configs, and text artifacts using diagnostic feedback. CX Codex +1 ★ 124repo stars dspy-miprov2-optimizer This skill guides MIPROv2 optimization of DSPy programs, searching for instruction and few-shot demo combinations with Bayesian optimization. Use it to tune a program against training data. CX Codex +1 ★ 124repo stars dspy-mcp-tool-integration A skill that walks through wiring an MCP server into DSPy: turning its tools into dspy.Tool and calling them from an async agent. CX Codex +1 ★ 124repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor