BODE-GEN

Tests Turn Prompting into Search

What I learned building the evaluation pipeline behind BODE-GEN, where executable tests turn code prompting into an optimization problem.

Prompt engineering is difficult to reason about when success means that an output simply feels better. Code gives us a sharper signal: generate a program, execute it, and count the tests it passes. Once that loop exists, prompt design stops being only a writing exercise and becomes an optimization problem.

That was the framing behind BODE-GEN, our study of Bayesian optimization for test-driven code generation. I built the evaluation pipeline and ran reproducible experiments across 164 HumanEval+ tasks and three code models. The headline numbers were strong, but the more durable lesson was about evaluation: tests can turn an ambiguous prompting process into a search problem with an explicit objective.

The evaluation is the objective

Suppose a coding task begins with an initial prompt and a set of developer tests. A base language model produces code, and the code receives a score from the fraction of tests it passes. We want a revised prompt that raises that score while trying as few prompts as possible.

The search is hard for two reasons. Prompts are discrete sequences drawn from a huge combinatorial space, and every candidate is expensive: it requires model inference followed by program execution. Randomly rewriting the prompt wastes the information contained in previous trials. Bayesian optimization is useful because it maintains a probabilistic model of that history and chooses the next candidate by balancing promising regions against uncertain ones.

The loop

  1. Choose a candidate embedding with Expected Improvement.
  2. Combine it with the original prompt and a fixed rewriting instruction.
  3. Use the auxiliary model to decode an interpretable candidate prompt.
  4. Ask the base model for code and execute that code against the tests.
  5. Return correctness to the surrogate model and repeat.
history = []
for candidate in optimizer:
    prompt = auxiliary_llm.decode(candidate, initial_prompt)
    code = base_llm.generate(prompt)
    score = run_tests(code)
    history.append((candidate, score))
    optimizer.update(history)

The important detail is that the optimizer never evaluates whether a prompt sounds more sophisticated. It only sees whether the resulting program works.

What I built

My contribution centered on the test-driven evaluation infrastructure. I built the pipeline that generated programs, executed them against the expanded HumanEval+ tests, aggregated correctness, and supported repeatable comparisons across the three base models and prompting baselines.

That work made a mundane point feel concrete: an optimization method is only as credible as the evaluator underneath it. A malformed generation, inconsistent harness, or nondeterministic comparison can look like an optimization gain. The experiment pipeline is not plumbing around the research result; it is part of the result.

Experimental setup

We evaluated all 164 Python tasks in HumanEval+. Compared with the original HumanEval, the benchmark expands the test suites by roughly 80 times, making it harder for superficially correct programs to survive evaluation.

The base models were ChatGPT-3.5 Turbo, CodeLlama-7B, and DeepSeek-Coder-33B. Each prompt produced three code samples for pass@1-style evaluation. The optimizer began with 20 randomly selected embedding points, then ran for 50 Bayesian optimization iterations across five seeds. The baselines were the initial HumanEval+ prompt, zero-shot Chain-of-Thought, and OPRO, an iterative LLM-driven prompt optimizer.

Results

The table reports the share of HumanEval+ tasks solved to full test-suite correctness. BODE-GEN improved over the initial prompt and OPRO for all three base models in our setup.

Bar charts comparing initial prompts, BODE-GEN, chain-of-thought, and OPRO on ChatGPT 3.5 and CodeLlama 7B
BODE-GEN achieved the highest aggregate correctness for both ChatGPT 3.5 and CodeLlama-7B in our evaluation. Figure 2 from the paper.
Share of tasks solved to 100% correctness
Base modelInitialCoTOPROBODE-GEN
ChatGPT-3.561%63%78%89%
CodeLlama-7B23%22%38%50%
DeepSeek-Coder-33B66%-78%94%

The search often found meaningful gains within the first 20 to 30 iterations and approached its best observed performance by iteration 50. The advantage over the baselines also grew on tasks where the initial prompt performed poorly. That matters because easy tasks leave little room for any optimizer to demonstrate value.

What optimized prompts changed

We manually examined 15 tasks with substantial correctness improvements. The optimized prompts did not converge on one magic phrase. They repeatedly made the task easier to parse:

Side-by-side comparison of an original HumanEval+ prompt and a more explicit BODE-GEN optimized prompt
One optimized prompt moves examples out of the docstring, names edge cases, and states the task in direct language. Excerpt from Figure 8 of the paper.
  • Examples became visible. Inputs and outputs were separated from dense docstrings.
  • Instructions became explicit. Short requirements were expanded into plain-language descriptions.
  • Structure improved. Assumptions, constraints, and examples were placed in distinct sections.
  • Edge cases were named. The prompt made hidden conditions harder for the model to overlook.
  • Tasks were decomposed. Multi-step behavior was described in the order the program needed to implement it.

These observations are useful, but they are not a causal proof that any one pattern produces the gain. The optimizer changes several aspects at once. The tests tell us which complete prompt worked, not which sentence deserves credit.

What the results do not say

HumanEval+ is a controlled benchmark, not a production codebase. Its function prompts and unit tests give us a clean objective, but real software tasks carry repository context, integration constraints, and requirements that are much harder to encode in one score.

The method also depends on having useful tests. If the test suite misses an important behavior, optimization can confidently select a prompt that exploits that omission. Better search does not repair a weak objective.

Finally, sample-efficient does not mean free. Each candidate still requires multiple generations and program executions, and model behavior remains stochastic. The experiments show that this search worked for the selected models and benchmark; they do not guarantee the same margin for newer models or arbitrary software tasks.

The broader lesson

Optimization does not rescue a bad evaluator. It amplifies it.

The most interesting part of BODE-GEN is not that Bayesian optimization can rewrite a prompt. It is that executable feedback changes what prompting can be. Without tests, revisions are judged by taste or a proxy model. With tests, each trial becomes evidence, and the history of failures can guide the next search decision.

I now think of evaluation as part of the learning system rather than a final report card. The same principle appears in agents and robotics: the behavior we can improve is constrained by the feedback we can measure. Better optimization helps only after that feedback represents what we actually care about.

Citation

The underlying research is available on arXiv, as a local PDF, and as a BibTeX record.

Please cite this essay as:

Ethan Villalovoz, "Tests Turn Prompting into Search," ethanvillalovoz.com, Jul 2026. https://ethanvillalovoz.com/writing/tests-turn-prompting-into-search/

Or use BibTeX:

@misc{villalovoz2026promptsearch,
  author = {Ethan Villalovoz},
  title = {Tests Turn Prompting into Search},
  year = {2026},
  howpublished = {ethanvillalovoz.com},
  note = {https://ethanvillalovoz.com/writing/tests-turn-prompting-into-search/}
}