A framework for optimizing LLM agent harness through Formulas.
Overview
Harness Optimizer provides a framework for defining, attaching, and optimizing context units (e.g., system prompts) for LLM agents. The core idea: optimize the LLM agent harness by using tunable Formulas to dynamically enhance the agent, and improving those Formulas with optimizers based on collected agent rollout trajectories.
Naming:
ContextUnitProcessor(CUP) has been renamed toFormula. Legacy names are available viastrands_harness_optimizer.compatwith deprecation warnings.
Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ Trainer.fit() │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ Adapter ┌───────────────────────────┐ │
│ │ Formula (CUP) ├───────────────▶│ LLM Agent │ │
│ │ get_tunable_params()│ (attach to │ (e.g. Strands Agent) │ │
│ │ update_params() │ agent) └───────────▲┬──────────────┘ │
│ └──▲──────────────────┘ invoke agent ││ │
│ │ ││ collect rollout│
│ │ ┌─────────────┐ ┌───────────────────────────┴▼──────────────┐ │
│ │ │ DataLoader │─▶│ AgentRolloutEngine │ │
│ │ │ Out: [data]│ │ In: [data], cup_params │ │
│ │ └─────────────┘ │ Out: [(rollout, data)...] │ │
│ │ └──────────┬────────────────────────────────┘ │
│ │ ▼ │
│ │ ┌───────────────────────────────────┐ │
│ │ │ Rollouts: [(rollout, data) ...] │ │
│ │ └───┬───────────────────────┬───────┘ │
│ │ ▼ ▼ │
│ │ ┌────────────────────┐ ┌───────────────────────────────────┐ │
│ │ │ RewardFunction │ │ FormulaOptimizer │ │
│ │ │ In: rollout, data │─▶│ In: params, [(rollout,data,rwrd)] │ │
│ │ │ Out: reward │ │ Out: new_params │ │
│ │ └────────────────────┘ └───────────────┬───────────────────┘ │
│ │ │ │
│ └──────────────────────────────────────────┘ │
│ new_params │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Data flow:
- DataLoader yields batches of task samples from the Dataset
- AgentRolloutEngine executes the agent on each sample using current Formula parameters, producing rollouts
- Adapter bridges Formula parameters to the agent framework (e.g.,
apply_formulas_on_strands_agent) - LLM Agent runs the task and produces a rollout (conversation trace)
- Adapter bridges Formula parameters to the agent framework (e.g.,
- RewardFunction scores each rollout
- Rollouts, data, and rewards are collected into a batch
- FormulaOptimizer analyzes the batch to propose new Formula parameters
- Formula updates its parameters and the loop repeats
Installation
pip install strands-harness-optimizer
Quick Example
from strands import Agent
from strands_harness_optimizer.formulas import SystemPromptFormula
from strands_harness_optimizer.adapters import apply_formulas_on_strands_agent
# Create a Formula
formula = SystemPromptFormula(system_prompt="You are a helpful assistant.")
# Attach to a strands agent
agent = Agent(model=model)
apply_formulas_on_strands_agent(agent, [formula])
# Get / update parameters (e.g., after optimization)
params = formula.get_tunable_params()
# {'system_prompt': 'You are a helpful assistant.'}
formula.update_params({'system_prompt': 'You are an expert coding assistant.'})
Core Interfaces
Formula (formulas/)
The optimizable unit, formerly known as ContextUnitProcessor (CUP).
class Formula(ABC):
def process(self, context: dict, **kwargs) -> dict: ...
def get_tunable_params(self) -> dict: ...
def update_params(self, params: dict) -> None: ...
def can_process(self, context: dict) -> bool: ...
Strands Adapter (adapters/)
Attaches Formulas to strands agents as hook callbacks.
apply_formulas_on_strands_agent(agent, [formula1, formula2])
RewardFunction (rewards/)
Scores agent rollouts. Returns a dict with reward_value and optional metadata.
class RewardFunction(ABC):
def __call__(self, **kwargs) -> dict: ...
FormulaOptimizer (optimizers/)
Optimizes Formula parameters based on accumulated rollouts and rewards.
Follows PyTorch's pattern: add_rollouts(), add_rewards(), step(), zero().
class FormulaOptimizer(ABC):
def add_rollouts(self, rollouts: list[dict]) -> None: ...
def add_rewards(self, rewards: list[dict]) -> None: ...
def step(self) -> None: ...
def zero(self) -> None: ...
def get_state(self) -> dict: ...
def load_state(self, state: dict) -> None: ...
AgentRolloutEngine (rollout_engines/)
Generates rollouts by executing agents on data samples.
class AgentRolloutEngine(ABC):
def generate_batch(self, data_samples: list[dict]) -> Iterator[list[dict]]: ...
Package Structure
strands_harness_optimizer/
├── __init__.py
├── compat.py # Legacy names (ContextUnitProcessor, etc.)
├── trainer.py # Minimal training loop
├── data/ # PyTorch-style data loading (stdlib adapted)
│ ├── dataset.py # Dataset, IterableDataset, ConcatDataset, Subset
│ ├── sampler.py # Sampler, SequentialSampler, RandomSampler, BatchSampler
│ └── dataloader.py # Simplified DataLoader
├── formulas/ # Formula framework
│ ├── formula.py # Formula ABC
│ ├── system_prompt_formula.py # Built-in: SystemPromptFormula
│ └── context_expansion_formula.py # Built-in: ContextExpansionFormula
├── optimizers/ # Optimization framework
│ ├── optimizer.py # FormulaOptimizer ABC
│ └── system_prompt/ # Built-in optimizers
│ ├── base_agentic_optimizer.py # BaseAgenticOptimizer
│ └── contrastive_reflection.py # ContrastiveReflectionOptimizer
├── rewards/ # Reward computation
│ └── reward_function.py # RewardFunction ABC
├── rollout_engines/ # Agent rollout generation
│ ├── agent_rollout_engine.py # AgentRolloutEngine ABC
│ ├── parallel_engine.py # ParallelAgentRolloutEngine (utilities)
│ ├── local_engine.py # LocalRolloutEngine
│ └── agentcore_engine.py # AgentCoreRolloutEngine
├── templates/ # Jinja2 templates for optimizers
│ └── contrastive_reflection/
│ ├── system_prompt.jinja
│ └── task_message_system_prompt.jinja
├── adapters/ # Agent framework adapters
│ ├── agent_adapter.py # AgentAdapter ABC
│ └── strands_adapter.py # StrandsAdapter, StrandsAgentWithFormulas
└── utils/ # Utilities
├── templates.py # load_builtin_template, list_builtin_templates
├── params_store.py # FormulaParamsStore, S3FormulaParamsStore
└── guardrails/
└── tool_output.py # ToolOutputGuardrail
Design Decisions
- Dict-based data: No wrapper classes for context or evaluation results — plain dicts throughout for simplicity and flexibility.
- Formula = CUP:
ContextUnitProcessorrenamed toFormula. Legacy names available viastrands_harness_optimizer.compat. - Minimal dependencies: Core depends on
strands-agents,strands-agents-tools,jinja2, andbotocorefor the built-in adapter and optimizer. - PyTorch Dataset/DataLoader reuse: Copied from PyTorch source with
torchreplaced by stdlibrandom. No PyTorch dependency. - Minimal Trainer: Users can easily write their own training loop. The built-in Trainer is just two nested for-loops.
Contributing ❤️
We welcome contributions! See our Contributing Guide for details on:
- Reporting bugs & features
- Development setup
- Contributing via Pull Requests
- Code of Conduct
- Reporting of security issues
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Security
See CONTRIBUTING for more information.
Release files for strands-harness-optimizer 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| strands_harness_optimizer-0.0.1.tar.gz | 39.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strands_harness_optimizer-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 88.8 kB
Release files / strands_harness_optimizer-0.0.1.tar.gz
| Download URL | strands_harness_optimizer-0.0.1.tar.gz |
|---|---|
| Size | 39.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ccfbc88c890d9daa82114801146f418c3f6f8cc0e5de7ed2b04b7e99f8856e8
|
|
BLAKE2b-256 checksum How to use checksums |
7f1c538b1cadadc1889393c14c1c4e421dca01cca8e9b9a05540d3a2f71ea8f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.
Transparency logRelease files / strands_harness_optimizer-0.0.1-py3-none-any.whl
| Download URL | strands_harness_optimizer-0.0.1-py3-none-any.whl |
|---|---|
| Size | 49.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9410ad4e3ea548e68fc815022d9510ec29680930c9c194d0fc6e61a069e939a7
|
|
BLAKE2b-256 checksum How to use checksums |
ca6740665afda5d8eaef6ef62c6721eca4ed414d36f077c59b6b0ce588de308f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.
Transparency log