Skip to content
Back to skills

Proactive Self Refinement

ASecurity

Enable models to refine outputs dynamically during generation based on internal signals, reducing token consumption by 41.6% while improving accuracy by 8.2%.

  • 6 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 9, 2026
ai-agentspythongogit

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill proactive-self-refinement --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Proactive Self Refinement?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Proactive Self Refinement
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-proactive-self-refinement/badge)](https://www.skillsdirectory.com/skills/adu2021-proactive-self-refinement)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: proactive-self-refinement
title: "A Stitch in Time: Proactive Self-Refinement for Language Models"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: https://arxiv.org/abs/2508.12903
keywords: [self-refinement, dynamic-revision, in-generation-improvement, token-efficiency]
description: "Enable models to refine outputs dynamically during generation based on internal signals, reducing token consumption by 41.6% while improving accuracy by 8.2%."
---

# A Stitch in Time: Proactive Self-Refinement for Language Models

## Core Concept

Traditional self-refinement works in fixed cycles: generate → evaluate → regenerate. This is inefficient because the model can't start refinement until generation completes.

Proactive Active Self-Refinement (PASR) lets models decide dynamically during generation whether, when, and how to refine. The model learns to detect when its reasoning is going wrong and self-correct mid-generation, like humans revising thoughts while speaking.

## Architecture Overview

- **Dynamic Refinement Trigger**: Learn to detect when refinement is needed
- **In-Generation Revision**: Backtrack and revise during generation
- **Internal Quality Signals**: Use model's own uncertainty/confidence
- **Learned Refinement Strategy**: Decide how aggressively to refine
- **Token Efficiency**: Avoid wasteful regeneration of correct portions
- **Adaptive Refinement**: Different tasks get different refinement patterns

## Implementation Steps

### 1. Define Refinement Points and Signals

```python
import torch
import torch.nn as nn
from typing import List, Tuple

class RefinementSignal:
    """Detect when refinement is needed"""
    def __init__(self, model):
        self.model = model

    def compute_confidence(self, logits: torch.Tensor) -> float:
        """Compute model's confidence in current prediction"""
        # Softmax probabilities
        probs = torch.softmax(logits, dim=-1)
        # Maximum probability = confidence
        confidence = probs.max().item()
        return confidence

    def compute_entropy(self, logits: torch.Tensor) -> float:
        """Compute entropy of output distribution"""
        probs = torch.softmax(logits, dim=-1)
        entropy = -(probs * torch.log(probs + 1e-10)).sum().item()
        return entropy

    def compute_consistency(self, logits_list: List[torch.Tensor]) -> float:
        """Compute consistency across multiple forward passes"""
        if len(logits_list) < 2:
            return 1.0

        # Compare top predictions
        predictions = [logits.argmax().item() for logits in logits_list]
        consistency = predictions.count(predictions[0]) / len(predictions)
        return consistency

    def should_refine(self, confidence: float, entropy: float,
                     token_count: int, max_tokens: int) -> bool:
        """Determine if refinement is needed"""
        # Refine if: low confidence + high entropy + not too many tokens
        low_confidence = confidence < 0.5
        high_entropy = entropy > 2.0
        reasonable_length = token_count < max_tokens * 0.8

        return low_confidence and high_entropy and reasonable_length
```

### 2. Implement Dynamic Backtracking

```python
class DynamicBacktracker:
    """Backtrack and revise during generation"""
    def __init__(self, model, tokenizer):
        self.model = model
        self.tokenizer = tokenizer
        self.token_history = []

    def find_refinement_point(self, current_tokens: List[int],
                            quality_scores: List[float]) -> int:
        """Find best point to backtrack to"""
        # Backtrack to where quality dropped
        min_quality_idx = 0
        min_quality = quality_scores[0]

        for i, score in enumerate(quality_scores):
            if score < min_quality:
                min_quality = score
                min_quality_idx = i

        # Don't backtrack too far (keep at least 20% of generated text)
        min_backtrack = int(len(current_tokens) * 0.2)
        backtrack_point = max(min_backtrack_idx, min_backtrack)

        return backtrack_point

    def revise_from_point(self, context_tokens: List[int],
                         backtrack_point: int, num_alternatives: int = 3):
        """Generate alternatives from backtrack point"""
        # Truncate to backtrack point
        revised_tokens = context_tokens[:backtrack_point]

        alternatives = []
        for temp in [0.7, 0.8, 0.9]:
            # Generate alternative continuation
            output = self.model.generate(
                torch.tensor([revised_tokens]),
                max_new_tokens=50,
                temperature=temp,
                do_sample=True
            )
            alternatives.append(output[0].tolist())

        return alternatives

    def select_best_alternative(self, alternatives: List[List[int]],
                               quality_fn) -> Tuple[List[int], float]:
        """Select best alternative based on quality"""
        best_seq = None
        best_quality = -1

        for alt in alternatives:
            # Decode and evaluate quality
            text = self.tokenizer.decode(alt)
            quality = quality_fn(text)

            if quality > best_quality:
                best_quality = quality
                best_seq = alt

        return best_seq, best_quality
```

### 3. Train Refinement Policy

```python
class RefinementPolicy(nn.Module):
    """Learn when and how to refine"""
    def __init__(self, hidden_size=768):
        super().__init__()

        # Input: embeddings of generated so far
        self.encoder = nn.TransformerEncoderLayer(
            d_model=hidden_size,
            nhead=8,
            dim_feedforward=2048,
            batch_first=True
        )

        # Output heads
        self.refinement_trigger = nn.Linear(hidden_size, 1)  # Binary: refine or not
        self.backtrack_distance = nn.Linear(hidden_size, 100)  # How far to backtrack
        self.refinement_intensity = nn.Linear(hidden_size, 1)  # How aggressive

    def forward(self, token_embeddings: torch.Tensor) -> dict:
        """
        Decide refinement strategy

        Args:
            token_embeddings: [seq_len, hidden_size] embeddings of generated tokens

        Returns:
            refinement_decision: dict with trigger, backtrack_distance, intensity
        """
        # Encode sequence
        context = self.encoder(token_embeddings.unsqueeze(0))
        context = context[0, -1, :]  # Take last token

        # Predict refinement strategy
        refine_logit = self.refinement_trigger(context)  # [1]
        refine_prob = torch.sigmoid(refine_logit)  # 0-1

        backtrack_logits = self.backtrack_distance(context)  # [100]
        backtrack_dist = torch.softmax(backtrack_logits, dim=0)

        intensity = torch.sigmoid(self.refinement_intensity(context))  # [1]

        return {
            'should_refine': refine_prob.item() > 0.5,
            'refine_probability': refine_prob.item(),
            'backtrack_distance': backtrack_dist.argmax().item(),
            'refinement_intensity': intensity.item()
        }

def train_refinement_policy(policy, model, tokenizer, train_data, num_epochs=10):
    """Train policy with RL"""
    optimizer = torch.optim.Adam(policy.parameters(), lr=1e-4)

    for epoch in range(num_epochs):
        for batch in train_data:
            prompts = batch['prompts']
            target_outputs = batch['outputs']

            losses = []

            for prompt, target in zip(prompts, target_outputs):
                # Generate with refinement
                generated_tokens = []
                token_embeddings = []
                refinements_applied = 0

                # Autoregressive generation
                tokens = tokenizer.encode(prompt)
                for step in range(256):  # Max generation length
                    # Get embeddings
                    embeddings = model.get_embeddings(torch.tensor([tokens]))

                    # Check if refinement needed
                    decision = policy(embeddings[0])

                    # Collect embeddings for policy
                    token_embeddings.append(embeddings[0, -1, :])

                    if decision['should_refine'] and step > 10:
                        # Apply refinement
                        backtrack_dist = decision['backtrack_distance']
                        tokens = tokens[:-backtrack_dist]
                        refinements_applied += 1

                    # Generate next token
                    logits = model(torch.tensor([tokens])).logits[0, -1, :]
                    next_token = logits.argmax().item()
                    tokens.append(next_token)

                    if next_token == tokenizer.eos_token_id:
                        break

                # Compute loss: reward based on correctness vs efficiency
                generated_text = tokenizer.decode(tokens)
                similarity = compute_similarity(generated_text, target)
                efficiency_bonus = (1.0 - len(tokens) / 256)  # Shorter is better

                reward = 0.8 * similarity + 0.2 * efficiency_bonus
                loss = -torch.tensor(reward)

                losses.append(loss)

            # Update policy
            total_loss = torch.stack(losses).mean()
            optimizer.zero_grad()
            total_loss.backward()
            optimizer.step()
```

### 4. Inference with PASR

```python
def generate_with_pasr(model, policy, tokenizer, prompt: str,
                      max_length: int = 256, refinement_threshold: float = 0.5):
    """Generate with dynamic proactive self-refinement"""
    tokens = tokenizer.encode(prompt)
    generated = []
    refinement_count = 0
    quality_scores = []

    for step in range(max_length):
        # Get current embeddings
        embeddings = model.get_embeddings(torch.tensor([tokens]))
        curr_embedding = embeddings[0, -1, :]

        # Get refinement decision
        decision = policy(curr_embedding.unsqueeze(0))

        # Compute current quality
        confidence = decision['refine_probability']
        quality_scores.append(confidence)

        # Check if refinement triggered
        if (decision['should_refine'] and
            confidence < refinement_threshold and
            step > 10 and len(generated) > 5):

            # Backtrack
            backtrack = decision['backtrack_distance']
            tokens = tokens[:-min(backtrack, len(generated))]
            generated = generated[:-min(backtrack, len(generated))]
            refinement_count += 1

            # Regenerate with higher temperature for diversity
            logits = model(torch.tensor([tokens])).logits[0, -1, :]
            logits = logits / 0.8  # Increase temperature
            next_token = torch.multinomial(
                torch.softmax(logits, dim=-1), num_samples=1
            ).item()
        else:
            # Normal generation
            logits = model(torch.tensor([tokens])).logits[0, -1, :]
            next_token = logits.argmax().item()

        tokens.append(next_token)
        generated.append(next_token)

        if next_token == tokenizer.eos_token_id:
            break

    # Decode result
    result_text = tokenizer.decode(generated)

    return {
        'text': result_text,
        'tokens_generated': len(generated),
        'refinements_applied': refinement_count,
        'efficiency': 1.0 - (refinement_count / len(generated))
    }
```

### 5. Evaluation

```python
def evaluate_pasr(model, policy, tokenizer, benchmark_tasks):
    """Evaluate PASR on accuracy and efficiency"""
    accuracy = 0.0
    token_efficiency = 0.0
    num_tasks = 0

    for task in benchmark_tasks:
        prompt = task['prompt']
        target = task['target']

        # Generate with PASR
        result = generate_with_pasr(model, policy, tokenizer, prompt)
        generated_text = result['text']

        # Check accuracy
        is_correct = check_correctness(generated_text, target)
        accuracy += 1.0 if is_correct else 0.0

        # Track token efficiency
        baseline_tokens = 100  # Estimated
        token_efficiency += 1.0 - (result['tokens_generated'] / baseline_tokens)

        num_tasks += 1

    avg_accuracy = accuracy / num_tasks if num_tasks > 0 else 0.0
    avg_efficiency = token_efficiency / num_tasks if num_tasks > 0 else 0.0

    print(f"Accuracy: {avg_accuracy * 100:.1f}%")
    print(f"Token Efficiency: {avg_efficiency * 100:.1f}%")

    return avg_accuracy, avg_efficiency
```

## Practical Guidance

- **Refinement Threshold**: 0.4-0.6 (lower = more aggressive refinement)
- **Backtrack Distance**: 5-20 tokens (avoid over-revision)
- **Temperature**: 0.7-0.9 for alternatives (higher = more diversity)
- **Policy Training**: Mix supervised + RL (80% supervised, 20% RL)
- **Quality Function**: Use task-specific metrics (BLEU, exact match, etc.)

## Reference

A Stitch in Time (2508.12903): https://arxiv.org/abs/2508.12903

Enable dynamic, in-generation self-refinement where models decide when to backtrack and revise, achieving 41.6% token reduction and 8.2% accuracy improvement over baseline generation.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.