# Rl Plus Capability Boundary

> Hybrid-policy optimization combining multiple importance sampling and exploration-based advantage functions. Prevents capability boundary collapse while maintaining verification rewards, enabling LLMs to exceed baseline boundaries.

- Skill: `adu2021/rl-plus-capability-boundary` (Agent Skill)
- Install (CLI): `npx skillmds@latest add adu2021/rl-plus-capability-boundary`
- Raw SKILL.md: https://api.skillmd.com/api/skills/adu2021/rl-plus-capability-boundary/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: adu2021 (https://skillmd.com/u/adu2021)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/adu2021/rl-plus-capability-boundary

---


# RL-PLUS: Countering Capability Boundary Collapse in RLVR

## Core Concept

RL-PLUS addresses a fundamental limitation in Reinforcement Learning with Verifiable Reward (RLVR): capability boundary collapse, where models narrow their problem-solving abilities rather than expanding them. The approach combines importance sampling to handle external data distributions and exploration-based advantage functions that guide models toward high-value, unexplored reasoning paths, enabling breakthrough performance on difficult tasks.

## Architecture Overview

- **Multiple Importance Sampling**: Addresses distributional mismatch between on-policy RL data and external training sources
- **Exploration-Based Advantage Function**: Quantifies value of unexplored reasoning paths
- **Hybrid Policy Optimization**: Balances on-policy verification rewards with off-policy external data
- **Capability Frontier Detection**: Identifies problems near model boundaries where exploration is most valuable
- **Adaptive Data Weighting**: Prioritizes external data that pushes capability boundaries

## Implementation Steps

### Step 1: Design Importance Sampling for Distribution Mismatch

Implement multiple importance sampling (MIS) to weight external data appropriately.

```python
import numpy as np
from scipy.special import softmax

def compute_importance_weights(model, external_data, on_policy_data, batch_size=32):
    """
    Compute importance weights for external data using MIS.

    Args:
        model: Current model to evaluate
        external_data: Off-policy data from external source
        on_policy_data: On-policy data from model rollouts
        batch_size: Batch size for computation

    Returns:
        Importance weights for each external sample
    """
    weights = []

    for batch in create_batches(external_data, batch_size):
        # Compute likelihood under current model
        model_logprobs = model.get_logprobs(batch)

        # Estimate data distribution (typically uniform or from original source)
        data_logprobs = estimate_data_distribution(batch)

        # Importance weight = p_model / p_data
        log_weights = model_logprobs - data_logprobs

        # Clip to prevent extreme values (Huber-like truncation)
        log_weights = np.clip(log_weights, -2.0, 2.0)

        weights.extend(np.exp(log_weights))

    return np.array(weights)


def multi_importance_sample(model, external_data, on_policy_data, num_samples=3):
    """
    Use multiple importance sampling estimators for robust weighting.

    Args:
        model: Current model
        external_data: External training data
        on_policy_data: Model-generated data
        num_samples: Number of importance estimators

    Returns:
        Robust importance weights (averaged across estimators)
    """
    all_weights = []

    for estimator_idx in range(num_samples):
        # Different importance estimators
        weights = compute_importance_weights(
            model,
            external_data,
            on_policy_data
        )

        # Optionally apply different truncation for each estimator
        max_weight = np.percentile(weights, 95)
        truncated_weights = np.minimum(weights, max_weight)

        all_weights.append(truncated_weights)

    # Average weights across estimators for robustness
    final_weights = np.mean(all_weights, axis=0)

    return final_weights / final_weights.sum()  # Normalize
```

### Step 2: Implement Exploration-Based Advantage Function

Create advantage function that rewards exploring high-value, low-confidence regions.

```python
class ExplorationBasedAdvantageFunction:
    """
    Quantifies value of exploring uncertain, high-potential regions.
    """

    def __init__(self, model, value_model, exploration_bonus_weight=0.5):
        self.model = model
        self.value_model = value_model
        self.exploration_bonus_weight = exploration_bonus_weight

    def compute_advantage(self, trajectories, returns):
        """
        Compute advantage with exploration bonus.

        Args:
            trajectories: List of (state, action, logprob) sequences
            returns: Actual returns from trajectories

        Returns:
            Advantage estimates [num_trajectories]
        """
        advantages = []

        for trajectory, trajectory_return in zip(trajectories, returns):
            # Baseline value estimate
            baseline = self.value_model.estimate_trajectory_value(trajectory)

            # Standard advantage
            standard_advantage = trajectory_return - baseline

            # Exploration bonus: higher when trajectory ventures into novel territory
            exploration_bonus = self._compute_exploration_bonus(trajectory)

            # Combined advantage
            total_advantage = (
                standard_advantage +
                self.exploration_bonus_weight * exploration_bonus
            )

            advantages.append(total_advantage)

        return np.array(advantages)

    def _compute_exploration_bonus(self, trajectory):
        """
        Compute bonus for exploring uncertain regions.

        Args:
            trajectory: Sequence of states and actions

        Returns:
            Exploration bonus value
        """
        # Measure uncertainty in value estimates
        bonus = 0.0

        for state in trajectory:
            # Get value estimate from value model
            value_estimate = self.value_model.predict(state)

            # Measure uncertainty (use bootstrap ensemble or variance)
            uncertainty = self.value_model.estimate_uncertainty(state)

            # Higher uncertainty = higher exploration value
            bonus += uncertainty

        # Normalize by trajectory length
        bonus /= len(trajectory)

        return bonus

    def detect_capability_frontier(self, problem_pool):
        """
        Identify problems at the edge of model capability.

        Args:
            problem_pool: Set of candidate problems

        Returns:
            Ranked list of frontier problems
        """
        frontier_scores = []

        for problem in problem_pool:
            # Get model's confidence on this problem
            model_output = self.model.generate(problem["prompt"])
            confidence = self.model.compute_confidence(model_output)

            # Check if problem is solvable but difficult
            difficulty = estimate_problem_difficulty(problem)

            # Problems with high difficulty but not impossible are frontier
            frontier_score = difficulty * (1.0 - confidence)

            frontier_scores.append({
                "problem": problem,
                "frontier_score": frontier_score,
                "difficulty": difficulty,
                "model_confidence": confidence
            })

        # Sort by frontier score
        frontier_scores.sort(key=lambda x: x["frontier_score"], reverse=True)

        return frontier_scores
```

### Step 3: Implement Hybrid Policy Optimization

Combine on-policy verification rewards with off-policy external data.

```python
def hybrid_policy_optimization_step(
    model,
    on_policy_batch,
    external_batch,
    importance_weights,
    advantage_function,
    learning_rate=1e-4,
    on_policy_weight=0.7,
    external_weight=0.3
):
    """
    Perform optimization step using hybrid on/off-policy objectives.

    Args:
        model: Policy model to optimize
        on_policy_batch: Batch from model rollouts with verifiable rewards
        external_batch: Batch from external training data
        importance_weights: Importance weights for external data
        advantage_function: Advantage estimator
        learning_rate: Optimizer learning rate
        on_policy_weight: Weight for on-policy objective
        external_weight: Weight for external data objective

    Returns:
        Updated model and loss metrics
    """
    # Compute on-policy loss (REINFORCE with baselines)
    on_policy_loss = compute_on_policy_loss(
        model,
        on_policy_batch,
        advantage_function
    )

    # Compute off-policy loss (importance-weighted)
    external_loss = compute_importance_weighted_loss(
        model,
        external_batch,
        importance_weights,
        target_logprobs=compute_target_logprobs(external_batch)
    )

    # Hybrid objective
    total_loss = (
        on_policy_weight * on_policy_loss +
        external_weight * external_loss
    )

    # Gradient step
    model.optimizer.zero_grad()
    total_loss.backward()

    # Gradient clipping to prevent instability
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

    model.optimizer.step()

    return {
        "total_loss": total_loss.item(),
        "on_policy_loss": on_policy_loss.item(),
        "external_loss": external_loss.item()
    }


def compute_importance_weighted_loss(model, batch, weights, target_logprobs):
    """
    Compute importance-weighted loss for off-policy data.

    Args:
        model: Policy model
        batch: Data batch
        weights: Importance weights
        target_logprobs: Target log probabilities from source model

    Returns:
        Weighted loss value
    """
    model_logprobs = model.get_logprobs(batch)

    # Importance-weighted KL divergence
    kl_div = model_logprobs - target_logprobs

    weighted_loss = (weights * kl_div).mean()

    return weighted_loss
```

### Step 4: Training Loop with Capability Boundary Detection

Integrate all components into training loop.

```python
def train_with_rl_plus(
    model,
    verification_function,
    problem_pool,
    external_training_data,
    config
):
    """
    Train model with RL-PLUS to prevent capability collapse.

    Args:
        model: LLM to train
        verification_function: Function to verify correct solutions
        problem_pool: Set of candidate problems
        external_training_data: External training data
        config: Training configuration

    Returns:
        Trained model with expanded capabilities
    """
    value_model = train_value_model(problem_pool)

    advantage_function = ExplorationBasedAdvantageFunction(
        model,
        value_model,
        exploration_bonus_weight=config.exploration_weight
    )

    for iteration in range(config.num_iterations):
        # 1. Identify capability frontier
        frontier = advantage_function.detect_capability_frontier(problem_pool)

        # 2. Rollout on frontier problems (on-policy)
        on_policy_rollouts = []
        for frontier_item in frontier[:config.frontier_batch_size]:
            problem = frontier_item["problem"]

            # Generate solution
            solution = model.generate(problem["prompt"])

            # Verify correctness
            is_correct = verification_function(solution, problem["gold"])

            # Compute return
            return_value = 1.0 if is_correct else 0.0

            on_policy_rollouts.append({
                "problem": problem,
                "solution": solution,
                "return": return_value,
                "is_correct": is_correct
            })

        # 3. Sample from external data with importance weighting
        external_sample = sample_external_batch(
            external_training_data,
            config.external_batch_size
        )

        # 4. Compute importance weights
        importance_weights = multi_importance_sample(
            model,
            external_sample,
            on_policy_rollouts,
            num_samples=3
        )

        # 5. Compute advantages with exploration bonus
        on_policy_advantages = advantage_function.compute_advantage(
            on_policy_rollouts,
            returns=[r["return"] for r in on_policy_rollouts]
        )

        # 6. Optimization step
        loss_metrics = hybrid_policy_optimization_step(
            model,
            on_policy_rollouts,
            external_sample,
            importance_weights,
            advantage_function,
            learning_rate=config.learning_rate
        )

        if iteration % config.log_freq == 0:
            print(f"Iteration {iteration}: Loss={loss_metrics['total_loss']:.4f}")

    return model
```

## Practical Guidance

### When to Use RL-PLUS

- **Capability expansion tasks**: Models must solve problems beyond baseline ability
- **Sparse reward environments**: Where on-policy exploration is inefficient
- **Hybrid data availability**: Mix of verified on-policy and external off-policy data
- **Reasoning tasks**: Math, coding where exploration of reasoning paths matters

### When NOT to Use RL-PLUS

- **Simple task adaptation**: Where verification rewards suffice
- **Abundant on-policy data**: No need for external data exploitation
- **Extremely sparse external data**: Importance weighting becomes unreliable
- **Real-time learning**: Multiple importance estimators add computational cost

### Hyperparameter Recommendations

- **On-policy weight**: 0.6-0.8 (prefer verified rewards)
- **External weight**: 0.2-0.4 (supplement with external data)
- **Exploration bonus weight**: 0.3-0.7 (depends on frontier difficulty)
- **Importance weight clipping**: Log-space clipping at ±2.0
- **Frontier batch size**: 4-8 problems per iteration

### Key Insights

The key insight is that standard RLVR narrows capability by optimizing solely on verifiable rewards. By explicitly incentivizing exploration of high-uncertainty regions combined with importance-weighted external data, models can break through their baseline boundaries. The hybrid approach prevents collapse by diversifying the optimization signal.

## Reference

**RL-PLUS: Countering Capability Boundary Collapse** (arXiv:2508.00222)

Introduces hybrid-policy optimization with multiple importance sampling and exploration-based advantage functions. Prevents capability boundary collapse while maintaining verification constraints, enabling LLMs to exceed baseline performance boundaries.

