# Pass intermediate results to subsequent prompts
context = {**dataset_item, "intermediate_result": some_value}
messages = prompt.get_messages(context)
```

### Best practices

* **Error handling**: Return meaningful error messages if execution fails
* **Model parameters**: Respect `prompt.model` and `prompt.model_kwargs` for consistency
* **Reproducibility**: Use the `seed` parameter when making LLM calls
* **Opik tracing**: The base class handles tracing automatically, but you can add custom metadata via `self.trace_metadata`

## Complete examples

### Single-prompt with ChatPrompt (default)

```python
from opik_optimizer import ChatPrompt, EvolutionaryOptimizer
from opik_optimizer.datasets import hotpot
from opik.evaluation.metrics import LevenshteinRatio

dataset = hotpot(count=300)

def metric(dataset_item, llm_output):
    return LevenshteinRatio().score(
        reference=dataset_item["answer"], 
        output=llm_output
    )

prompt = ChatPrompt(
    system="You are a helpful assistant.",
    user="{question}",
    model="openai/gpt-4o-mini"
)

optimizer = EvolutionaryOptimizer(
    model="openai/gpt-4o-mini",
    population_size=5,
    num_generations=3
)

result = optimizer.optimize_prompt(
    prompt=prompt,
    dataset=dataset,
    metric=metric,
    n_samples=50
)

result.display()
```

### Multi-prompt workflow

```python
from typing import Any
from opik_optimizer import ChatPrompt, OptimizableAgent, HRPO
from opik.evaluation.metrics import LevenshteinRatio
from opik_optimizer.datasets import hotpot
from openai import OpenAI

class TwoStepAgent(OptimizableAgent):
    def __init__(self, model: str = "gpt-4o-mini"):
        super().__init__()
        self.model = model
        self.client = OpenAI()

    def invoke_agent(
        self,
        prompts: dict[str, ChatPrompt],
        dataset_item: dict[str, Any],
        allow_tool_use: bool = False,
        seed: int | None = None,
    ) -> str:
        # First step
        step1_prompt = prompts["step1"]
        step1_messages = step1_prompt.get_messages(dataset_item)
        step1_response = self.client.chat.completions.create(
            model=self.model,
            messages=step1_messages,
            seed=seed,
        )
        step1_result = step1_response.choices[0].message.content

        # Second step uses result from first step
        step2_prompt = prompts["step2"]
        step2_context = {**dataset_item, "step1_result": step1_result}
        step2_messages = step2_prompt.get_messages(step2_context)
        step2_response = self.client.chat.completions.create(
            model=self.model,
            messages=step2_messages,
            seed=seed,
        )
        
        return step2_response.choices[0].message.content