AdaptiveGraph
from adaptivegraph import LearnableEdge
AdaptiveGraph provides LearnableEdge – a conditional edge that improves routing decisions over time through reinforcement learning.
What is LearnableEdge?
LearnableEdge replaces static routing logic with a learning-based approach. Instead of hard-coded if/else statements, it learns from feedback which routes work best for different inputs.
Key Features:
- 🧠 Learning: Adapts routing decisions based on feedback (currently LinUCB, more policies coming)
- ⚡ Lightweight: No training phase, no model files – learns online
- 🎯 Balanced: Balances exploration (trying new routes) vs exploitation (using proven routes)
- 🔧 Flexible: Works with strings, dicts, numpy arrays, or custom embeddings
Why LearnableEdge?
Traditional routing logic is static and brittle. LearnableEdge adds plasticity – it learns which routes work best through experience, automatically adapting as patterns change.
Installation
From PyPI:
pip install adaptivegraph
From source:
git clone https://github.com/BharathBillawa/adaptivegraph.git
cd adaptivegraph
pip install -e .
With optional dependencies:
# For semantic embeddings
pip install adaptivegraph[embed]
# For persistent storage
pip install adaptivegraph[faiss]
# For development
pip install adaptivegraph[dev]
# Everything
pip install adaptivegraph[all]
Quick Start
from adaptivegraph import LearnableEdge
# Create edge with routing options
edge = LearnableEdge(options=["expert_model", "fast_model", "cheap_model"])
# Make decisions
route = edge({"user": "premium", "query": "complex question"})
# Provide feedback so it learns
edge.record_feedback(result={}, reward=1.0)
See more examples:
examples/basic_routing.py- Simple routing with feedbackexamples/customer_support_agent.py- LangGraph integrationnotebooks/interactive_demo.ipynb- Interactive walkthrough
How LearnableEdge Works
Think of LearnableEdge as a smart traffic router that learns which highway to recommend:
- Input State → You provide any state (string, dict, array)
- Encoding → Converts state into a fixed-size vector (32-dim by default)
- UCB Scoring → For each option, calculates:
- Expected reward (what worked before)
- Uncertainty bonus (exploration value)
- UCB Score = expected_reward + α × uncertainty
- Selection → Picks option with highest UCB score
- Feedback → You call
record_feedback(reward) - Learning → Updates internal belief about which options work best
The algorithm balances:
- Exploitation → Using routes with good historical performance
- Exploration → Trying routes with high uncertainty
Features
- **Semantic Routing**: Use sentence transformers for similarity-based decisions (requires `adaptivegraph[embed]`)
- **Async Feedback**: Provide feedback hours later using event IDs
- **Trajectory Rewards**: Reward entire multi-step sessions with decay
- **Policy Persistence**: Save and restore learned routing policies
## Usage Examples
### Async Feedback
Pass `event_id` in the state to track decisions, then use it to record feedback later.
```python
# 1. Make decision with event_id
state = {"user": "premium", "query": "async test", "event_id": "req_123"}
route = edge(state)
# 2. Record feedback later using the same ID (no state needed)
edge.record_feedback(result={}, reward=1.0, event_id="req_123")
```
### Trajectory (Multi-step) Rewards
Pass `trace_id` in the state to group decisions into a session.
```python
# Step 1
edge({"step": 1, "intent": "greeting", "trace_id": "session_abc"})
# Step 2
edge({"step": 2, "intent": "params", "trace_id": "session_abc"})
# Reward the whole trace
edge.complete_trace(trace_id="session_abc", final_reward=1.0)
```
### Statistics
Inspect memory to see what the model has learned.
```python
stats = edge.memory.get_statistics()
print(f"Total decisions: {stats['total_decisions']}")
print(f"Average reward: {stats['average_reward']:.2f}")
# Access raw history
print(f"History size: {len(edge.memory.state_history)}")
```
## Notes & Gotchas
* **Numpy Arrays**: Must match `feature_dim` (default 32). E.g., `np.random.randn(32)`.
* **Factory Method**: `LearnableEdge.create()` defaults to `embedding="sentence-transformers"`, which requires the optional dependency.
* To use **without** optional dependencies, set `embedding=None` (uses hashing).
* **Optional Dependencies**:
* `embedding="sentence-transformers"` requires `pip install adaptivegraph[embed]`
* `memory="faiss"` requires `pip install adaptivegraph[faiss]`
See [`examples/`](examples/) and [`notebooks/`](notebooks/) for detailed usage.
Comparison
LearnableEdge vs alternatives:
- vs If/Else Rules: Learns from feedback instead of requiring manual updates
- vs ML Classifiers: No training data needed, learns online from real usage
- vs LLM Routers: Faster, cheaper, and adapts based on actual outcomes
- vs Random/Epsilon-Greedy: Uses context to make smarter decisions, not just random exploration
Performance
On a typical customer support routing task (3 options, 1000 decisions):
- Convergence: Achieves >95% accuracy within 50-100 iterations
- Throughput: ~10,000 decisions/second on MacBook Pro M1
- Memory: <50MB for 10,000 experiences
Roadmap
Completed ✅
- Core LinUCB policy
- Persistent storage (FAISS/Pickle)
- Semantic state encoding (Sentence Transformers)
- Async / ID-based feedback
- Trajectory / trace rewards
- Policy state persistence
- Input validation and logging
Planned 🚧
- Thompson Sampling policy
- Epsilon-Greedy policy
- Shared feature LinUCB (not disjoint)
- Distributed training support
- Visualization dashboard
- Automated hyperparameter tuning
- Integration examples (FastAPI, Streamlit)
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Quick Start for Contributors
# Clone and setup
git clone https://github.com/BharathBillawa/adaptivegraph.git
cd adaptivegraph
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Format code
black src/ tests/
isort src/ tests/
Citation
If you use AdaptiveGraph in your research, please cite:
@software{adaptivegraph2024,
title = {AdaptiveGraph: Learnable Conditional Edges for Agentic Workflows},
author = {BharathPoojary},
year = {2024},
url = {https://github.com/BharathBillawa/adaptivegraph}
}
License
MIT License - see LICENSE for details.
Acknowledgments
- Built for LangGraph but framework-agnostic
- LinUCB algorithm from Li et al. (2010)
- Inspired by contextual bandit research in recommendation systems
Support
Made with ❤️ for the AI agent community
Metadata
Release files for adaptivegraph 0.1.2
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 | |
|---|---|---|---|---|
| adaptivegraph-0.1.2.tar.gz | 63.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| adaptivegraph-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 79.5 kB
Release files / adaptivegraph-0.1.2.tar.gz
| Download URL | adaptivegraph-0.1.2.tar.gz |
|---|---|
| Size | 63.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a1bd44e2daafeb145503e36e49b5a249e3a1f7be645979b7a8b2f22df28a6dc0
|
|
BLAKE2b-256 checksum How to use checksums |
408e1961e6e59ca9b365efec9a04c6657101829c7f8c71c95fcacd624f77376c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.11
|
Release files / adaptivegraph-0.1.2-py3-none-any.whl
| Download URL | adaptivegraph-0.1.2-py3-none-any.whl |
|---|---|
| Size | 16.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
07b96c4258f8c9a258764665456457f3f6ae7d253c0fad79afcbc1cd0c1517fb
|
|
BLAKE2b-256 checksum How to use checksums |
dbfc9ea74b7676169026df2c34bb828c49980d5e69237c4523c7f123bedb0c84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.11
|
Security for adaptivegraph 0.1.2
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.