Observed since 20 Oct, 21:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Leave-one-out ablation testing, backward elimination, and ROI evaluation for multi-agent decision systems — find out which agents' findings actually change the outcome.
Leave-one-out ablation testing, backward elimination, and ROI evaluation for multi-agent systems in Python. You have a set of per-agent findings (scores, confidences, telemetry) and a function or model that turns those findings into a verdict. agent-ablation answers the key production questions:
Zero runtime dependencies. Pure Python 3.9+.
pip install agent-ablation
from typing import List
from agent_ablation import Finding, run_ablation
def decide(findings: List[Finding]) -> str:
# Noisy-OR combination
survival = 1.0
for f in findings:
survival *= (1.0 - f.score / 100.0)
risk = 1.0 - survival
if risk >= 0.7:
return "decline"
if risk <= 0.3:
return "approve"
return "escalate"
findings = [
Finding(agent_id="transaction_pattern", score=25),
Finding(agent_id="identity_signal", score=90),
Finding(agent_id="network_analysis", score=20),
]
result = run_ablation(findings, decide)
print(result.baseline) # "decline"
print(result.load_bearing_ratio) # 0.33 (1 out of 3 agents flipped the outcome)
for p in result.per_agent:
print(p.removed_agent_id, "->", p.verdict_without, "(load-bearing)" if p.changed else "")
Pass telemetry (cost, tokens, latency_ms) inside your findings. batch_ablation computes the exact ROI metrics and identifies expensive agents with low decision impact:
from agent_ablation import Finding, batch_ablation, format_markdown_report
cases = [
[
Finding(agent_id="expensive_reasoner", score=90, cost=0.15, tokens=3000),
Finding(agent_id="cheap_heuristic", score=10, cost=0.002, tokens=50),
],
[
Finding(agent_id="expensive_reasoner", score=20, cost=0.15, tokens=3000),
Finding(agent_id="cheap_heuristic", score=85, cost=0.002, tokens=50),
],
]
results, summary = batch_ablation(cases, decide)
print(summary.roi.agents["expensive_reasoner"].cost_per_verdict_flip) # Cost per decision flip
print(summary.roi.recommendations) # Automated pruning/downgrade advice
# Format into a Markdown report for PRs or documentation
print(format_markdown_report(summary))
When your decision step is an async LLM call with temperature, use run_ablation_async or batch_ablation_async. Set samples=k to take a majority-vote consensus across runs to eliminate sampling noise:
import asyncio
from agent_ablation import Finding, run_ablation_async
async def llm_supervisor_decide(findings: List[Finding]) -> str:
res = await call_llm_judge(findings)
return res["verdict"]
result = await run_ablation_async(
findings,
llm_supervisor_decide,
samples=5, # Runs 5 samples per ablation to filter out temperature noise
)
If you have correlated or redundant agents (e.g., three critics looking at the same context), simple leave-one-out might mark all of them as not load-bearing because the others compensate.
run_backward_elimination iteratively eliminates agents one-by-one until removing any further agent flips the verdict, revealing the minimal viable panel:
from agent_ablation import run_backward_elimination
result = run_backward_elimination(all_specialists, decide)
print(result.minimal_agent_ids) # ["critic_1", "security_auditor"]
print(result.eliminated_agent_ids) # ["critic_2", "critic_3", "scout_noisy"]
print(result.steps) # Step-by-step elimination trace
For detecting 2nd-order joint dependencies, run_pairwise_ablation(findings, decide) evaluates all pairs $(A, B)$ to catch cases where neither agent alone is load-bearing, but removing both together flips the outcome.
Supply ground truth labels in batch_ablation to measure whether an agent's load-bearing presence actually improved accuracy or injected errors / hallucinations:
results, summary = batch_ablation(
cases,
decide,
ground_truth=["approve", "decline", "approve", "escalate"],
)
# Per-agent stats:
# - Protective: removing the agent caused a correct verdict to become incorrect
# - Harmful: removing the agent fixed an incorrect verdict
print(summary.per_agent_stats["hallucinating_agent"].role) # "Harmful"
print(summary.per_agent_stats["hallucinating_agent"].net_accuracy_impact) # -0.25
Zero-dependency adapters to map telemetry and messages from popular agent frameworks directly into Finding:
from agent_ablation import from_langgraph_messages
findings = from_langgraph_messages(
state["messages"],
score_of=lambda msg: msg["content"]["score"],
confidence_of=lambda msg: msg["content"].get("confidence"),
)
from agent_ablation import from_crewai_tasks
findings = from_crewai_tasks(
crew_output.tasks_output,
score_of=lambda task: task.json_dict.get("score", 0),
)
from agent_ablation import from_autogen_messages
findings = from_autogen_messages(
chat_history,
score_of=lambda msg: msg["content"]["risk_score"],
)
from agent_ablation import from_ai_sdk_steps
findings = from_ai_sdk_steps(
steps,
score_of=lambda step: step["result"]["score"],
)
from agent_ablation import from_records
findings = from_records(
custom_audit_records,
agent_id=lambda r, idx: r.specialist_id,
score_of=lambda r, idx: r.risk_score,
confidence_of=lambda r, idx: r.confidence_level,
)
SentryMesh is a four-specialist multi-agent fraud investigation system. Its eval harness runs an ablation over its 23-case bank and reports: of 9 cases auto-resolved without human escalation, only 3 survive removal of their single loudest specialist — 6 collapse to escalate.
tests/test_ablation.py reproduces all 6 cases verbatim with agent-ablation.
decide() measures causal weight with zero LLM re-invocation cost.| Function | Description |
|---|---|
run_ablation(findings, decide, equals=None) | Synchronous leave-one-out ablation for a single case. |
run_ablation_async(findings, decide, equals=None, samples=1, aggregate_samples=None) | Async leave-one-out ablation with optional $K$-sampling / majority voting. |
batch_ablation(cases, decide, equals=None, ground_truth=None) | Batch ablation with telemetry ROI and ground-truth metrics. |
batch_ablation_async(cases, decide, equals=None, samples=1, aggregate_samples=None, ground_truth=None) | Async batch ablation. |
run_backward_elimination(findings, decide, equals=None) | Greedy backward elimination to find the minimal agent panel. |
run_backward_elimination_async(findings, decide, ...) | Async greedy backward elimination. |
run_pairwise_ablation(findings, decide, equals=None) | Evaluates all 2-agent pairs to detect interaction/redundancy effects. |
format_markdown_report(summary, title=..., include_roi=True, include_recommendations=True) | Formats summary into a GitHub/Dev.to markdown report with ROI tables. |
format_ascii_table(summary) | Formats summary into a clean terminal ASCII table. |
from_langgraph_messages(...) | Adapter for LangGraph message arrays. |
from_crewai_tasks(...) | Adapter for CrewAI task outputs. |
from_autogen_messages(...) | Adapter for AutoGen chat histories. |
from_ai_sdk_steps(...) | Adapter for AI SDK / tool execution traces. |
from_records(...) | Generic record mapper. |
MIT © Ayush Verma — ayushv3533e@gmail.com
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.0 | 22 Sept 2026 | 1 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f27a7e3f11164565f3817b1a0e665d8064a4e0a845025c0aa0ae886dda6872c1