We use cookies

We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.
Learn more.

CookbooksAI AgentsReasoning Loop

Reasoning Loop

AI agents follow a reason-act-observe loop that can run for minutes or hours, repeating until the LLM determines the task is complete or a deterministic exit condition is met (max iterations, timeout, tool signal).

In Hatchet, this is implemented as a durable task with a loop. At each iteration, the task spawns a child to call the LLM, execute any tool calls, and determine whether additional iterations are required. Each completed iteration is checkpointed, so the agent survives crashes and worker slots are freed between iterations.

When to use

ScenarioFit
Chatbot that picks tools based on user messagesGood: the loop runs until the agent has a final answer
Multi-step research that may take minutesGood: durable execution survives long-running loops
Agent that needs human approval mid-loopGood: combine with Human-in-the-Loop
Fixed pipeline (prompt, generate, validate)Skip: use LLM Pipelines instead
One-shot classification or extractionSkip: a single task is simpler

Step-by-step walkthrough

You’ll build a durable agent task that streams tokens and survives restarts.

Reasoning loop

Define the core loop. Each iteration calls the LLM, executes any tool calls, and checks whether the task is complete.

The examples above use a mock LLM. To call a real provider, swap get_llm_service() with one of these. Tool execution is typically your own APIs; encapsulate them in a service module like the get_tool_service() helper shown above.

OpenAI’s Chat Completions API provides access to GPT models for text generation, function calling, and structured outputs. It’s the most widely adopted LLM API and supports streaming, tool use, and JSON mode.

Wrap it in a durable task

Create a durable task that invokes the reasoning loop from Step 1. Concurrency is set to CANCEL_IN_PROGRESS so new user messages cancel stale runs.

Stream the response

Emit LLM tokens from the task as they are generated. Clients subscribe to the stream and receive them in real-time. See Streaming for the full API.

Run the worker

Start the worker. The task definitions above use CANCEL_IN_PROGRESS concurrency so new user messages cancel stale runs. Pass session_id in input for per-session grouping.

⚠️

Always set a timeout and max iteration count on agent loops. Without bounds, an agent can loop indefinitely. See Timeouts for configuration.

Variant: Evaluator-Optimizer

The evaluator-optimizer is a specialized reasoning loop that uses two LLM calls per iteration: one to generate a candidate output and one to evaluate it against a rubric. If the score is below a threshold, the evaluator provides feedback and the generator tries again. This trades compute cost for output quality.

Use caseGeneratorEvaluator
Content writingDraft post/email/copyScore clarity, tone, length; provide edit suggestions
Code generationWrite function or queryRun tests or linter; feed back errors
Data extractionExtract fields from textValidate against schema; flag missing fields
TranslationTranslate textBack-translate and compare; score fidelity

Define the generator and evaluator tasks

Create separate tasks for generation and evaluation. The generator takes a topic and optional feedback; the evaluator scores a draft.

Optimization loop

The evaluator-optimizer task loops: generate, evaluate, check score. Each generator and evaluator call is a spawned child task that is checkpointed on completion.

Next Steps