Loops and Budgets
for and while repeat work. enumerate, zip, break, continue, any/all, and a hard step budget so the loop cannot run forever.
A loop does the same kind of work more than once. for walks every item in a list. while keeps going until a test is false.
A budget is a max number of steps. An agent is a loop: while the goal is not done and the budget remains, think, act, observe. Always count steps. Never write a loop with no stop. A model that never says “finish” must still hit max_steps.
While the goal is not done and steps remain, repeat. Budget is a hard stop.
A loop with a budgetIf a live box hangs, you probably wrote while True without break, or you forgot to add to the counter. The site will eventually stop it. On a paid API, that hang is money.
for, range, enumerate, zip
for item in tools: sets item to each value, one at a time. A string, list, tuple, or dict keys can all be walked this way. for ch in "act": walks characters. for key in action: walks keys. Prefer for key, value in action.items(): when you need both.
range(n) is the numbers 0 through n - 1. range(1, 4) is 1, 2, 3. range is not a list. Wrap with list(range(3)) if you want to print it as a list. for i in range(3): is the usual retry loop: three tries, numbered 0, 1, 2. Use start=1 in enumerate when you want to print “step 1.”
enumerate gives you (index, item) together. zip walks two lists side by side and stops at the shorter one. Extra items on the longer list are ignored. If you need to notice a length mismatch, compare len first.
for name in [class="tok-s">"search", class="tok-s">"read", class="tok-s">"answer"]:
print(name)
for i in range(3):
print(i) class="tok-c"># 0, 1, 2
for i, name in enumerate([class="tok-s">"search", class="tok-s">"read"], start=1):
print(i, name)
for tool, query in zip([class="tok-s">"search", class="tok-s">"read"], [class="tok-s">"weather", class="tok-s">"file.txt"]):
print(tool, query)while, break, continue, and a budget
while test: repeats as long as the test is true. You must make the test false later. Forgetting to add to a counter is how you get an infinite loop (a loop that never ends).
break leaves the loop now. continue skips the rest of this round and starts the next one. Neither is evil. break on “goal done” is the agent’s success exit. continue on empty text skips a bad observation.
| Code | Typical use |
|---|---|
for msg in messages | Walk a log to build a prompt |
for i in range(3) | Retry a small number of times |
enumerate(steps, start=1) | Print step numbers |
zip(names, args) | Pair tool names with arguments |
while used < max_steps | The agent loop with a budget |
any(flags) / all(flags) | Did any fail? Did every field arrive? |
sorted(names) | Stable order for a print |
break | Goal met, or a fatal error |
continue | Skip empty text |
Never while True around a paid model call without a hard cap. Always count used against max_steps. A second cap on tokens or dollars is even better. The step cap is the one you can write today.
used += 1 should happen once per turn, at a known place. If you increment in two branches, you will double-count. If you increment after continue, you might skip counting. Put the increment at the top of the loop body.
any, all, and sorted
any(tests) is True if at least one item counts as yes. all(tests) is True only if every item counts as yes. Empty any([]) is False. Empty all([]) is True (no counterexamples). That empty case surprises people. Prefer not to call them on lists that might be empty unless you know the rule.
oks = [True, True, False]
print(any(oks)) class="tok-c"># True — at least one step worked
print(all(oks)) class="tok-c"># False — not every step workedUse any for "did any tool fail?" Use all for "did every required field arrive?"
sorted(names) returns a new list in order. The old list does not change. Print a set of tool names with sorted(...) so the order is stable. list.sort() changes the list in place and returns None — the same trap as append.
else on a for or while
A loop can have else. That else runs only if the loop did not break.
for step in range(1, 4):
if step == 99:
print(class="tok-s">"found")
break
else:
print(class="tok-s">"never found")That is how a budget stop can print "stop: budget" when finish never happened. If you break on finish, the else is skipped. The word else is confusing here. Think “if no break.” You will use this in the mini-agent lesson.
Common mistakes
while Truewith nobreakand no budget.- Forgetting
used += 1. continuebefore you record the step.- Expecting
zipto error on different lengths. for i in len(xs):—lenreturns a number, which you cannot walk. Userange(len(xs))or, better,enumerate.- Using
forwhen the stop condition is “until done or budget,” which is awhile.
Run to execute this in your browser. Nothing is sent to a server.
Change the inner if used >= 4 to if used >= 99 so finish never happens. Then used should hit 8 and the while should stop on budget. That is the agent’s last seatbelt.
How agents use this
An agent is a while loop with a budget. Each turn adds one to used. for walks messages or tool names. enumerate numbers the trace so a person can say "step 7". any / all check a list of flags. break stops when the goal is done. A loop else runs only if you never broke — that is a clean "budget used up" message. Never let this loop run with no stop.
Retries are a small for i in range(3) around one tool, not a second infinite while. Nested unbounded loops are how a single user request becomes a thousand model calls. One outer while with max_steps. Inner loops over known lists.
Print used, goal_done, and the last observation every turn while you learn. That print is the trace. Later you append dicts instead of only printing. The loop does not change: test, act, record, test again.
Check your understanding