agent-ablation (Python)
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:
- Load-Bearing Influence: Which agents' findings actually changed the verdict, and which were along for the ride?
- Cost & Token ROI: How many dollars and tokens did each specialist burn per verdict flip? Does that small accuracy bump justify the API bill?
- Correlated Agents & Pruning: Which redundant agents can be safely pruned via greedy backward elimination without breaking the final verdict?
- Protective vs. Harmful Signals: When ground truth is provided, did an agent's presence prevent an error (protective), or did it cause a hallucination/false positive (harmful)?
- Stochastic & Async LLM Judges: Handles async decisions and repeated sampling with majority voting to filter out LLM temperature variance.
Zero runtime dependencies. Pure Python 3.9+.
Install
pip install agent-ablation
Core Features & Usage
1. Basic Leave-One-Out 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 "")
2. Cost & Token ROI Analysis ("Cost per Verdict Flip")
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))
3. Async & Stochastic Decision Functions (LLM-as-a-Judge)
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
)
4. Greedy Backward Elimination & Minimal Viable Panel
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.
5. Ground-Truth & Net Accuracy Impact ("Protective vs. Harmful")
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
Framework Adapters
Zero-dependency adapters to map telemetry and messages from popular agent frameworks directly into Finding:
LangGraph / LangChain
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"),
)
CrewAI
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),
)
AutoGen
from agent_ablation import from_autogen_messages
findings = from_autogen_messages(
chat_history,
score_of=lambda msg: msg["content"]["risk_score"],
)
Vercel AI SDK / Trace Steps
from agent_ablation import from_ai_sdk_steps
findings = from_ai_sdk_steps(
steps,
score_of=lambda step: step["result"]["score"],
)
Generic Custom Records
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,
)
Worked Example: SentryMesh 33% Multi-Signal Finding
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.
Architectural Note: Leaf Ablation vs. DAG Subgraph Replay
- Leaf Finding Ablation (This Package): Best for parallel / fan-out / fan-in panels where specialists independently produce findings that feed a decision gate. Because findings are generated independently, dropping an item at
decide()measures causal weight with zero LLM re-invocation cost. - Sequential DAG Replay: If your pipeline is sequential (Agent A feeds intermediate prompt context to Agent B), removing Agent A at the final decision gate misses that Agent B's output already reflects Agent A. Measuring sequential pipelines requires replaying downstream subgraphs or injecting mock messages into the trace.
API Summary
| 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. |
License
MIT © Ayush Verma — ayushv3533e@gmail.com
Metadata
Release files for agent-ablation 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| agent_ablation-0.3.0.tar.gz | 25.6 kB | Without provenance | Details for agent_ablation-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| agent_ablation-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for agent_ablation-0.3.0-py3-none-any.whl |
Total release size: 45.0 kB
Release files / agent_ablation-0.3.0.tar.gz
| Download URL | agent_ablation-0.3.0.tar.gz |
|---|---|
| Size | 25.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3671e555b500000d7cd6ea0ce6a142990129066d50d54abce1a44c0a0cde60e
|
|
BLAKE2b-256 checksum How to use checksums |
742358fcec21cf0fe332b30a43c450658865e71d0d1068f6806dba3032d33eee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Release files / agent_ablation-0.3.0-py3-none-any.whl
| Download URL | agent_ablation-0.3.0-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f1f43295155c8b5f0db0cc50cdfaac72ff5dc272dd1b78a51e7f54fad36f8fe
|
|
BLAKE2b-256 checksum How to use checksums |
a97021b16259fc136975e42fd4fdb63f028995bbe8ca05e4d1913cd0f0d7801e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Security for agent-ablation 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.