Agentic Loop ve stop_reason Semantiği
Agent'ın yaşam döngüsü, stop_reason değerlerinin her birinin anlamı, end_turn'ün neden TEK güvenilir completion sinyali olduğu, multi-turn tool calling'de state yönetimi ve anti-pattern'ler.
Öğreneceklerin
- Agentic loop'un istek → stop_reason → tool → tekrar döngüsünü açıklamak
- 4 stop_reason değerinin (end_turn, tool_use, max_tokens, stop_sequence) her birini somut örnekle ayırt etmek
- 'Assistant text'ten completion parse etmek' anti-pattern'inin neden tehlikeli olduğunu göstermek
- Doğru termination stratejisini minimal Python/TypeScript pseudo-code ile ifade etmek
- Multi-turn tool calling'de state yönetiminin temel kurallarını saymak
Bu ders, Foundations sınavının en kritik teknik kavramına dalıyor: bir agent ne zaman “bitti” der, bunu nasıl anlarsın, hangi sinyale güvenip hangisine güvenmemelisin? D1 (%27) ve D5 (%15) sorularının omurgası.
Hook — gerçek bir bug: Bir agent kendi kendine
"Görev tamamlandı."yazdı, döngüden çıktın — ama model aynı yanıttatool_usebloğu da koymuştu. Tool hiç çalışmadı, kullanıcı yarım cevap aldı. Suçlu kod:if "tamam" in response.text: return. Tek güvenilir sinyal:stop_reason. Bu ders onu öğretiyor.
Büyük resim — sequence diyagramı
Bir agent çağrısının ömrü budur. Her okun sonunda stop_reason döner ve o tek alan döngünün sonraki adımını belirler:
[Sen] [Claude API]
│ │
│── messages (user) ──────────────────────▶│
│ │
│◀────────── response + stop_reason ───────│
│ │
├── stop_reason == "tool_use" ──▶ tool çalıştır
│ │
│◀── messages + tool_result ───────┤
│ (tekrar sor)
│
├── stop_reason == "end_turn" ────▶ ✅ DÖNGÜ BİTTİ, kullanıcıya göster
│
├── stop_reason == "max_tokens" ──▶ max_tokens ↑ veya özetle → tekrar sor
│
└── stop_reason == "stop_sequence" ▶ kasıtlı kesim → değerlendir
Neden bu sıra? Anthropic’in resmi tutorial’ı tam bu akışı öğretir: önce kodu çalıştır,
stop_reasonalanını gör, sonra genelle. Biz de aynısını yapıyoruz — kavram yükünü gözlem → döngü → hata yönetimi şeklinde bölüyoruz.
Ring 1 — Gözlem: stop_reason’ı ilk kez gör
Kod yok, terminal var. Claude Code’a bir soru sor ve JSON modunda çalıştır:
claude --output-format json -p "echo hello"
# Çıktıda "stop_reason": "end_turn" göreceksin.
Şimdi tool çağrısı zorla:
claude --output-format json -p "src/ dizininde kaç .ts dosyası var?"
# İlk yanıt: "stop_reason": "tool_use" → model Bash çalıştırmak istiyor
# Tool çalışınca: "stop_reason": "end_turn" → model işi bitirdi
Çıkar: stop_reason bir ayrımcı (discriminator). İki değer gördün: tool_use (devam et) ve end_turn (bitir). Şimdi bunu kodda yap.
Ring 2 — Döngü: while stop_reason == “tool_use”
Anthropic SDK’sında minimal doğru yapı budur — sadece iki case:
import anthropic
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "src/ altındaki tüm .ts dosyalarını listele."}]
tools = [{"name": "Bash", "description": "Run shell", "input_schema": {...}}]
while True:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
tools=tools,
messages=messages,
)
if response.stop_reason == "end_turn":
return response.content[0].text # ✅ BİTTİ — tek çıkış noktası
if response.stop_reason == "tool_use":
results = []
for block in response.content:
if block.type == "tool_use":
out = execute_tool(block.name, block.input) # senin executor'ın
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": out,
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": results})
continue # bir tur daha
break # max_tokens veya stop_sequence → Ring 4'te işleyeceğiz
Anahtar kural: stop_reason == "tool_use" ise görev bitmemiştir. Çalıştır, geri besle, tekrar sor. end_turn ise bitmiştir, kullanıcıya göster. Başka hiçbir yol yok.
Multi-turn state — client-side append-only
Dikkat: messages.append(...) her turda iki kez çağrılıyor — bir asistan mesajı, bir de tool_result içeren user mesajı. Bu, server’ın state tutmadığı anlamına gelir:
- State client’tadır. Server-side session yok.
messageslistesi senin sorumluluğun. tool_use_idkorelasyonu şart. Hertool_resultbir öncekitool_useile eşleşmeli. Yanlış ID → model sonucu reddeder.- Sıralama:
[user, assistant, user, assistant, ...]— iki user arka arkaya gelemez (istisna: birden fazlatool_resultaynı user’da olabilir). - Trimming: Çok turlu conversation’da eski
tool_result’ları özetleyebilirsin, amatool_use_idgörünür kalmalı; attribution koparsa model karışır.
Sınav tuzağı: “Claude session’ı tekrar kullanıyorum, server state’i koruyor” diye düşünme. Hayır. State client’ta, her istekte tam listeyi gönderiyorsun.
Ring 3–5 — sonraki derslerde
Bu derste kasıtlı olarak yalnızca Ring 1 (gözlem) ve Ring 2 (döngü) var. Geri kalanı:
- Ring 3 — paralel tool_use + çoklu tool çağrısı tek turda (D1)
- Ring 4 —
max_tokensretry stratejisi,refusalpropagation,pause_turn(server-side tool loop) (D5) - Ring 5 — SDK ile production-ready executor, error recovery, observability (D5)
Bu ring’leri ayrı derslerde göreceğiz; şimdilik iki şeyi bilmek yeterli: stop_reason’a göre dallan, messages’i client’ta append et.
Anti-pattern’ler — sınavda en çok düşülen 2 hata
1. Assistant text’ten completion parse etmek
# ❌ YANLIŞ — kırılgan
if "tamam" in response.text or "İşte sonuç" in response.text:
return response.text
Neden yanlış: model “İşte sonuç: 42” yazıp ardından bir tool_use bloğu koyabilir (think-then-validate kalıbı). Text parse erken çıkar, tool çalışmaz, kullanıcı yarım cevap alır. Sınavda “agent neden boş döndü?” sorusunun klasik cevabı.
2. tool_use geldiğinde end_turn varsaymak
# ❌ YANLIŞ — kritik hata
if response.stop_reason != "max_tokens":
return response.content[0].text # tool_use buraya düşer
Doğrusu: Sadece stop_reason == "end_turn" ise çık. tool_use, max_tokens, stop_sequence — hepsi farklı ele alınır. Yukarıdaki kod tool_use’u görmezden gelip son kullanıcıya ara metni gösterir.
Hands-on (5 dk)
# Terminalde iki deney:
claude --output-format json -p "echo hello" # → stop_reason: end_turn
claude --output-format json -p "pwd nedir?" # → önce tool_use, sonra end_turn
# JSON içindeki stop_reason alanını bul ve sırayı takip et.
Sonra dosyada değişiklik yap: Ring 2 pseudo-code’undaki if response.stop_reason == "end_turn" satırını bilerek sil. Ne oluyor? (Cevap: sonsuz döngü veya erken çıkış — tool_use asla handle edilmez.)
Özet
- 4
stop_reason:end_turn(tek güvenilir completion),tool_use(döngü devam),max_tokens(kesim — Ring 4’te),stop_sequence(kasıtlı dur). - Anti-pattern:
if "tamam" in response.text— kırılgan, erken çıkışa yol açar. Tek güvenilir sinyalstop_reason. - Doğru:
if response.stop_reason == "end_turn": return ...— başka hiçbir yol yok. - Multi-turn state:
tool_use_idkorelasyonu, sıralı mesaj listesi, client-side (server session değil).