skills/skillxiv-v0.0.2-claude-opus-4.6/attntrace-context-attribution/SKILL.md
Identify influential texts in long contexts via attention weights using top-K filtering and context subsampling, achieving 10-20x speedup over perturbation methods.
npx skillsauth add ADu2021/skillXiv attntrace-context-attributionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
AttnTrace identifies which texts most influence an LLM's output by analyzing attention weights. Rather than expensive perturbation-based attribution (requiring hundreds of forward passes), it leverages the model's internal attention signals with two key innovations: filtering noise via top-K tokens and subsampling competing contexts to sharpen attention signals.
Understanding which context texts influence model outputs is important for debugging and auditing. Perturbation methods—removing texts and measuring output change—are accurate but require hundreds of forward passes. AttnTrace exploits attention mechanisms: high attention weight to a text indicates influence. However, raw attention is noisy (diffuse across many tokens) and gets diluted when competing texts exist. The solution: (1) average only top-K high-attention tokens per text, and (2) subsample competing texts to concentrate attention signals.
Step 1: Extract and Analyze Attention Weights
import torch
import torch.nn.functional as F
import numpy as np
from typing import List, Tuple, Dict
class AttentionExtractor:
"""Extract attention weights during forward pass."""
def __init__(self, model):
self.model = model
self.attention_weights = []
self._register_hooks()
def _register_hooks(self):
"""Register hooks to capture attention in each layer."""
for layer in self.model.transformer.h:
# Hook into attention module
layer.self_attn.register_forward_hook(self._attention_hook)
def _attention_hook(self, module, input, output):
"""Capture attention weights from forward pass."""
# output is typically (batch, num_heads, seq_len, seq_len)
if isinstance(output, tuple):
attn_weights = output[0] # First output is attention
else:
attn_weights = output
self.attention_weights.append(attn_weights.detach())
def extract(self, input_ids: torch.Tensor) -> List[torch.Tensor]:
"""Run forward pass and return attention weights."""
self.attention_weights = []
with torch.no_grad():
_ = self.model(input_ids)
return self.attention_weights
class TopKAttentionFilter:
"""Filter attention by top-K tokens per text."""
def __init__(self, k: int = 5):
self.k = k
def filter_attention(self, attention: torch.Tensor, token_ranges: Dict[str, Tuple[int, int]]) -> Dict[str, float]:
"""
Filter attention weights to top-K tokens per text.
Args:
attention: (batch, num_heads, seq_len_query, seq_len_key)
token_ranges: {text_name: (start_idx, end_idx)}
Returns:
importance_per_text: {text_name: score}
"""
# Average over batch and heads
attention_avg = torch.mean(attention, dim=(0, 1)) # (seq_len_q, seq_len_k)
importance_per_text = {}
for text_name, (start, end) in token_ranges.items():
# Get attention to tokens in this text range
text_attention = attention_avg[:, start:end] # (seq_len_query, tokens_in_text)
# For each query position, find top-K attended tokens in this text
top_k_per_query = torch.topk(text_attention, k=min(self.k, end - start), dim=1)
# Average the top-K values
importance = torch.mean(top_k_per_query.values).item()
importance_per_text[text_name] = importance
return importance_per_text
Step 2: Implement Context Subsampling
class ContextSubsampler:
"""Subsample competing texts to sharpen attention signals."""
def __init__(self, model):
self.model = model
self.extractor = AttentionExtractor(model)
def subsample_context(self, full_context_ids: torch.Tensor, text_ranges: Dict,
subsample_fraction: float = 0.7) -> torch.Tensor:
"""
Randomly select subset of context texts.
Args:
full_context_ids: Full input token IDs
text_ranges: {text_name: (token_start, token_end)}
subsample_fraction: Fraction to keep
Returns:
subsampled_ids: Token IDs with some texts removed
"""
keep_mask = torch.ones_like(full_context_ids, dtype=torch.bool)
text_names = list(text_ranges.keys())
# Randomly decide which texts to keep
num_texts = len(text_names)
num_to_keep = max(1, int(num_texts * subsample_fraction))
texts_to_keep = np.random.choice(text_names, size=num_to_keep, replace=False)
# Zero out tokens from removed texts
for text_name, (start, end) in text_ranges.items():
if text_name not in texts_to_keep:
keep_mask[0, start:end] = False
# Create subsampled input
subsampled = full_context_ids * keep_mask.long()
return subsampled
def compute_importance_with_subsampling(self, full_context_ids: torch.Tensor,
text_ranges: Dict, num_subsamples: int = 10) -> Dict[str, float]:
"""
Compute importance scores across multiple random subsamples.
Averaging across subsamples reduces noise and sharpens signals.
"""
all_importance = {text: [] for text in text_ranges.keys()}
for _ in range(num_subsamples):
# Subsample context
subsampled_ids = self.subsample_context(full_context_ids, text_ranges)
# Extract attention
attn_weights = self.extractor.extract(subsampled_ids)
# Average attention weights across layers
avg_attn = torch.mean(torch.stack(attn_weights), dim=0)
# Filter to top-K per text
filter = TopKAttentionFilter(k=5)
importance_this_subsample = filter.filter_attention(avg_attn, text_ranges)
# Accumulate
for text, importance in importance_this_subsample.items():
all_importance[text].append(importance)
# Average across subsamples
final_importance = {}
for text, values in all_importance.items():
final_importance[text] = np.mean(values)
return final_importance
Step 3: Handle Attention Dispersion
def analyze_attention_dispersion(attention: torch.Tensor, num_competing_texts: int) -> float:
"""
Theoretical analysis: more competing texts → lower max attention.
This explains why subsampling sharpens signals.
"""
# Max attention value achieved
max_attn = torch.max(attention).item()
# Expected max with n competing texts follows extreme value distribution
# Heuristic: max_attn ≈ 1 / num_competing_texts for uniform distribution
expected_dilution = 1.0 / max(1, num_competing_texts)
return expected_dilution
def compute_dilution_factor(full_context_ids: torch.Tensor, subsampled_ids: torch.Tensor) -> float:
"""
Quantify how much attention was diluted in full context vs. subsampled.
"""
num_texts_full = torch.sum(full_context_ids > 0).item()
num_texts_sub = torch.sum(subsampled_ids > 0).item()
dilution_ratio = num_texts_full / num_texts_sub
return dilution_ratio
Step 4: Implement Full Attribution Pipeline
class ContextAttributor:
"""Complete pipeline for attributing outputs to context texts."""
def __init__(self, model):
self.model = model
self.subsampler = ContextSubsampler(model)
def attribute_output(self, full_context: str, context_texts: Dict[str, str],
query: str, num_subsamples: int = 10) -> Dict[str, float]:
"""
Attribute model output to source texts.
Args:
full_context: Complete input text
context_texts: {text_name: text_content}
query: Query/prompt text
num_subsamples: Subsamples for averaging
Returns:
importance_scores: {text_name: importance_score}
"""
# Tokenize
tokenizer = self.model.tokenizer
full_ids = tokenizer.encode(full_context, return_tensors='pt')
# Map text ranges in tokenized form
text_ranges = self._compute_text_ranges(full_context, context_texts, tokenizer)
# Compute importance via subsampling
importance = self.subsampler.compute_importance_with_subsampling(
full_ids, text_ranges, num_subsamples=num_subsamples
)
# Normalize to [0, 1]
max_importance = max(importance.values())
if max_importance > 0:
importance = {k: v / max_importance for k, v in importance.items()}
return importance
def _compute_text_ranges(self, full_text: str, text_chunks: Dict[str, str], tokenizer) -> Dict:
"""Compute token ranges for each text chunk in full context."""
ranges = {}
current_pos = 0
for text_name, text_content in text_chunks.items():
start = full_text.find(text_content, current_pos)
if start == -1:
continue
end = start + len(text_content)
# Convert char positions to token positions
start_tokens = len(tokenizer.encode(full_text[:start]))
end_tokens = len(tokenizer.encode(full_text[:end]))
ranges[text_name] = (start_tokens, end_tokens)
current_pos = end
return ranges
Step 5: Benchmark Against Perturbation
import time
def benchmark_attribution_methods(model, context_texts: Dict, query: str):
"""
Compare AttnTrace speed vs. perturbation-based attribution.
"""
# AttnTrace
start = time.time()
attributor = ContextAttributor(model)
attntrace_scores = attributor.attribute_output(
' '.join(context_texts.values()),
context_texts,
query,
num_subsamples=10
)
attntrace_time = time.time() - start
# Perturbation (for comparison)
start = time.time()
perturbation_scores = {}
for text_name in context_texts.keys():
# Ablate this text
ablated_context = ' '.join(
text for name, text in context_texts.items() if name != text_name
)
# Measure output change (expensive!)
perturbation_scores[text_name] = 0.5 # Placeholder
perturbation_time = time.time() - start
print(f"AttnTrace: {attntrace_time:.2f}s")
print(f"Perturbation: {perturbation_time:.2f}s (estimate)")
print(f"Speedup: {perturbation_time / attntrace_time:.1f}x")
return attntrace_scores
When to Use:
When NOT to Use:
Hyperparameters:
| Parameter | Default | Impact |
|-----------|---------|--------|
| k_top_tokens | 5 | Higher = less noise but may miss important signals |
| subsample_fraction | 0.7 | Lower = sharper signals but fewer texts represented |
| num_subsamples | 10 | More = better averaging, higher computation |
Paper: AttnTrace: Attention-based Context Traceback for Long-Context LLMs (2508.03793)
testing
Uses flow maps as look-ahead operators to enable principled reward-guided diffusion by predicting trajectory endpoints at any denoising step. Deploy when applying rewards or preferences to diffusion trajectories with meaningful gradients throughout generation.
testing
Train language models where each expert learns independently on closed datasets, enabling flexible inference with selective data inclusion or exclusion. 41% performance improvement while allowing users to opt out of specific data sources without retraining.
data-ai
Understand how token generation flexibility in diffusion LMs paradoxically constrains reasoning, as models exploit ordering flexibility to avoid uncertain tokens, and apply simplified approaches that preserve parallel decoding benefits. Use when optimizing diffusion-based language models for reasoning tasks.
devops
Enable LLM agents to improve continuously during deployment by constructing structured experience libraries through self-reflection on successes and failures—achieving 23% improvement on reasoning without gradient-based parameter updates or external training.