Evolutionary Optimization
Production use
To apply the engine to Purple8 itself (routing policy, RAG retrieval) or to your own app via online experiments, with every result reviewed by a person, see Sentinel & Capability Evolution.
Some tuning problems don't have a closed-form solution — you have a handful of parameters that interact non-linearly, a fitness signal that only comes from observing real outcomes, and no gradient to follow. Purple8 Graph ships a general-purpose evolutionary optimization engine for exactly this class of problem: population-based search over a parameter space, driven by whatever fitness signal your application defines.
This is a domain-agnostic primitive in the core engine — not a packaged product for any single use case. You define a gene specification (the parameters and their bounds) and a fitness function (how good a given configuration is), and the engine handles population management, selection, recombination, and convergence tracking.
What it's used for today
Two Purple8 verticals already delegate to this engine internally rather than reimplementing parameter search from scratch:
| Consumer | What it's tuning |
|---|---|
| SOC & Anomaly Detection | Detection-sensitivity parameters, evaluated against outcome feedback over time |
| AEC Algorithms — generative design (MORL) | Multi-objective design-space search across competing structural/spatial objectives |
The engine itself is exposed as a Python primitive so you can apply the same approach to your own tuning problems — anywhere you'd otherwise hand-tune a handful of interacting parameters against a slow, noisy, or non-differentiable feedback signal.
Core concepts
- Gene specification — a named, typed, bounded parameter (
float,int, orbool) with a default value. A set of gene specs defines the search space. - Genome — one candidate configuration: a point in that search space, plus its recorded fitness score(s) once evaluated.
- Fitness function — your code. Given a genome, run whatever evaluation makes sense for your domain (a backtest, a simulation, a batch of live outcomes) and return a score.
- Population — the engine maintains a pool of genomes across generations, applying selection, recombination, and mutation to explore the space while preserving the best-performing configurations found so far.
from purple8_graph.core.evolution import GeneSpec, EvolutionaryEngine
genes = [
GeneSpec("learning_rate", "float", 0.001, 0.5, default=0.01),
GeneSpec("num_layers", "int", 1, 8, default=3),
GeneSpec("use_dropout", "bool", default=True),
]
def my_fitness(genome) -> float:
config = genome.to_config()
# ... evaluate `config` against your own outcome data ...
return score # higher is better
engine = EvolutionaryEngine(gene_specs=genes, fitness_fn=my_fitness)
engine.seed_population()
for cycle in range(100):
config = engine.active_config
# ... use `config` in your application, observe an outcome ...
engine.record_outcome(engine.champion.id, score=observed_score)
engine.end_cycle()
print(engine.stats)Beyond single-objective tuning
The engine supports several search modes beyond a single scalar fitness score, selected via constructor options rather than separate APIs:
| Mode | When to use it |
|---|---|
| Multi-objective (Pareto) search | You're optimizing several competing objectives at once (e.g. accuracy vs. cost vs. latency) and want the full trade-off frontier, not one "best" answer forced onto a single score. |
| Novelty search | Fitness is sparse, deceptive, or you specifically want to discover unusual/unclassified configurations rather than converge on one optimum — useful for surfacing outliers a purely fitness-driven search would ignore. |
| Island model | You want several sub-populations evolving semi-independently (occasionally cross-pollinating) rather than one converging population — improves diversity and supports safely trialling candidates in isolation before promoting them. |
| Coevolution | Fitness depends on a second, simultaneously-evolving population (e.g. a detector and an evasion strategy) rather than a fixed evaluation target. |
Each mode is opt-in and composable with the base single-objective flow shown above — see the module docstring in your local installation (purple8_graph.core.evolution) for full constructor signatures.
MCP Tools (evolution.* namespace)
AI agents can create and run evolutionary experiments directly through MCP (part of Purple8's 125 MCP tools across 16 namespaces):
evolution.create_experiment— define genes, bounds, and population parametersevolution.list_experiments— inspect active experiments and generation progressevolution.suggest— fetch a candidate genome configuration to evaluateevolution.report— record an observed outcome score for a genomeevolution.propose— open a human-gated Sentinel finding when a candidate beats the baselineevolution.production— retrieve the currently promoted production configurationevolution.routing_policy— evolve LLM model routing policies against cost/quality outcomesevolution.rag_retrieval— evolvefusion_alpha,max_hops, andseed_kagainst an evaluation set
See Sentinel — Human-Gated Proactive Intelligence for the full REST and MCP workflow.
Related guides
- Sentinel & Capability Evolution
- SOC & Anomaly Detection
- AEC Algorithms
- Graph Analytics — for algorithms with a closed-form/deterministic solution (PageRank, community detection, etc.) rather than population-based search