> ## Documentation Index
> Fetch the complete documentation index at: https://dsrs.herumbshandilya.com/llms.txt
> Use this file to discover all available pages before exploring further.

# COPRO

> Fast iterative prompt refinement

COPRO (Collaborative Prompt Optimizer) is a simple but effective optimizer that iteratively refines prompts through generation and evaluation cycles.

## How it Works

COPRO uses a straightforward approach:

1. **Generate candidates**: Create multiple prompt variations using an LLM
2. **Evaluate**: Test each candidate on your training data
3. **Refine**: Use the best candidates to generate improved versions
4. **Repeat**: Continue for a fixed number of depth iterations

## Configuration

```rust theme={null}
let copro = COPRO::builder()
    .breadth(10)              // Number of candidates per iteration
    .depth(3)                 // Number of refinement iterations
    .init_temperature(1.4)    // Temperature for generation
    .track_stats(false)       // Track optimization statistics
    .build();
```

## Usage Example

```rust theme={null}
use anyhow::Result;
use bon::Builder;
use facet;
use dspy_rs::{
    COPRO, ChatAdapter, Example, LM, MetricOutcome, Module, Optimizer, Predict, PredictError,
    Predicted, Signature, TypedMetric, configure, init_tracing,
};

#[derive(Signature, Clone, Debug)]
struct QA {
    #[input]
    question: String,

    #[output]
    answer: String,
}

#[derive(Builder, facet::Facet)]
#[facet(crate = facet)]
struct MyModule {
    #[builder(default = Predict::<QA>::new())]
    predictor: Predict<QA>,
}

impl Module for MyModule {
    type Input = QAInput;
    type Output = QAOutput;

    async fn forward(&self, inputs: QAInput) -> Result<Predicted<QAOutput>, PredictError> {
        self.predictor.call(inputs).await
    }
}

struct ExactMatchMetric;

impl TypedMetric<QA, MyModule> for ExactMatchMetric {
    async fn evaluate(&self, example: &Example<QA>, prediction: &Predicted<QAOutput>) -> Result<MetricOutcome> {
        let expected = example.output.answer.trim().to_lowercase();
        let actual = prediction.answer.trim().to_lowercase();
        Ok(MetricOutcome::score((expected == actual) as u8 as f32))
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    init_tracing()?;

    // API key automatically read from OPENAI_API_KEY env var
    configure(
        LM::builder()
            .model("gpt-4o-mini".to_string())
            .build()
            .await?,
        ChatAdapter,
    );
    
    let mut module = MyModule::builder().build();
    let trainset = vec![
        Example::new(
            QAInput {
                question: "What is 2+2?".to_string(),
            },
            QAOutput {
                answer: "4".to_string(),
            },
        ),
        Example::new(
            QAInput {
                question: "Capital of France?".to_string(),
            },
            QAOutput {
                answer: "Paris".to_string(),
            },
        ),
    ];
    
    let copro = COPRO::builder()
        .breadth(10)
        .depth(3)
        .build();
    let metric = ExactMatchMetric;
    
copro.compile::<QA, _, _>(&mut module, trainset, &metric).await?;
    
    Ok(())
}
```

### Typed Data Loading

Use the shared data ingress guide: [`DataLoader`](/docs/data/dataloader).

## When to Use COPRO

**Best for:**

* Quick iteration cycles
* Simple tasks
* Limited compute budget
* When you need results fast

**Avoid when:**

* You need best possible quality (use MIPROv2 or GEPA)
* Task has complex failure modes (use GEPA)
* You want to leverage prompting best practices (use MIPROv2)

## Comparison with Other Optimizers

| Feature       | COPRO  | MIPROv2  | GEPA         |
| ------------- | ------ | -------- | ------------ |
| **Speed**     | Fast   | Slow     | Medium       |
| **Quality**   | Good   | Better   | Best         |
| **Feedback**  | Score  | Score    | Score + Text |
| **Diversity** | Low    | Medium   | High         |
| **Setup**     | Simple | Moderate | Moderate     |

## Configuration Details

### Breadth

Number of candidate prompts generated at each iteration. Higher breadth means more exploration but more compute.

Recommended: 5-15

### Depth

Number of refinement iterations. Each iteration builds on the best candidates from the previous one.

Recommended: 2-5

### Temperature

Controls randomness in prompt generation. Higher temperature means more diverse candidates.

Recommended: 1.0-1.5

### Track Stats

When enabled, COPRO tracks detailed statistics about all evaluated candidates and their scores over time.

## Implementation Notes

COPRO maintains:

* All evaluated candidates with their scores
* Best candidates from each iteration
* History of improvements over iterations

The algorithm avoids re-evaluating candidates it has already seen by caching results.

## Examples

<Card title="COPRO Examples" icon="code" href="https://github.com/krypticmouse/DSRs/tree/main/crates/dspy-rs/examples">
  See examples 03-evaluate-hotpotqa.rs and 04-optimize-hotpotqa.rs
</Card>
