Installation & Setup

Installation

Add DSPy.rb to your Gemfile:

gem 'dspy'

Or install it directly:

gem install dspy

For bleeding-edge features, you can install from GitHub:

gem 'dspy', github: 'vicentereig/dspy.rb'

Required Dependencies

DSPy.rb requires Ruby 3.3+ and automatically installs these dependencies:

  • Core dependencies: dry-configurable (~> 1.0), dry-logger (~> 1.0), async (~> 2.29)
  • LLM provider clients: openai (~> 0.22.0), anthropic (~> 1.5.0), gemini-ai (~> 4.3)
  • Sorbet integration: sorbet-runtime (~> 0.5), sorbet-schema (~> 0.3)
  • Other: informers (~> 1.2), opentelemetry-sdk (~> 1.8)

You don’t need to add these to your Gemfile—they’re installed automatically when you install dspy.

Observability

DSPy.rb uses structured logging for observability. The logs can be parsed and sent to any monitoring platform you prefer.

Configuration

Basic Configuration

# Configure DSPy with your LLM provider
DSPy.configure do |c|
  c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
  # or
  c.lm = DSPy::LM.new('anthropic/claude-3-sonnet', api_key: ENV['ANTHROPIC_API_KEY'])
  # or use Ollama for local models
  c.lm = DSPy::LM.new('ollama/llama3.2')
  # or use OpenRouter for access to multiple providers (auto-fallback enabled)
  c.lm = DSPy::LM.new('openrouter/deepseek/deepseek-chat-v3.1:free', api_key: ENV['OPENROUTER_API_KEY'])
end

Environment Variables

Set up your API keys:

# OpenAI
export OPENAI_API_KEY=sk-your-key-here

# Anthropic
export ANTHROPIC_API_KEY=sk-ant-your-key-here

# OpenRouter (access to multiple providers)
export OPENROUTER_API_KEY=sk-or-your-key-here

# Ollama (no API key needed for local instances)

# Optional: Observability platforms
export OTEL_SERVICE_NAME=my-dspy-app
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export LANGFUSE_SECRET_KEY=sk_your_key
export LANGFUSE_PUBLIC_KEY=pk_your_key
export NEW_RELIC_LICENSE_KEY=your_license_key

Advanced Configuration

DSPy.configure do |c|
  # LLM Configuration
  c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])

  # Logging Configuration
  c.logger = Dry.Logger(:dspy, formatter: :json) do |logger|
    logger.add_backend(stream: 'log/dspy.log')
  end
end

Provider Setup

OpenAI Setup

  1. Sign up at OpenAI
  2. Create an API key
  3. Set the environment variable:
    export OPENAI_API_KEY=sk-your-key-here
    
  4. Use in DSPy:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
    end
    

Anthropic Setup

  1. Sign up at Anthropic
  2. Create an API key
  3. Set the environment variable:
    export ANTHROPIC_API_KEY=sk-ant-your-key-here
    
  4. Use in DSPy:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('anthropic/claude-3-sonnet', api_key: ENV['ANTHROPIC_API_KEY'])
    end
    

OpenRouter Setup (Multiple Providers)

  1. Sign up at OpenRouter
  2. Create an API key
  3. Set the environment variable:
    export OPENROUTER_API_KEY=sk-or-your-key-here
    
  4. Use in DSPy:
    DSPy.configure do |c|
      # Basic usage - structured outputs enabled by default, auto-fallback if needed
      c.lm = DSPy::LM.new('openrouter/openai/gpt-5-nano',
        api_key: ENV['OPENROUTER_API_KEY']
     )
    end
    
  5. With custom headers for app attribution:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('openrouter/anthropic/claude-3.5-sonnet',
        api_key: ENV['OPENROUTER_API_KEY'],
        http_referrer: 'https://your-app.com',
        x_title: 'Your App Name'
      )
    end
    
  6. For models that don’t support structured outputs, explicitly disable:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('openrouter/deepseek/deepseek-chat-v3.1:free',
        api_key: ENV['OPENROUTER_API_KEY'],
        structured_outputs: false  # Skip structured output attempt entirely
      )
    end
    
  7. Models with native structured output support work seamlessly:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('openrouter/x-ai/grok-4-fast:free',
        api_key: ENV['OPENROUTER_API_KEY']
      )  # structured_outputs: true by default
    end
    

Ollama Setup (Local Models)

  1. Install Ollama from ollama.com
  2. Pull a model:
    ollama pull llama3.2
    
  3. Use in DSPy (no API key needed):
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('ollama/llama3.2')
    end
    
  4. For remote Ollama instances:
    DSPy.configure do |c|
      c.lm = DSPy::LM.new('ollama/llama3.2',
        base_url: 'https://my-ollama.example.com/v1',
        api_key: 'optional-auth-token'
      )
    end
    

Structured Outputs Support

Different providers support structured JSON extraction in different ways:

Provider Structured Outputs How to Enable
OpenAI ✅ Native JSON mode structured_outputs: true
Gemini ✅ Native JSON schema structured_outputs: true
Anthropic ✅ Tool-based extraction (default)
✅ Enhanced prompting
structured_outputs: true (default)
structured_outputs: false
Ollama ✅ OpenAI-compatible JSON structured_outputs: true
OpenRouter ⚠️ Varies by model Check model capabilities

Example:

# OpenAI with native structured outputs
DSPy.configure do |c|
  c.lm = DSPy::LM.new(
    'openai/gpt-4o-mini',
    api_key: ENV['OPENAI_API_KEY'],
    structured_outputs: true
  )
end

# Anthropic - tool extraction by default (can be disabled)
DSPy.configure do |c|
  # Use tool-based extraction (default, most reliable)
  c.lm = DSPy::LM.new(
    'anthropic/claude-sonnet-4-5-20250929',
    api_key: ENV['ANTHROPIC_API_KEY'],
    structured_outputs: true  # Default, can be omitted
  )

  # Or use enhanced prompting instead
  # c.lm = DSPy::LM.new(
  #   'anthropic/claude-sonnet-4-5-20250929',
  #   api_key: ENV['ANTHROPIC_API_KEY'],
  #   structured_outputs: false  # Use enhanced prompting extraction
  # )
end

Verification

Test your installation:

require 'dspy'

# Configure with your provider
DSPy.configure do |c|
  c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
end

# Test basic functionality
class TestSignature < DSPy::Signature
  description "Test DSPy installation"

  input do
    const :message, String
  end

  output do
    const :response, String
  end
end

predictor = DSPy::Predict.new(TestSignature)
result = predictor.call(message: "Hello, DSPy!")

puts "✅ DSPy is working! Response: #{result.response}"

Troubleshooting

Common Issues

“LoadError: cannot load such file”

  • Make sure you’ve added the gem to your Gemfile and run bundle install

“API key not found”

  • Verify your environment variables are set correctly
  • Check that you’re using the correct provider prefix (e.g., openai/gpt-4, not just gpt-4)

“Unsupported provider”

  • DSPy requires provider prefixes. Use openai/model-name, anthropic/model-name, or ollama/model-name
  • Legacy format without provider is no longer supported

“Connection refused” with Ollama

  • Make sure Ollama is running: ollama serve
  • Check that the model is downloaded: ollama list
  • Verify the base URL if using a custom port

Sorbet type errors

  • Make sure you’re using the correct types in your signatures
  • Check that input/output structs match your signature definitions

Getting Help

  • Check the documentation
  • Report issues on GitHub
  • Email the maintainer directly for urgent issues