Claude Architect · Les

Beëindigen op stop_reason

Laat end_turn de lus beëindigen, niet uw stringmatching

Les 2 van 413 stappen

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 voor max_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_sequence

Het 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-wrong

De 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})
        continue

Volledige 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_result toe aan messages;
  • 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 request

Beslissingen 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_turn

Waar 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_tokens expliciet 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)})
        continue

Korte 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_turn beëindigt de lus; tool_use betekent dat je tools uitvoert, de resultaten toevoegt en doorgaat.
  • Handel max_tokens expliciet 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.

Gratis beginnen

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

  1. De kernlus
  2. Beëindigen op stop_reason
  3. Antipatroon: tekst parseren om voltooiing te herkennen
  4. Antipatroon: willekeurige iteratielimieten
← Terug naar Claude Architect