Beëindigen op stop_reason
Laat end_turn de lus beëindigen, niet uw stringmatching
Beëindigen op stop_reason is een gratis Claude Architect-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Claude Architect. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Claude Architect bevat in totaal 4 lessen.
De lus heeft een uitgang nodig
Een agentische lus is eenvoudig: je stuurt een aanvraag, Claude antwoordt en je bepaalt of je doorgaat. De moeilijke vraag is wanneer je stopt.
Elke API-respons bevat een veld stop_reason. Dit is het eigen signaal van het model over waarom het is gestopt met genereren. Je lus moet naar dat signaal luisteren — niet raden door de woorden in het antwoord te lezen.
Deze les leert je de regel die robuuste agents onderscheidt van kwetsbare: laat end_turn de lus beëindigen, niet het zoeken naar tekenreeksen.
De vier stopredenen
Claude geeft bij elke beurt een van vier waarden voor stop_reason terug:
end_turn— het model heeft zijn antwoord vanzelf voltooid. De beurt van de taak is voltooid.tool_use— het model wil een hulpmiddel aanroepen. Voer het uit, voeg het resultaat toe en ga verder.max_tokens— de uitvoer is afgekapt door je limiet voormax_tokens.stop_sequence— er is een aangepaste stopreeks bereikt die je hebt ingesteld.
Deze vier waarden vormen een volledige, betrouwbare afspraak. Je besturingsstroom moet er rechtstreeks op vertakken.
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(resp.stop_reason) # end_turn | tool_use | max_tokens | stop_sequenceHet antipatron: tekst ontleden
Een verleidelijke snelkoppeling is om de tekst van het model te lezen en te zoeken naar een trefwoord als "done" of "finished" om te bepalen of de lus voorbij is.
Dit is een klassiek antipatron. Tekst is probabilistisch. Het model kan zeggen "Ik ben klaar met nadenken, laat me nu een hulpmiddel aanroepen" — waarna je zoeker te vroeg stopt. Of het model formuleert de voltooiing anders en je lus blijft eindeloos draaien.
Ontleed tekst nooit om voltooiingssignalen te vinden. De gestructureerde stop_reason bestaat precies zodat dat niet nodig is.
# ANTI-PATTERN: do NOT do this
text = resp.content[0].text
if "done" in text.lower():
break # fragile, unreliable, exam-wrongDe canonieke lus
Hier zie je de juiste vorm van de lus. Je controleert stop_reason bij elke beurt. Wanneer deze tool_use is, voer je de hulpmiddelen uit en voeg je hun resultaten toe aan het gesprek. Je herhaalt dit tot stop_reason end_turn is.
Let erop dat de lus volledig door het gestructureerde signaal wordt aangestuurd — geen enkele tekstcontrole bepaalt de beëindiging.
while True:
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
break
if resp.stop_reason == "tool_use":
results = run_tools(resp.content)
messages.append({"role": "user", "content": results})
continueVolledige geschiedenis, bij elke beurt
Een reden waarom de lus werkt: het model bewaart geen status tussen verzoeken. Elke API-aanroep moet de VOLLEDIGE geschiedenis van messages bevatten.
Daarom voeg je na een tool_use-beurt zowel de inhoud van de toolaanroep van de assistent ALS de toolresultaten weer toe aan messages voordat je het volgende verzoek verstuurt. Het model leest de volledige conversatie opnieuw en beslist of er meer tools nodig zijn of dat het kan eindigen met end_turn.
Laat je de geschiedenis weg, dan raakt het model de draad kwijt — het kan geen samenhangende end_turn bereiken.
# Each request resends EVERYTHING
messages = [
{"role": "user", "content": "Refund order 4471."},
{"role": "assistant", "content": [tool_use_block]}, # prior turn
{"role": "user", "content": [tool_result_block]}, # prior turn
]
resp = client.messages.create(model=MODEL, max_tokens=1024,
tools=tools, messages=messages)tool_use is geen stopteken
Een veelgemaakte fout is om tool_use als een eindstatus te behandelen. Dat is het niet. Het betekent: "pauzeer, voer deze tool uit en kom daarna bij mij terug."
Wanneer je tool_use ziet:
- voer je de gevraagde tool(s) uit in je eigen code;
- voeg je de blokken met
tool_resulttoe aanmessages; - verstuur je het verzoek opnieuw, zodat het model kan doorgaan.
Alleen end_turn betekent dat het werk voor deze beurt echt klaar is.
if resp.stop_reason == "tool_use":
tool_results = []
for block in resp.content:
if block.type == "tool_use":
output = dispatch(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
messages.append({"role": "user", "content": tool_results})
# loop continues -> next requestBeslissingen worden door het model genomen
Het onderliggende principe: laat het model beslissen wanneer het klaar is. Het model beschikt over de volledige context — het doel van de gebruiker, de toolresultaten en de conversatie tot nu toe. Het is beter in staat dan een hardgecodeerde regel om te beoordelen of de taak voltooid is.
Jouw taak als architect is om goede tools en duidelijke instructies te bieden en vervolgens te vertrouwen op het signaal end_turn. Gebruik hardgecodeerde besturingslogica alleen voor garanties die je niet aan waarschijnlijkheid kunt overlaten.
De iteratielimiet is een vangnet
Je moet nog steeds een bewaking voor het maximale aantal iteraties toevoegen — maar begrijp wel welke rol die heeft. Een iteratielimiet is een vangnet dat onbeheerste lussen of sterk oplopende kosten voorkomt. Het is NIET het primaire stopmechanisme.
De primaire stop is altijd end_turn. De limiet treedt alleen in werking in het zeldzame, abnormale geval waarin het model nooit convergeert. Als je lus op de limiet vertrouwt om normaal te eindigen, is je ontwerp gebrekkig.
MAX_ITERS = 20 # safety net, NOT the normal exit
for i in range(MAX_ITERS):
resp = client.messages.create(model=MODEL, max_tokens=1024,
tools=tools, messages=messages)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
break # normal exit
# ... handle tool_use ...
else:
log.warning("Hit iteration cap without end_turn")Omgaan met max_tokens
max_tokens is een apart geval waarvoor je een eigen afhandeling nodig hebt. Het betekent dat het antwoord tijdens het genereren is afgekapt — het model heeft zijn gedachte niet afgemaakt.
Als je dit als een normale voltooiing behandelt, wordt het werk van de agent stilzwijgend afgebroken. Afhankelijk van je ontwerp kun je max_tokens verhogen, het model vragen om door te gaan of de beurt markeren. Wat je NIET mag doen, is gewoon doorgaan en aannemen dat de taak klaar is.
if resp.stop_reason == "max_tokens":
# output was cut off - NOT a completion
log.warning("Response truncated; consider raising max_tokens or continuing")
# handle explicitly; do not treat as end_turnWaar hardgecodeerde code thuishoort
Als beslissingen door het model de standaard zijn, wanneer kies je dan voor deterministische code?
Voor garanties — uitkomsten die elke keer moeten gelden, ongeacht het oordeel van het model. Voorbeelden zijn een voorwaarde die een terugbetaling blokkeert totdat get_customer een geverifieerde ID retourneert, of een hook die elke terugbetaling boven een beleidsdrempel afwijst.
Dit zijn volledig deterministische handhavingspunten. Beëindiging is daarentegen een beslissing van het model die je uit stop_reason afleest. Verwar die twee niet: codeer garanties hard, maar vertrouw voor de processtroom op end_turn.
Alles samenbrengen
Een agentlus van productiekwaliteit combineert alle onderdelen:
- vertak op
stop_reason— nooit op tekst; - verstuur bij elke beurt de volledige geschiedenis opnieuw (het model is stateless);
tool_use→ uitvoeren, toevoegen, doorgaan.end_turn→ stoppen;- handel
max_tokensexpliciet af — afkappen is geen voltooiing; - gebruik een iteratielimiet alleen als vangnet.
Dit vormt de basis van elke betrouwbare agent die je bouwt.
for _ in range(MAX_ITERS):
resp = client.messages.create(model=MODEL, max_tokens=2048,
tools=tools, messages=messages)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
break
if resp.stop_reason == "max_tokens":
handle_truncation(resp); break
if resp.stop_reason == "tool_use":
messages.append({"role": "user",
"content": run_tools(resp.content)})
continueKorte controle: de lus beëindigen
Een supportagent die is gebouwd met de Agent SDK loopt soms oneindig door en stopt soms voordat hij een benodigde tool aanroept. De lus wordt momenteel afgebroken wanneer de tekst van de assistent het woord "resolved" bevat. Wat is de juiste oplossing?
Samenvatting: vertrouw op het signaal
Belangrijkste punten:
- Beëindig op
stop_reason, nooit door tekst te ontleden op woorden zoals "done" of "resolved". end_turnbeëindigt de lus;tool_usebetekent dat je tools uitvoert, de resultaten toevoegt en doorgaat.- Handel
max_tokensexpliciet af — afkappen is geen voltooiing. - Het model is stateless: verstuur bij elke beurt de volledige berichtgeschiedenis opnieuw.
- Beëindiging is een beslissing van het model; de iteratielimiet is alleen een vangnet.
- Gebruik hardgecodeerde handhaving voor garanties (voorwaarden, hooks), niet om de lus te beëindigen.
Laat end_turn de lus beëindigen. Die ene discipline maakt je agents voorspelbaar en klaar voor productie.
Leer Python met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 26
- Lessen
- 104
Veelgestelde vragen
Is de les “Beëindigen op stop_reason” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Claude Architect, waaronder “Beëindigen op stop_reason”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Claude Architect bevat in totaal 4 lessen.
Wat leer ik in “Beëindigen op stop_reason”?
Laat end_turn de lus beëindigen, niet uw stringmatching Je oefent met Claude Architect door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Claude Architect te beginnen?
Ervaring vooraf is niet nodig. Claude Architect op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Beëindigen op stop_reason”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Claude Architect?
Ja. Elke les over Claude Architect bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- De kernlus
- Beëindigen op stop_reason
- Antipatroon: tekst parseren om voltooiing te herkennen
- Antipatroon: willekeurige iteratielimieten