Examples

Examples are type-safe training and evaluation data objects. DSPy.rb provides two types of examples: basic examples for evaluation and few-shot examples for prompt enhancement.

Creating Basic Examples

class ClassifyText < DSPy::Signature
  description "Classify text sentiment"
  
  class Sentiment < T::Enum
    enums do
      Positive = new('positive')
      Negative = new('negative')
      Neutral = new('neutral')
    end
  end
  
  input do
    const :text, String
  end
  
  output do
    const :sentiment, Sentiment
    const :confidence, Float
  end
end

# Create examples with known correct outputs
examples = [
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "I absolutely love this product!" },
    expected: { 
      sentiment: ClassifyText::Sentiment::Positive, 
      confidence: 0.95 
    }
  ),
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "This is the worst experience ever." },
    expected: { 
      sentiment: ClassifyText::Sentiment::Negative, 
      confidence: 0.92 
    }
  ),
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "The weather is okay today." },
    expected: { 
      sentiment: ClassifyText::Sentiment::Neutral, 
      confidence: 0.78 
    }
  )
]

Type Safety and Validation

Examples are automatically validated against your signature’s type constraints:

# This will raise a validation error
invalid_example = DSPy::Example.new(
  signature_class: ClassifyText,
  input: { text: "Sample text" },
  expected: { 
    sentiment: "positive",  # String instead of Sentiment enum - ERROR!
    confidence: 1.5
  }
)
# => ArgumentError: Type error in expected output for ClassifyText: ...

Working with Examples

Accessing Example Data

example = DSPy::Example.new(
  signature_class: ClassifyText,
  input: { text: "Great product!" },
  expected: { sentiment: ClassifyText::Sentiment::Positive, confidence: 0.9 }
)

# Access input values
input_values = example.input_values
# => { text: "Great product!" }

# Access expected output values
expected_values = example.expected_values  
# => { sentiment: #<Sentiment::Positive>, confidence: 0.9 }

# Convert to hash for serialization
example.to_h
# => { signature_class: "ClassifyText", input: {...}, expected: {...} }

Evaluating Predictions

# Test if a prediction matches the expected output
predictor = DSPy::Predict.new(ClassifyText)
result = predictor.call(text: "Great product!")

# Check if prediction matches expected
if example.matches_prediction?(result)
  puts "Prediction matches expected output!"
else
  puts "Prediction differs from expected output"
end

Batch Validation

# Validate multiple examples at once
examples_data = [
  {
    input: { text: "Great product!" },
    expected: { sentiment: ClassifyText::Sentiment::Positive, confidence: 0.9 }
  },
  {
    input: { text: "Terrible service." },
    expected: { sentiment: ClassifyText::Sentiment::Negative, confidence: 0.8 }
  }
]

validated_examples = DSPy::Example.validate_batch(ClassifyText, examples_data)
# Returns array of validated DSPy::Example objects

Few-Shot Examples

Few-shot examples provide context to improve model performance:

# Create few-shot examples
few_shot_examples = [
  DSPy::FewShotExample.new(
    input: { text: "I love this product!" },
    output: { sentiment: "positive", confidence: 0.95 },
    reasoning: "The phrase 'I love' indicates strong positive sentiment."
  ),
  DSPy::FewShotExample.new(
    input: { text: "This is terrible." },
    output: { sentiment: "negative", confidence: 0.9 },
    reasoning: "The word 'terrible' clearly indicates negative sentiment."
  )
]

# Use with predictor
predictor = DSPy::Predict.new(ClassifyText)
optimized_predictor = predictor.with_examples(few_shot_examples)

result = optimized_predictor.call(text: "This movie was incredible!")

Working with FewShotExample

# Access FewShotExample properties
few_shot = DSPy::FewShotExample.new(
  input: { text: "Great product!" },
  output: { sentiment: "positive" },
  reasoning: "Positive language indicates good sentiment."
)

# Convert to hash
few_shot.to_h
# => { input: {...}, output: {...}, reasoning: "..." }

# Create from hash
few_shot = DSPy::FewShotExample.from_h({
  input: { text: "Bad experience" },
  output: { sentiment: "negative" },
  reasoning: "Negative words indicate poor sentiment"
})

# Generate prompt section
few_shot.to_prompt_section
# => "## Input\n```json\n{...}\n```\n## Reasoning\n...\n## Output\n```json\n{...}\n```"

Serialization

# Save and load examples
example = DSPy::Example.new(
  signature_class: ClassifyText,
  input: { text: "Sample text" },
  expected: { sentiment: ClassifyText::Sentiment::Positive, confidence: 0.8 },
  id: "example_1",
  metadata: { source: "manual", created_at: Time.current }
)

# Convert to hash for persistence
example_hash = example.to_h

# Recreate from hash
registry = { "ClassifyText" => ClassifyText }
reloaded_example = DSPy::Example.from_h(example_hash, signature_registry: registry)

Testing Examples

RSpec.describe DSPy::Example do
  let(:signature) { ClassifyText }
  
  describe "validation" do
    it "accepts valid examples" do
      example = DSPy::Example.new(
        signature_class: signature,
        input: { text: "Sample text" },
        expected: { 
          sentiment: ClassifyText::Sentiment::Positive,
          confidence: 0.8
        }
      )
      
      expect(example.input_values[:text]).to eq("Sample text")
      expect(example.expected_values[:sentiment]).to be_a(ClassifyText::Sentiment)
    end
    
    it "rejects invalid input types" do
      expect {
        DSPy::Example.new(
          signature_class: signature,
          input: { invalid_field: "value" },
          expected: { sentiment: ClassifyText::Sentiment::Positive, confidence: 0.8 }
        )
      }.to raise_error(ArgumentError)
    end
  end
end

Integration with Evaluation

# Examples work with the evaluation framework
examples = [
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "Great product!" },
    expected: { sentiment: ClassifyText::Sentiment::Positive, confidence: 0.9 }
  ),
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "Terrible service." },
    expected: { sentiment: ClassifyText::Sentiment::Negative, confidence: 0.8 }
  )
]

# Use with DSPy::Evaluate
predictor = DSPy::Predict.new(ClassifyText)
evaluator = DSPy::Evaluate.new(metric: :exact_match)

results = evaluator.evaluate(examples: examples) do |example|
  predictor.call(example.input_values)
end

puts results.score  # Accuracy score

Usage with ChainOfThought

# FewShotExamples can include reasoning for ChainOfThought
reasoning_examples = [
  DSPy::FewShotExample.new(
    input: { text: "I love this!" },
    output: { sentiment: "positive" },
    reasoning: "The phrase 'I love' shows strong positive emotion."
  )
]

# Use with ChainOfThought predictor
cot_predictor = DSPy::ChainOfThought.new(ClassifyText)
optimized_cot = cot_predictor.with_examples(reasoning_examples)

result = optimized_cot.call(text: "Amazing product!")
puts result.reasoning  # Will include step-by-step reasoning

Best Practices

1. Balanced Examples

# Ensure balanced representation across all output categories
def create_balanced_examples
  categories = ClassifyText::Sentiment.values
  examples_per_category = 20
  
  categories.flat_map do |sentiment|
    create_examples_for_sentiment(sentiment, count: examples_per_category)
  end
end

2. Include Edge Cases

# Include edge cases and boundary conditions
edge_case_examples = [
  # Minimal text
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "Ok." },
    expected: { sentiment: ClassifyText::Sentiment::Neutral, confidence: 0.6 }
  ),
  
  # Mixed sentiment
  DSPy::Example.new(
    signature_class: ClassifyText,
    input: { text: "I love the product but hate the price." },
    expected: { sentiment: ClassifyText::Sentiment::Neutral, confidence: 0.7 }
  )
]

3. Type Safety

# Always ensure types match your signature
example = DSPy::Example.new(
  signature_class: ClassifyText,
  input: { text: "Sample text" },
  expected: { 
    sentiment: ClassifyText::Sentiment::Positive,  # Use enum, not string
    confidence: 0.8                                # Use Float, not String
  }
)

Examples provide the foundation for evaluation and few-shot prompting with type safety through Sorbet integration.