Choosing an algorithm¶
All algorithms share one contract (an event-in, events-out function over projected run state), so they compose: a
PlanAndExecute executes steps with a ToolLoop, a Router delegates to any algorithm, a Supervisor coordinates
several. Start from the simplest one that fits.
flowchart TD
Q{What decides<br/>the next step?}
Q -->|The model, by calling my functions| T[ToolLoop]
Q -->|The model, but it cannot do tool calling| R[ReAct]
Q -->|A plan the model writes first| P[PlanAndExecute]
Q -->|Me, in code| W{Cycles or long waits<br/>for outside events?}
W -->|No: a DAG| WG[WorkflowGraph]
W -->|Yes| F[FSM]
Q -->|One of several specialists| RT[Router]
Q -->|Several specialists at once| SV[Supervisor]
Q -->|I can check the output| V{With code or with a model?}
V -->|Code: schema, tests, rules| G[GenerateTestRepair]
V -->|Another model| C[GeneratorCritic]
Q -->|Same question, vote| S[SelfConsistency]
Q -->|Answer from my documents| RG[RAGAgent]
At a glance¶
| Algorithm | Control flow decided by | LLM calls | Key knobs | Result value |
|---|---|---|---|---|
ToolLoop |
the model | 1 per turn | max_turns, tool_names, system, stream |
{"text", "turns"} |
ReAct |
the model (text protocol) | 1 per turn | same | {"text", "turns"} |
PlanAndExecute |
model plans, code schedules | plan + per-step + synthesis | executor, max_parallel, max_replans, synthesize |
{"text", "results"} |
Router |
rules, then optionally the model | 0 or 1 | classifier, default, routes |
the chosen child's value |
Supervisor |
the model, via delegate tools | per turn + workers | workers, extra_tools |
{"text", "turns"} |
GenerateTestRepair |
your validator | 1 per attempt | validator, max_iterations |
{"candidate", "iterations"} |
GeneratorCritic |
a critic model | 2 per attempt | critic_model, max_iterations |
{"candidate", "iterations"} |
WorkflowGraph |
your DAG | 0 | nodes, output |
the output node's result |
FSM |
your transition table + events | 0 | transitions, terminal, on_enter |
{"state", "path"} |
SelfConsistency |
vote | n in parallel |
n, temperature, extract |
{"answer", "votes", "samples", "agreement"} |
RAGAgent |
the model | per turn | index, k |
{"text", "turns"} |
Rules of thumb¶
- Prefer determinism you can have. If the steps are known, a
WorkflowGraphis cheaper, faster and more predictable than asking a model to rediscover them. Use the LLM where judgement is needed and code elsewhere. - Verify with code before verifying with a model.
GenerateTestRepairwith a real check (a schema, a unit test, a business rule) beatsGeneratorCriticwhenever you can write the check. - Voting is for exact answers.
SelfConsistencyhelps when answers can be compared (numbers, labels, extracted fields). It does not help with free-form prose. - Plans cost latency.
PlanAndExecutepays for planning and synthesis calls. It earns that back when steps run in parallel or are long; for a two-tool task aToolLoopis better. - Cap everything. Give every algorithm a
Budget, andmax_turns/max_iterationswhere offered. Loops that can run forever eventually will.
Common to all¶
- Input is a dict. The built-ins read
task(a string);ToolLoop/ReActalso acceptmessages(a full message list in theMessageshape) for complete control of the starting conversation. - Pass
model=to choose a model per algorithm, andparams={"temperature": 0, ...}for request parameters. - Each algorithm's
namemust be unique within an engine's cluster (it is how runs are routed).ToolLoop(..., name="billing")renames an instance. - Every outcome kind is possible; see Outcomes and errors.