
Reading Time: 20 minutes
Difficulty: Intermediate to Advanced
What you'll learn:
This advanced tutorial will guide you through using PDO with prompt-ops to optimize prompts for Llama models through competitive dueling. We’ll cover:
1. Introduction to PDO
Before we dive into the theory, a quick note: if you're the type who learns best by doing, we've prepared an interactive notebook that demonstrates PDO concepts through runnable code. Feel free to start there and reference back to this guide as needed.
PDO (Prompt Duel Optimizer) is a novel prompt optimization technique introduced in the paper "Prompt Dueling Optimization: Tournament-Driven Prompt Discovery and Evaluation". Instead of scoring prompts individually, PDO treats optimization as a competitive tournament where prompts duel head-to-head to determine superiority.
Paper Reference: [arXiv:2510.13907](https://arxiv.org/abs/2510.13907) (2025)
Implementation: [meta-llama/prompt-ops](https://github.com/meta-llama/prompt-ops)
Traditional prompt optimization methods face several critical challenges:
PDO addresses these limitations through a dueling bandit approach that treats prompt optimization as a competitive head-to-head tournament rather than absolute scoring.
Design Choice: Pairwise vs. Pointwise Evaluation
PDO uses pairwise comparison even when labels are available—trading computational efficiency for more robust prompt evaluation.
The paper explores several novel concepts in prompt optimization
PDO addresses these limitations through a dueling bandit approach that treats prompt optimization as a competitive head-to-head tournament rather than absolute scoring.
Design Choice: Pairwise vs. Pointwise Evaluation
PDO uses pairwise comparison even when labels are available—trading computational efficiency for more robust prompt evaluation.
The paper compares PDO with several baseline approaches:
Method | Approach | Limitations | PDO's Advantage |
|---|---|---|---|
Manual Prompting | Human-written instructions | Time-consuming, subjective | Automated competitive optimization |
Few-shot Learning | Examples in prompt | Limited by context window | Optimizes instructions through duels |
DSPy MIPRO | Bayesian-based optimization | Local optima, absolute scoring | Global exploration via bandits |
OPRO | LLM-based optimization | Greedy, expensive | Efficient exploration via Thompson sampling |
The paper’s key insight is that relative comparisons are more reliable than absolute scores. Dueling bandits are well-suited for prompt optimization because they:
To understand why PDO’s dueling approach is superior, let’s compare it with traditional optimization:
The Traditional Problem:
When you score prompts independently (e.g., P4 gets 0.78, P5 gets 0.74), small differences might just be noise. Is P4 really better, or did it just get lucky on the test set? You can’t be sure.
PDO’s Solution:
Instead of asking “How good is this prompt?” (absolute), PDO asks “Which prompt is better?” (relative). By running head-to-head duels on the same examples, PDO eliminates scoring bias and reveals consistent winners.
The Visualization Below Shows:
Key Insight: A prompt that wins 60%+ of duels against every opponent is a validated champion. This is PDO’s core innovation: reliable relative comparison through competition.
This section explores the core components of PDO as described in the research paper, focusing on the theoretical foundations and algorithmic innovations.
PDO consists of six main components:
Let’s explore each component in detail.
The paper introduces PDO’s use of Dueling Bandits as the central optimization paradigm:
Traditional Multi-Armed Bandits:
Dueling Bandits (PDO’s Approach):
noneInitialize:- Start with base prompt + generate initial variations- Initialize Win matrix W (all zeros)For each round t = 1 to T:1. Use Thompson Sampling to select prompt pair (i, j)2. Run duel: Both prompts answer the same examples3. LLM judge decides winner on each example4. Update W[i,j] with wins, W[j,i] with losses5. Compute multi-ranker scores (Copeland, Borda, Elo, TrueSkill)6. [Optional] Generate new prompts by combining top performers7. [Optional] Prune worst-performing promptsReturn:- Best prompt according to aggregated rankings
Key Innovation: The Win matrix W becomes increasingly informative, guiding both exploration (via Thompson sampling) and exploitation (via ranking systems).
One of PDO’s most sophisticated components is its Double Thompson Sampling strategy:
Thompson Sampling is a probabilistic approach to the exploration-exploitation dilemma:
The paper describes a two-stage selection process:
Benefits:
The diagram below shows Beta distributions representing our belief about each prompt’s win probability. This is the heart of how PDO decides which prompts to compare in duels:
The Three Scenarios:
PDO’s Smart Strategy:
The Key Insight: By choosing C as the opponent, PDO maximizes information gain. After this duel:
This is why PDO converges faster than naive approaches – it strategically explores high-uncertainty regions rather than randomly sampling prompts.
One of PDO’s most important innovations is using multiple ranking algorithms simultaneously to create a more robust evaluation system.
Imagine you’re trying to determine the best chess player. Would you:
PDO chooses Option B – it fuses (combines) the opinions of 5 different ranking algorithms, each with its own strengths and blind spots. This is called Multi-Ranker Fusion.
The Core Problem: No single ranking system is perfect. Each has biases:
By combining all 5, PDO gets a consensus view that’s more reliable than any individual ranker.
Different ranking systems capture different aspects of prompt quality:
Ranking System | What It Measures | Strengths | Weaknesses |
|---|---|---|---|
Copeland | Number of opponents beaten | Simple, intuitive | Ignores margin of victory |
Borda | Sum of win probabilities | Accounts for all matchups | Can be dominated by many weak wins |
Average Win Rate | Mean win probability | Easy to interpret | Doesn't account for opponent strength |
Elo | Chess-style rating | Accounts for opponent strength | Sensitive to order of matches |
TrueSkill | Bayesian skill rating | Confidence intervals, robust | More complex, computational cost |
The paper describes a sophisticated fusion approach:
noneFor each round:1. Compute all 5 ranking scores for each prompt2. Normalize each to [0, 1] range3. Sample fusion weights from Dirichlet(1,1,1,1,1)→ Introduces randomness in how rankings are combined4. Compute weighted combination: score = Σ(weight_i × ranking_i)5. Use fused scores for prompt selection
Benefits:
Let’s say we have 3 prompts after some duels:
Prompt | Copeland | Borda | Win Rate | Elo | TrueSkill | Average |
|---|---|---|---|---|---|---|
P1 | 1st | 1st | 1st | 2nd | 1st | 1st (winner!) |
P2 | 2nd | 2nd | 3rd | 1st | 2nd | 2nd |
P3 | 3rd | 3rd | 2nd | 3rd | 3rd | 3rd |
Key Insight: P1 wins 4 out of 5 ranking systems – it’s a consensus champion. Even though P2 tops the Elo ranking (maybe it beat one strong opponent), P1 is more consistently excellent across all evaluation criteria.
This is why Multi-Ranker Fusion is powerful: It prevents a prompt from gaming one specific metric and ensures true, well-rounded superiority.
The paper emphasizes that PDO’s evaluation mechanism is crucial for effective optimization:
Traditional Metrics: Hard-coded rules (exact match, F1, BLEU, etc.)
PDO’s LLM Judge:
pythonYou are an expert evaluator. Compare these two responses:Input: {question}Expected Answer: {label}Response A:{response_from_prompt_A}Response B:{response_from_prompt_B}Which response is better? Consider:- Correctness: Does it match the expected answer?- Completeness: Does it address all aspects?- Clarity: Is it well-structured and understandable?Output format:{"reasoning": "Your detailed comparison","winner": "A" or "B"}
Benefits of LLM-as-Judge:
Now that we understand the theoretical foundations, let’s create a real PDO project using the MS MARCO dataset as our example, you can also follow along this hands-on section here: Github notebook.
MS MARCO (Microsoft MAchine Reading COmprehension) is an excellent dataset for demonstrating PDO because:
We’ll use a pre-configured MS MARCO PDO project that demonstrates best practices:
Before we can work with the MS MARCO example, we need to install prompt-ops. You can install it from PyPI or from source for the latest features.
python# Install from source# Clone and install in development mode (editable install)!git clone -b pdo-notebook https://github.com/meta-llama/prompt-ops.git!cd prompt-ops && pip install -e .
With prompt-ops installed, we can now clone and explore the MS MARCO PDO example:
python# Clone the pre-configured MS MARCO PDO example!cd prompt-ops/use-cases/ms-marco-pdo && ls -la
Let’s examine the key configuration elements for this open-ended QA task:
python# PDO Configuration for MS MARCO Open-Ended QAname: ms-marco-qamodels:task_model: "openrouter/meta-llama/llama-3.3-70b-instruct" # Model to optimizeproposer_model: "openrouter/meta-llama/llama-3.3-70b-instruct" # For evolution & judgingprovider: "openrouter"temperature: 0.0 # Zero temp for consistencydataset:path: "dataset/ms_marco_description.json"input_field: "question" # Direct field (not nested)golden_output_field: "answer" # Ground truth answersoptimization:strategy: "pdo" # PDO strategytask_type: "open_ended" # Open-ended QA task# Judge rubric aligned with final evaluation criteriajudge_requirement: |- Accuracy: Correct and contextually faithful.- Relevance: Stays on-topic.- Clarity: Clear and well-structured.- Conciseness: Uses only necessary information; avoids unnecessary detail.# Core dueling parameterstotal_rounds: 30 # Number of optimization roundsnum_duels_per_round: 3 # Duels per roundnum_eval_examples_per_duel: 10 # Examples per duelnum_initial_instructions: 2 # Start with 2 prompts# Instruction evolutionnum_top_prompts_to_combine: 2 # Top K for combinationnum_new_prompts_to_generate: 1 # New prompts per gen roundmax_prompts_to_generate: 10 # Max total prompt pool sizegen_new_prompt_round_frequency: 2 # Generate every 2 rounds# Execution parametersmax_concurrent_threads: 10 # Parallel API callsverbose: true # Detailed loggingprompts:system: "prompts/prompt.txt" # Initial prompt filemetric:class: "llama_prompt_ops.core.metrics.LLMJudgeStandardMetric"
For close-ended (classification) tasks, set optimization.task_type to close_ended in your configuration, and specify optimization.answer_choices (such as ["Yes", "No"]), though this defaults to yes/no if omitted. In this mode, the model returns its answer as a JSON object that includes both reasoning and the chosen answer, and judging uses a fixed rubric—evaluating both correctness and reasoning quality.
pythonoptimization:strategy: "pdo"task_type: close_endedanswer_choices: ["Yes", "No"]
For open-ended tasks (meaning any task that isn’t simple classification), set optimization.task_type to open_ended in your configuration. You can also provide a custom evaluation rubric by specifying optimization.judge_requirement. If you omit this, PDO will automatically generate appropriate judging criteria based on your dataset summary and sample questions. In open-ended mode, the model generates free-form answers, and the judge selects the better response using either your custom rubric or the automatically generated one, providing both an explanation and a winner. For example, if you are working on a summarization task, your YAML might look like this with a specific customized requirement:
pythonoptimization:strategy: "pdo"task_type: open_endedjudge_requirement: |- Key points coverage (40%): Captures major decisions, actions, owners, dates.- Faithfulness (30%): No invented details or attributions.- Structure (15%): Logical, grouped bullets or sections.- Brevity & clarity (10%): Minimal fluff; readable.- Tie-Breaker (5%): Better prioritization of actionable items.
The MS MARCO dataset included in our example contains curated question-answer pairs. PDO works effectively with:
Let’s look at the MS MARCO data structure:
json{"question": "what is the purpose of an mri","answer": "Magnetic resonance imaging (MRI) is a medical imaging technique used to visualize internal structures of the body in detail. MRI makes use of the property of nuclear magnetic resonance (NMR) to image nuclei of atoms inside the body. An MRI scan can be used as an extremely accurate method of disease detection throughout the body and is most often used after other testing fails to provide sufficient information to confirm a patient's diagnosis."}
For MS MARCO, we start with a simple, neutral prompt that PDO will optimize:
Design principles:
PDO will evolve this through competitive testing to discover:
prompts/prompt.txt:
pythoninitial_prompt = """You are an expert answerer.Read the question and the provided context (if any).Write a concise, accurate answer in your own words."""
pythoninitial_prompt = """You are an expert answerer.Read the question and the provided context (if any).Write a concise, accurate answer in your own words."""
Round 1: Basic prompt (above)
Round 5: Adds ‘provide clear explanations’
Round 10: Discovers ‘step-by-step’ improves clarity
Round 20: Adds role specification (‘knowledgeable researcher’)
Round 30: Converges on optimal prompt through competition
For the evaluation of open-ended tasks, an increasing number of benchmarks now rely on LLM judges due to their flexibility and the availability of more capable frontier or fine-tuned models. In MS MARCO, we also use an LLM judge to evaluate the outputs generated by the model.
The final evaluation of a prompt involves comparing the LLM-generated response, produced in response to the instruction prompt, with the ground-truth answer using an LLM judge template as shown below.
pythonJUDGE_PROMPT = """Begin your evaluation by carefully comparing the AI-generated answer with the reference solution. Identify any outputs that aren't true, as well as omissions, or deviations, and simulate human judgments in explaining how these impact the overall quality of the response. Ensure that your assessment is objective and consistent.At the end of your evaluation, assign a score from 1 to 5 based on the following scale:- 1: Very poor—does not meet the requirements or is significantly incorrect.- 2: Poor—contains major errors or omissions.- 3: Fair—adequate but with notable flaws.- 4: Good—meets the requirements with minor errors.- 5: Excellent—fully accurate and well-articulated.[User Question]{question}[Reference Solution]{ground_truth}[AI-Generated Answer]{prediction}Your response should be a valid json string (no backticks) following this schema:{{"explanation": "{{Detailed reasoning based on the comparison}}","score": {{1-5}}}}"""
Now let’s run PDO on the MS MARCO dataset and watch the optimization process in action.
Before running PDO, ensure you have:
shell# Set your API key (or add to .env file)export OPENROUTER_API_KEY="your-key-here"# Or if using a .env fileecho "OPENROUTER_API_KEY=your-key-here" > .env
For open-ended tasks like MS MARCO, PDO uses an LLM judge to compare answers. The judge evaluates based on the criteria in judge_requirement:
This aligns with how we’ll evaluate the final optimized prompt
python!cd prompt-ops/use-cases/ms-marco-pdo && prompt-ops migrate --config config.yaml
After running PDO, we store the optimized prompt as follows, ready for final evaluation.
pythonOPTIMIZED_PROMPT = ("""Embody the role of a knowledgeable researcher and provide a clear,step-by-step explanation to answer the user's question, utilizing the providedcontext and avoiding technical jargon unless absolutely necessary, to ensure aconcise and accurate response.""")
In this section, we evaluate the performance of the optimized prompt after running PDO against the initial prompt. We compare generated answers against ground truth using the judge prompt from Section 1 (returns JSON with explanation + 1–5 score).
shelldef judge_scores(preds: list[str]):"""Judge with guided JSON decoding (fallback to free-form if unsupported)."""import json as _jsonimport numpy as _npscores = []explanations = []judge_prompts = []for pred, r in zip(preds, rows):judge_prompts.append(JUDGE_PROMPT.format(question=r["question"],ground_truth=r["answer"],prediction=pred,))response_format = {"type": "json_schema","json_schema": {"name": "judge_score","schema": {"type": "object","properties": {"explanation": {"type": "string","description": "Detailed reasoning based on the comparison",},"score": {"type": "integer","description": "Score from 1 to 5","enum": [1, 2, 3, 4, 5],},},"required": ["explanation", "score"],"additionalProperties": False,},"strict": True,},}try:outs = model.generate_batch(judge_prompts, max_threads=10, temperature=0.0, response_format=response_format)except Exception:outs = model.generate_batch(judge_prompts, max_threads=10, temperature=0.0)for o in outs:obj = _try_json_parse(o)score = obj.get("score", 0)exp = obj.get("explanation", "")try:score = float(score)except Exception:score = 0.0scores.append(score)explanations.append(exp)return _np.array(scores), explanations
shellimport os, jsonimport numpy as npfrom pathlib import Pathimport syssys.path.append(os.path.abspath("../../src"))from prompt_ops.core.model import setup_model# Load datasetDATA_PATH = "prompt-ops/use-cases/ms-marco-pdo/dataset/ms_marco_description.json"rows = json.load(open(DATA_PATH, "r"))# Model for answering and for judging (same adapter; different prompts)model = setup_model(adapter_type="litellm",model_name="openrouter/meta-llama/llama-3.3-70b-instruct",api_base=os.environ.get("OPENROUTER_API_BASE", "https://openrouter.ai/api/v1"),api_key=os.environ.get("OPENROUTER_API_KEY"),max_tokens=4096,temperature=0.0,)# Helperdef _try_json_parse(s: str):try:start = s.find("{"); end = s.rfind("}") + 1blob = s[start:end] if (start >= 0 and end > start) else sreturn json.loads(blob)except Exception:return {}# Baselines and PDO instructionBASELINES = {"Initial Prompt": """You are an expert answerer.Read the question and the provided context (if any).Write a concise, accurate answer in your own words.""",}def predict_answers(instruction: str):prompts = []for r in rows:q = r["question"].strip()prompts.append(f"{instruction}\n\nQuestion:\n{q}")return model.generate_batch(prompts, max_threads=10, temperature=0.0)results = {}# Evaluate baselinesfor name, instr in BASELINES.items():print(f"evaluating... {name}")preds = predict_answers(instr)s, _ = judge_scores(preds)results[name] = float(np.mean(s)) if len(s) else 0.0# Evaluate PDO (if you paste the optimized instruction)if OPTIMIZED_PROMPT:print("evaluating... PDO")preds = predict_answers(OPTIMIZED_PROMPT)s, _ = judge_scores(preds)results["PDO"] = float(np.mean(s)) if len(s) else 0.0print("\n=== LLM Judge Avg Score (1–5) on MS MARCO Description ===")for k, v in results.items():print(f"{k}: {v:.2f}")
PDO achieves a higher average LLM judge score (4.64) than the Initial Prompt (4.48) on the MS MARCO Description, indicating a measurable improvement in answer quality.
pythonimport matplotlib.pyplot as pltplt.figure(figsize=(8, 4.5))bars = plt.bar(results.keys(), results.values(), color="#4e79a7", edgecolor="#2e4a62", linewidth=1.5, width=0.55)plt.title("LLM Judge Avg Score (1–5) on MS MARCO Description", fontsize=15, fontweight="bold", pad=14)plt.ylabel("Avg Score (1–5)", fontsize=13)plt.ylim(4, 5.1)plt.xticks(rotation=15, fontsize=11)plt.yticks(fontsize=11)plt.grid(axis='y', linestyle='--', alpha=0.25)for bar, v in zip(bars, results.values()):plt.text(bar.get_x() + bar.get_width() / 2, v + 0.10, f"{v:.2f}", ha="center", va="bottom", fontsize=12, fontweight="bold", color="#34495e")ax = plt.gca()ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)plt.tight_layout()plt.show()
Based on our exploration of the PDO paper and practical implementation:
The paper suggests PDO is particularly effective for:
The paper demonstrates PDO’s effectiveness:
PDO represents an important advance in prompt optimization by bringing dueling bandit algorithms to LLM prompt engineering. Its competitive approach, combined with sophisticated exploration strategies and multi-ranker fusion, creates a powerful framework for discovering high-quality prompts through natural selection in a tournament setting.
The key insight is that asking “which is better?” is often more reliable than asking “how good is this?” – PDO leverages this principle throughout its design.
For more details, refer to the full paper and implementation documentation.
use_merge: true for best results
This tutorial covered the theoretical foundations and practical implementation of PDO based on dueling bandits and the research paper. For hands-on practice, try the web of lies tutorial or adapt PDO to your own classification or generation tasks.
Subscribe to our newsletter to keep up with the latest AI updates, releases and more.