İçeriğe atla

2025-12-08

Chatbot'lardan Otonom Agent'lara: Mimari Desenler

Kural tabanlı chatbot'lardan otonom AI agent'larına mimari evrimi keşfet. ReAct, Plan-and-Execute ve çoklu-agent desenleri TypeScript implementasyonları ve pratik geçiş stratejileriyle öğren.

Özet

Kural tabanlı chatbot’lardan otonom AI agent’larına geçiş, sadece bir yetenek yükseltmesi değil; temel bir mimari değişimi temsil ediyor. Chatbot’lar önceden tanımlanmış intent’lere göre scriptli konuşmalar takip ederken, AI agent’ları memory, planlama yetenekleri ve tool erişimine sahipler. Bu, onların karmaşık görevleri otonomca parçalayabilmesini, kararlar alabilmesini ve sistemler arası çok adımlı workflow’ları execute edebilmesini sağlıyor.

Bu yazıda basit chatbot sistemlerinden sofistike agent mimarilerine mimari yolculuğu inceliyoruz. Design pattern’lere (ReAct, Plan-and-Execute, çoklu-agent koordinasyonu), infrastructure kararlarına ve pratik trade-off’lara odaklanıyoruz. Agent’ları “daha iyi chatbot’lar” olarak görmek yerine, farklı mimari pattern’leri ve her birinin production sistemleri için ne zaman mantıklı olduğunu inceliyoruz.

Mimari Evrim Spektrumu

İkili bir seçim yerine, chatbot’tan agent’a evrimi bir spektrum olarak düşün:

Ekle

Ekle

Ekle

Ekle

Ekle

Kural Tabanli

Chatbot

Intent Tabanli

Chatbot

Context-Aware

Asistan

Tool Kullanan

Agent

Planning

Agent

Multi-Agent

System

NLU/ML

Session Memory

Dynamic Tools

Planning & LTM

Specialization

Level 0: Kural Tabanlı Chatbot’lar - Decision tree’ler ve regex pattern’ler. Tamamen deterministik. Örnek: “Saatler için 1, lokasyon için 2 yazın”

Level 1: Intent-Driven Chatbot’lar - Intent classification için NLU ile intent başına önceden tanımlanmış flow’lar. Örnek: Müşteri destek FAQ bot’ları

Level 2: Context-Aware Asistanlar - Session içinde conversation memory ile sınırlı API entegrasyonları. Örnek: Sesli asistanlar (Siri, Alexa)

Level 3: Tool Kullanan Agent’lar - Single-agent ReAct pattern’i ile dinamik tool seçimi. Örnek: Claude Code, GitHub Copilot

Level 4: Planning Agent’lar - Long-term memory ile çok adımlı task decomposition. Örnek: Research asistanları, kod generation agent’ları

Level 5: Multi-Agent Sistemler - Agent koordinasyon pattern’leriyle specialized sub-agent’lar. Örnek: Software development ekipleri, otonom operasyonlar

Geleneksel Chatbot Kısıtlamalarını Anlamak

Klasik Destek Bot Senaryosu

Bir destek chatbot’u şunu handle ediyor: “Neden iki kez ücretlendirildim?”

Chatbot’un yapması gerekenler:

  • Payment geçmişini kontrol et (Stripe API)
  • Order durumunu doğrula (database)
  • Destek ticket’larını gözden geçir (Zendesk)
  • Bilinen issue’ları kontrol et (Confluence)

Geleneksel yaklaşım: Tam sırayı hardcode et, ya da kullanıcıya birden fazla açıklayıcı soru sor.

Agent yaklaşımı: Tüm sistemlerden otonomca context topla, bulguları sentezle ve çözüm öner.

Integration Explosion Problemi

Geleneksel chatbot’larla: 5 chatbot × 10 backend sistem = 50 hardcode edilmiş entegrasyon

Her yeni feature birden fazla chatbot flow’u güncellemeyi gerektirir. Chatbot’lar arası paylaşılan öğrenme yok. Sistemler evrim geçirdikçe maintenance giderek zorlaşır.

Temel Mimari Farklar

Chatbot Mimarisi: Input → Intent Classification → Scriptli Response → Output

Agent Mimarisi: Input → Reasoning Loop (Observe → Plan → Act → Reflect) → Tool Execution → Memory Update → Output

Temel farklar:

  1. Memory Sistemleri: Long-term knowledge graph’lar vs. conversation buffer’ları
  2. Planning Mekanizmaları: Task decomposition ve multi-step reasoning vs. single-turn response’lar
  3. Tool Orchestration: Dinamik tool seçimi ve composition vs. sabit API çağrıları
  4. Autonomy Seviyeleri: Self-directed execution vs. user-driven etkileşimler
  5. Error Recovery: Adaptive retry stratejileri vs. “Anlamadım” fallback’leri

Pattern 1: Geleneksel Intent-Based Chatbot

Geleneksel bir chatbot mimarisini ve kısıtlamalarını inceleyelim:

interface ChatbotMessage {
  role: "user" | "assistant";
  content: string;
}

interface Intent {
  name: string;
  confidence: number;
  entities: Record<string, any>;
}

class TraditionalChatbot {
  private conversationHistory: ChatbotMessage[] = [];

  async processMessage(userMessage: string): Promise<string> {
    // History'ye ekle (son N mesajla sınırlı)
    this.conversationHistory.push({ role: "user", content: userMessage });
    if (this.conversationHistory.length > 10) {
      this.conversationHistory.shift(); // En eskiyi at
    }

    // Intent classification
    const intent = await this.classifyIntent(userMessage);

    // Intent'e göre handler'a route et
    switch (intent.name) {
      case "check_order":
        return await this.handleOrderCheck(intent.entities);
      case "return_request":
        return await this.handleReturnRequest(intent.entities);
      case "product_question":
        return await this.handleProductQuestion(intent.entities);
      default:
        return "Bunu nasıl yardımcı olacağımdan emin değilim. Yeniden ifade edebilir misin?";
    }
  }

  private async classifyIntent(message: string): Promise<Intent> {
    // NLU servisi veya LLM'e intent classification çağrısı
    const response = await fetch("https://api.nlp-service.com/classify", {
      method: "POST",
      body: JSON.stringify({ text: message })
    });
    return response.json();
  }

  private async handleOrderCheck(entities: Record<string, any>): Promise<string> {
    // Sabit flow: order ID çıkar → database sorgusu → response formatla
    const orderId = entities.order_id;
    if (!orderId) {
      return "Sipariş numaran nedir?";
    }

    const order = await this.fetchOrder(orderId);
    return `Sipariş ${orderId} durumu ${order.status}. Tahmini teslimat: ${order.eta}`;
  }

  private async fetchOrder(orderId: string): Promise<any> {
    // Database query implementasyonu
    return { status: "kargoda", eta: "2025-12-05" };
  }
}

Vurgulanan kısıtlamalar:

  • Task decomposition yok (“geçen ayki tüm siparişlerimi kontrol et” handle edemez)
  • 10 mesaj sonra memory kaybedilir
  • Hardcode edilmiş intent → handler mapping
  • Explicit programlama olmadan birden fazla data source’u birleştiremez
  • Yeni senaryolara adapte olma yeteneği yok

Pattern 2: ReAct Agent (Reasoning and Acting)

ReAct pattern’i tool kullanımıyla iterative reasoning sağlar:

Evet

Hayir

User Task

Thought:

Ne yapacagini

dusun

Cevap icin

yeterli bilgi

var mi?

Final Cevabi Don

Action:

Tool ve

parametre sec

Tool'u Execute Et

Observation:

Tool sonucunu al

Bitti

Production-ready implementasyon:

interface Tool {
  name: string;
  description: string;
  parameters: Record<string, any>;
  execute: (params: any) => Promise<any>;
}

interface AgentStep {
  thought: string;
  action?: { tool: string; input: any };
  observation?: any;
}

class ReActAgent {
  private tools: Map<string, Tool>;
  private memory: ConversationMemory;
  private maxIterations = 10;

  constructor(tools: Tool[], memorySystem: ConversationMemory) {
    this.tools = new Map(tools.map(t => [t.name, t]));
    this.memory = memorySystem;
  }

  async processTask(task: string): Promise<string> {
    const steps: AgentStep[] = [];
    let finalAnswer: string | null = null;

    // Memory'den ilgili context'i al
    const context = await this.memory.retrieve(task);

    for (let i = 0; i < this.maxIterations; i++) {
      // Sonraki adımı generate et: thought + action
      const step = await this.generateNextStep(task, steps, context);
      steps.push(step);

      // Final cevap var mı kontrol et
      if (!step.action) {
        finalAnswer = step.thought;
        break;
      }

      // Action'ı execute et
      const tool = this.tools.get(step.action.tool);
      if (!tool) {
        step.observation = { error: `Tool ${step.action.tool} bulunamadı` };
        continue;
      }

      try {
        const result = await tool.execute(step.action.input);
        step.observation = result;
      } catch (error) {
        step.observation = { error: error.message };
      }
    }

    // Conversation'ı long-term memory'de sakla
    await this.memory.store(task, steps, finalAnswer);

    return finalAnswer || "Bu task'ı iteration limiti içinde tamamlayamadım.";
  }

  private async generateNextStep(
    task: string,
    previousSteps: AgentStep[],
    context: any
  ): Promise<AgentStep> {
    // ReAct pattern'iyle prompt oluştur
    const prompt = this.buildReActPrompt(task, previousSteps, context);

    // Thought ve action generate etmek için LLM çağır
    const response = await this.callLLM(prompt);

    // Response'u structured step'e parse et
    return this.parseReActResponse(response);
  }

  private buildReActPrompt(task: string, steps: AgentStep[], context: any): string {
    const toolDescriptions = Array.from(this.tools.values())
      .map(t => `${t.name}: ${t.description}`)
      .join("\n");

    const stepHistory = steps.map((s, i) =>
      `Adim ${i + 1}:\nDusunce: ${s.thought}\n` +
      (s.action ? `Aksiyon: ${s.action.tool}(${JSON.stringify(s.action.input)})\n` : "") +
      (s.observation ? `Gozlem: ${JSON.stringify(s.observation)}\n` : "")
    ).join("\n");

    return `Tool'ları kullanarak reasoning yapan bir AI agent'sın.

Gorev: ${task}

Mevcut Tool'lar:
${toolDescriptions}

Memory'den Ilgili Context:
${JSON.stringify(context, null, 2)}

Onceki Adimlar:
${stepHistory || "Henuz yok"}

Ne yapacagini dusunup bir tool secerek sonraki adimi generate et.
Cevaplamak icin yeterli bilgin varsa, action yerine final cevabi ver.

Format:
Dusunce: [bir sonraki adim hakkinda reasoning'in]
Aksiyon: [tool_name]
Input: [JSON olarak tool input]

VEYA cevaplamaya hazirsan:
Dusunce: [final reasoning]
Cevap: [gorev icin final cevap]`;
  }

  private parseReActResponse(response: string): AgentStep {
    // LLM output'unu structured step'e parse et
    const thoughtMatch = response.match(/Dusunce: (.+?)(?=\n|$)/s);
    const actionMatch = response.match(/Aksiyon: (.+?)(?=\n|$)/);
    const inputMatch = response.match(/Input: (.+?)(?=\n|$)/s);
    const answerMatch = response.match(/Cevap: (.+?)(?=\n|$)/s);

    const thought = thoughtMatch?.[1].trim() || "";

    if (answerMatch) {
      // Final cevap, action yok
      return { thought: answerMatch[1].trim() };
    }

    if (actionMatch && inputMatch) {
      return {
        thought,
        action: {
          tool: actionMatch[1].trim(),
          input: JSON.parse(inputMatch[1].trim())
        }
      };
    }

    return { thought };
  }

  private async callLLM(prompt: string): Promise<string> {
    // LLM API çağrısı (Anthropic, OpenAI, vs.)
    throw new Error("LLM entegrasyonu implement et");
  }
}

Demonstre edilen temel pattern’ler:

  • Configurable max iteration’larla iterative reasoning loop
  • Context’te sağlanan tool açıklamaları
  • Long-term context için memory retrieval
  • Sonraki adıma dahil edilen observation feedback
  • Tool error’larının graceful handling’i
  • LLM response’larının structured parsing’i

ReAct’i ne zaman kullan:

  • Plan’ların önceden belirlenemediği dinamik environment’lar
  • Step-by-step verification gerektiren task’lar
  • Agent’ın observation’lara göre adapte olması gereken durumlar
  • Bütçe task başına $0.01-0.05 izin veriyor

Production düşünceleri:

  • Infinite loop’ları önlemek için iteration limitleri implement et
  • Debugging için tüm thought’ları ve action’ları logla
  • Token consumption’ı monitor et (basit completion’ın 5-10 katı olabilir)
  • Transparency için thought’ları kullanıcılara stream etmeyi düşün

Pattern 3: Plan-and-Execute

Net yapıya sahip karmaşık task’lar için Plan-and-Execute daha iyi cost efficiency sunuyor:

Evet

Hayir

User Goal

Planning Fazi:

Subtask'lara

ayir

Dependency'leri

Analiz Et

Execution Fazi

Paralel

calisabilir mi?

Task'lari

Concurrently Execute Et

Task'lari

Sequentially Execute Et

Synthesis Fazi:

Sonuclari Birlestir

Final Cevap

Implementasyon:

interface Task {
  id: string;
  description: string;
  status: "pending" | "in-progress" | "completed" | "failed";
  dependencies: string[];
  result?: any;
  error?: string;
  metadata?: any;
}

interface ExecutionPlan {
  goal: string;
  tasks: Task[];
  strategy: string;
}

class PlanAndExecuteAgent {
  private tools: Map<string, Tool>;
  private memory: ConversationMemory;

  async execute(goal: string): Promise<any> {
    // Faz 1: Planning
    console.error("[Planning Fazi] Goal'i task'lara ayiriyor...");
    const plan = await this.createPlan(goal);
    console.error(`[Planning Fazi] ${plan.tasks.length} task ile plan olusturuldu`);

    // Faz 2: Execution
    console.error("[Execution Fazi] Task'lar execute ediliyor...");
    const results = await this.executePlan(plan);

    // Faz 3: Synthesis
    console.error("[Synthesis Fazi] Sonuclar birlestiriliyor...");
    const finalResult = await this.synthesizeResults(goal, plan, results);

    return finalResult;
  }

  private async createPlan(goal: string): Promise<ExecutionPlan> {
    // Memory'den ilgili geçmiş plan'ları al
    const pastExperiences = await this.memory.retrieve(goal);

    const planningPrompt = `Bir planning agent'sın. Bu goal'i executable task'lara ayır.

Goal: ${goal}

Mevcut Tool'lar:
${Array.from(this.tools.values()).map(t => `- ${t.name}: ${t.description}`).join("\n")}

Benzer Gecmis Task'lar:
${JSON.stringify(pastExperiences, null, 2)}

Soyle task'larla plan olustur:
1. Mumkun oldugunda independent (paralel execution icin)
2. Dependency'leri explicit belirt
3. Mevcut tool'lara map'le
4. Verification adimlarini icersin

Return formati:
{
  "strategy": "yaklasimin aciklamasi",
  "tasks": [
    {
      "id": "task-1",
      "description": "ne yapilacak",
      "tool": "tool_name",
      "dependencies": [],
      "params": {}
    }
  ]
}`;

    const planResponse = await this.callLLM(planningPrompt);
    const planData = JSON.parse(planResponse);

    return {
      goal,
      strategy: planData.strategy,
      tasks: planData.tasks.map((t: any) => ({
        id: t.id,
        description: t.description,
        status: "pending" as const,
        dependencies: t.dependencies || [],
        metadata: { tool: t.tool, params: t.params }
      }))
    };
  }

  private async executePlan(plan: ExecutionPlan): Promise<Map<string, any>> {
    const results = new Map<string, any>();
    const taskMap = new Map(plan.tasks.map(t => [t.id, t]));

    // Dependency'leri respect ederek task'ları execute et
    while (results.size < plan.tasks.length) {
      // Execute etmeye hazır task'ları bul (pending dependency yok)
      const readyTasks = plan.tasks.filter(task => {
        if (task.status !== "pending") return false;

        return task.dependencies.every(depId => {
          const depTask = taskMap.get(depId);
          return depTask?.status === "completed";
        });
      });

      if (readyTasks.length === 0) {
        // Takılıp kalmadık mı kontrol et (circular dependency veya hepsi failed)
        const pendingTasks = plan.tasks.filter(t => t.status === "pending");
        if (pendingTasks.length > 0) {
          console.error("[Execution Fazi] Takildi - circular dependency tespit edildi");
          break;
        }
        break;
      }

      // Hazır task'ları paralel execute et
      console.error(`[Execution Fazi] ${readyTasks.length} task paralel execute ediliyor`);
      await Promise.all(
        readyTasks.map(task => this.executeTask(task, results))
      );
    }

    return results;
  }

  private async executeTask(task: Task, results: Map<string, any>): Promise<void> {
    task.status = "in-progress";
    console.error(`[Task ${task.id}] Basliyor: ${task.description}`);

    try {
      // Dependency sonuçlarını al
      const depResults = task.dependencies.reduce((acc, depId) => {
        acc[depId] = results.get(depId);
        return acc;
      }, {} as Record<string, any>);

      // Tool'u parametreler ve dependency sonuçlarıyla execute et
      const tool = this.tools.get(task.metadata.tool);
      if (!tool) {
        throw new Error(`Tool ${task.metadata.tool} bulunamadi`);
      }

      const params = {
        ...task.metadata.params,
        dependencyResults: depResults
      };

      const result = await tool.execute(params);

      task.status = "completed";
      task.result = result;
      results.set(task.id, result);

      console.error(`[Task ${task.id}] Basariyla tamamlandi`);
    } catch (error) {
      task.status = "failed";
      task.error = error.message;
      results.set(task.id, { error: error.message });

      console.error(`[Task ${task.id}] Basarisiz: ${error.message}`);
    }
  }

  private async synthesizeResults(
    goal: string,
    plan: ExecutionPlan,
    results: Map<string, any>
  ): Promise<any> {
    const synthesisPrompt = `Bir goal'e ulasmak icin plan execute ettin. Sonuclari coherent bir cevap haline getir.

Goal: ${goal}

Plan Stratejisi: ${plan.strategy}

Task Sonuclari:
${Array.from(results.entries()).map(([id, result]) =>
  `${id}: ${JSON.stringify(result)}`
).join("\n")}

Original goal'i adreslemeyen comprehensive bir cevap ver, tum task'lardan insight'ları dahil et.`;

    const synthesis = await this.callLLM(synthesisPrompt);

    // Basarili plan'i future reference icin memory'de sakla
    if (results.size === plan.tasks.length) {
      await this.memory.store(goal, { plan, results: Array.from(results.entries()) }, synthesis);
    }

    return synthesis;
  }

  private async callLLM(prompt: string): Promise<string> {
    throw new Error("LLM entegrasyonu implement et");
  }
}

Trade-off’lar:

  • Artıları: Daha az LLM call (bir kez plan, execute), paralel execution, öngörülebilir cost’lar
  • Eksileri: Environment execution ortasında değiştiğinde kırılgan, beklenmedik sonuçlara adapte olmak daha zor

Best practice’ler:

  • Başarılı plan’ları yeniden kullanım için memory’de sakla
  • Plan’a verification task’ları dahil et
  • Execution fail olursa re-planning’e izin ver
  • Individual task’lar için timeout kullan

Memory Mimarisi: Short-Term vs Long-Term

Chatbot’lar ve agent’lar arasındaki en önemli farklardan biri memory mimarisi:

Current task

Recent context

Retrieve

Retrieve

Top-k similar

Time-based

Store important

Append

Agent

Working Memory

In-Context

Short-Term Memory

Buffer

Long-Term Memory

Vector DB

Semantic Search

Episodic Recall

Implementasyon karşılaştırması:

interface MemoryEntry {
  timestamp: Date;
  content: any;
  metadata: Record<string, any>;
  embedding?: number[];
}

// Basit buffer memory (chatbot tarzı)
class BufferMemory {
  private buffer: MemoryEntry[] = [];
  private maxSize = 10;

  async store(content: any, metadata: Record<string, any> = {}): Promise<void> {
    this.buffer.push({ timestamp: new Date(), content, metadata });
    if (this.buffer.length > this.maxSize) {
      this.buffer.shift(); // FIFO eviction
    }
  }

  async retrieve(query: string): Promise<any[]> {
    // Tüm buffer içeriğini döndür (filtreleme yok)
    return this.buffer.map(e => e.content);
  }

  async clear(): Promise<void> {
    this.buffer = [];
  }
}

// Vector tabanlı long-term memory (agent tarzı)
class VectorMemory {
  private vectorStore: VectorDatabase;
  private embeddingModel: EmbeddingModel;

  constructor(vectorStore: VectorDatabase, embeddingModel: EmbeddingModel) {
    this.vectorStore = vectorStore;
    this.embeddingModel = embeddingModel;
  }

  async store(content: any, metadata: Record<string, any> = {}): Promise<void> {
    // Semantic search için embedding generate et
    const text = this.contentToText(content);
    const embedding = await this.embeddingModel.embed(text);

    await this.vectorStore.insert({
      timestamp: new Date(),
      content,
      metadata: {
        ...metadata,
        importance: this.calculateImportance(content, metadata)
      },
      embedding
    });
  }

  async retrieve(query: string, options: { limit?: number; threshold?: number } = {}): Promise<any[]> {
    // Embedding'ler kullanarak semantic search
    const queryEmbedding = await this.embeddingModel.embed(query);

    const results = await this.vectorStore.search({
      embedding: queryEmbedding,
      limit: options.limit || 5,
      threshold: options.threshold || 0.7
    });

    // En ilgili memory'leri, recency ve importance'a göre ağırlıklandırarak döndür
    return results
      .map(r => ({
        content: r.content,
        relevance: r.similarity,
        recency: this.calculateRecency(r.timestamp),
        importance: r.metadata.importance
      }))
      .sort((a, b) => {
        const scoreA = a.relevance * 0.6 + a.recency * 0.2 + a.importance * 0.2;
        const scoreB = b.relevance * 0.6 + b.recency * 0.2 + b.importance * 0.2;
        return scoreB - scoreA;
      })
      .map(r => r.content);
  }

  async forget(criteria: { olderThan?: Date; importance?: number }): Promise<void> {
    // Zamana ve importance'a göre selective forgetting
    const deleteFilter: any = {};

    if (criteria.olderThan) {
      deleteFilter.timestamp = { $lt: criteria.olderThan };
    }
    if (criteria.importance !== undefined) {
      deleteFilter["metadata.importance"] = { $lt: criteria.importance };
    }

    await this.vectorStore.delete(deleteFilter);
  }

  private calculateImportance(content: any, metadata: Record<string, any>): number {
    // Heuristik scoring: user correction'ları, explicit feedback, task outcome'ları
    let score = 0.5; // baseline

    if (metadata.userCorrection) score += 0.3;
    if (metadata.explicitFeedback) score += 0.2;
    if (metadata.taskSuccess === false) score += 0.15; // Failure'lardan öğren
    if (metadata.toolError) score += 0.1; // Issue'ları hatırla

    return Math.min(score, 1.0);
  }

  private calculateRecency(timestamp: Date): number {
    const ageMs = Date.now() - timestamp.getTime();
    const ageDays = ageMs / (1000 * 60 * 60 * 24);

    // Exponential decay: taze memory'ler daha yüksek score alır
    return Math.exp(-ageDays / 30); // 30 günlük half-life
  }

  private contentToText(content: any): string {
    if (typeof content === "string") return content;
    return JSON.stringify(content);
  }
}

// Production agent'lar için hybrid memory sistem
class HybridMemory implements ConversationMemory {
  private shortTerm: BufferMemory;
  private longTerm: VectorMemory;

  constructor(vectorStore: VectorDatabase, embeddingModel: EmbeddingModel) {
    this.shortTerm = new BufferMemory();
    this.longTerm = new VectorMemory(vectorStore, embeddingModel);
  }

  async store(task: string, steps: any[], result: any): Promise<void> {
    // Immediate recall için short-term'de sakla
    await this.shortTerm.store({ task, steps, result });

    // Semantic retrieval için long-term'de sakla
    await this.longTerm.store(
      { task, steps, result },
      {
        taskSuccess: result !== null,
        stepCount: steps.length,
        timestamp: new Date()
      }
    );
  }

  async retrieve(query: string): Promise<any> {
    // Her iki memory sistemini birleştir
    const recent = await this.shortTerm.retrieve(query);
    const relevant = await this.longTerm.retrieve(query, { limit: 3 });

    return {
      recentContext: recent,
      relevantExperiences: relevant
    };
  }
}

Memory karşılaştırma insight’ları:

  • Buffer memory: Hızlı, basit, semantic anlayış yok
  • Vector memory: Semantic search, importance-weighted, selective forgetting
  • Hybrid yaklaşım: Production agent’lar için her ikisinin de en iyisi

Multi-Agent Koordinasyon Pattern’leri

Specialized expertise gerektiren karmaşık sistemler için:

Peer-to-Peer Pattern

Agent 1

Agent 2

Agent 3

Orchestrator Pattern

Orchestrator

Agent 1

Agent 2

Agent 3

Orchestrator pattern (production için önerilen):

  • Net control flow
  • Debug etmesi daha kolay
  • Öngörülebilir cost’lar
  • Single point of failure (retry’larla mitigate edilir)

Peer-to-peer pattern (deneysel):

  • Decentralized
  • Fault-tolerant
  • Debug etmesi zor
  • Öngörülemeyen cost’lar

Implementasyon başlangıç kodu yukarıdaki İngilizce versiyonla aynı TypeScript interface’lerini kullanır.

Güvenlik ve Guardrail’ler

Production agent’lar birden fazla güvenlik katmanı gerektirir:

Evet

Hayir

User Input

Input Guardrail:

Validation

Agent Processing

Tool Guardrail:

Authorization

Tool Execution

Output Guardrail:

Filtering

Human

onay

gerekli mi?

Human Review

User Output

Audit Log

Guardrail sistemleri input validation, tool authorization, output filtering ve PII redaction içerir. Implementasyon detayları İngilizce versiyondaki kodla aynı mantığı takip eder.

Cost Analizi ve Trade-off’lar

Token Consumption Karşılaştırması

“Sipariş durumunu kontrol et ve para iadesi işle” gibi tipik bir task için:

MimariLLM Call’larıAvg Token’larTask Başına Cost
Chatbot2-31,000$0.002
ReAct Agent5-88,000$0.016
Plan-Execute Agent3-44,000$0.008
Multi-Agent6-1010,000$0.020

Cost’lar Claude Sonnet pricing’e göre: 3/Minput,3/M input, 15/M output token. Not: Prompt caching ve batch processing cost’ları %50-90 azaltabilir

Infrastructure Cost’ları

  • Chatbot: Minimal (stateless API)
  • Single Agent: Orta (memory için vector DB: ayda $50-200)
  • Multi-Agent: Daha yüksek (coordination layer, birden fazla DB: ayda $200-500)

Performance Özellikleri

Latency:

  • Chatbot: 500ms - 2s (tek LLM call)
  • ReAct Agent: 5s - 30s (birden fazla iteration)
  • Plan-Execute: 3s - 15s (planning overhead, paralel execution)
  • Multi-Agent: 10s - 60s (koordinasyon + birden fazla agent)

Accuracy (karmaşık çok adımlı task’lar için):

  • Chatbot: %40-60 (önceden tanımlanmış flow’larla sınırlı)
  • ReAct Agent: %70-85 (adaptive, ama takılabilir)
  • Plan-Execute: %75-90 (yapılandırılmış yaklaşım)
  • Multi-Agent: %80-95 (specialized expertise)

Ne Zaman Ne Kullanılır

Basit, FAQ

Orta, Esnek

Yuksek, Multi-Domain

Hayir

Evet

Dusuk

Orta

Orta

Yuksek

AI Sistemi Gerekli

Task

Karmasikligi?

Intent-Based

Chatbot

Planning

Gerekli mi?

Multi-Agent

System

ReAct Agent

Plan-Execute

Agent

Butce?

Butce?

Butce?

Butce?

Uygun

Plan-Execute Dusun

Uygun

Uygun

Chatbot kullan:

  • Task’lar net intent’lerle iyi tanımlanmış (< 20 intent)
  • Response’lar scriptlenebilir veya template-based
  • Bütçe sıkı ($0.001-0.005 per interaction)
  • Latency < 2 saniye olmalı
  • Minimal maintenance kadrosu

ReAct Agent kullan:

  • Task’lar dinamik adaptasyon gerektiriyor
  • Tüm senaryolar önceden tahmin edilemiyor
  • Transparency gerekli (reasoning audit trail)
  • Bütçe task başına $0.01-0.05 izin veriyor
  • Ekipte LLM expertise var

Plan-Execute Agent kullan:

  • Net yapıya sahip karmaşık task’lar
  • Paralel execution’dan faydalanabilir
  • Öngörülebilir cost’lar gerekli
  • Kalite hızdan önemli
  • Task’lar mantıksal olarak decompose edilebilir

Multi-Agent System kullan:

  • Domain’ler arası specialized expertise gerekli
  • En yüksek accuracy gerekli
  • Chatbot’a göre 5-10x cost justify edilebilir
  • Coordination logic’i maintain edecek ekip var
  • Failure cost’u yüksek (healthcare, finans)

Yaygın Tuzaklar ve Çözümler

Tuzak 1: ReAct Agent’larda Infinite Loop’lar

Agent aynı tool call’larını tekrarlayarak takılıyor.

Çözüm: Loop’ları detect et ve kır

async function reactLoopWithDetection(task: string) {
  const actionHistory = new Set<string>();

  for (let i = 0; i < maxIterations; i++) {
    const step = await generateStep();

    // Bu action'ın signature'ını oluştur
    const actionSignature = `${step.action.tool}:${JSON.stringify(step.action.input)}`;

    if (actionHistory.has(actionSignature)) {
      console.error("[Loop Tespit Edildi] Tekrarlanan action'dan cikiliyor");
      return { error: "Agent loop'ta takildi, sonlandiriliyor" };
    }

    actionHistory.add(actionSignature);
    await executeStep(step);
  }
}

Tuzak 2: Context Window Overflow

Conversation history context limitini aşıyor.

Çözüm: Summarization ile sliding window implement et

class ManagedConversationHistory {
  private messages: Message[] = [];
  private maxMessages = 20;
  private summaries: string[] = [];

  async add(message: Message) {
    this.messages.push(message);

    if (this.messages.length > this.maxMessages) {
      // En eski 10 mesajı summarize et
      const toSummarize = this.messages.splice(0, 10);
      const summary = await this.summarize(toSummarize);
      this.summaries.push(summary);
    }
  }

  getContext(): string {
    return [
      ...this.summaries.map(s => `[Ozet] ${s}`),
      ...this.messages.map(m => `${m.role}: ${m.content}`)
    ].join("\n");
  }
}

Tuzak 3: Tool Description Bloat

Çok fazla tool veya verbose açıklamalar sağlamak. Çözüm: Task context’e göre tool’ları dinamik yükle. ContextualToolLoader ile semantic search kullan, max 8 tool, concise description.

Progressive Migration Stratejisi

Chatbot ile başla, incremental olarak agent yetenekleri ekle:

class HybridChatbotAgent {
  private intentClassifier: IntentClassifier;
  private agentMode: boolean = false;

  async process(message: string): Promise<string> {
    // Önce intent-based handling dene (hızlı, ucuz)
    const intent = await this.intentClassifier.classify(message);

    if (intent.confidence > 0.85 && !intent.requiresToolUse) {
      // Geleneksel chatbot flow kullan
      return await this.handleIntent(intent);
    }

    // Karmaşık query'ler için agent mode'a geç
    console.error("[Hybrid] Karmasik query icin agent mode'a geciliyor");
    this.agentMode = true;
    return await this.agentProcess(message);
  }
}

Başarı metrikleri: Query’lerin %80’i hızlı chatbot path’le, %20’si agent ile handle ediliyor, pure agent yaklaşımına göre %40 cost reduction sağlanıyor.

Tool’lar ve Teknolojiler

Agent Framework’leri

LangGraph (LangChain):

  • Dil: Python, TypeScript
  • Güçlü yönler: State management, graph-based workflow’lar, production-ready

AutoGen (Microsoft):

  • Dil: Python
  • Güçlü yönler: Multi-agent conversation’lar, built-in pattern’ler
  • Not: AutoGen maintenance mode’da, Microsoft’un Agent Framework’ü ile değiştiriliyor

CrewAI:

  • Dil: Python
  • Güçlü yönler: Role-based agent’lar, lightweight

Memory Sistemleri

Vector Database’ler:

  • Pinecone: Managed, serverless
  • Qdrant: Open-source, self-hosted
  • Weaviate: GraphQL interface, hybrid search
  • Chroma: Lightweight, embedded option

Specialized Memory:

  • Mem0: Priority scoring ile intelligent memory layer (yakın zamanda Series A yatırım, AWS partnership)
  • Letta (eski adıyla MemGPT): Context management için memory block’lar

Observability

LangSmith: Agent execution’ları trace et, reasoning chain’leri debug et, prompt’lar için A/B testing

Langfuse: Open-source LLM observability, cost tracking, latency monitoring

Helicone: LLM request monitoring, cost analytics, caching

Temel Çıkarımlar

  1. Mimari Evrim: Chatbot’lar ve agent’lar bir continuum üzerinde; task complexity, bütçe ve ekip expertise’ine göre seç

  2. Pattern Seçimi Önemli: Dinamik adaptasyon için ReAct, yapılandırılmış task’lar için Plan-Execute, specialization için multi-agent

  3. Memory Kritik: Long-term memory agent’ları chatbot’lardan ayırır: vector database’lere ve retrieval stratejilerine yatırım yap

  4. Guardrail’ler Vazgeçilmez: Production sistemleri için input validation, tool authorization, output filtering ve human-in-the-loop implement et

  5. Cost vs Kalite Trade-off’u: Agent’lar chatbot’lardan 5-10x daha pahalı olabilir ama karmaşık task’larda 2-3x daha yüksek accuracy sağlar

  6. Tool Design Prensipleri: Küçük, composable tool’lar monolithic’leri yener; test etmesi, debug etmesi ve yeniden kullanması daha kolay

  7. Progressive Enhancement: Chatbot ile başla, ihtiyaçlar büyüdükçe incremental olarak agent yetenekleri ekle

  8. Evaluation Temel: Completion rate, task başına token, latency ve user satisfaction track et; dataya göre iterate et

  9. Error Recovery Kazanır: Fallback stratejileriyle intelligent retry logic production agent’larını prototype’lardan ayırır

  10. Context Window Management: Summarization, structured note’lar ve sub-agent’lar uzun conversation’larda context overflow’u önler

Chatbot’lardan otonom agent’lara bu mimari yolculuk, sadece yetenek eklemekten fazlasını temsil ediyor; AI sistemlerini nasıl tasarladığımızda temel bir değişim. Burada özetlenen pattern’ler ve practice’ler, autonomy ile control’ü dengeleyen production-ready agent sistemleri inşa etmek için bir temel sunuyor.

İlgili yazılar

JavaScript'te SOLID Prensipleri: TypeScript ve React ile Pratik Rehber

SOLID prensiplerininin modern JavaScript geliştirmede nasıl uygulanacağını öğrenin. TypeScript, React hooks ve fonksiyonel pattern'ler ile pratik örnekler - ayrıca ne zaman kullanmalı, ne zaman gereksiz.

typescriptjavascriptreact+5
AWS Bedrock AgentCore ile Production-Ready AI Agentları Geliştirmek

AWS Bedrock AgentCore'un agentic AI'ı ölçekte deploy etme altyapı zorluklarını nasıl çözdüğünü öğrenin - prototipten production'a runtime, memory, gateway ve multi-agent koordinasyonu ile.

aws-bedrockai-agentsagentic-ai+4
AWS Bedrock AgentCore'u CDK ile deploy etmek: hızlı başlangıç

AgentCore Runtime üzerinde minimal bir Strands agent'ı CDK ile deploy etme rehberi — parametrize stack, arm64 build, deploy ve invoke akışı, ve ilk çağrıdan önce gereken IAM ve Marketplace ön koşulları.

aws-bedrockai-agentsaws-cdk+3
Zapier MCP ile İzin Kontrol Katmanı: AI Agent'lar için Geniş API Erişimini Yönetmek

Zapier MCP'nin AI agent'lar için aksiyon bazlı beyaz liste, merkezi kimlik yönetimi ve insan onay mekanizması sunması. Özel proxy çözümlerine yönetilen bir alternatif.

mcpsecurityai-agents+4
SaaS Yetkilendirme için AWS Cognito + Verified Permissions

AWS Cognito ve Verified Permissions ile SaaS yetkilendirme mimarisi. Cedar politika dili, çok kiracılı desenler, JWT token akışı, maliyet analizi ve TypeScript örnekleriyle yaygın hatalar.

authorizationawscognito+4