Install any skill in seconds. Free to start, no credit card required.
Get Started Free →This skill should be used when working with DSPy.rb, a Ruby framework for building type-safe, composable LLM applications. Use this when implementing predictable AI features, creating LLM signatures and modules, configuring language model providers (OpenAI, Anthropic, Gemini, Ollama), building agent systems with tools, optimizing prompts, or testing LLM-powered functionality in Ruby applications.
.claude/skills/davekilleen-dspy-ruby/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 86% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 139% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 51% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 192% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 80% | 0% |
DSPy.rb is a Ruby framework that enables developers to program LLMs, not prompt them. Instead of manually crafting prompts, define application requirements through type-safe, composable modules that can be tested, optimized, and version-controlled like regular code.
This skill provides comprehensive guidance on:
Create input/output contracts for LLM operations with runtime type checking.
When to use: Defining any LLM task, from simple classification to complex analysis.
Quick reference:
rubyclass EmailClassificationSignature < DSPy::Signature description "Classify customer support emails" input do const :email_subject, String const :email_body, String end output do const :category, T.enum(["Technical", "Billing", "General"]) const :priority, T.enum(["Low", "Medium", "High"]) end end
Templates: See assets/signature-template.rb for comprehensive examples including:
Best practices:
desc: parameterFull documentation: See references/core-concepts.md sections on Signatures and Type Safety.
Build reusable, chainable modules that encapsulate LLM operations.
When to use: Implementing any LLM-powered feature, especially complex multi-step workflows.
Quick reference:
rubyclass EmailProcessor < DSPy::Module def initialize super @classifier = DSPy::Predict.new(EmailClassificationSignature) end def forward(email_subject:, email_body:) @classifier.forward( email_subject: email_subject, email_body: email_body ) end end
Templates: See assets/module-template.rb for comprehensive examples including:
Module composition: Chain modules together to create complex workflows:
rubyclass Pipeline < DSPy::Module def initialize super @step1 = Classifier.new @step2 = Analyzer.new @step3 = Responder.new end def forward(input) result1 = @step1.forward(input) result2 = @step2.forward(result1) @step3.forward(result2) end end
Full documentation: See references/core-concepts.md sections on Modules and Module Composition.
Choose the right predictor for your task:
Predict: Basic LLM inference with type-safe inputs/outputs
rubypredictor = DSPy::Predict.new(TaskSignature) result = predictor.forward(input: "data")
ChainOfThought: Adds automatic reasoning for improved accuracy
rubypredictor = DSPy::ChainOfThought.new(TaskSignature) result = predictor.forward(input: "data") # Returns: { reasoning: "...", output: "..." }
ReAct: Tool-using agents with iterative reasoning
rubypredictor = DSPy::ReAct.new( TaskSignature, tools: [SearchTool.new, CalculatorTool.new], max_iterations: 5 )
CodeAct: Dynamic code generation (requires dspy-code_act gem)
rubypredictor = DSPy::CodeAct.new(TaskSignature) result = predictor.forward(task: "Calculate factorial of 5")
When to use each:
Full documentation: See references/core-concepts.md section on Predictors.
Support for OpenAI, Anthropic Claude, Google Gemini, Ollama, and OpenRouter.
Quick configuration examples:
ruby# OpenAI DSPy.configure do |c| c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY']) end # Anthropic Claude DSPy.configure do |c| c.lm = DSPy::LM.new('anthropic/claude-3-5-sonnet-20241022', api_key: ENV['ANTHROPIC_API_KEY']) end # Google Gemini DSPy.configure do |c| c.lm = DSPy::LM.new('gemini/gemini-1.5-pro', api_key: ENV['GOOGLE_API_KEY']) end # Local Ollama (free, private) DSPy.configure do |c| c.lm = DSPy::LM.new('ollama/llama3.1') end
Templates: See assets/config-template.rb for comprehensive examples including:
Provider compatibility matrix:
| Feature | OpenAI | Anthropic | Gemini | Ollama | |---------|--------|-----------|--------|--------| | Structured Output | ✅ | ✅ | ✅ | ✅ | | Vision (Images) | ✅ | ✅ | ✅ | ⚠️ Limited | | Image URLs | ✅ | ❌ | ❌ | ❌ | | Tool Calling | ✅ | ✅ | ✅ | Varies |
Cost optimization strategy:
Full documentation: See references/providers.md for all configuration options, provider-specific features, and troubleshooting.
Process images alongside text using the unified DSPy::Image interface.
Quick reference:
rubyclass VisionSignature < DSPy::Signature description "Analyze image and answer questions" input do const :image, DSPy::Image const :question, String end output do const :answer, String end end predictor = DSPy::Predict.new(VisionSignature) result = predictor.forward( image: DSPy::Image.from_file("path/to/image.jpg"), question: "What objects are visible?" )
Image loading methods:
ruby# From file DSPy::Image.from_file("path/to/image.jpg") # From URL (OpenAI only) DSPy::Image.from_url("https://example.com/image.jpg") # From base64 DSPy::Image.from_base64(base64_data, mime_type: "image/jpeg")
Provider support:
Full documentation: See references/core-concepts.md section on Multimodal Support.
Write standard RSpec tests for LLM logic.
Quick reference:
rubyRSpec.describe EmailClassifier do before do DSPy.configure do |c| c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY']) end end it 'classifies technical emails correctly' do classifier = EmailClassifier.new result = classifier.forward( email_subject: "Can't log in", email_body: "Unable to access account" ) expect(result[:category]).to eq('Technical') expect(result[:priority]).to be_in(['High', 'Medium', 'Low']) end end
Testing patterns:
Full documentation: See references/optimization.md section on Testing.
Automatically improve prompts and modules using optimization techniques.
MIPROv2 optimization:
rubyrequire 'dspy/mipro' # Define evaluation metric def accuracy_metric(example, prediction) example[:expected_output][:category] == prediction[:category] ? 1.0 : 0.0 end # Prepare training data training_examples = [ { input: { email_subject: "...", email_body: "..." }, expected_output: { category: 'Technical' } }, # More examples... ] # Run optimization optimizer = DSPy::MIPROv2.new( metric: method(:accuracy_metric), num_candidates: 10 ) optimized_module = optimizer.compile( EmailClassifier.new, trainset: training_examples )
A/B testing different approaches:
ruby# Test ChainOfThought vs ReAct approach_a_score = evaluate_approach(ChainOfThoughtModule, test_set) approach_b_score = evaluate_approach(ReActModule, test_set)
Full documentation: See references/optimization.md section on Optimization.
Track performance, token usage, and behavior in production.
OpenTelemetry integration:
rubyrequire 'opentelemetry/sdk' OpenTelemetry::SDK.configure do |c| c.service_name = 'my-dspy-app' c.use_all end # DSPy automatically creates traces
Langfuse tracing:
rubyDSPy.configure do |c| c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY']) c.langfuse = { public_key: ENV['LANGFUSE_PUBLIC_KEY'], secret_key: ENV['LANGFUSE_SECRET_KEY'] } end
Custom monitoring:
Full documentation: See references/optimization.md section on Observability.
bashgem install dspy dspy-openai # or dspy-anthropic, dspy-gemini
assets/config-template.rb):rubyrequire 'dspy' DSPy.configure do |c| c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY']) end
assets/signature-template.rb):rubyclass MySignature < DSPy::Signature description "Clear description of task" input do const :input_field, String, desc: "Description" end output do const :output_field, String, desc: "Description" end end
assets/module-template.rb):rubyclass MyModule < DSPy::Module def initialize super @predictor = DSPy::Predict.new(MySignature) end def forward(input_field:) @predictor.forward(input_field: input_field) end end
rubymodule_instance = MyModule.new result = module_instance.forward(input_field: "test") puts result[:output_field]
references/optimization.md):rubyRSpec.describe MyModule do it 'produces expected output' do result = MyModule.new.forward(input_field: "test") expect(result[:output_field]).to be_a(String) end end
rubygem 'dspy' gem 'dspy-openai' # or other provider
config/initializers/dspy.rb (see assets/config-template.rb for full example):rubyrequire 'dspy' DSPy.configure do |c| c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY']) end
app/llm/ directory:ruby# app/llm/email_classifier.rb class EmailClassifier < DSPy::Module # Implementation here end
rubyclass EmailsController < ApplicationController def classify classifier = EmailClassifier.new result = classifier.forward( email_subject: params[:subject], email_body: params[:body] ) render json: result end end
rubyclass AnalysisPipeline < DSPy::Module def initialize super @extract = DSPy::Predict.new(ExtractSignature) @analyze = DSPy::ChainOfThought.new(AnalyzeSignature) @summarize = DSPy::Predict.new(SummarizeSignature) end def forward(text:) extracted = @extract.forward(text: text) analyzed = @analyze.forward(data: extracted[:data]) @summarize.forward(analysis: analyzed[:result]) end end
rubyclass ResearchAgent < DSPy::Module def initialize super @agent = DSPy::ReAct.new( ResearchSignature, tools: [ WebSearchTool.new, DatabaseQueryTool.new, SummarizerTool.new ], max_iterations: 10 ) end def forward(question:) @agent.forward(question: question) end end class WebSearchTool < DSPy::Tool def call(query:) results = perform_search(query) { results: results } end end
rubyclass SmartRouter < DSPy::Module def initialize super @classifier = DSPy::Predict.new(ClassifySignature) @simple_handler = SimpleModule.new @complex_handler = ComplexModule.new end def forward(input:) classification = @classifier.forward(text: input) if classification[:complexity] == 'Simple' @simple_handler.forward(input: input) else @complex_handler.forward(input: input) end end end
rubyclass RobustModule < DSPy::Module MAX_RETRIES = 3 def forward(input, retry_count: 0) begin @predictor.forward(input) rescue DSPy::ValidationError => e if retry_count < MAX_RETRIES sleep(2 ** retry_count) forward(input, retry_count: retry_count + 1) else # Fallback to default or raise raise end end end end
This skill includes comprehensive reference materials and templates:
Trigger this skill when:
Other measured skills in the registry, with their headline benchmark lift.