İçeriğe atla

TypeScript AI SDK Karşılaştırması: Agent Geliştirme için Vercel AI SDK vs OpenAI Agents SDK

Agent geliştirmek için TypeScript SDK karşılaştırması: Vercel AI SDK, OpenAI Agents SDK ve AWS Bedrock entegrasyonu, kod örnekleri ve karar frameworkleri ile.

Ayhan Sipahi Ayhan Sipahi

TypeScript’te AI agent geliştirmeye başlarken ilk karar sıkıcı olanı: tool çağrılarını, streamingi ve provider kimlik bilgilerini hangi SDK taşıyacak. Üç cevap öne çıkıyor ve her biri farklı bir şeyi optimize ediyor. Vercel AI SDK, providera özgü yüzeyi taşınabilirlik karşılığında bırakıyor; OpenAI Agents SDK multi-agent orkestrasyonunu çalışma zamanına gömüyor; direkt provider SDK’leri ise her ayarı açıkta bırakıyor.

Çoğu TypeScript ve Next.js kod tabanında varsayılan Vercel AI SDK. Asıl soru bu varsayılanın nerede yetersiz kaldığı: yoğun multi-agent orkestrasyonu ve hiçbir soyutlamanın henüz açmadığı bir özelliğe ihtiyaç duyan tek providerlı servisler.

TypeScript AI SDK Ekosistemi#

Üçü de soyutlamayı farklı bir seviyeye yerleştiriyor:

  1. Vercel AI SDK: 70’den fazla provider desteği ile provider-agnostic birleşik arayüz
  2. OpenAI Agents SDK: Native handofflarla multi-agent sistemler için özel olarak tasarlanmış
  3. Direkt Provider SDK’leri: Providera özgü özelliklerle maksimum kontrol

Zorluk, gereksinimlerinizi doğru seviyeyle eşleştirmek.

Multi-provider

Multi-agent

Tek provider

Direkt SDK'ler

openai

@anthropic-ai/sdk

AWS Bedrock

OpenAI Agents SDK

Agentlar

Handofflar

Guardraillar

Vercel AI SDK

AI SDK Core

AI SDK UI

70+ Provider

Kullanım Senaryonuz?

Vercel AI SDK: Provider-Agnostic Yaklaşım#

Vercel AI SDK birleşik arayüz yaklaşımını benimsiyor. Bir kez yaz, herhangi bir providera deploy et. Bu esneklik, gereksinimler değiştiğinde veya güvenilirlik için fallback providerlara ihtiyaç duyduğunuzda önem kazanıyor.

Temel Mimari#

SDK, sorumlulukları temiz bir şekilde ayırıyor:

  • AI SDK Core: Sunucu tarafı işlemleri (generateText, streamText, generateObject)
  • AI SDK UI: Chat arayüzleri için React hookları (useChat, useCompletion)
  • AI SDK RSC: React Server Components entegrasyonu

Zod ile Tool Tanımlama#

Toollar type-safe Zod şemalarıyla tanımlanıyor. SDK parametre doğrulamasını otomatik olarak yapıyor:

import { tool, generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const weatherTool = tool({
  description: 'Bir şehir için güncel hava durumunu getir',
  parameters: z.object({
    city: z.string().describe('Şehir adı'),
    unit: z.enum(['celsius', 'fahrenheit']).default('celsius'),
  }),
  execute: async ({ city, unit }) => {
    // API çağrınız burada
    const response = await fetch(
      `https://api.weather.example/v1/current?city=${city}&unit=${unit}`
    );
    return response.json();
  },
});

const searchTool = tool({
  description: 'Web üzerinde bilgi ara',
  parameters: z.object({
    query: z.string().describe('Arama sorgusu'),
    limit: z.number().optional().default(5),
  }),
  execute: async ({ query, limit }) => {
    // Arama implementasyonu
    return { results: [`Sonuç: ${query}`], count: limit };
  },
});

maxSteps ile Agent Döngüsü#

Çok turlu tool kullanımı için maxSteps parametresi otomatik tool çalıştırma döngüleri sağlıyor:

import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: openai('gpt-4o'),
    messages,
    system: 'Hava durumu ve arama yeteneklerine sahip yardımcı bir asistansın.',
    tools: {
      weather: weatherTool,
      search: searchTool,
    },
    maxSteps: 5, // 5 tura kadar tool çalıştırmaya izin ver
  });

  return result.toDataStreamResponse();
}

SDK tüm döngüyü yönetiyor: LLM’i çağır, tool çağrılarını tespit et, toolları çalıştır, sonuçları ekle, tamamlanana veya maxSteps’e ulaşılana kadar tekrarla.

Provider Değiştirme Patternı#

Birleşik arayüzün karşılığını aldığı yer provider değiştirme. Aynı kod, farklı backend:

import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
import { google } from '@ai-sdk/google';
import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
import { generateText } from 'ai';

// Providerları yapılandır
const bedrock = createAmazonBedrock({ region: 'us-east-1' });

// Provider kayıt defteri
const providers = {
  'gpt-4o': openai('gpt-4o'),
  'gpt-4o-mini': openai('gpt-4o-mini'),
  'claude-sonnet': anthropic('claude-sonnet-4-6-20250217'),
  'claude-haiku': anthropic('claude-haiku-4-5-20241022'),
  'gemini-flash': google('gemini-2.5-flash'),
  'bedrock-claude': bedrock('anthropic.claude-sonnet-4-6-20250217-v1:0'),
};

// Aynı fonksiyon herhangi bir provider ile çalışıyor
async function generate(prompt: string, providerId: keyof typeof providers) {
  const { text, usage } = await generateText({
    model: providers[providerId],
    prompt,
  });

  return { text, usage };
}

// Değiştirmek çok basit
const openaiResult = await generate('Kuantum bilişimi açıkla', 'gpt-4o');
const claudeResult = await generate('Kuantum bilişimi açıkla', 'claude-sonnet');

React Entegrasyonu ile Streaming#

AI SDK UI, streaming karmaşıklığını yöneten hooklar sağlıyor:

// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';

export const runtime = 'edge';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: openai('gpt-4o'),
    messages,
    tools: {
      calculate: tool({
        description: 'Aritmetik işlem yap',
        parameters: z.object({ expression: z.string() }),
        execute: async ({ expression }) => {
          // Productionda güvenli bir matematik parser kullanın
          return { result: eval(expression) };
        },
      }),
    },
    maxSteps: 3,
  });

  return result.toDataStreamResponse();
}
// components/Chat.tsx
'use client';

import { useChat } from 'ai/react';

export function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: '/api/chat',
  });

  return (
    <div className="flex flex-col h-screen">
      <div className="flex-1 overflow-y-auto p-4">
        {messages.map((m) => (
          <div key={m.id} className={`mb-4 ${m.role === 'user' ? 'text-right' : ''}`}>
            <span className="font-bold">{m.role}:</span> {m.content}
          </div>
        ))}
      </div>
      <form onSubmit={handleSubmit} className="p-4 border-t">
        <input
          value={input}
          onChange={handleInputChange}
          disabled={isLoading}
          className="w-full p-2 border rounded"
          placeholder="Mesaj yazın..."
        />
      </form>
    </div>
  );
}

OpenAI Agents SDK: Multi-Agent Uzmanı#

OpenAI’nin Agents SDK’si farklı bir yaklaşım benimsiyor. Provider soyutlaması yerine, agent orkestrasyon patternlerine odaklanıyor: uzman agentlar arası handofflar, doğrulama için guardraillar ve yerleşik tracing.

Temel Kavramlar#

SDK dört anahtar kavram sunuyor:

  1. Agentlar: Talimatlar, toollar ve handoff yeteneği olan LLM’ler
  2. Handofflar: Konuşma sahipliğini aktaran özel tool çağrıları
  3. Guardraillar: Agent çalıştırmasıyla paralel çalışan input/output doğrulaması
  4. Tracing: Yerleşik debug ve izleme

Handofflarla Multi-Agent#

Handoff patternı, birbirine devredebilen uzman agentları mümkün kılıyor:

import { Agent, run, tool } from '@openai/agents';
import { z } from 'zod';

// Uzman toolları tanımla
const getWeatherTool = tool({
  name: 'get_weather',
  description: 'Bir şehir için hava durumu getir',
  parameters: z.object({
    city: z.string(),
  }),
  execute: async ({ city }) => {
    return `${city} hava durumu: 22C, güneşli`;
  },
});

const searchDatabaseTool = tool({
  name: 'search_database',
  description: 'Dahili veritabanında ara',
  parameters: z.object({
    query: z.string(),
  }),
  execute: async ({ query }) => {
    return `${query} için 3 sonuç bulundu`;
  },
});

// Uzman agentlar oluştur
const weatherAgent = new Agent({
  name: 'Hava Durumu Uzmanı',
  instructions: 'Bir hava durumu uzmanısın. Detaylı hava bilgisi sağla.',
  tools: [getWeatherTool],
  handoffDescription: 'Hava durumuyla ilgili sorular için uzman',
});

const dataAgent = new Agent({
  name: 'Veri Uzmanı',
  instructions: 'Bir veri uzmanısın. Veritabanı bilgilerini ara ve analiz et.',
  tools: [searchDatabaseTool],
  handoffDescription: 'Veritabanı sorguları ve veri analizi için uzman',
});

// Handofflarla triaj agentı oluştur
const triageAgent = new Agent({
  name: 'Triaj Agent',
  instructions: `Soruları uzmanlara yönlendiren yardımcı bir asistansın.
  - Hava durumu soruları için Hava Durumu Uzmanına devret
  - Veri/veritabanı soruları için Veri Uzmanına devret
  - Genel soruları doğrudan yanıtla`,
  handoffs: [weatherAgent, dataAgent],
});

// Agent iş akışını çalıştır
async function handleQuery(userMessage: string) {
  const result = await run(triageAgent, userMessage);

  return {
    finalOutput: result.finalOutput,
    agentPath: result.history
      .filter(h => h.type === 'handoff')
      .map(h => h.agent),
  };
}

Agent Döngüsü#

SDK sofistike bir çalıştırma döngüsünü yönetiyor:

Son Metin

Tool Çağrıları

Handoff

Kullanıcı Mesajı

Agent İşleme

LLM Çağrısı

Yanıt Türü?

Yanıtı Dön

Toolları Çalıştır

Agent Değiştir

Sonuçları Topla

Karmaşık Tool Şemaları#

SDK, otomatik doğrulamayla iç içe şemaları yönetiyor:

const createOrderTool = tool({
  name: 'create_order',
  description: 'Yeni bir müşteri siparişi oluştur',
  parameters: z.object({
    customerId: z.string().uuid(),
    items: z.array(z.object({
      productId: z.string(),
      quantity: z.number().int().positive(),
      price: z.number().positive(),
    })),
    shippingAddress: z.object({
      street: z.string(),
      city: z.string(),
      country: z.string(),
      postalCode: z.string(),
    }),
    priority: z.enum(['standard', 'express', 'overnight']).default('standard'),
  }),
  execute: async ({ customerId, items, shippingAddress, priority }) => {
    const order = await orderService.create({
      customerId,
      items,
      shippingAddress,
      priority,
    });

    return {
      orderId: order.id,
      status: 'created',
      estimatedDelivery: order.estimatedDelivery,
    };
  },
});

AWS Bedrock Entegrasyonu#

AWS altyapısına yatırım yapmış takımlar için Bedrock, IAM, VPC entegrasyonu ve uyumluluk kontrolleri gibi kurumsal özelliklerle birden fazla temel modele erişim sağlıyor.

Bedrock Provider ile AI SDK#

En temiz yaklaşım AI SDK’nin Bedrock providerını kullanıyor:

import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
import { generateText, streamText } from 'ai';

const bedrock = createAmazonBedrock({
  region: 'us-east-1',
  // Varsayılan olarak AWS credential chain kullanır
});

// Bedrock üzerinden Claude
const claudeModel = bedrock('anthropic.claude-sonnet-4-6-20250217-v1:0');

// Bedrock üzerinden Llama
const llamaModel = bedrock('meta.llama3-70b-instruct-v1:0');

// Amazon Nova (multi-region kullanılabilirlik için cross-region inference ID kullan)
const novaModel = bedrock('amazon.nova-pro-v1:0');
// Alternatif: bedrock('us.amazon.nova-pro-v1:0') cross-region inference için

async function generateWithBedrock(prompt: string) {
  const { text, usage } = await generateText({
    model: claudeModel,
    prompt,
    maxTokens: 1024,
  });

  return { text, usage };
}

Lambda Entegrasyonu#

Bedrock, IAM role credentialları kullanarak Lambda ile doğal olarak çalışıyor:

import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { generateText } from 'ai';
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';

const bedrock = createAmazonBedrock({
  region: process.env.AWS_REGION || 'us-east-1',
  credentialProvider: fromNodeProviderChain(),
});

export const handler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  const { prompt } = JSON.parse(event.body || '{}');

  const { text } = await generateText({
    model: bedrock('anthropic.claude-sonnet-4-6-20250217-v1:0'),
    prompt,
  });

  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ response: text }),
  };
};

Pratik Karşılaştırma#

Özellik Matrisi#

ÖzellikVercel AI SDKOpenAI Agents SDKDirekt SDK’ler
Multi-Provider70+ providerAdapter gerekliTek
Tool CallingBirinci sınıfBirinci sınıfProvidera özgü
StreamingYerleşikYerleşikProvidera özgü
Multi-AgentKompozisyon ileNative handoffManuel
Edge RuntimeTam destekKısmiDeğişken
React EntegrasyonuNative hooklarManuelManuel
Type SafetyTam TypeScriptTam TypeScriptDeğişken
GözlemlenebilirlikDevTools + OTELYerleşik tracingManuel

Kurulum Eforu#

İlk çalışan implementasyona ulaşmak için gereken göreli efor:

GörevAI SDKOpenAI AgentsDirekt SDK
Temel chatDüşükDüşükOrta
Streaming UIDüşükOrtaYüksek
Tool callingDüşükDüşükOrta
Multi-agentOrtaDüşükYüksek
Provider değiştirmeDüşükOrtaYüksek

Son satır, projenin ilerleyen dönemlerinde karşınıza çıkan satır. Birleşik bir API’de provider değiştirmek kayıt defterinde bir düzenleme; direkt SDK’lerde eklediğiniz her provider için çağrı katmanını yeniden yazmak demek.

Maliyet Tarafı#

Tüm SDK’ler ücretsiz. Maliyetler API kullanımından geliyor:

ModelProviderInput (1M başına)Output (1M başına)
GPT-4oOpenAI$2.50$10.00
GPT-4o-miniOpenAI$0.15$0.60
Claude Sonnet 4.6Anthropic/Bedrock$3.00$15.00
Claude Haiku 4.5Anthropic/Bedrock$1.00$5.00
Llama 3.3 70BBedrock$0.72$0.72

Karar Ağacı#

Doğru SDK, elinizdeki gereksinimlere göre değişiyor:

Evet

Hayır

Evet

Hayır

Evet

Hayır

Evet

Hayır

Evet

Hayır

Yeni AI Agent Projesi

Birden fazla AI provider?

React/Next.js frontend?

Multi-agent sistem?

Vercel AI SDK

Streaming gerekli?

OpenAI Agents SDK

AWS altyapısı?

AI SDK + Bedrock

Direkt Provider SDK

Vercel AI SDK Ne Zaman Uygun#

  • Next.js veya React ile geliştiriyorsanız
  • Birden fazla AI provider desteklemeniz gerekiyorsa
  • Hazır streaming UI istiyorsanız
  • Type-safe, birleşik API’ye değer veriyorsanız
  • Edge runtime uyumluluğuna ihtiyacınız varsa
  • Provider değiştirebilecek ürünler geliştiriyorsanız

OpenAI Agents SDK Ne Zaman Uygun#

  • Karmaşık multi-agent sistemler geliştiriyorsanız
  • Native handoff patternlerine ihtiyacınız varsa
  • Yerleşik guardraillar istiyorsanız
  • Açık tracing ve debug tercih ediyorsanız
  • Çoğunlukla OpenAI modellerini kullanıyorsanız
  • Python agent frameworklerinden geliyorsanız

Direkt SDK’ler Ne Zaman Uygun#

  • Providera özgü özelliklere ihtiyacınız varsa
  • Maksimum performans kritikse
  • Tek provider ile basit kullanım senaryosu varsa
  • Minimum bağımlılıklarla çalışmak istiyorsanız
  • Başkaları için SDK veya kütüphane geliştiriyorsanız

AI SDK ile Bedrock Ne Zaman Uygun#

  • AWS-native altyapı varsa
  • Kurumsal güvenliğe ihtiyacınız varsa (VPC, IAM)
  • Doğrudan Anthropic faturası olmadan Claude istiyorsanız
  • Düzenlenmiş sektörler için geliştiriyorsanız
  • Tek platformda model çeşitliliğine ihtiyacınız varsa

Production Patternleri#

Katmanlı Model Yönlendirme#

Model yeteneğini sorgu karmaşıklığına eşleştirin:

const modelTiers = {
  simple: openai('gpt-4o-mini'),
  standard: openai('gpt-4o'),
  complex: anthropic('claude-sonnet-4-6-20250217'),
};

function classifyComplexity(input: string): keyof typeof modelTiers {
  if (input.length < 50 && !input.includes('analiz')) return 'simple';
  if (input.includes('karşılaştır') || input.includes('tasarla')) return 'complex';
  return 'standard';
}

async function smartGenerate(input: string) {
  const tier = classifyComplexity(input);
  return generateText({ model: modelTiers[tier], prompt: input });
}

Bunun ne kadar tasarruf sağladığı tamamen trafik dağılımınıza bağlı. Bir sayı varsaymadan önce kısa, arama tipi sorguların payını ölçün.

Fallback Zinciri#

Yüksek kullanılabilirlik için birden fazla providerı zincirleyin:

const providerChain = [
  openai('gpt-4o'),
  anthropic('claude-sonnet-4-6-20250217'),
  bedrock('anthropic.claude-sonnet-4-5-20250929-v1:0'),
];

async function generateWithFallback(prompt: string) {
  for (const model of providerChain) {
    try {
      return await generateText({ model, prompt });
    } catch (error) {
      console.log(`Provider başarısız, sonrakini deniyorum: ${error.message}`);
      continue;
    }
  }
  throw new Error('Tüm providerlar başarısız oldu');
}

Gözlemlenebilirlik Kurulumu#

Productionda kritik metrikleri izleyin:

import { trace, SpanStatusCode } from '@opentelemetry/api';

const tracer = trace.getTracer('ai-agent');

async function generateWithTracing(prompt: string) {
  return tracer.startActiveSpan('ai.generate', async (span) => {
    try {
      span.setAttributes({
        'ai.model': 'gpt-4o',
        'ai.prompt.length': prompt.length,
      });

      const { text, usage } = await generateText({
        model: openai('gpt-4o'),
        prompt,
      });

      span.setAttributes({
        'ai.completion.tokens': usage.completionTokens,
        'ai.prompt.tokens': usage.promptTokens,
        'ai.total.tokens': usage.totalTokens,
      });

      span.setStatus({ code: SpanStatusCode.OK });
      return { text, usage };
    } catch (error) {
      span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
      throw error;
    } finally {
      span.end();
    }
  });
}

Yaygın Tuzaklar#

Sınırsız Agent Döngüleri#

Adım limitleri olmadan agentlar süresiz çalışabilir:

// Problem: Sınır yok
const result = streamText({
  model: openai('gpt-4'),
  tools: myTools,
  // maxSteps yok - sonsuza kadar dönebilir
});

// Çözüm: Her zaman limit belirle
const result = streamText({
  model: openai('gpt-4'),
  tools: myTools,
  maxSteps: 10, // Açık sınır
});

Streamleri Bloklama#

Tam yanıtları beklemek streaming avantajlarını yok eder:

// Problem: Tamamlanana kadar bloklar
const result = await streamText({ model, prompt });
const fullText = await result.text;
return new Response(fullText);

// Çözüm: Streami ilet
const result = streamText({ model, prompt });
return result.toDataStreamResponse();

Context Limitlerini Görmezden Gelme#

Büyük konuşma geçmişleri context pencerelerini aşıyor:

// Problem: Sınırsız context
const messages = tumKonusmaGecmisi;
await generateText({ model, messages });

// Çözüm: Contexti aktif olarak yönet
const maxTokens = 100000;
const trimmedMessages = trimToFitContext(messages, maxTokens);
await generateText({ model, messages: trimmedMessages });

Varsayılan Nerede Geçerli#

Vercel AI SDK varsayılanı, agentınız toolların bağlandığı tek bir döngüden ibaret olduğu sürece geçerli; ürün işlerinin çoğu da böyle. Provider kayıt defteri, streaming taşıması ve React hookları tek pakette geldiği için provider değişikliği kayıt defterinde bir düzenleme olarak kalıyor.

İki durumda bundan sapın. Birkaç uzman agentın konuşmayı birbirine devretmesi gerekiyorsa OpenAI Agents SDK, elde yazılmış yönlendirme yerine handoff, guardrail ve tracing veriyor. Tek providera bağlıysanız ve hiçbir soyutlamanın henüz açmadığı bir yeteneğe ihtiyacınız varsa, o providerın kendi SDK’si bir wrapperla boğuşmaktan daha ucuza geliyor.

Her iki durumda da, agent soyutlamalarına bağlanmadan önce iki toollu bir generateText() çağrısı kurgunun işe yarayıp yaramadığını göstermeye yeter.

Kaynaklar#

İlgili yazılar