BİLGİSAYAR ERİŞİM SİSTEMİ

Ajan Bellek Sistemleri: Yapay Zekanıza Kalıcı Bağlam Kazandırma


Her yapay zeka ajanının bir bellek sorunu var. Modele yapılan her çağrı durumsuz. Model son isteği hatırlamaz. Kullanıcının adını, tercihlerini veya önceki kararları hatırlamaz. Harici bellek olmadan, ajanınız her turda sıfırdan başlar.

Bu rehber, dörtten oluşan bellek stratejilerini — en basitinden en güçlüsüne kadar — ve her birini ne zaman kullanacağınızı ele alır. Tüm örnekler TypeScript ve Anthropic SDK kullanır.

Ajanlar Neden Belleğe İhtiyaç Duyar

Bir kod inceleme ajanı düşünün. İlk çalıştırmada, kullanıcı ekibinin kurallarını açıklar: any türleri yok, hataları her zaman açıkça işleyin, işlevsel stili tercih edin. Ajan iyi bir inceleme üretir.

İkinci çalıştırmada, kullanıcı başka bir dosya gönderir. Ajan her şeyi unuttu. Dün işaretlediği kural ihlallerini kaçırır.

Bu temel sorundur: ajanlar durumsuz, ancak yararlı ajanların sürekliliğe ihtiyacı var.

Bellek, ajanlara üç yetenek kazandırır:

  • Geri çağırma — bir konuşmanın önceki kısmından veya önceki bir oturumdan gerçekleri alma
  • Kişiselleştirme — zamanla kullanıcı tercihlerine uyum sağlama
  • Koordinasyon — çok ajanlı sistemlerde, ajanlar arasında durum paylaşma

Dört Bellek Türü

Kod yazmadan önce stratejileri açıkça adlandırmak yardımcı olur. Ajan belleği dört desene ayrılır:

TürNerede saklanırKapsamEn iyisi
TamponBağlamda (mesaj dizisi)Mevcut oturumKısa konuşmalar
ÖzetBağlamda (sıkıştırılmış)Mevcut oturumUzun konuşmalar
AnlamsalHarici (vektör DB)Oturumlar arasıBilgi geri çağırma
EpizodikHarici (anahtar-değer deposu)Oturumlar arasıKullanıcı gerçekleri, tercihler

Her stratejinin basitlik, maliyet ve yetenek arasında farklı bir dengesi vardır. Probleminizi çözen minimumu seçin.

Strateji 1: Konuşma Tamponu

En basit strateji, tam konuşma geçmişini her model çağrısına iletmektir. Model her önceki mesajı görür ve tam bağlamla yanıt verir.

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
interface Message {
role: "user" | "assistant";
content: string;
}
// Tampon tam konuşma geçmişini tutar
const buffer: Message[] = [];
async function chat(userMessage: string): Promise<string> {
// Yeni kullanıcı mesajını tampona ekleyin
buffer.push({ role: "user", content: userMessage });
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
// Her çağrıda tam tamponu iletin
messages: buffer,
});
const assistantMessage =
response.content[0].type === "text" ? response.content[0].text : "";
// Asistan yanıtını tampona ekleyin
buffer.push({ role: "assistant", content: assistantMessage });
return assistantMessage;
}
// Örnek kullanım
await chat("My name is Alex and I prefer Python over TypeScript.");
await chat("What language should I use for my next project?");
// Model ilk mesajda belirtilen tercihi hatırlar

Ne zaman kullanılır: 20 turdan az konuşmalar. Basit sohbet botları. Prototipler.

Sınır: Bağlam pencereleri sınırlıdır. Uzun bir oturum sonunda token limitini aşar ve en eski mesajların düşürülmesi gerekir. Model erken bağlamı sessizce kaybeder, bu da tutarsız davranışa yol açar.

Strateji 2: Kayan Özet

Konuşmalar uzadığında, eski turları atmak yerine özetleyin. Kayan bir son mesaj penceresinin öncesinde ne olduğunun sıkıştırılmış bir özetini tutun.

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
interface ConversationState {
summary: string; // Eski turların sıkıştırılmış geçmişi
recentMessages: Array<{ role: "user" | "assistant"; content: string }>;
maxRecentTurns: number; // Son N turu harfi harfine tutun
}
const state: ConversationState = {
summary: "",
recentMessages: [],
maxRecentTurns: 6, // 3 kullanıcı + 3 asistan turu
};
// Eski turları süren özete sıkıştırın
async function compressSummary(
currentSummary: string,
messagesToCompress: Array<{ role: string; content: string }>
): Promise<string> {
const formatted = messagesToCompress
.map((m) => `${m.role.toUpperCase()}: ${m.content}`)
.join("\n");
const response = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 512,
messages: [
{
role: "user",
content: `Update the conversation summary by adding the new exchanges below.
Return only the updated summary. Keep it under 200 words.
Current summary:
${currentSummary || "(none)"}
New exchanges:
${formatted}`,
},
],
});
return response.content[0].type === "text" ? response.content[0].text : currentSummary;
}
async function chat(userMessage: string): Promise<string> {
// Tampon limiti aştığında, en eski yarısını sıkıştırın
if (state.recentMessages.length >= state.maxRecentTurns * 2) {
const toCompress = state.recentMessages.splice(0, state.maxRecentTurns);
state.summary = await compressSummary(state.summary, toCompress);
}
state.recentMessages.push({ role: "user", content: userMessage });
// Mesaj dizisi oluşturun: sistem özeti + son harfi harfine turlar
const messages = [
...(state.summary
? [
{
role: "user" as const,
content: `Context from earlier in this conversation:\n${state.summary}`,
},
{
role: "assistant" as const,
content: "Understood. I will use that context.",
},
]
: []),
...state.recentMessages,
];
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages,
});
const assistantMessage =
response.content[0].type === "text" ? response.content[0].text : "";
state.recentMessages.push({ role: "assistant", content: assistantMessage });
return assistantMessage;
}

Özet çağrısı hızlı, ucuz bir model (Haiku) kullanır. Ana konuşma yetenekli modeli (Sonnet) kullanır. Bu bölünme, kaliteyi korurken maliyetleri düşük tutar.

Ne zaman kullanılır: 20 turdan fazla oturumlar. Destek ajanları. Uzun süreli görev ajanları.

Sınır: Özetler detayları kaybeder. Bir konuşmanın başlarında belirtilen spesifik gerçekler belirsiz ifadelere sıkıştırılabilir. Spesifik gerçeklerin kesin geri çağrılması için epizodik bellek kullanın.

Strateji 3: Epizodik Bellek

Epizodik bellek, bir kullanıcı veya oturumla ilgili spesifik gerçekleri bir anahtar-değer deposunda saklar. Ajan bir konuşma sırasında gerçekleri çıkarır ve bunları gelecek oturumlarda alır.

import Anthropic from "@anthropic-ai/sdk";
import fs from "fs/promises";
import path from "path";
const client = new Anthropic();
// Üretimde, bu dosya deposunu Redis veya bir veritabanıyla değiştirin
const MEMORY_PATH = "./memory.json";
interface EpisodicStore {
[userId: string]: Record<string, string>;
}
async function loadMemory(): Promise<EpisodicStore> {
try {
const data = await fs.readFile(MEMORY_PATH, "utf-8");
return JSON.parse(data);
} catch {
return {};
}
}
async function saveMemory(store: EpisodicStore): Promise<void> {
await fs.writeFile(MEMORY_PATH, JSON.stringify(store, null, 2));
}
// Son değişimden yapılandırılmış gerçekleri çıkarın
async function extractFacts(
userMessage: string,
assistantReply: string
): Promise<Record<string, string>> {
const response = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 256,
messages: [
{
role: "user",
content: `Extract any personal facts, preferences, or important decisions from this exchange.
Return a JSON object of key-value pairs. Return {} if there is nothing worth remembering.
User: ${userMessage}
Assistant: ${assistantReply}`,
},
],
});
try {
const text = response.content[0].type === "text" ? response.content[0].text : "{}";
const match = text.match(/\{[\s\S]*\}/);
return match ? JSON.parse(match[0]) : {};
} catch {
return {};
}
}
// Saklanan gerçekleri bir sistem istemi enjeksiyonu olarak biçimlendirin
function formatMemory(facts: Record<string, string>): string {
const entries = Object.entries(facts);
if (entries.length === 0) return "";
return (
"What you know about this user:\n" +
entries.map(([k, v]) => `- ${k}: ${v}`).join("\n")
);
}
async function chat(userId: string, userMessage: string): Promise<string> {
const store = await loadMemory();
const userFacts = store[userId] ?? {};
const systemPrompt = formatMemory(userFacts);
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
system: systemPrompt || undefined,
messages: [{ role: "user", content: userMessage }],
});
const assistantMessage =
response.content[0].type === "text" ? response.content[0].text : "";
// Gerçekleri çıkarın ve gelecek oturumlar için kalıcı hale getirin
const newFacts = await extractFacts(userMessage, assistantMessage);
if (Object.keys(newFacts).length > 0) {
store[userId] = { ...userFacts, ...newFacts };
await saveMemory(store);
}
return assistantMessage;
}
// Oturum 1
await chat("user-123", "I prefer concise answers. No bullet points unless necessary.");
// Oturum 2 (farklı bir süreç, günler sonra)
await chat("user-123", "Explain how TCP handshakes work.");
// Ajan oturum 1'deki biçimlendirme tercihini hatırlar

Ne zaman kullanılır: Oturumlar arasında çalışan kullanıcı odaklı ajanlar. Kişiselleştirme. Tercih takibi.

Sınır: Gerçekler zamanla birikir. Eski gerçekler yanlış davranışa neden olabilir (kullanıcı tercih ettikleri dili değiştirir; eski tercih hâlâ depoda). Gerçekleri güncellemek veya sona erdirmek için bir mekanizma ekleyin.

Strateji 4: Anlamsal Bellek (Vektör Arama)

Epizodik bellek ayrık gerçekleri saklar. Anlamsal bellek, anlama göre indekslenmiş belgeleri, kodları veya konuşma parçalarını saklar. Ajan bilgiye ihtiyaç duyduğunda, bir sorgu kullanarak indeksi arar.

Bu, Retrieval-Augmented Generation (RAG) temlidir.

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
interface Document {
id: string;
content: string;
embedding?: number[];
}
// Bir metin dizesi için embedding vektörü oluşturun
async function embed(text: string): Promise<number[]> {
// Claude doğrudan bir embeddings endpoint'i sunmaz.
// Özel bir embedding modeli kullanın. Bu örnek gösterim için bir taslak kullanır.
// Üretimde: text-embedding-3-small (OpenAI), embed-english-v3 (Cohere),
// veya nomic-embed-text gibi kendi barındırılan bir model kullanın.
throw new Error("Replace this stub with a real embedding call");
}
// İki vektör arasındaki kosinüs benzerliğini hesaplayın
function cosineSimilarity(a: number[], b: number[]): number {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dot / (magA * magB);
}
class SemanticMemory {
private documents: Document[] = [];
// Daha sonra almak için bir belge indeksleyin
async add(id: string, content: string): Promise<void> {
const embedding = await embed(content);
this.documents.push({ id, content, embedding });
}
// Bir sorgu için en alakalı top-k belgeleri alın
async search(query: string, topK = 3): Promise<Document[]> {
const queryEmbedding = await embed(query);
return this.documents
.filter((doc) => doc.embedding)
.map((doc) => ({
doc,
score: cosineSimilarity(queryEmbedding, doc.embedding!),
}))
.sort((a, b) => b.score - a.score)
.slice(0, topK)
.map(({ doc }) => doc);
}
}
const memory = new SemanticMemory();
async function answerWithContext(question: string): Promise<string> {
// İlgili belgeleri alın
const relevant = await memory.search(question);
const context = relevant.map((d) => d.content).join("\n\n---\n\n");
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
system: context
? `Answer the question using the following context:\n\n${context}`
: undefined,
messages: [{ role: "user", content: question }],
});
return response.content[0].type === "text" ? response.content[0].text : "";
}
// Örnek: bir bilgi tabanı indeksleyin ve sorgulayın
await memory.add("doc-1", "The team uses React 18 with the app router pattern.");
await memory.add("doc-2", "All API routes must validate input with Zod schemas.");
await memory.add("doc-3", "Database queries use Drizzle ORM. Avoid raw SQL.");
const answer = await answerWithContext("How should I write a new API endpoint?");
// Ajan doc-2 ve doc-3'ü alır ve gerekçeli bir yanıt üretir

Üretim kullanımı için, bellekteki depoyu özel bir vektör veritabanıyla değiştirin. Pgvector (PostgreSQL uzantısı), zaten Postgres çalıştırıyorsanız en basit seçenektir. Chroma ve Qdrant iyi bağımsız seçeneklerdir.

Ne zaman kullanılır: Dokümantasyon asistanları. Kod arama ajanları. Bilgi tabanı Q&A. Büyük bir korpus genelinde geri çağırma gerektiren her şey.

Belleği MCP’ye Bağlama

MCP sunucu rehberini takip ettiyseniz, belleği bir MCP kaynağı olarak sunabilirsiniz. Bu, bellek katmanınızı Claude Code dahil herhangi bir MCP uyumlu istemci tarafından erişilebilir kılar.

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "memory-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// Araç: bir gerçeği sakla
server.setRequestHandler("tools/call", async (request) => {
if (request.params.name === "remember") {
const { key, value, userId } = request.params.arguments as {
key: string;
value: string;
userId: string;
};
await storeEpisodicFact(userId, key, value);
return { content: [{ type: "text", text: `Stored: ${key} = ${value}` }] };
}
if (request.params.name === "recall") {
const { userId } = request.params.arguments as { userId: string };
const facts = await loadEpisodicFacts(userId);
return {
content: [{ type: "text", text: JSON.stringify(facts, null, 2) }],
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);

MCP konuşan herhangi bir ajan artık remember ve recall’u standart araçlar olarak çağırabilir. Bellek, ajan başına uygulama yerine paylaşılan bir hizmet haline gelir.

Doğru Stratejiyi Seçme

Bu karar tablosunu başlangıç noktası olarak kullanın:

DurumStrateji
Tek oturum, 20 turdan azTampon
Tek oturum, uzun süreliÖzet
Çok oturumlu, kullanıcı tercihleriEpizodik
Sorgulanacak büyük bilgi tabanıAnlamsal
Yukarıdakilerin hepsiBirleştirin: oturum için özet + oturumlar arası epizodik/anlamsal

Tamponla başlayın. Konuşmalar uzadığında bir özet katmanı ekleyin. Kullanıcılar oturumlar arasında geri döndüğünde epizodik bellek ekleyin. Alınacak bir belge korpusu olduğunda anlamsal bellek ekleyin.

İhtiyacınız olmadan önce karmaşıklık eklemeyin. Konuşma tamponu çoğu prototip için doğru cevaptır. Belleği erken aşırı tasarlamak, orantısız fayda olmadan maliyet, gecikme ve bakım yüzeyi ekler.

Sonuç

Bellek tek bir şey değildir — farklı kapsamlarda farklı sorunları ele alan bir strateji yığınıdır. Tampon mevcut oturumu yönetir. Özet bu oturumu uzatır. Epizodik bellek oturumları köprüler. Anlamsal bellek yanıtları bir bilgi tabanına dayandırır.

Bugün sahip olduğunuz sorunu çözen katmanı seçin. Uygulamaları daha sonra değiştirebilmek için temiz bir arayüzün arkasına sarın. Ve ajanlarınız MCP aracılığıyla iletişim kuruyorsa, belleği paylaşılan bir araç olarak ortaya koyun — bu her ajanı basit tutar ve sisteme bir bütün olarak kalıcı bir beyin verir.


İlgili Makaleler