Agentic AI çoğunlukla vibe'larla yazılmış bir while(true)
Uzun süreli agent döngülerini production'da çalıştırmaktan çıkan dersler, gerçekten işe yarayan fallback pattern'leri ve agent'ın aynı tool'u 47 kere denediği gün.
Agent loop'u prodüksiyona ilk attığımda üç saat boyunca pırıl pırıl çalıştı, sonra sessiz sessiz $312'lık bir fatura biriktirdi — aynı tool'u kırk yedi kez çağırarak. Çünkü upstream API, 200 OK döndürüp body'de "service temporarily unavailable" yazıyordu. Model, her zamanki gibi yardımsever, bunu geçici bir hıçkırık olarak değerlendirdi. Üst üste kırk yedi kez.
Agent'lardan distributed system'ler hakkında çok şey öğreniyoruz. Hiçbiri yeni değil — 2008'de cron job'lardan öğrendiğimiz aynı dersler — ama model, hata modlarını bir tık daha gürültülü hale getiren özel bir özgüven taşıyor.
Naif şekli
Her agentic-AI tutorial aynı şekilde başlıyor. Bir loop yazıyorsun:
async function agentLoop(task: string) {
const messages = [{ role: "user", content: task }];
while (true) {
const response = await llm.complete({ messages, tools });
if (response.stop_reason === "end_turn") {
return response.content;
}
for (const toolCall of response.tool_calls) {
const result = await runTool(toolCall);
messages.push({ role: "tool", content: result });
}
}
}Demoda gayet hoş. Model birkaç turda bitirir, döner. Sen de yayına alırsın.
Production'da bu loop, cüzdanına doğrultulmuş bir para topudur.
Nerede patlıyor
Biz mühendislerin gözünden gördüğüm, eksiksiz olmayan bir liste:
- Model bir fonksiyon çağrısının "neredeyse doğru" olduğuna karar verdi, aynı argümanların on iki varyasyonunu denedi, sonra vazgeçti.
- Tool 500 döndü. Model retry'ladı. Tool 500 döndü. Model aynı argümanlarla tekrar retry'ladı. Bunu 91 kere yaptık, sonra bütçe alarmı çaldı.
- Model anlamadığı bir tool sonucuyla karşılaştı, var olmayan ikinci bir tool halüsine etti, ardından kendini toparlamak için o tool'u çağırmaya çalıştı.
- Kullanıcının görevi ikinci adımda zaten bitmişti, ama model "emin olmak için" search tool'larını çağırmaya devam etti — 100k context limitine vurup çöktü.
- Multi-agent sistemde iki agent birbirine tool call ping-pong'u başlattı. Çok kibar şekilde.
Asıl problem loop değil. Asıl problem, modelin ne kadar süre çalışması gerektiğine dair bir görüşü olmaması. Evrenin ısı ölümüne kadar mutlu mesut devam eder — ya da sen ona bu zevki fatura edene kadar.
Gerçekten işe yarayan şey
Üç kontrol, bana en çok ağrı çektirenden başlayarak:
1. Retry sayısı değil — bütçe
Tool call saymak yanlış birim. Token-harcama doğru birim, çünkü canını yakan o. Loop'un içinde takip et, kısa devre yaptır:
type Budget = {
maxInputTokens: number;
maxOutputTokens: number;
maxToolCalls: number;
spentInput: number;
spentOutput: number;
toolCalls: number;
};
function overBudget(b: Budget): boolean {
return (
b.spentInput > b.maxInputTokens ||
b.spentOutput > b.maxOutputTokens ||
b.toolCalls > b.maxToolCalls
);
}
async function agentLoop(task: string, budget: Budget) {
const messages: Message[] = [{ role: "user", content: task }];
while (!overBudget(budget)) {
const response = await llm.complete({ messages, tools });
budget.spentInput += response.usage.input_tokens;
budget.spentOutput += response.usage.output_tokens;
if (response.stop_reason === "end_turn") return response.content;
for (const call of response.tool_calls) {
budget.toolCalls += 1;
const result = await runTool(call);
messages.push({ role: "tool", content: result });
}
}
// Throw etme — yapılandırılmış kısmi sonuç döndür.
return {
status: "budget_exceeded",
partial: messages.at(-1),
spent: budget,
};
}Ucuz iç görü: bütçe bittiğinde throw etme. Yapılandırılmış kısmi sonuç döndür. Throw etmek, çağrıyı yapanın context'ini siler atar. status: "budget_exceeded" taşıyan kısmi sonuç, çağıranın karar vermesine izin verir — insana eskale et, daha basit bir yola düş ya da sadece logla.
2. Tool çağrıları idempotent değil. Yap.
Model bir tool'u retry'larken yan etkilerin çarpıp gitmesini istemezsin. Her tool'u argümanlarından üretilmiş bir idempotency key ile sar, loop içinde sonucu cache'le:
function toolKey(name: string, args: unknown): string {
return `${name}:${stableStringify(args)}`;
}
const toolCache = new Map<string, ToolResult>();
async function runToolMemoized(call: ToolCall) {
const key = toolKey(call.name, call.arguments);
const hit = toolCache.get(key);
if (hit) {
return { ...hit, _cached: true };
}
const result = await runTool(call);
toolCache.set(key, result);
return result;
}Model aynı tool'u aynı argümanlarla aynı loop içinde iki kez çağırırsa, cache'lenmiş sonucu işaretleyerek dönersin. Model genelde cache ipucundan "başka bir şey deneyeyim" sonucuna varır. Bazen varmaz. Onun için bütçe var.
3. Fallback gerçek bir ürün özelliğidir
Her agent loop'un bütçesi bittiğinde, sabrı tükendiğinde ya da geri döndürülemez bir tool hatasına çarptığında nihai bir cevabı olmalı. Fallback "throw exception" değildir. Fallback, ne denendiğini, ne öğrenildiğini ve agent'ın sıradaki adımın ne olması gerektiğine dair tahminini söyleyen mütevazı, yapılandırılmış bir cevaptır.
type AgentResult =
| { status: "ok"; answer: string; trace: TraceEntry[] }
| { status: "partial"; bestGuess: string; missing: string[]; trace: TraceEntry[] }
| { status: "failed"; reason: string; trace: TraceEntry[] };Eğer agent'ın { status: "failed", reason: "elimden geleni yaptım" } dönerse, bu bir bug değil. Bu loop'un ne zaman duracağını bilmesi. Agentic AI'nin zor kısmı tam olarak budur: ne zaman denemeyi bırakacağını bilmek. Model sana söylemez. Senin söylemen gerekir.
Trade-off'lar
Tek bir arama yapıp özetleyen, beş tur süren bir agent için bunların hiçbirine ihtiyacın yok. Ama agent birden fazla tool çağırmaya, bir dakikadan uzun çalışmaya ya da çağrı başına bir cent'ten fazlaya mal olmaya başladığı anda her satırı lazım.
Pattern aşağıya, sıfıra kadar ölçeklenir — budget=Infinity bir no-op'tur — yukarıya, saatlerce çalışana kadar ölçeklenir. Yazmanın maliyeti küçük. Yazmamanın maliyeti bende, üzerinde "API kullanımı" yazan ve yanında dört haneli bir rakam olan bir satırdı.
Yöneticinin istediği özet
Agentic AI çoğunlukla vibe'larla yazılmış bir while(true) döngüsü. Vibe'lar kolay kısım. Loop da kolay kısım. Zor olan bütçe, idempotency ve fallback — biz mühendislerin 2008'de cron job'lar için zaten yazdığı üç şey.
Model, distributed system'lere yeni bir şey eklemiyor. Sadece hataları daha ifadeli hale getiriyor.
// madem buradasın
- 11 dk okuma
Qdrant ile hibrit arama: BM25 + dense + görsel'in kitabında olmayan tarafı
Anahtar kelime, dense vektör ve görsel embedding'i tek bir sıralamada birleştirirken gerçekten ne bağlıyorsun — named vector, fusion, drift ve Türkçe aramanın apostroflarla bozulduğu gün.
hybrid-searchqdrantembeddingsproduction - 8 dk okuma
React Native, native driver ve nihayet hissedebildiğin jank
useNativeDriver sana ne zaman gerçekten bir şey kazandırır, ne zaman yalan söyler ve barkod ekranını yavaş hissettiren o düşen frame'i nasıl bulursun.
react-nativeperformancemobile