Optimization runs without a config
This topic explains how to define judges, model choices, and evaluation parameters directly in code without a LaunchDarkly configuration object. This lets you perform optimization runs without an optimization config.
Code example
Here is a complete example using optimize_from_options with the Claude Agent SDK:
Code explanation
Section 1: Handlers
Section 1 sets up the agent call for our provider to handle the LLM invocations. These methods are intended to be provider-agnostic, so you can use your own models as long as your orchestrator or framework can reach them.
There are two different handlers. They are:
handle_agent_callexecutes the actual agent and receives a response. This code path is also used to generate new variations when the system requires it. To allow this, pass the calls through as generically as possible. Evaluators may need access to your tools for evaluation, so make sure it’s configured for both execution and new variation generation.handle_judge_call(optional) executes the evaluation calls. It falls back tohandle_agent_callif not provided. Specify this as a discrete handler if you want to capture response information, log metrics, or otherwise run judge calls differently from agent calls.
Your evaluator may need access to the same tools as your model. If you separate evaluator and model calls, specify tools for both.
Section 2: Optimization parameters
Section 2 sets up the optimization parameters. Here’s how:
judgesdefines the scoring mechanisms used to find prompt acceptance. Judges can be acceptance statements or judge configs. To learn more, read Performing optimization runs.context_choices(optional) defines the list of LaunchDarkly contexts that can be automatically chosen from when running a completion.max_attemptssets the maximum number of iterations allowed before failing. Use this to prevent over-spending on complex optimizations that may not reach a useful outcome. This does not correlate to the exact number of LLM calls made. Each optimization attempt incurs multiple LLM calls.model_choicesdefines the models that the optimizer is allowed to choose between throughout the optimization process.judge_modeldefines the model used for judging. This remains consistent across executions unless you intervene.variable_choicesdefines a list of variable choice sets that are randomly chosen when executing the agent. Larger numbers ofvariable_choicesanduser_input_optionsleads to more possible permutations and lessens the chance of instruction overfitting.user_input_optionsdefines a list of user inputs that are randomly chosen when executing the agent.handle_agent_callexecutes the agent calls.handle_judge_call(optional) executes the evaluation (judge) calls. It falls back tohandle_agent_callif not provided.
Output
In (3), we’re initializing the client and running the actual optimization. If you have info logging turned on, you can read the process as it runs in your logs. Here’s an example of the output with info logging turned on:
This call returns an OptimizationContext representing the final output of the optimization. You can access OptimizationContext.history to get all of the historical OptimizationContexts generated during the run.
Here is an abbreviated example output: