Single#
One agent solves the task end to end in a reason-act loop with its tools. It is the control condition: every multi-agent result is read against it.
How it works#
- The runner reads the seed prompt
configs/prompts/single/<dataset>/solver.txtand wraps it with the dataset's protected output contract fromcore/output_contracts.py(for HotpotQA: end with one lineAnswer: <short-form>). HotpotQA and MATH also append a short format note. - It builds one agent with LangGraph's prebuilt
create_react_agent, bound to the dataset's tools:wikipedia_searchandwikipedia_pagefor HotpotQA,calculatorfor GPQA and MATH,python_execfor LiveCodeBench and APPS,file_read,file_write,list_dir,search_repoandshell_execfor SWE-bench, and tools built from the function schemas for BFCL. - The agent alternates between reasoning and tool calls. Each tool result is appended to its history. The loop ends when the model replies without a tool call, or when LangGraph's recursion limit is reached (25 steps; 100 for SWE-bench).
- The runner parses the final message with the dataset's extractor and scores it.
There is no hand-off, no second agent and no vote. Whatever the one prompt makes the model do is the result.
Agent role and seed prompt#
Every dataset uses a single role, solver:
| Dataset folder | Seed prompt |
|---|---|
gpqa, hotpotqa, math, lcb, apps, bfcl, swe, toolhop, apibank |
configs/prompts/single/<dataset>/solver.txt |
The role descriptions the prompts were generated from are under single: in configs/prompts/roles.yaml. The optimizers read these files and never overwrite them; a job keeps its prompts under its own --out folder.
Implementation#
- Reference scaffold:
topologies/single/langgraph_base.pyshows the pattern in 54 lines:create_react_agentwith toy tools (add,multiply, a mockweb_search). It is a demo, not a benchmark runner. - Dataset runners:
topologies/single/<dataset>/langgraph_<dataset>.py, one per dataset. Each wires the real tools to the same ReAct agent; the loader, scorer and records come from the dataset's task module incore/tasks/. - ToolHop and API-Bank: these two runners don't use LangGraph objects. ToolHop runs a plain tool loop on the
openaiclient (9 turns by default,TOOLHOP_MAX_TURNS); API-Bank makes one model call. Both live incore/tasks/toolhop.pyandcore/tasks/apibank.py, shared by every topology's runner.
Run it#
Run from the repository root with a model endpoint configured (Connect a Model).
python -m topologies.single.hotpotqa.langgraph_hotpotqa
python -m topologies.single.hotpotqa.langgraph_hotpotqa --batch --limit 100 \
--out-dir results/topologies_baseline/single_hotpotqa
Other datasets follow the same module path with a different folder and file name, for example topologies.single.math.langgraph_math. BFCL, SWE-bench, ToolHop and API-Bank have no demo and always run a batch. See the task pages for each dataset's options.
Optimize it#
The protocol topology is single, with one prompt to tune, solver. In the experiment grid, the Single topology is optimized by GEPA and MIPRO; the other six methods optimize multi-agent teams.
python -m optimizers.protocol.run --method gepa --dataset math --topology single \
--model qwen --seed 0 --out runs/gepa/math/single/qwen/0
See Run an Optimizer for endpoints and outputs.