dspy-rs 0.7.0

A DSPy rewrite(not port) to Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
<div align='center'>
<img width="768" alt="logo" src="https://github.com/user-attachments/assets/bdb80520-216e-4742-b016-b71ca6eaac03" />

# DSRs
<em>A high-performance DSPy rewrite in Rust for building LM-powered applications</em>

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![Rust](https://img.shields.io/badge/rust-1.70+-orange.svg)](https://www.rust-lang.org)
[![Crates.io](https://img.shields.io/crates/v/dspy-rs)](https://crates.io/crates/dspy-rs)
[![Documentation](https://docs.rs/dspy-rs/badge.svg)](https://docs.rs/dspy-rs)
[![Build Status](https://img.shields.io/badge/build-passing-green.svg)](#)

[Documentation](https://dsrs.herumbshandilya.com) โ€ข [API Reference](https://docs.rs/dspy-rs) โ€ข [Examples](crates/dspy-rs/examples/) โ€ข [Issues](https://github.com/krypticmouse/dsrs/issues) โ€ข [Discord](https://discord.com/invite/ZAEGgxjPUe)

</div>

---

## ๐Ÿš€ Overview

**DSRs** (DSPy Rust) is a ground-up rewrite of the [DSPy framework](https://github.com/stanfordnlp/dspy) in Rust, designed for building robust, high-performance applications powered by Language Models. Unlike a simple port, DSRs leverages Rust's type system, memory safety, and concurrency features to provide a more efficient and reliable foundation for LM applications.

## ๐Ÿ“ฆ Installation

Add DSRs to your `Cargo.toml`:

```toml
[dependencies]
# Option 1: Use the shorter alias (recommended)
dsrs = { package = "dspy-rs", version = "0.5.0" }

# Option 2: Use the full name
dspy-rs = "0.5.0"
```

Or use cargo:

```bash
# Option 1: Add with alias (recommended)
cargo add dsrs --package dspy-rs

# Option 2: Add with full name
cargo add dspy-rs
```

## ๐Ÿ”ง Quick Start

Here's a simple example to get you started:

```rust
use anyhow::Result;
use dspy_rs::*;

#[Signature]
struct SentimentAnalyzer {
    /// Predict the sentiment of the given text 'Positive', 'Negative', or 'Neutral'.

    #[input]
    pub text: String,

    #[output]
    pub sentiment: String,
}

#[tokio::main]
async fn main() -> Result<()> {
    let lm = LM::builder()
        .api_key(std::env::var("OPENAI_API_KEY")?.into())
        .config(
            LMConfig::builder()
                .model("gpt-4.1-nano".to_string())
                .temperature(0.5)
                .build(),
        )
        .build();

    configure(lm, ChatAdapter);

    // Create a predictor
    let predictor = Predict::new(SentimentAnalyzer::new());

    // Prepare input
    let example = example! {
        "text": "input" => "Acme is a great company with excellent customer service.",
    };

    // Execute prediction
    let result = predictor.forward(example).await?;

    println!("Answer: {}", result.get("sentiment", None));

    Ok(())
}

```
Result:
```
Answer: "Positive"
```

## ๐Ÿ—๏ธ Architecture

DSRs follows a modular architecture with clear separation of concerns:

```
dsrs/
โ”œโ”€โ”€ core/           # Core abstractions (LM, Module, Signature)
โ”œโ”€โ”€ adapter/        # LM provider adapters (OpenAI, etc.)
โ”œโ”€โ”€ data/           # Data structures (Example, Prediction)
โ”œโ”€โ”€ predictors/     # Built-in predictors (Predict, Chain, etc.)
โ”œโ”€โ”€ evaluate/       # Evaluation framework and metrics
โ””โ”€โ”€ macros/         # Derive macros for signatures
```

### Core Components

#### 1. **Signatures** - Define Input/Output Specifications
```rust
#[Signature(cot)]  // Enable chain-of-thought reasoning
struct TranslationSignature {
    /// Translate the text accurately while preserving meaning
    
    #[input]
    pub text: String,
    
    #[input]
    pub target_language: String,
    
    #[output]
    pub translation: String,
}
```

#### 2. **Modules** - Composable Pipeline Components
```rust
#[derive(Builder)]
pub struct CustomModule {
    predictor: Predict,
}

impl Module for CustomModule {
    async fn forward(&self, inputs: Example) -> Result<Prediction> {
        // Your custom logic here
        self.predictor.forward(inputs).await
    }
}
```

#### 3. **Predictors** - Pre-built LM Interaction Patterns
```rust
// Get prediction
let predict = Predict::new(MySignature::new());
```

#### 4. **Language Models** - Configurable LM Backends
```rust
// Configure with OpenAI
let lm = LM::builder()
    .api_key(secret_key)
    .model("gpt-4")
    .temperature(0.7)
    .max_tokens(1000)
    .build();
```

#### 5. **Evaluation** - Evaluating your Modules

```rust
impl Evaluator for MyModule {
    async fn metric(&self, example: &Example, prediction: &Prediction) -> f32 {
        // Define your custom metric logic
        let expected = example.get("answer", None);
        let predicted = prediction.get("answer", None);
        
        // Example: Exact match metric
        if expected.to_lowercase() == predicted.to_lowercase() {
            1.0
        } else {
            0.0
        }
    }
}

// Evaluate your module
let test_examples = load_test_data();
let module = MyModule::new();

// Automatically runs predictions and computes average metric
let score = module.evaluate(test_examples).await;
println!("Average score: {}", score);
```

#### 6. **Optimization** - Optimize your Modules

DSRs provides two powerful optimizers:

**COPRO (Collaborative Prompt Optimization)**
```rust
#[derive(Optimizable)]
pub struct MyModule {
    #[parameter]
    predictor: Predict,
}

// Create and configure the optimizer
let optimizer = COPRO::builder()
    .breadth(10)  // Number of candidates per iteration
    .depth(3)     // Number of refinement iterations
    .build();

// Prepare training data
let train_examples = load_training_data();

// Compile optimizes the module in-place
let mut module = MyModule::new();
optimizer.compile(&mut module, train_examples).await?;
```

**MIPROv2 (Multi-prompt Instruction Proposal Optimizer v2)** - Advanced optimizer using LLMs
```rust
// MIPROv2 uses a 3-stage process:
// 1. Generate execution traces
// 2. LLM generates candidate prompts with best practices
// 3. Evaluate and select the best prompt

let optimizer = MIPROv2::builder()
    .num_candidates(10)    // Number of candidate prompts to generate
    .num_trials(20)        // Number of evaluation trials
    .minibatch_size(25)    // Examples per evaluation
    .temperature(1.0)      // Temperature for prompt generation
    .build();

optimizer.compile(&mut module, train_examples).await?;
```

See `examples/08-optimize-mipro.rs` for a complete example (requires `parquet` feature).

**Component Freezing:**
```rust
// The Optimizable derive macro automatically implements the trait and marks Module Optimizable
#[derive(Builder, Optimizable)]
pub struct ComplexPipeline {
    #[parameter]  // Mark optimizable components
    analyzer: Predict,
    
    // Non-parameter fields won't be optimized
    summarizer: Predict,
    
    // Non-parameter fields won't be optimized
    config: Config,
}
```

## ๐Ÿ“š Examples

### Example 1: Multi-Step Reasoning Pipeline

```rust
use dsrs::prelude::*;

#[Signature]
struct AnalyzeSignature {
    #[input]
    pub text: String,
    
    #[output]
    pub sentiment: String,
    
    #[output]
    pub key_points: String,
}

#[Signature]
struct SummarizeSignature {
    #[input]
    pub key_points: String,
    
    #[output]
    pub summary: String,
}

#[derive(Builder)]
pub struct AnalysisPipeline {
    analyzer: Predict,
    summarizer: Predict,
}

impl Module for AnalysisPipeline {
    async fn forward(&self, inputs: Example) -> Result<Prediction> {
        // Step 1: Analyze the text
        let analysis = self.analyzer.forward(inputs).await?;
        
        // Step 2: Summarize key points
        let summary_input = example! {
            "key_points": "input" => analysis.get("key_points", None),
        };
        let summary = self.summarizer.forward(summary_input).await?;
        
        // Combine results
        Ok(prediction! {
            "sentiment" => analysis.get("sentiment", None),
            "key_points" => analysis.get("key_points", None),
            "summary" => summary.get("summary", None),
        })
    }
}
```

## ๐Ÿงช Testing

Run the test suite:

```bash
# All tests
cargo test

# Specific test
cargo test test_predictors

# With output
cargo test -- --nocapture

# Run examples
cargo run --example 01-simple
```

## ๐Ÿ› ๏ธ Other Features

### Chain of Thought (CoT) Reasoning
```rust
#[Signature(cot)]  // Enable CoT with attribute
struct ComplexReasoningSignature {
    #[input(desc="Question")
    pub problem: String,
    
    #[output]
    pub solution: String,
}
```

### Optimizer Comparison

| Feature | COPRO | MIPROv2 |
|---------|-------|---------|
| **Approach** | Iterative refinement | LLM-guided generation |
| **Complexity** | Simple | Advanced |
| **Best For** | Quick optimization | Best results |
| **Training Data** | Uses scores | Uses traces & descriptions |
| **Prompting Tips** | No | Yes (15+ best practices) |
| **Program Understanding** | Basic | LLM-generated descriptions |
| **Few-shot Examples** | No | Yes (auto-selected) |

**When to use COPRO:**
- Fast iteration needed
- Simple tasks
- Limited compute budget

**When to use MIPROv2:**
- Best possible results needed
- Complex reasoning tasks
- Have good training data (15+ examples recommended)

---

## ๐Ÿ“ˆ Project Status

โš ๏ธ **Beta Release** - DSRs is in active development. The API is stabilizing but may have breaking changes.

## ๐Ÿค Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/krypticmouse/dsrs.git
cd dsrs

# Build the project
cargo build

# Run tests
cargo test

# Run with examples
cargo run --example 01-simple

# Check formatting
cargo fmt -- --check

# Run clippy
cargo clippy -- -D warnings
```

## ๐Ÿ“„ License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

## ๐Ÿ™ Acknowledgments

- Inspired by the original [DSPy]https://github.com/stanfordnlp/dspy framework
- Built with the amazing Rust ecosystem
- Special thanks to the DSPy community for the discussion and ideas
- MIPROv2 implementation

## ๐Ÿ”— Resources

- [Documentation]https://dsrs.herumbshandilya.com
- [API Reference]https://docs.rs/dspy-rs
- [Examples]crates/dspy-rs/examples/
- [GitHub Issues]https://github.com/krypticmouse/dsrs/issues
- [Discord Community]https://discord.com/invite/ZAEGgxjPUe
- [Original DSPy Paper]https://arxiv.org/abs/2310.03714

---

<div align="center">
<strong>Built with ๐Ÿฆ€ by the DSPy x Rust community</strong>
<br>
<sub>Star โญ this repo if you find it useful!</sub>
</div>