A framework for optimizing LLM agent harness through Formulas.
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.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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
pip install strands-harness-optimizerfrom 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.'})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: ...Attaches Formulas to strands agents as hook callbacks.
apply_formulas_on_strands_agent(agent, [formula1, formula2])Scores agent rollouts. Returns a dict with reward_value and optional metadata.
class RewardFunction(ABC):
def __call__(self, **kwargs) -> dict: ...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: ...Generates rollouts by executing agents on data samples.
class AgentRolloutEngine(ABC):
def generate_batch(self, data_samples: list[dict]) -> Iterator[list[dict]]: ...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
- 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.
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
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
See CONTRIBUTING for more information.