LangChain Nedir: LLM Uygulamaları Geliştirmenin Yeni Yolu

Sistem yöneticisi olarak yıllarca sunucu kuruyorsun, log analiz ediyorsun, otomasyon scriptleri yazıyorsun. Sonra bir gün fark ediyorsun ki bu işlerin büyük bir kısmını artık yapay zeka destekli araçlarla çok daha hızlı yapabilirsin. İşte tam bu noktada LangChain sahneye çıkıyor ve “peki bunu nasıl entegre ederim?” sorusu kaçınılmaz hale geliyor.

LangChain, büyük dil modelleri (LLM) üzerine uygulama geliştirmeyi kolaylaştıran açık kaynaklı bir framework. Python ve JavaScript versiyonları mevcut. Temelde şunu yapıyor: OpenAI, Anthropic, Google gibi farklı LLM sağlayıcılarını, veri kaynaklarını, araçları ve hafıza bileşenlerini bir araya getiren bir yapı sunuyor. Bunu yaparken her sağlayıcı için ayrı ayrı API entegrasyonu yazma derdini ortadan kaldırıyor.

LangChain’in Temel Mantığı

Diyelim ki bir log analiz aracı yazmak istiyorsun. Kullanıcı sana bir hata mesajı yapıştırıyor, sen de bu hatanın ne anlama geldiğini, nasıl çözüleceğini ve ilgili log satırlarını analiz edip raporluyorsun. Bunu vanilla Python ile yapmak istersen OpenAI API’sine istek atarsın, prompt’u hazırlarsın, response’u parse edersin. Basit görünüyor ama işin içine hafıza (önceki konuşmaları hatırlama), harici araçlar (dosya okuma, web arama) veya birden fazla LLM çağrısını birbirine bağlama girdiğinde her şey karmaşıklaşıyor.

LangChain bu karmaşıklığı chain (zincir) kavramıyla çözüyor. Bir görevi küçük adımlara böldüğünde her adım bir zincir halkası oluyor ve bunları birbirine bağlamak için standart bir arayüz sağlıyor.

Temel bileşenler şunlar:

  • LLMs / Chat Models: OpenAI GPT, Anthropic Claude, Google Gemini, yerel Ollama modelleri gibi farklı model sağlayıcılarına tek arayüzden erişim
  • Prompts: Dinamik ve yeniden kullanılabilir prompt şablonları
  • Chains: Birden fazla adımı sırayla veya paralel çalıştıran iş akışları
  • Memory: Konuşma geçmişini saklamak için farklı bellek stratejileri
  • Tools & Agents: LLM’in kendi kararıyla araçları çağırabildiği otonom yapılar
  • Document Loaders & Vector Stores: PDF, web sayfası, veritabanı gibi kaynaklardan bilgi çekme ve vektör tabanlı arama

Kurulum ve İlk Adımlar

Önce ortamı hazırlayalım. Sanal ortam kullanmak burada şart, yoksa bağımlılık cehennemi seni bekliyor.

# Python sanal ortamı oluştur
python3 -m venv langchain-env
source langchain-env/bin/activate

# Temel paketleri kur
pip install langchain langchain-openai langchain-community

# Eğer Anthropic kullanacaksan
pip install langchain-anthropic

# Vector store için chromadb
pip install chromadb

# Gereksinimleri kaydet
pip freeze > requirements.txt

API anahtarlarını environment variable olarak ayarla, asla kod içine gömme:

# .env dosyası oluştur
cat > .env << 'EOF'
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=ls__xxxxxxxxxxxx
EOF

# .gitignore'a ekle
echo ".env" >> .gitignore

İlk LangChain Uygulaması: Log Analiz Aracı

Gerçek bir sysadmin senaryosuyla başlayalım. Nginx log dosyalarını analiz eden basit bir araç yazacağız.

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

load_dotenv()

# Model tanımla
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# Prompt şablonu
prompt = ChatPromptTemplate.from_messages([
    ("system", """Sen deneyimli bir Linux sistem yöneticisisin. 
    Verilen log satırlarını analiz et ve şunları belirle:
    1. Hata türü ve ciddiyeti
    2. Olası kök neden
    3. Önerilen çözüm adımları
    Türkçe yanıt ver."""),
    ("human", "Şu log satırlarını analiz et:nn{log_content}")
])

# Chain oluştur: prompt -> llm -> output parser
chain = prompt | llm | StrOutputParser()

# Test log içeriği
log_sample = """
2024-01-15 14:23:45 [error] 1234#1234: *5678 connect() failed (111: Connection refused) 
while connecting to upstream, client: 192.168.1.100, server: api.example.com, 
request: "POST /api/v1/users HTTP/1.1", upstream: "http://127.0.0.1:8080/api/v1/users"
2024-01-15 14:23:46 [error] 1234#1234: *5679 upstream timed out (110: Connection timed out)
"""

result = chain.invoke({"log_content": log_sample})
print(result)

Bu örnekte LCEL (LangChain Expression Language) kullandık. | operatörü bileşenleri birbirine bağlıyor. Soldan sağa akış mantığı var: prompt hazırla, LLM’e gönder, çıktıyı parse et.

Hafıza ile Çalışmak: Çok Turlu Konuşmalar

Log analiz aracımızı geliştirelim. Kullanıcı birden fazla soru sorduğunda önceki bağlamı hatırlamasını istiyoruz.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Sen deneyimli bir Linux sistem yöneticisisin. Türkçe yanıt ver."),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

chain = prompt | llm

# Session bazlı hafıza yönetimi
store = {}

def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

chain_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history"
)

# Konuşma başlat
session_id = "sysadmin-session-001"
config = {"configurable": {"session_id": session_id}}

response1 = chain_with_history.invoke(
    {"input": "Nginx'de 502 Bad Gateway hatası alıyorum, ne yapmalıyım?"},
    config=config
)
print("1. Yanıt:", response1.content)

response2 = chain_with_history.invoke(
    {"input": "Upstream servisim Node.js, bu durumda ne kontrol etmeliyim?"},
    config=config
)
print("2. Yanıt:", response2.content)
# İkinci soruda "upstream" ve "502" bağlamını hatırlayacak

RAG (Retrieval-Augmented Generation): Dokümantasyon Asistanı

En güçlü LangChain kullanım senaryolarından biri RAG. Şirket içi wiki’ni, runbook’larını veya teknik dökümanlarını LLM’e besleyip üzerinden soru sorabiliyorsun. Üretim ortamında bu gerçekten hayat kurtarıyor.

from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain

# Runbook dosyalarını yükle
loader = DirectoryLoader(
    "./runbooks/",
    glob="**/*.md",
    loader_cls=TextLoader,
    loader_kwargs={"encoding": "utf-8"}
)
documents = loader.load()

# Metni parçalara böl
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    length_function=len
)
splits = text_splitter.split_documents(documents)

# Vector store oluştur ve kaydet
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
    documents=splits,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# Retriever tanımla
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

# RAG chain kur
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

system_prompt = """Sen şirket içi runbook ve prosedürleri bilen bir DevOps asistanısın.
Sadece aşağıdaki bağlamdaki bilgileri kullan. Eğer cevap bağlamda yoksa bunu açıkça söyle.

Bağlam:
{context}"""

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{input}")
])

question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

# Soru sor
response = rag_chain.invoke({
    "input": "PostgreSQL backup prosedürümüz nasıl işliyor?"
})

print("Yanıt:", response["answer"])
print("nKaynaklar:")
for doc in response["context"]:
    print(f"- {doc.metadata.get('source', 'Bilinmiyor')}")

Agents: LLM’in Kendi Kararıyla Araç Kullanması

Agent yapısı LangChain’in en güçlü özelliklerinden biri. LLM’e araçlar tanımlıyorsun ve hangi aracı ne zaman kullanacağına kendisi karar veriyor. Bunu bir sysadmin senaryosuna uyarlayalım:

from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
import subprocess
import psutil

@tool
def check_disk_usage(path: str) -> str:
    """Belirtilen dizinin disk kullanımını kontrol eder."""
    try:
        usage = psutil.disk_usage(path)
        return (f"Yol: {path}n"
                f"Toplam: {usage.total / (1024**3):.2f} GBn"
                f"Kullanılan: {usage.used / (1024**3):.2f} GBn"
                f"Boş: {usage.free / (1024**3):.2f} GBn"
                f"Kullanım: %{usage.percent}")
    except Exception as e:
        return f"Hata: {str(e)}"

@tool
def check_service_status(service_name: str) -> str:
    """Linux servisinin durumunu kontrol eder."""
    try:
        result = subprocess.run(
            ["systemctl", "is-active", service_name],
            capture_output=True, text=True, timeout=10
        )
        status = result.stdout.strip()
        return f"{service_name} servisi: {status}"
    except Exception as e:
        return f"Hata: {str(e)}"

@tool
def get_top_processes(count: int = 5) -> str:
    """CPU kullanımına göre en yüksek prosesleri listeler."""
    processes = []
    for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
        try:
            processes.append(proc.info)
        except psutil.NoSuchProcess:
            pass
    
    sorted_procs = sorted(processes, key=lambda x: x['cpu_percent'], reverse=True)
    result = "CPU Kullanımına Göre Top Prosesler:n"
    for p in sorted_procs[:count]:
        result += f"PID: {p['pid']} | {p['name']} | CPU: %{p['cpu_percent']:.1f} | RAM: %{p['memory_percent']:.1f}n"
    return result

# Agent kurulumu
tools = [check_disk_usage, check_service_status, get_top_processes]

llm = ChatOpenAI(model="gpt-4o", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", """Sen bir Linux sistem izleme asistanısın. 
    Elindeki araçları kullanarak sistem durumunu analiz et ve Türkçe rapor ver."""),
    MessagesPlaceholder(variable_name="chat_history"),
    ("human", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad")
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

response = agent_executor.invoke({
    "input": "Sistemin genel durumunu kontrol et. Disk, servisler ve yüksek CPU kullanan proseslere bak.",
    "chat_history": []
})
print(response["output"])

Streaming ile Gerçek Zamanlı Çıktı

Uzun analiz raporları için streaming kullanmak kullanıcı deneyimini ciddi iyileştiriyor. Yanıt gelmeye başladığı anda ekrana yansıyor, kullanıcı beklemiyor.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0, streaming=True)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Sen bir Linux güvenlik uzmanısın. Detaylı analiz yap."),
    ("human", "{input}")
])

chain = prompt | llm | StrOutputParser()

print("Güvenlik analizi başlıyor...n")
print("-" * 50)

# Streaming ile çıktıyı anlık al
for chunk in chain.stream({
    "input": "SSH brute force saldırılarına karşı alınması gereken önlemleri anlat."
}):
    print(chunk, end="", flush=True)

print("n" + "-" * 50)

LangSmith ile Debugging ve Monitoring

Production’a almadan önce mutlaka LangSmith’i aktif et. Hangi prompt’ların gittiğini, kaç token harcandığını, nerede hata olduğunu görmek için biçilmiş kaftan.

# LangSmith ortam değişkenlerini ayarla
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
export LANGCHAIN_API_KEY="ls__xxxxxxxxxx"
export LANGCHAIN_PROJECT="sysadmin-tools"

# Bu değişkenler aktifken yaptığın tüm LangChain çağrıları
# otomatik olarak LangSmith'e loglanır
python3 log_analyzer.py

LangSmith dashboard’undan şunları görebilirsin:

  • Latency: Her chain adımının ne kadar sürdüğü
  • Token kullanımı: İstek başına maliyet hesabı
  • Hata oranları: Hangi prompt’ların başarısız olduğu
  • Input/Output: Tam prompt ve model yanıtları

Farklı Modeller Arasında Geçiş

LangChain’in güzel özelliklerinden biri model değiştirmenin trivial olması. Yerel Ollama modeli kullanmak istediğinde sadece model tanımını değiştiriyorsun:

# Önce Ollama'yı kur ve modeli çek
curl -fsSL https://ollama.ai/install.sh | sh
ollama pull llama3.1:8b
ollama pull mistral:7b
from langchain_ollama import ChatOllama
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

# Ollama - yerel, ücretsiz, gizlilik odaklı
llm_local = ChatOllama(model="llama3.1:8b", temperature=0)

# OpenAI - en güçlü, ücretli
llm_openai = ChatOpenAI(model="gpt-4o", temperature=0)

# Anthropic - uzun bağlam için iyi
llm_anthropic = ChatAnthropic(model="claude-3-5-sonnet-20241022", temperature=0)

# Aynı chain'i farklı modellerle test et
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template(
    "Şu Linux komutunu açıkla: {command}"
)

for model_name, llm in [("Ollama Llama3", llm_local), 
                          ("OpenAI GPT-4o", llm_openai)]:
    chain = prompt | llm | StrOutputParser()
    print(f"n=== {model_name} ===")
    result = chain.invoke({"command": "find / -name '*.log' -mtime +30 -delete"})
    print(result)

Gerçek Dünya Senaryosu: Otomatik Incident Response

Tüm öğrendiklerimizi bir araya getirerek gerçekçi bir kullanım senaryosu yaratalım. Monitoring sisteminizden gelen alert’leri otomatik analiz edip Slack’e özet gönderen bir sistem:

import json
import requests
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

class IncidentReport(BaseModel):
    severity: str = Field(description="critical/high/medium/low")
    summary: str = Field(description="Kısa özet, max 100 karakter")
    root_cause: str = Field(description="Olası kök neden")
    immediate_actions: list[str] = Field(description="Acil alınacak aksiyonlar")
    escalate: bool = Field(description="Eskalasyon gerekiyor mu")

def analyze_and_respond_to_incident(alert_data: dict, slack_webhook: str):
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    
    prompt = ChatPromptTemplate.from_messages([
        ("system", """Sen bir NOC mühendisisin. Alert verilerini analiz et ve
        JSON formatında yapılandırılmış bir incident raporu oluştur."""),
        ("human", "Alert verisi:n{alert_json}")
    ])
    
    parser = JsonOutputParser(pydantic_object=IncidentReport)
    chain = prompt | llm | parser
    
    report = chain.invoke({"alert_json": json.dumps(alert_data, ensure_ascii=False)})
    
    # Slack mesajı formatla
    severity_emoji = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🟢"}
    emoji = severity_emoji.get(report["severity"], "⚪")
    
    slack_message = {
        "text": f"{emoji} *Incident Alert*",
        "blocks": [
            {"type": "section", "text": {"type": "mrkdwn", 
             "text": f"{emoji} *{report['summary']}*"}},
            {"type": "section", "text": {"type": "mrkdwn",
             "text": f"*Kök Neden:* {report['root_cause']}"}},
            {"type": "section", "text": {"type": "mrkdwn",
             "text": "*Aksiyonlar:*n" + "n".join(f"• {a}" for a in report['immediate_actions'])}}
        ]
    }
    
    if slack_webhook:
        requests.post(slack_webhook, json=slack_message)
    
    return report

# Test
alert = {
    "host": "prod-db-01",
    "metric": "disk_usage",
    "value": 94,
    "threshold": 90,
    "timestamp": "2024-01-15T14:23:45Z",
    "service": "postgresql"
}

report = analyze_and_respond_to_incident(alert, slack_webhook="")
print(json.dumps(report, ensure_ascii=False, indent=2))

Dikkat Edilmesi Gereken Noktalar

LangChain kullanmaya başlarken bazı tuzaklardan kaçınmak gerekiyor:

  • Maliyet kontrolü: Her LLM çağrısı para. Token kullanımını takip et, gereksiz yere büyük context gönderme. gpt-4o-mini birçok sysadmin görevinde gpt-4o kadar başarılı.
  • Prompt injection: Kullanıcıdan gelen log veya metin içeriklerini doğrudan system prompt’una ekleme. Mutlaka ayır ve sanitize et.
  • Rate limiting: OpenAI API’si rate limit hataları verebilir. Retry mekanizması kur, LangChain’in built-in retry desteğini kullan.
  • Context window: Çok büyük log dosyalarını direkt gönderme. Text splitter kullan, sadece ilgili kısımları retrieval ile getir.
  • Versiyon değişiklikleri: LangChain hızlı gelişiyor ve API’ler değişiyor. requirements.txt ile versiyonları sabitle.
  • Yerel model vs. bulut model: Hassas log ve konfigürasyon verilerini bulut API’ye gönderirken güvenlik politikanı kontrol et. Gerekirse Ollama ile yerel model kullan.

Sonuç

LangChain, sysadmin araç kutusuna gerçekten değer katan bir framework. Özellikle RAG tabanlı dokümantasyon asistanları, otomatik log analizi ve agent tabanlı sistem izleme senaryolarında inanılmaz hız kazandırıyor. Aylarca “keşke bu prosedürleri hızlıca sorgulayabilsem” dediğin noktalar için pratik çözümler üretiyor.

Başlangıç için karmaşık agent yapıları yerine basit chain’lerden başla. Bir log analiz scripti, bir runbook asistanı yaz ve nasıl çalıştığını kavra. Sonra hafıza ve RAG ekle. Agent’ları ancak gerçekten dinamik karar verme ihtiyacın olduğunda devreye sok.

LangSmith entegrasyonunu da ihmal etme. Production’da ne kadar token harcadığını, hangi prompt’ların işe yarayıp yaramadığını görmeden körü körüne geliştirme yapmazsın. Tıpkı sunucularında Prometheus kurmadan monitoring yapmadığın gibi, LLM uygulamalarında da observability şart.

Bu ekosistem hızla büyüyor ve değişiyor. LangGraph, LangChain’in en yeni çocuğu ve daha karmaşık çok adımlı iş akışları için tasarlanmış. Agentic sistemler kuruyorsan bir sonraki adımın LangGraph olmasi büyük ihtimalle.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir