Domain-agnostic adaptive experimentation framework: experiment → measure → learn → challenge.
Project description
adaptive_iteration
Domain-agnostic adaptive experimentation framework.
A lightweight Python framework that abstracts the experiment → measure → learn → challenge cycle into reusable components. Bring your own domain; the framework handles the rest.
What It Is
adaptive_iteration/
├── core/ # pure Python stdlib, zero domain deps
│ ├── experiment.py # Experiment / Variant dataclasses + ExperimentState
│ ├── ledger.py # JSON append-only results ledger
│ ├── analyzer.py # top/bottom performer detection, variance per dimension
│ ├── hypothesis.py # HypothesisEngine: ledger + analysis → LLM → Experiment candidates
│ └── config.py # AdaptiveConfig: JSON config + winner hints
└── adapters/
├── base.py # DomainAdapter ABC (3 methods to implement)
└── short_video.py # Example adapter: YouTube + Instagram (simulated data)
Installation
# with uv (recommended)
uv add adaptive-iteration
# with pip
pip install adaptive-iteration
Requires Python 3.10+. The only runtime dependency is openai (used only in
HypothesisEngine; the rest of core/ is stdlib-only).
Quick Start
import os
from pathlib import Path
from adaptive_iteration.core.ledger import Ledger
from adaptive_iteration.core.analyzer import Analyzer
from adaptive_iteration.core.hypothesis import HypothesisEngine
from adaptive_iteration.core.config import AdaptiveConfig
# 1. Load / create config
cfg = AdaptiveConfig(Path("data/adaptive_config.json"))
cfg.update({"domain": "my_domain", "primary_metric": "conversion_rate"})
# 2. Open ledger
ledger = Ledger(Path("data/adaptive_ledger.json"))
# 3. Record experiment results
ledger.append(
domain="my_domain",
experiment_id="exp001",
variable="cta_style",
variant="soft",
metric_values={"conversion_rate": 4.2, "bounce_rate": 31.0},
winner=True,
)
# 4. Analyse
analyzer = Analyzer(ledger, primary_metric="conversion_rate")
analysis = analyzer.analyze(domain="my_domain")
print(f"Top performers: {[p['variant'] for p in analysis.top_performers]}")
print(f"Winning patterns: {analysis.winning_patterns}")
# 5. Generate next hypotheses (requires OPENAI_API_KEY)
engine = HypothesisEngine(
ledger=ledger,
api_key=os.environ["OPENAI_API_KEY"],
)
candidates = engine.generate(domain="my_domain", analysis=analysis)
for exp in candidates:
print(f" [{exp.tier}] {exp.variable}: {exp.description}")
Integrating a New Domain
Subclass DomainAdapter and implement three methods:
from adaptive_iteration.adapters.base import DomainAdapter
class MyDomainAdapter(DomainAdapter):
def collect_metrics(self, item_ids: list[str]) -> list[dict]:
"""Pull raw metrics from your external system for each item_id."""
results = []
for item_id in item_ids:
raw = my_api.get_metrics(item_id)
results.append({"id": item_id, **raw})
return results
def get_signals(self, metrics: list[dict]) -> dict:
"""Normalise to framework signals."""
primary = sum(m["conversion_rate"] for m in metrics) / len(metrics)
return {
"primary_metric": primary,
"secondary_metrics": {
"bounce_rate": sum(m["bounce_rate"] for m in metrics) / len(metrics),
},
}
def format_context(self, top_items, bottom_items) -> str:
lines = ["Top performers:"]
for item in top_items:
lines.append(f" [{item['id']}] conversion_rate={item.get('conversion_rate')}")
lines.append("Bottom performers:")
for item in bottom_items:
lines.append(f" [{item['id']}] conversion_rate={item.get('conversion_rate')}")
return "\n".join(lines)
See adapters/short_video.py for a complete reference implementation.
Experiment Modes
| Mode | When to use | Description |
|---|---|---|
interleaved |
Tier 2 | Rotate variants across different items; maximises volume |
paired |
Tier 1 | Generate two variants for the same item; cleaner causal inference |
Tier 1 experiments (high-impact variables) should use paired mode to eliminate
confounding factors introduced by item-level differences.
Import Verification
python3 -c "from adaptive_iteration.core.experiment import Experiment; print('ok')"
Design Principles
core/has zero external deps — pure Python stdlib only (openaiinhypothesis.pyis lazy-imported and optional until you callHypothesisEngine).DomainAdapteris the only layer that touches external systems.Ledgeris the single source of truth — append-only JSON, no database required.HypothesisEngineuses structured JSON output prompting so parsing is deterministic.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adaptive_iteration-0.1.0.tar.gz.
File metadata
- Download URL: adaptive_iteration-0.1.0.tar.gz
- Upload date:
- Size: 12.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ba960fe90d517b50e659e3b90c9a7ba7bf6aa962dcc8fa266588ee71a7b1655
|
|
| MD5 |
e6455ff39565c021962013d95db6d7e4
|
|
| BLAKE2b-256 |
8f05e788ff806d031fda1c31983fb7ea9204fb1e673dad6e6393895e101f48a1
|
File details
Details for the file adaptive_iteration-0.1.0-py3-none-any.whl.
File metadata
- Download URL: adaptive_iteration-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8dda3731cdffcfce61dffb9756424e83926dba2af1cb1a60cf719e6b8855a5a4
|
|
| MD5 |
a62a2b6ab117841d3462a6340a8db711
|
|
| BLAKE2b-256 |
1cf9d6ce4d04d22b0638cd7ea33af8fb441c1558cf83aa5117ce0371b7a70b68
|