Claude Architect · leksjon

Avslutte ved stop_reason

La end_turn avslutte løkken, ikke strengsammenligning.

Leksjon 2 av 413 trinn

Avslutte ved stop_reason er en gratis leksjon i Claude Architect på CoddyKit. Dette er leksjon 2 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Claude Architect, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Claude Architect inneholder totalt 4 leksjoner.

Løkken trenger en utgang

En agentisk løkke er enkel: De sender en forespørsel, Claude svarer, og De avgjør om den skal fortsette. Det vanskelige spørsmålet er når den skal stoppe.

Hvert API-svar inneholder et stop_reason-felt. Dette er modellens eget signal om hvorfor den sluttet å generere. Løkken Deres bør lytte til dette signalet — ikke gjette ved å lese ordene i svaret.

Denne leksjonen lærer bort én regel som skiller robuste agenter fra skjøre: la end_turn avslutte løkken, ikke strengsammenligning.

De fire stoppårsakene

Claude returnerer én av fire stop_reason-verdier i hver omgang:

  • end_turn — modellen fullførte svaret sitt på naturlig vis. Oppgaveomgangen er fullført.
  • tool_use — modellen ønsker å kalle et verktøy. Kjør det, legg til resultatet og fortsett.
  • max_tokens — utskriften ble avkortet av max_tokens-grensen Deres.
  • stop_sequence — en egendefinert stoppsekvens De konfigurerte, ble truffet.

Disse fire verdiene utgjør en komplett og pålitelig kontrakt. Kontrollflyten bør forgrene seg direkte basert på dem.

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

Antimønsteret: Tolking av tekst

En fristende snarvei er å lese modellens tekst og se etter et nøkkelord som «ferdig» eller «fullført» for å avgjøre om løkken er over.

Dette er et klassisk antimønster. Tekst er probabilistisk. Modellen kan si «Jeg er ferdig med å tenke, nå vil jeg kalle et verktøy» — og tekstsøket Deres stopper for tidlig. Eller den kan uttrykke fullføringen på en annen måte, slik at løkken kjører for alltid.

Tolk aldri tekst for å finne signaler om fullføring. Det strukturerte stop_reason finnes nettopp for at De ikke skal måtte gjøre det.

# ANTI-PATTERN: do NOT do this
text = resp.content[0].text
if "done" in text.lower():
    break  # fragile, unreliable, exam-wrong

Den kanoniske løkken

Her er løkkens riktige form. De undersøker stop_reason i hver omgang. Når den er tool_use, kjører De verktøyene og legger resultatene til i samtalen. De gjentar til stop_reason er end_turn.

Legg merke til at løkken styres fullstendig av det strukturerte signalet — ingen tekstinspeksjon avgjør avslutningen.

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

Full historikk i hver omgang

En av grunnene til at løkken fungerer, er at modellen ikke beholder tilstand mellom forespørsler. Hvert API-kall må inneholde hele historikken i messages.

Derfor legger De, etter en tool_use-runde, både assistentens innhold for verktøykallet OG verktøyresultatene tilbake i messages før neste forespørsel. Modellen leser gjennom hele samtalen på nytt og avgjør om flere verktøy trengs, eller om den kan avslutte med end_turn.

Hvis De utelater historikken, mister modellen tråden — den klarer ikke å nå en sammenhengende end_turn.

# 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 er ikke et stopp

En vanlig feil er å behandle tool_use som en sluttstatus. Det er det ikke. Det betyr «sett på pause, kjør dette verktøyet, og kom deretter tilbake til meg».

Når De ser tool_use, skal De:

  • Kjøre de forespurte verktøyene i Deres egen kode.
  • Legge tool_result-blokkene til i messages.
  • Sende forespørselen på nytt slik at modellen kan fortsette.

Bare end_turn betyr at arbeidet i denne runden faktisk er ferdig.

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

Beslutninger styres av modellen

Det dypere prinsippet er: la modellen avgjøre når den er ferdig. Modellen har hele konteksten — brukerens mål, verktøyresultatene og samtalen så langt. Den er bedre posisjonert enn en hardkodet regel til å vurdere om oppgaven er fullført.

Deres oppgave som arkitekt er å tilby gode verktøy og tydelige instruksjoner, og deretter stole på signalet end_turn. Bruk hardkodet kontrollflyt for garantier De ikke kan overlate til sannsynligheten.

Iterasjonsgrensen er et sikkerhetsnett

De bør fortsatt legge inn en grense for maksimalt antall iterasjoner — men forstå hvilken rolle den har. En iterasjonsgrense er et sikkerhetsnett som skal forhindre løkker som løper løpsk eller uforutsette kostnadsøkninger. Den er IKKE den primære stoppmekanismen.

Det primære stoppet er alltid end_turn. Grensen utløses bare i det sjeldne, patologiske tilfellet der modellen aldri konvergerer. Hvis løkken Deres er avhengig av grensen for å avsluttes normalt, er utformingen feil.

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")

Håndtering av max_tokens

max_tokens er et særtilfelle som krever egen håndtering. Det betyr at svaret ble avkortet midt i genereringen — modellen rakk ikke å fullføre tanken.

Hvis De behandler dette som en ren fullføring, avbryter De agentens arbeid i stillhet. Avhengig av utformingen kan De øke max_tokens, be modellen om å fortsette eller markere runden. Det De IKKE må gjøre, er å fortsette som normalt og anta at oppgaven er ferdig.

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

Hvor hardkodet logikk hører hjemme

Hvis modellstyrte beslutninger er standarden, når bør De bruke deterministisk kode?

For garantier — resultater som må gjelde hver eneste gang, uavhengig av modellens vurdering. Eksempler er en forutsetning som blokkerer en refusjon til get_customer returnerer en bekreftet ID, eller en hook som avviser alle refusjoner over en terskel fastsatt i retningslinjene.

Dette er 100 % deterministiske håndhevingspunkter. Avslutning er derimot en modellstyrt beslutning som De leser fra stop_reason. Ikke bland de to: hardkod garantier, og stol på end_turn for kontrollflyten.

Slik henger det sammen

En agentløkkke klar for produksjon kombinerer alle delene:

  • Gren på stop_reason — aldri på tekst.
  • Send hele historikken på nytt i hver runde (modellen er tilstandsløs).
  • tool_use → kjør, legg til, fortsett. end_turn → stopp.
  • Håndter max_tokens eksplisitt — avkorting er ikke fullføring.
  • Behold en iterasjonsgrense som et sikkerhetsnett, og ikke noe mer.

Dette er ryggraden i enhver pålitelig agent De utformer.

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

Kort kontroll: avslutte løkken

En supportagent bygget på Agent SDK går noen ganger i løkke for alltid og stopper andre ganger før den kaller et nødvendig verktøy. Løkken avsluttes nå når teksten fra assistenten inneholder ordet «resolved». Hva er den riktige løsningen?

Oppsummering: stol på signalet

Viktigste punkter:

  • Avslutt på stop_reason, aldri ved å analysere tekst etter ord som «done» eller «resolved».
  • end_turn avslutter løkken; tool_use betyr at De skal kjøre verktøy, legge til resultatene og fortsette.
  • Håndter max_tokens eksplisitt — avkorting er ikke fullføring.
  • Modellen er tilstandsløs: send hele meldingshistorikken på nytt i hver runde.
  • Avslutning er en modellstyrt beslutning; iterasjonsgrensen er bare et sikkerhetsnett.
  • Begrens hardkodet håndheving til garantier (forutsetninger, hooker), ikke til å avslutte løkken.

La end_turn avslutte løkken. Denne ene disiplinen gjør agentene Deres forutsigbare og klare for produksjon.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
26
Leksjoner
104

Ofte stilte spørsmål

Er leksjonen «Avslutte ved stop_reason» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Claude Architect, inkludert «Avslutte ved stop_reason», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Claude Architect inneholder totalt 4 leksjoner.

Hva lærer jeg i «Avslutte ved stop_reason»?

La end_turn avslutte løkken, ikke strengsammenligning. Du øver på Claude Architect med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Claude Architect?

Ingen tidligere erfaring er nødvendig. Claude Architect på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Avslutte ved stop_reason»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Claude Architect-leksjonen?

Ja. Alle Claude Architect-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Kjerneløkken
  2. Avslutte ved stop_reason
  3. Antimønster: Analysere tekst for å finne fullføring
  4. Antimønster: Vilkårlige grenser for antall iterasjoner
← Tilbake til Claude Architect