Back
intermediate

Agent frameworks

Inside an AI agent's control loop

Trace an agent decision, separate model proposals from application authority, and design a stopping rule.

Lesson 27 of 44About 25 min with practice

An assistant looks up a room, finds that it is unavailable, and searches for another. Where did the second search come from? That decision is the useful place to start understanding agents.

Before you begin: Complete Chains, agents, and tools. You should understand a function call and a saved conversation.

Find the decision in the loop

In a fixed workflow, your program determines the steps. In an agent loop, a model can propose the next step using the information available so far. The surrounding program still decides which proposals are allowed and executes the tools. A model that prints “reservation confirmed” has not reserved anything.

Think of a run as a sequence of observations and decisions. The user supplies a goal. The model sees instructions and available tool descriptions. It proposes a call. Your program checks the arguments and permission, executes the function, and returns its result. The model can then answer, ask for clarification, or propose another call. The original ReAct research explored this combination of reasoning and interaction; it did not establish that any unrestricted loop becomes reliable.

Follow one request

Our fictional request is “Find a room for 12 people after 2 pm.” The available tools are list_rooms and read_availability. Neither tool can create a booking.

StepNew evidenceReasonable next step
List roomsA seats 8; B seats 16Discard A for this request
Read BFree from 3 pmReport B at 3 pm
User asks to bookNo booking tool existsExplain the limit

The model is useful for interpreting the request and selecting a relevant lookup. Capacity checks can remain ordinary code. Making every comparison another model call would add cost and another opportunity for error.

Now change one observation: B's availability service times out. “No room is free” is no longer supported. A failed lookup and a successful empty result are different states. Preserve that distinction in tool output and in the answer.

What changed in the world after this action?

A tool call is an event, not necessarily progress. If a search returns the same passages as before, the agent’s evidence may be unchanged. Represent the goal in terms of required facts or completed actions, then compare the current state with that goal after each step.

Set budgets for time, calls and repeated failures. When a loop cannot reduce uncertainty, the useful response may be to ask for missing information or return a partial result. The challenge makes the stopping decision part of the design instead of hoping that another iteration will solve the problem.

Example

Forty searches return overlapping evidence and no supported conclusion.

What changes

Compare each result with the unresolved evidence requirements and remaining budget.

Result

The system can recognize stalled progress and stop with an honest explanation.

Activity count is not an outcome metric. Track changes in evidence and task state.

Define progress before adding autonomy

A state is the information the application keeps about the run: request, evidence, pending calls, results, and status. A policy is the rule for choosing or allowing a next action. Some policy lives in instructions; hard limits belong in code.

For this task, progress means learning something new about a suitable room. Repeating the same failed call without a changed condition is not progress. Set a deadline and a bounded retry rule. Count model turns, tool calls, and elapsed time separately. One model response can contain more than one tool call.

An illustrative control policy, not executable Python, is:

text
Validate the request.
While time and call budgets remain:
  Ask for an answer or a permitted lookup.
  Reject invalid or repeated calls without new evidence.
  Record the lookup result, including failures.
  Stop when an answer is supported or clarification is needed.
Return the answer, its evidence, and the run status.

Decide how this run should end

The model calls read_availability("B") three times and receives the same timeout. It then proposes book_room("B"). What should the application do, and what should the user see?

Inspect the decision

Reject the unavailable booking tool and stop the repeated lookup under the retry policy. Report that B fits the size requirement but availability could not be confirmed. Do not imply a booking happened. The useful record includes the attempted lookup and failure status, not a fabricated successful outcome.

Sketch a second run where the user never supplied the number of people. A good first step is a question, because room capacity cannot be evaluated yet. This is an agent doing less work to reach a better result.

Practice with feedback

Lesson challenge

Define progress before adding autonomy

An agent has looped 40 times, calling search with slightly different phrasings, and has produced nothing.

Locate the decision in a loop and state how a run should end.

Check your understanding

Question 1 of 3
What is missing from the design?
Score: 0/0

Your task

Add a progress test and a termination rule to a looping agent.

These notes stay on this page. Download them before leaving.

What to include

  • A new fact is defined mechanically, for example a source id not seen before
  • The no-progress rule has a number and an action
  • All three terminations produce distinct outputs
  • The trace inspection targets the first divergence
Compare with a worked answer

Here is one way to answer. Check how it uses the information in the task.

The loop's goal: answer 'which classes have places left this week' from the notices. What counts as a new fact: an observation containing a source id not already in the trace, or a value for a sub-question that is still open. Progress test after each observation: did the set of resolved sub-questions grow, or did the set of seen source ids grow? If neither, the step made no progress. On 3 consecutive no-progress steps: stop the loop, return partial with the open sub-questions, and log the three repeated calls. Three rather than one, because a single redundant search is normal exploration.

Termination conditions: success: every sub-question has at least one cited observation. Returns claims plus sources. partial: some resolved, some open, either from the no-progress rule or the budget. Returns what is grounded and names what is not. exhausted: 12 steps spent with nothing resolved. Returns not_finished with the trace, and never a paragraph that reads like an answer.

What I inspect first in a failed trace: the first observation that contradicted the plan. In the 40-step run, step 2 returned an empty list, and the planner treated empty as 'try different words' instead of 'this class does not exist'. Everything after step 2 was noise generated by that one misreading.

When you are signed in, opening the challenge carries your edited working notes into its draft in this browser. The challenge has its own completion record. Practising here does not award points or mark it complete.

Next, put this boundary into a framework and inspect which parts it makes easier to express.

Sources

ReAct paper introduces interleaved reasoning and action. OpenAI Agents SDK running guide documents one concrete runner loop and its limits.

Practise this lesson

Define progress before adding autonomy

Locate the decision in a loop and state how a run should end.

About 10 min55 points3 checks and one applied task
Loading your lesson progress...