Chapter 5

COPA Compiler Optimization

Learn to implement the COPA framework: treating compilation (demonstrations) and prompt optimization (instructions) as a unified, iterative process.

Introduction

COPA (Compiler and Prompt Optimization) is a synergistic framework that alternates between optimizing model parameters (via demonstration selection/compilation) and optimizing prompt instructions. Instead of choosing either good examples or good instructions, COPA optimizes both in a coordinated loop.

🔄

The Cycle: COPA works by treating the optimization space as unified. It iterates between a "Compilation Phase" (finding better examples) and a "Prompt Phase" (finding better descriptions), transferring insights between the two.

Core Principles

  1. Unified Optimization Space: Prompts and demonstrations are optimized together.
  2. Iterative Refinement: Phase 1 (Compilation) informs Phase 2 (Content/Prompt), and vice versa.
  3. Knowledge Transfer: Insights from compilation (e.g., "these examples work best") help the prompt optimizer (e.g., "therefore, we should emphasize this rule").

💻 Implementation Strategy

Implementing COPA involves creating a custom optimizer class that orchestrates the two phases.

class COPAOptimizer:
    def optimize(self, program, trainset, valset):
        
        # Iterative Loop
        for i in range(self.max_iterations):
            
            # Phase 1: Compilation (Demonstrations)
            # Uses BootstrapFewShot to find best examples
            if i % 2 == 0:
                print("Phase 1: Compilation")
                program = self.compilation_phase(program, trainset)
                
            # Phase 2: Prompt Optimization (Instructions)
            # Uses MIPRO to refine instructions based on current examples
            else:
                print("Phase 2: Prompt Optimization")
                program = self.prompt_phase(program, trainset)
                
            # Check for convergence...
            
        return program

✨ Best Practices

  • Start with Compilation: It's usually better to anchor the model with good examples first before refining the instructions.
  • Balanced Iterations: 2-3 full cycles (4-6 total phases) are usually sufficient for convergence.
  • Use Constraints: Applying constraints (as learned in the previous section) helps stabilize the alternating optimization steps.