Öğrenecekleriniz
Bölümünün Detaylı Açıklaması
Gönderdiğiniz belgedeki
"Öğrenecekleriniz" (What you will learn)
paragrafı, modern bir yapay zeka geliştiricisinin
bilmesi gereken en kritik konuları içeriyor. Bu bölümde yer alan her bir
maddeyi, büyük dil modellerinin (LLM) çalışma mantığından başlayarak yazılım
projelerine nasıl entegre edileceğine kadar adım adım ve detaylıca inceleyelim.
1. Temel LLM
Mekanizmaları: Tokenization ve Context
Window
Büyük dil modellerinin arkasındaki temel
matematiksel ve sistemsel sınırları anlamak, hem
bütçenizi korumak hem de uygulamanızın doğru çalışmasını sağlamak için şarttır.
Tokenization (Tokenlaştırma) Nedir?
Modeller bizim gibi kelimeleri doğrudan
okuyamazlar. Metinleri token adı verilen daha
küçük parçalara (bazen bir kelime, bazen birkaç harf) bölerler. Her tokene sayısal bir kimlik (ID) verilir.
Context Window (Bağlam Penceresi) Nedir?
Bir yapay zeka modelinin
tek bir seferde hafızasında tutabileceği, okuyabileceği ve cevap üretebileceği
toplam token sınırıdır. Bu sınır aşıldığında model
konuşmanın başını unutmaya başlar.
🛠️
Uygulama: Python ile Token Sayımı
OpenAI'ın tiktoken kütüphanesini kullanarak bir metnin kaç token tuttuğunu bilgisayarımızda şu şekilde
hesaplayabiliriz:
import tiktoken
# GPT-4 modelleri için kullanılan tokenizer'ı yüklüyoruz
enc = tiktoken.encoding_for_model("gpt-4")
metin = "Prompt mühendisliği öğrenmek harika!"
token_listesi = enc.encode(metin)
print(metin)
print(f"Token ID'leri:
{token_listesi}")
print(f"Toplam Token
Sayısı: {len(token_listesi)}")
2. Gelişmiş Prompt Mühendisliği Pattern'leri
(Kalıpları)
Yapay zekadan her zaman en iyi sonucu almak için
ona sadece "bunu yap" demek yetmez. Belirli düşünme kalıpları
vermemiz gerekir.
Persona Pattern
(Kişilik Kalıbı)
Yapay zekaya belirli bir meslek veya uzmanlık
rolü vermektir. Model, o rolün bilgi birikimine ve konuşma tarzına bürünür.
Chain of Thought (Düşünce Zinciri - CoT)
Yapay zekaya karmaşık bir soruyu çözmeden önce
"adım adım düşünmesini" söylemektir. Bu, modelin mantık hataları
yapmasını engeller.
Self-Critique
(Öz-Eleştiri / Kendi Kendini Düzeltme)
Modelin ürettiği ilk çıktıyı yine modele
inceleterek hatalarını bulmasını ve daha iyi bir ikinci taslak yazmasını
sağlama yöntemidir.
🛠️
Uygulama: Self-Critique Pipeline
(Kod Örneği)
Bir metni önce yazdırıp, sonra yapay zekaya kendi
yazdığı metni eleştirterek düzelttirelim:
from litellm import completion
# 1. Adım: İlk Taslağı Oluşturma
prompt1 = "Yapay zekanın geleceği hakkında kısa bir paragraf yaz."
yanit1 = completion(model="openai/gpt-4o", messages=[{"role": "user", "content": prompt1}])
ilk_taslak = yanit1.choices[0].message.content
print(f"--- İLK
TASLAK ---\n{ilk_taslak}\n")
# 2. Adım: Kendi Kendini Eleştirme
ve Düzenleme (Self-Critique)
prompt2 = f"Aşağıdaki metni oku.
Akıcılık ve teknik doğruluk açısından eleştir ve daha profesyonel bir sürümünü
yaz.\nMetin: {ilk_taslak}"
yanit2 = completion(model="openai/gpt-4o", messages=[{"role": "user", "content": prompt2}])
son_hali = yanit2.choices[0].message.content
print(f"---
ELEŞTİRİLMİŞ SON HALİ ---\n{son_hali}")
3. Makine
Tarafından Okunabilir Güvenilir Çıktılar (JSON Formatı)
Yapay zekayı bir web sitesine veya otomasyon
sistemine bağladığınızda, size şiirsel cümleler kurması işe yaramaz. Yazılım
kodlarının anlayabileceği temiz veri formatlarına (özellikle JSON) ihtiyaç
duyarsınız.
🛠️
Uygulama: response_format ile JSON
Garanti Altına Alma
OpenAI ve LiteLLM kütüphanelerinde response_format parametresini
kullanarak modelin kesinlikle geçerli bir JSON objesi döndürmesini
sağlayabiliriz:
import json
from litellm import completion
kullanici_yorumu = "Ürün çok
hızlı geldi ama kutusu yırtıktı, kırılmadığı için şanslıyım."
sistem_promptu = """
Kullanıcı yorumunu analiz et ve
sonucu şu JSON formatında döndür:
{
"durum": "olumlu" veya "olumsuz" veya
"notr",
"kargo_hizi": 1 ile 5 arasinda puan
}
Kesinlikle JSON dışında hiçbir
açıklama metni yazma.
"""
response = completion(
model="openai/gpt-4o",
response_format={"type": "json_object"}, # JSON modunu aktif ediyoruz
messages=[
{"role": "system", "content": sistem_promptu},
{"role": "user", "content": kullanici_yorumu}
]
)
cikti = response.choices[0].message.content
# Çıktıyı python
sözlüğüne dönüştürüp güvenle kullanabiliriz
veri = json.loads(cikti)
print(veri)
print(f"Kargo Hızı Puanı: {veri['kargo_hizi']}")
4. Function Calling (Fonksiyon
Çağırma / Araç Kullanımı)
Büyük dil modelleri internetteki güncel verileri
veya bilgisayarınızdaki yerel dosyaları doğrudan bilemezler. Function Calling,
yapay zekaya "ihtiyacın olduğunda şu araçları veya kodları
tetikleyebilirsin" yetkisi vermektir.
🛠️
Uygulama: Basit Bir Kod Analiz Aracı Tanımlama
Yapay zekanın bir Python kodundaki hataları
denetlemek için yerel bir aracı (linter)
çağırabilmesi için gerekli şema hazırlığı:
# Modelin anlayacağı fonksiyon
şeması (Araç tanımı)
kod_denetleyici_araci = {
"type": "function",
"function": {
"name": "python_kod_kontrol_et",
"description": "Verilen Python kodunu hata ve
güvenlik açıkları için tarar.",
"parameters": {
"type": "object",
"properties": {
"kod_icerigi": {
"type": "string",
"description": "Analiz
edilecek ham python kod blokları."
}
},
"required": ["kod_icerigi"]
}
}
}
5. API
Maliyetlerini Hesaplama ve Yönetme
Yapay zeka servisleri (OpenAI, Anthropic vb.) ücretsiz
değildir. Gönderdiğiniz girdiler (input tokens) ve aldığınız çıktılar (output
tokens) üzerinden turn
başına (karşılıklı her konuşmada) ücretlendirilirsiniz. Konuşma uzadıkça,
geçmiş mesajlar da her seferinde tekrar gönderildiği için maliyet katlanarak
artar.
🛠️
Uygulama: Token Kullanımını ve Maliyeti Takip Etme
from litellm import completion
response = completion(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Bana 5 kelimelik bir
motivasyon cümlesi yaz."}]
)
# Harcanan token
miktarını response üzerinden okuyoruz
girdi_token = response.usage.prompt_tokens
cikti_token = response.usage.completion_tokens
# Örnek fiyatlar (Fiyatlar
modellere göre değişir)
girdi_maliyeti_1k = 0.005 # 1000 token başı dolar
cikti_maliyeti_1k = 0.015
toplam_maliyet = ((girdi_token *
girdi_maliyeti_1k) + (cikti_token *
cikti_maliyeti_1k)) / 1000
print(f"Kullanılan Girdi Token: {girdi_token}")
print(f"Kullanılan Çıktı Token: {cikti_token}")
print(f"Bu sorgunun yaklaşık maliyeti: ${toplam_maliyet:.6f}")
6.
Sağlayıcıdan Bağımsız Kodlama: LiteLLM Kullanımı
Eğer kodunuzu sadece OpenAI
kütüphanesiyle yazarsanız, yarın bir gün Anthropic
(Claude) ya da yerel bir modele geçmek istediğinizde tüm kod tabanınızı baştan
aşağı değiştirmeniz gerekir. LiteLLM, tüm yapay zeka sağlayıcılarını tek bir standart çatı altında
birleştiren açık kaynaklı harika bir araçtır.
🛠️
Uygulama: Model Değiştirme Deneyimi
import litellm
import os
# API anahtarlarını çevre değişkeni
olarak tanımlıyoruz
os.environ["OPENAI_API_KEY"] = "your-openai-key"
os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-key"
# OpenAI
modelini çağırmak için:
yanit_openai = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "Merhaba!"}]
)
# Kodda neredeyse hiçbir şeyi
değiştirmeden Anthropic modeline geçmek için:
yanit_anthropic = litellm.completion(
model="anthropic/claude-3-5-sonnet",
messages=[{"role": "user", "content": "Merhaba!"}]
)
7. Yapay Zeka Kodlama Ajanları ve GitHub
Copilot
Yazılım geliştirirken kodları sıfırdan yazmak
yerine yapay zeka tabanlı kodlama yardımcılarını (GitHub Copilot, Cursor vb.) bir
"yazılım ortağı" gibi kullanmayı öğreneceksiniz. Projenin ana
iskeletini (scaffolding) oluşturmaktan test
senaryoları yazmaya kadar tüm süreci hızlandırır.
8. Gerçek Bir
Proje Geliştirme: Yapay Zeka Destekli CLI Aracı
Kurstaki teorik bilgileri birleştiren ana
uygulama, terminal üzerinden (komut satırı) çalışan bir CLI aracı
geliştirmektir. Bu araç iki ana işi yapay zeka ile
otomatikleştirir:
9. Yapay Zeka Entegreli Kodlar İçin Unit
Test (Birim Testi) Yazma
Yapay zeka modelleri her
seferinde tamamen aynı yanıtı vermeyebilir (buna deterministik olmayan yapı
denir). Peki, çıktısı sürekli değişebilen bir fonksiyonun doğru çalışıp
çalışmadığını nasıl test edebiliriz?
İşte burada Mocking
(Taklit Etme) devreye girer. Test ortamında gerçek yapay zeka
API'sine bağlanıp para harcamak ve rastgele yanıtlar
beklemek yerine, API'yi taklit eden sahte
fonksiyonlar yazarız. pytest-mock fixture'ları ile litellm.completion fonksiyonunun
tam olarak bizim istediğimiz sabit bir test cümlesini döndürmesini sağlarız.
🛠️
Uygulama: Yapay Zeka Fonksiyonunu Test Etme (Mock Örneği)
Yapay zekadan gelen cevaba göre çalışan bir
fonksiyonumuz olsun ve biz bunu test edelim:
# Kodumuzun yer aldığı dosya:
program.py
import litellm
def yapay_zeka_selamla():
response = litellm.completion(model="gpt-4o", messages=[{"role": "user", "content": "Selam
de"}])
return response.choices[0].message.content.upper()
# Gelen cevabı büyütüyor
# Test dosyamız: test_program.py
def test_yapay_zeka_selamla(mocker):
# Gerçek API
çağrısını engellemek için sahte bir yanıt objesi hazırlıyoruz
sahte_yanit = mocker.Mock()
sahte_yanit.choices
= [mocker.Mock(message=mocker.Mock(content="Merhaba dunya"))]
# litellm.completion çağrıldığında
internete gitme, direkt sahte_yanit'ı döndür diyoruz
mocker.patch('litellm.completion', return_value=sahte_yanit)
# Fonksiyonu
test ediyoruz
sonuc = yapay_zeka_selamla()
#
Fonksiyonumuz çıktıyı BÜYÜTMELİYDİ. "Merhaba dunya" -> "MERHABA DUNYA" olmalı.
assert sonuc == "MERHABA DUNYA"
print("Test başarıyla geçti! Gerçek API'ye hiç istek atılmadı.")
Gönderdiğiniz belgedeki tüm kritik teknik
konuları, production (canlı sistem) seviyesinde, hata
yönetimleri ve en iyi pratiklerle harmanlanmış derinlemesine kod
uygulamalarıyla genişletelim.
Aşağıdaki tüm uygulamalar birbiriyle uyumlu,
modüler ve gerçek projelerinizde doğrudan kullanabileceğiniz şekilde
hazırlanmıştır.
1. Tokenization ve Dinamik Context Window Yönetimi
Büyük projelerde LLM'e
göndereceğiniz metin bağlam penceresini (Context Window) aşarsa sistem kilitlenir veya bütçeniz hızla
tükenir. Bu dinamik yapıyı yönetmek için metni akıllıca kırpan (truncate) ve token sayısını
hesaplayan gelişmiş bir sınıf tasarlayalım.
import tiktoken
from typing import List, Dict
class ContextManager:
def __init__(self, model_name: str = "gpt-4"):
self.model_name
= model_name
try:
self.encoder = tiktoken.encoding_for_model(model_name)
except KeyError:
# Model bulunamazsa varsayılan cl100k_base (cl100k_base gpt-4 ve gpt-3.5
tarafından kullanılır) yüklenir
self.encoder = tiktoken.get_encoding("cl100k_base")
def count_tokens(self, text: str) -> int:
"""Verilen
ham metnin toplam token sayısını
hesaplar."""
if not text:
return 0
return len(self.encoder.encode(text))
def count_chat_messages_tokens(self, messages: List[Dict[str,
str]]) -> int:
"""OpenAI chat formatındaki (system, user, assistant)
mesajların
arka planda
harcayacağı kesin token miktarını
hesaplar."""
# Her mesaj
için protokol token ek yükleri vardır
tokens_per_message = 3
tokens_per_name = 1
num_tokens = 0
for message in messages:
num_tokens += tokens_per_message
for key, value in message.items():
num_tokens += self.count_tokens(value)
if key == "name":
num_tokens += tokens_per_name
num_tokens
+= 3 # Her yanıtın
asistan tarafından başlatılması için gereken ek yük
return num_tokens
def truncate_text_to_limit(self, text: str, max_tokens: int) -> str:
"""Metni,
belirtilen token sınırını aşmayacak şekilde güvenle
sondan kırpar."""
tokens = self.encoder.encode(text)
if len(tokens) <= max_tokens:
return text
# Sadece izin
verilen sınırdaki tokenları al ve metne geri dönüştür
truncated_tokens = tokens[:max_tokens]
return self.encoder.decode(truncated_tokens)
# --- Canlı Test Örneği ---
manager = ContextManager("gpt-4")
uzun_kod_blok = "def
hesapla(x):\n return
x * 2\n" * 100
print(f"Ham Metin Karakter Sayısı: {len(uzun_kod_blok)}")
print(f"Hesaplanan Token Sayısı: {manager.count_tokens(uzun_kod_blok)}")
# Güvenli Kırpma Uygulaması
kirpilmis_kod = manager.truncate_text_to_limit(uzun_kod_blok, max_tokens=50)
print(f"50 Token'a Kırpılmış Metin Token
Sayısı: {manager.count_tokens(kirpilmis_kod)}")
2. Gelişmiş Prompt Mühendisliği: Çok Adımlı Self-Critique
ve Geçişli Kalıplar
Yapay zekaya karmaşık bir yazılım mimarisi
inceletirken, önce bir uzman kimliği verip (Persona), ardından adım adım
düşünmesini sağlayıp (Chain of Thought),
en son kendi çıktısını acımasızca eleştirmesini (Self-Critique)
tek bir akışta birleştirelim.
import os
from litellm import completion
from typing import Tuple
# API Anahtarı simülasyonu (Kendi
anahtarınızı girmelisiniz)
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY", "mock-key")
class AdvancedPromptPipeline:
@staticmethod
def run_review_workflow(implementation_plan: str) -> Tuple[str, str]:
"""Persona,
CoT ve Self-Critique
kalıplarını ardışık çalıştıran boru hattı."""
# 1. Adım:
Persona ve Chain of Thought
ile İlk Analiz
system_prompt = (
"Sen
Kıdemli bir Bulut Çözümleri Mimarı ve Siber Güvenlik Uzmanısın. "
"Sana
verilen mimari planları siber güvenlik, maliyet ve ölçeklenebilirlik açısından
incele. "
"Yanıtını
üretirken acele etme, önce sorunları adım adım düşün (<dusunme_asamasi>
etiketleri içinde), "
"ardından
nihai analiz raporunu sun."
)
user_prompt = f"İncelemeni istediğim
plan şu şekildedir:\n\n{implementation_plan}"
print("[1/2] Mimar Persona ve CoT ile ilk analiz üretiliyor...")
first_response = completion(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
temperature=0.2
)
initial_analysis = first_response.choices[0].message.content
# 2. Adım:
Self-Critique (Öz-Eleştiri) Aşaması
critique_system_prompt = (
"Sen katı
ve titiz bir Yazılım Kalite Güvence (QA) Direktörüsün. "
"Bir
uzmanın hazırladığı mimari raporu oku. Gözden kaçırdığı potansiyel riskleri,
"
"aşırı
maliyetli olabilecek önerileri ve belirsiz kalan noktaları acımasızca
eleştirerek raporu güncelle."
)
critique_user_prompt = (
f"İlk hazırlanan analiz raporu:\n{initial_analysis}\n\n"
f"Lütfen bu raporu eleştir ve eksiklerini kapatarak nihai, kusursuz raporu
oluştur."
)
print("[2/2] QA Direktörü kimliğiyle
Self-Critique aşaması çalışıyor...")
second_response = completion(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": critique_system_prompt},
{"role": "user", "content": critique_user_prompt}
],
temperature=0.1
)
final_analysis = second_response.choices[0].message.content
return initial_analysis, final_analysis
# --- Çalıştırma ---
plan = "Kullanıcı
şifrelerini veritabanında MD5 ile düz metin gibi
saklayacağız ve AWS üzerinde tek bir EC2 makinesinde çalışacağız."
# Not: Gerçek bir API anahtarınız
varsa aşağıdaki satırı çalıştırabilirsiniz.
# ilk, son = AdvancedPromptPipeline.run_review_workflow(plan)
# print(son)
3. Pydantic ve response_format ile Tipi Garanti Altına Alınmış JSON Çıktı
Yazılım otomasyonlarında ham JSON string parçalamak yerine Python'ın
tip güvenceli pydantic kütüphanesini LLM yapılandırılmış çıktıları (Structured Outputs) ile tam
entegre kullanmalıyız.
import json
from pydantic import BaseModel, Field
from typing import List, Optional
from litellm import completion
# Çıktı formatının şemasını
doğrulama kurallarıyla birlikte tanımlıyoruz
class CodeDefectAnalysis(BaseModel):
has_bug: bool = Field(description="Kod
bloklarında herhangi bir bug veya mantık hatası var
mı?")
risk_level: str = Field(description="Hatanın
ciddiyeti: 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'")
line_numbers: List[int]
= Field(default=[], description="Hatalı
veya iyileştirilmesi gereken satır numaraları.")
explanation: str = Field(description="Hatanın
detaylı açıklaması ve çözüm önerisi.")
refactored_code: Optional[str] = Field(None, description="Eğer varsa, kodun düzeltilmiş temiz hali.")
class StructuredOutputEngine:
@staticmethod
def analyze_code_quality(code_snippet: str) -> CodeDefectAnalysis:
system_instructions = (
"Sana
verilen kaynak kodu analiz et ve hatayı tespit et. "
"Çıktıyı
kesinlikle sağlanan JSON şemasına birebir uyacak şekilde döndür."
)
# Pydantic şemasını OpenAI/LiteLLM'in anlayacağı JSON Schema
formatına çeviriyoruz
json_schema = CodeDefectAnalysis.model_json_schema()
response = completion(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": system_instructions},
{"role": "user", "content": f"Analiz edilecek kod:\n{code_snippet}"}
],
response_format={
"type": "json_object",
"schema": json_schema # Şemayı zorunlu kılıyoruz
},
temperature=0.0
)
raw_content = response.choices[0].message.content
# Gelen ham string'i Pydantic nesnesine
dönüştürüp tip kontrolü sağlıyoruz
data_dict = json.loads(raw_content)
return CodeDefectAnalysis(**data_dict)
# --- Canlı Test Örneği ---
hatali_kod = """1:
def bolme_islemi(a, b):
2: # Burada sıfıra bölme hatası kontrol
edilmemiş
3: sonuc = a / b
4: return sonuc
"""
# analiz_sonucu
= StructuredOutputEngine.analyze_code_quality(hatali_kod)
# print(f"Bug
Var mı?: {analiz_sonucu.has_bug} | Seviye: {analiz_sonucu.risk_level}")
4. Gelişmiş Function Calling: Dinamik Araç
Kayıt ve Yürütme Döngüsü
Yapay zekanın dış dünyaya (dosya sistemi, API'ler vb.) güvenle açılmasını sağlayan, LLM'den gelen fonksiyon çağrı sinyalini yakalayıp dinamik
olarak çalıştıran tam döngülü (Loop) sistem mimarisi:
import json
from litellm import completion
from typing import Dict, Any, Callable
# 1. Gerçek Dünyada Çalışacak
Fonksiyonları Tanımlayalım (Yerel Araçlar)
def sistem_guvenlik_taramasi(hedef_dizin: str) -> str:
"""Belirtilen
dizindeki zararlı olabilecek dosyaları denetler."""
if "admin" in hedef_dizin.lower():
return json.dumps({"durum": "TEHLIKE", "bulgular": "Kritik sisteme yetkisiz tarama isteği!"})
return json.dumps({"durum": "TEMIZ", "bulgular": f"{hedef_dizin} üzerinde
şüpheli bir duruma rastlanmadı."})
# 2. Araç Kayıt Defteri (Registry) Yapısı
class ToolRegistry:
def __init__(self):
self._registry: Dict[str, Tuple[Callable,
Dict[str, Any]]] = {}
def register_tool(self, name: str, func: Callable, schema: Dict[str,
Any]):
self._registry[name] = (func, schema)
def get_all_schemas(self) -> list:
return [details[1] for details in self._registry.values()]
def execute_tool(self, name: str, arguments_str: str) -> str:
if name not in self._registry:
return json.dumps({"hata": f"'{name}' isimli araç sistemde bulunamadı."})
func, _ = self._registry[name]
try:
args = json.loads(arguments_str)
return func(**args)
except Exception as e:
return json.dumps({"hata": f"Araç çalışırken hata oluştu: {str(e)}"})
# 3. Şemayı Hazırlama ve Kayıt
İşlemi
tarama_semasi = {
"type": "function",
"function": {
"name": "sistem_guvenlik_taramasi",
"description": "Belirtilen yerel dizini
güvenlik açıkları ve yetkisiz dosyalar için tarar.",
"parameters": {
"type": "object",
"properties": {
"hedef_dizin": {"type": "string", "description": "Taranacak
klasörün tam yolu (örn: /var/www veya /home/user)"}
},
"required": ["hedef_dizin"]
}
}
}
registry = ToolRegistry()
registry.register_tool("sistem_guvenlik_taramasi", sistem_guvenlik_taramasi, tarama_semasi)
# 4. Yapay Zeka
Araç Yönetim Döngüsü (Agent Loop)
def run_agent_turn(user_query: str):
messages = [{"role": "user", "content": user_query}]
# LLM'e mevcut araçlarımızı bildirerek çağrı yapıyoruz
response = completion(
model="openai/gpt-4o",
messages=messages,
tools=registry.get_all_schemas(),
tool_choice="auto"
)
response_message = response.choices[0].message
# Yapay zeka bir fonksiyon çalıştırmak istedi mi?
if response_message.get("tool_calls"):
print("-> Yapay zeka yerel bir
aracı tetikleme kararı aldı.")
messages.append(response_message) # Asistanın
kararını geçmişe ekle
for tool_call in response_message["tool_calls"]:
func_name = tool_call.function.name
func_args = tool_call.function.arguments
# Aracı çalıştırıp cevabını alıyoruz
tool_result = registry.execute_tool(func_name, func_args)
print(f" [Araç Çıktısı]: {tool_result}")
# Aracın ürettiği sonucu LLM'e geri bildirmek
üzere mesaj geçmişine ekliyoruz
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": func_name,
"content": tool_result
})
# Model aracı
kullandıktan sonra nihai bir insani özet çıkarsın diye tekrar çağırıyoruz
final_response = completion(model="openai/gpt-4o", messages=messages)
return final_response.choices[0].message.content
return response_message.content
# --- Test ---
# print(run_agent_turn("/etc/admin klasörünü acil tarar mısın?"))
5. Multi-Turn Konuşmalarda Kümülatif Maliyet Takip Sistemi
Yapay zeka ile
karşılıklı konuşma (chat) uzadıkça, her yeni mesajda
önceki tüm konuşma geçmişi (Context) modele tekrar
iletilir. Bu durum girdi token maliyetlerini
geometrik olarak artırır. Bunu izleyen gerçekçi bir bütçe takip motoru
hazırlayalım:
class TokenCostTracker:
# Model bazlı
anlık fiyat listesi (1000 Token Başına Dolar
Cinsinden)
PRICING = {
"gpt-4o": {"input": 0.0050, "output": 0.0150},
"claude-3-5-sonnet": {"input": 0.0030, "output": 0.0150}
}
def __init__(self, model_name: str = "gpt-4o"):
self.model_name
= model_name
self.total_input_tokens
= 0
self.total_output_tokens
= 0
self.total_cost
= 0.0
def log_turn(self, response_usage_obj)
-> float:
"""API
yanıtından gelen usage objesini okuyarak kümülatif
maliyeti günceller."""
prompt_tokens = response_usage_obj.prompt_tokens
completion_tokens = response_usage_obj.completion_tokens
self.total_input_tokens
+= prompt_tokens
self.total_output_tokens
+= completion_tokens
# Maliyet
hesaplama
model_prices = self.PRICING.get(self.model_name, {"input": 0.0, "output": 0.0})
turn_cost = ((prompt_tokens * model_prices["input"])
+ (completion_tokens * model_prices["output"])) / 1000
self.total_cost
+= turn_cost
return turn_cost
def get_summary_report(self) -> str:
return (
f"--- BÜTÇE VE KULLANIM RAPORU
({self.model_name}) ---\n"
f"Toplam Girdi (Input) Token: {self.total_input_tokens}\n"
f"Toplam Çıktı (Output) Token: {self.total_output_tokens}\n"
f"Şu Ana Kadar Harcanan Toplam Tutar: ${self.total_cost:.6f}\n"
f"----------------------------------------"
)
# --- Simüle Edilmiş Oturum Akışı
---
tracker = TokenCostTracker("gpt-4o")
# 1. Karşılıklı Konuşma Adımı
(Küçük Veri)
# response1 = completion(...) -> tracker.log_turn(response1.usage)
# 2. Konuşma Adımı (Geçmiş
eklendiği için girdi tokenları şişer)
# response2 = completion(...) -> tracker.log_turn(response2.usage)
6. Sağlayıcı
Değiştirebilen (Ollama / Local
Destekli) Soyut Mimari
Projenizin tek bir LLM sağlayıcısına bağımlı
kalmaması için, konfigürasyon üzerinden yerel (Ollama
/ Llama3) veya bulut (OpenAI, Anthropic)
arasında sıfır kod değişimiyle geçiş sağlayan esnek yapıyı inşa edelim.
import os
import litellm
from typing import List, Dict, Any
class AgnosticLLMEngine:
def __init__(self, provider: str = "openai", local_url: str = None):
"""
provider:
'openai', 'anthropic' veya
'ollama'
"""
self.provider
= provider.lower()
self.local_url
= local_url or "http://localhost:11434" # Ollama
varsayılan portu
def generate_text(self, messages: List[Dict[str,
str]], model_name: str, **kwargs) -> str:
call_params: Dict[str,
Any] = {
"messages": messages,
**kwargs
}
if self.provider == "openai":
call_params["model"] = f"openai/{model_name}"
elif self.provider == "anthropic":
call_params["model"] = f"anthropic/{model_name}"
elif self.provider == "ollama":
# Ollama yerel sunucusu için LiteLLM
API base yönlendirmesi yapar
call_params["model"] = f"ollama/{model_name}"
call_params["api_base"] = self.local_url
else:
raise ValueError(f"Desteklenmeyen sağlayıcı: {self.provider}")
# Birleşik
arayüz üzerinden çağrıyı gerçekleştiriyoruz
response = litellm.completion(**call_params)
return response.choices[0].message.content
# --- Kullanım Çeşitliliği Örneği
---
# Yerel Ollama
altyapısında bilgisayarınızda yüklü olan llama3'ü tetiklemek için:
# local_engine
= AgnosticLLMEngine(provider="ollama")
# print(local_engine.generate_text([{"role":"user","content":"Selam!"}],
model_name="llama3"))
# Aynı metodu bulut servis
sağlayıcısı ile çalıştırmak için:
# cloud_engine
= AgnosticLLMEngine(provider="anthropic")
# print(cloud_engine.generate_text([{"role":"user","content":"Selam!"}],
model_name="claude-3-5-sonnet"))
7. Tam Güvenli
Unit Test (Pytest Mocking) Senaryosu
Yapay zeka entegrasyonu
barındıran uygulamanızın (Örn: Git diff okuyup commit mesajı üreten
CLI fonksiyonunuzun) test kodlarını yazarken internete çıkmasını engellemek,
her zaman kararlı ve masrafsız çalışmasını sağlamak için profesyonel test
kurgusu:
# --- KOD DOSYASI: app_logic.py ---
import litellm
def generate_git_commit_suggestion(git_diff_text: str) -> str:
"""Git
değişikliklerini okuyup standart kurallı commit
mesajı üretir."""
if not git_diff_text.strip():
return "chore: no changes
detected"
prompt = f"Aşağıdaki git diff kodunu oku ve tek satırlık commit
mesajı yaz:\n{git_diff_text}"
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.0
)
return response.choices[0].message.content.strip()
# --- TEST DOSYASI:
test_app_logic.py ---
import pytest
from unittest.mock import MagicMock
def test_generate_git_commit_suggestion_with_mock(mocker):
# 1. ADIM: LiteLLM yanıt şablonunu taklit eden (mock)
bir sahte nesne hiyerarşisi kuruyoruz
mock_response = MagicMock()
mock_choice = MagicMock()
mock_message = MagicMock()
# Yapay
zekanın döndüreceği sahte commit metnini enjekte
ediyoruz
mock_message.content
= "feat(auth): implement jwt token rotation
mechanism"
mock_choice.message
= mock_message
mock_response.choices
= [mock_choice]
# 2. ADIM:
Gerçek 'litellm.completion'
fonksiyonunun önünü kesip bizim sahte nesneyi vermesini sağlıyoruz
patched_completion = mocker.patch("litellm.completion", return_value=mock_response)
# 3. ADIM:
Fonksiyonu test girdisiyle çağırıyoruz
test_diff = "+ def rotate_jwt_token(self):
pass"
generated_msg = generate_git_commit_suggestion(test_diff)
# 4. ADIM:
Doğrulama (Assertions)
# Fonksiyon
bizim sahte cevabımızı manipüle etmeden alabildi mi?
assert generated_msg == "feat(auth): implement jwt token
rotation mechanism"
# Arka planda
gerçekten de bizim patch'lediğimiz fonksiyon çağrıldı
mı?
patched_completion.assert_called_once()
print("\n✅ Yapay zeka unit
testi başarıyla tamamlandı. API bağımlılığı izole edildi.")
Bu iki güçlü özelliği tek bir yapıda
birleştiriyoruz! Projenizin kod değişikliklerini (git diff) okuyan,
yerel bir güvenlik/kalite kontrolünden (Linter)
geçiren ve ardından tüm bu bulguları yapay zekaya analiz ettirerek kurallara
uygun Git Commit mesajları ve kod inceleme raporları
sunan, terminalden çalışan (CLI) tam teşekküllü bir otomasyon aracı inşa
edeceğiz.
Projemizi sıfırdan oluşturmak, bağımlılıkları
yönetmek ve terminale entegre etmek için Python'ın
modern standart komut satırı kütüphanesi olan click ve kod
analizi için flake8 / bandit mantığını taklit eden bir yapı kullanacağız.
Proje Dosya
Yapısı
Projemizin klasör mimarisi şu şekilde olacaktır:
ai_cli_tool/
│
├──
ai_engine.py # Yapay zeka motoru ve prompt şablonları
├──
linter.py # Yerel kod kalitesi
ve güvenlik denetleyicisi (Linter)
├──
cli.py # Click
kütüphanesi ile CLI komut yönetimi
└──
requirements.txt # Gerekli kütüphaneler
listesi
1. Adım:
Bağımlılıkların Belirlenmesi (requirements.txt)
Öncelikle projenizin çalışması için gerekli
kütüphaneleri içeren dosyayı oluşturun:
click>=8.0.0
litellm>=1.0.0
tiktoken>=0.5.0
pydantic>=2.0.0
2. Adım: Yerel
Güvenlik ve Kalite Denetleyicisi (linter.py)
Bu modül, projenizdeki Python dosyalarını yapay
zekaya göndermeden önce yerel olarak analiz eder. Kodun içindeki tehlikeli
fonksiyonları (örn: eval, exec), zayıf şifreleme algoritmalarını (örn: md5) ve temel sözdizimi/stil hatalarını (örn: çok
uzun satırlar, boş fonksiyonlar) yakalar.
import re
from typing import List, Dict, Any
class LocalSecurityLinter:
"""Yerel
kod kalitesi ve temel siber güvenlik açıklarını tarayan
motor."""
@staticmethod
def analyze_code_string(filename: str, code_content: str) -> List[Dict[str,
Any]]:
issues = []
lines = code_content.split('\n')
# Güvenlik ve
kalite için regex kuralları
security_patterns = {
r"eval\(|exec\(": {"level": "CRITICAL", "msg": "Tehlikeli
dinamik kod yürütme fonksiyonu (eval/exec) kullanımı tespit edildi!"},
r"md5\(": {"level": "HIGH", "msg": "Zayıf ve
kırılmış şifreleme algoritması (MD5) tespiti. SHA-256 tercih edilmelidir."},
r"password\s*=\s*['\"][^'\"]+['\"]": {"level": "HIGH", "msg": "Kod
içinde açık metin (Hardcoded) şifre/parola
tanımlanmış olabilir!"},
r"http://": {"level": "MEDIUM", "msg": "Güvensiz HTTP bağlantısı tespiti. HTTPS protokolü
kullanılmalıdır."}
}
for idx, line in enumerate(lines, start=1):
# 1. Güvenlik Taramaları
for pattern, info in security_patterns.items():
if re.search(pattern, line):
issues.append({
"file": filename,
"line": idx,
"category": "SECURITY",
"level": info["level"],
"message": info["msg"],
"code_snippet": line.strip()
})
# 2. Kod Kalitesi Taramaları
if len(line) > 100:
issues.append({
"file": filename,
"line": idx,
"category": "QUALITY",
"level": "LOW",
"message": "Satır
uzunluğu PEP8 standart sınırı olan 100 karakteri aşmaktadır.",
"code_snippet": line.strip()
})
if "except:" in line:
issues.append({
"file": filename,
"line": idx,
"category": "QUALITY",
"level": "MEDIUM",
"message": "Çok
geniş kapsamlı (Bare except)
hata yakalama. Spesifik hata sınıfları belirtilmelidir.",
"code_snippet": line.strip()
})
return issues
3. Adım: Yapay
Zeka Motoru ve Yapılandırılmış Çıktılar (ai_engine.py)
Yapay zeka ile iletişim
kurduğumuz katmandır. Hem otomatik commit mesajları
üretir hem de linter'dan gelen çıktıları yorumlayarak
akıllı bir rapor hazırlar. Pydantic şeması kullanarak
modelden kusursuz JSON verisi alırız.
import os
import json
from pydantic import BaseModel, Field
from typing import List, Optional
import litellm
# Yapay zekanın döndüreceği
yapılandırılmış analiz şeması
class AIReviewReport(BaseModel):
summary: str = Field(description="Kod
değişikliklerinin ve linter bulgularının genel
özeti.")
critical_risks: List[str]
= Field(description="Kodda acilen çözülmesi gereken en riskli noktalar.")
refactor_suggestion: Optional[str] = Field(description="Hataları çözen, temiz ve optimize edilmiş düzeltme kod örneği.")
class AICLIEngine:
def __init__(self):
# Varsayılan
model tanımı (İsterseniz çevre değişkenlerinden de beslenebilir)
self.model
= "openai/gpt-4o"
def generate_commit_message(self, git_diff: str) -> str:
"""Git
değişiklik analizine göre kurallara uygun konvansiyonel commit
mesajı yazar."""
if not git_diff.strip():
return "chore: no changes
detected"
system_prompt = (
"Sen
profesyonel bir yazılım sürüm yöneticisisin. Sana verilen Git Diff (kod değişiklikleri) çıktısını oku. "
"Değişikliğin
türüne göre (feat, fix, docs, style, refactor,
test, chore) kurallara uygun, "
"öz,
sadece TEK BİR SATIRLIK conventional commit mesajı oluştur. Başka hiçbir şey yazma."
)
response = litellm.completion(
model=self.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Git Değişiklikleri:\n{git_diff}"}
],
temperature=0.1
)
return response.choices.message.content.strip()
def generate_smart_review(self, code_content: str, linter_findings: List[dict])
-> AIReviewReport:
"""Yerel
linter bulgularını ve kaynak kodu harmanlayarak
akıllı inceleme raporu üretir."""
system_prompt = (
"Sen
kıdemli bir kod kalitesi ve siber güvenlik denetçisisin. Kullanıcının kaynak
kodunu "
"ve yerel
statik analiz aracından (linter) gelen uyarıları
incele. "
"Hataların
neden sorun yarattığını açıklayan ve nasıl çözüleceğini gösteren
yapılandırılmış bir rapor hazırla."
)
user_content = {
"source_code": code_content,
"local_linter_warnings": linter_findings
}
response = litellm.completion(
model=self.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": json.dumps(user_content, ensure_ascii=False)}
],
response_format={"type": "json_object", "schema": AIReviewReport.model_json_schema()},
temperature=0.2
)
raw_json = json.loads(response.choices.message.content)
return AIReviewReport(**raw_json)
4. Adım: Click Komut Satırı Arayüzü (cli.py)
Tüm parçaların birleştiği, terminal ekranından
kullanıcıyla etkileşime geçen ana giriş kapısıdır. Bu dosya üzerinden terminal
komutlarımızı yönetiriz.
import click
import subprocess
import os
import json
from linter import LocalSecurityLinter
from ai_engine import AICLIEngine
# CLI Araç Grubumuzu Tanımlıyoruz
@click.group()
def main():
"""🤖 AI-CLI: Yapay Zeka Destekli Geliştirici ve
Güvenlik Otomasyon Aracı."""
pass
@main.command()
@click.option('--file', '-f', type=click.Path(exists=True), help="Doğrudan taranacak dosyanın yolu.")
def lint(file):
"""Linter ve Yapay Zeka ile kod
kalitesi/güvenlik taraması gerçekleştirir."""
if not
file:
click.echo(click.style("❌ Hata: Lütfen taramak için bir dosya yolu belirtin. Örn:
-f dosya.py", fg="red"))
return
click.echo(click.style(f"🔍 {file} dosyası üzerinde yerel linter
çalıştırılıyor...", fg="cyan"))
with open(file, 'r', encoding='utf-8') as f:
code_content = f.read()
# 1. Yerel linter'ı çalıştır
linter_issues = LocalSecurityLinter.analyze_code_string(file,
code_content)
if linter_issues:
click.echo(click.style(f"⚠️ Yerel taramada {len(linter_issues)} adet potansiyel sorun bulundu!", fg="yellow"))
for issue in linter_issues:
click.echo(f" [{issue['category']}] Satır {issue['line']} ({issue['level']}): {issue['message']}")
else:
click.echo(click.style("✅ Yerel statik analiz temiz çıktı.", fg="green"))
# 2. Yapay
zekaya derin analiz yaptır
click.echo(click.style("🧠 Bulgular yapay zeka denetçisine gönderiliyor...", fg="magenta"))
ai = AICLIEngine()
try:
report = ai.generate_smart_review(code_content, linter_issues)
click.echo("\n" + click.style("===
YAPAY ZEKA İNCELEME RAPORU ===", fg="green", bold=True))
click.echo(click.style("📝 Özet:", fg="cyan") + f" {report.summary}")
if report.critical_risks:
click.echo(click.style("\n🚨 Kritik Riskler ve Açıklar:", fg="red", bold=True))
for risk in report.critical_risks:
click.echo(f" • {risk}")
if report.refactor_suggestion:
click.echo(click.style("\n💡 Önerilen Güvenli Kod Değişikliği (Refactored):", fg="green"))
click.echo(click.style(report.refactor_suggestion, fg="white"))
except Exception as e:
click.echo(click.style(f"❌ Yapay zeka analizi sırasında bir sorun oluştu: {str(e)}", fg="red"))
@main.command()
@click.option('--execute', '-e', is_flag=True, help="Üretilen commit mesajını onay sonrası
otomatik commit eder.")
def commit(execute):
"""Git
staging alanındaki (staged)
değişiklikleri analiz edip akıllı commit mesajı
üretir."""
# Git diff kodunu terminalden alıyoruz
try:
diff_output = subprocess.check_output(["git", "diff", "--staged"], text=True)
except subprocess.CalledProcessError:
click.echo(click.style("❌ Git diff komutu çalıştırılamadı. Bir git
reposunda olduğunuzdan emin olun.", fg="red"))
return
if not diff_output.strip():
click.echo(click.style("⚠️ Staging alanında (git add)
bekleyen bir değişiklik bulunamadı!", fg="yellow"))
return
click.echo(click.style("📝 Git değişiklikleri analiz ediliyor...", fg="cyan"))
ai = AICLIEngine()
commit_msg = ai.generate_commit_message(diff_output)
click.echo("\n" + click.style("🤖 Önerilen Commit Mesajı:", fg="magenta", bold=True))
click.echo(click.style(f" {commit_msg}", fg="white", bg="blue"))
# Eğer
kullanıcı otomatik çalıştırma bayrağı (-e) eklediyse veya onay verirse commit et
if execute:
if click.confirm("\nBu mesajla commit
işlemini onaylıyor musunuz?", default=True):
subprocess.run(["git", "commit", "-m", commit_msg])
click.echo(click.style("🚀 Kod başarıyla commit
edildi!", fg="green"))
else:
click.echo(click.style("❌ İşlem kullanıcı tarafından iptal
edildi.", fg="yellow"))
if __name__ == '__main__':
main()
Nasıl Test
Edilir ve Çalıştırılır?
1. Hazırlık ve Ortam Kurulumu
Öncelikle gerekli kütüphaneleri yükleyin ve OpenAI API anahtarınızı terminale tanımlayın:
pip install -r requirements.txt
export OPENAI_API_KEY="sk-your-real-api-key-here"
2. Güvenlik ve Kalite Linter
Aracını Test Etme
Uygulamayı test etmek için içinde bilerek siber
güvenlik açığı barındıran sahte bir Python dosyası oluşturalım (deneme.py):
# deneme.py içeriği
import hashlib
def login_user(username, password_raw):
# Açık açık
kod içinde şifre saklama riski
system_pass = "123456_admin_secret"
# Güvensiz
şifreleme algoritması (MD5) kullanımı
hashed = hashlib.md5(password_raw.encode()).hexdigest()
# Güvensiz ağ
protokolü çağrısı uyarısı
api_url = "http://internal.company"
eval("print('Giris yapiliyor')") # Kritik
güvenlik riski
return hashed
Şimdi bu hatalı dosyayı CLI aracımızla
denetleyelim:
python cli.py lint -f deneme.py
Terminal Çıktısı: Aracınız önce
LocalSecurityLinter sayesinde eval, md5, http:// ve password kalıplarını yakalayacak, ardından bunları GPT-4o
modeline göndererek size harika bir güvenli kod mimari düzeltmesi (Refactoring) ve raporu basacaktır!
3. Yapay Zeka Destekli
Akıllı Commit Aracını Test Etme
Bir dosyayı değiştirip git add yaptıktan
sonra terminale şu komutu vermeniz yeterlidir:
python cli.py commit -e
Araç kodun
içindeki satır değişikliklerini çıkarıp doğrudan size feat(auth): secure login architecture with sha-256 and remove eval gibi nokta
atışı bir öneri sunacak ve onaylarsanız commit
işlemini gerçekleştirecektir.
Uygulamanızı yerel bilgisayarınızda küresel bir
komut gibi (ai-cli lint veya ai-cli commit) doğrudan çalıştırabilmeniz için projeyi modern
paketleme standartlarına uygun hale getirelim.
Günümüzün modern Python standartlarına en uygun
yaklaşım olan pyproject.toml dosyasını
kullanacağız. Bu dosya, projenizin bağımlılıklarını ve terminale kaydedilecek
kısayol komutlarını (entry-points) tek bir yerden yönetmenizi
sağlar.
1. Adım: Proje
Klasör Düzenini Güncelleme
Komut satırı araçlarının temiz kurulabilmesi için
kaynak kodlarımızı bir paket klasörü altına toplamak en iyi pratiktir. Dosya
yapınızı şu küçük değişiklikle güncelleyin:
ai_cli_tool/
│
├──
pyproject.toml # Yeni ekleyeceğimiz paket yapılandırma
dosyası
├──
requirements.txt # Mevcut bağımlılıklar
listesi
│
└──
src/
# Kodlarımızı bu klasörün içine taşıyoruz
├── __init__.py # Boş bir dosya (klasörü paket yapmak için)
├── ai_engine.py
├── cli.py
└── linter.py
Not: src klasörünü
oluşturun, __init__.py adında tamamen boş bir dosya ekleyin ve önceki
adımda yazdığımız ai_engine.py, cli.py ve linter.py dosyalarını bu src/ klasörünün
içine taşıyın.
2. Adım: pyproject.toml Dosyasını Oluşturma
Projenizin ana dizinine (yani src/ klasörünün dışına, yanına) pyproject.toml isimli bir
dosya açın ve içine şu kodları ekleyin:
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "ai-cli-tool"
version = "0.1.0"
description = "Yapay
Zeka Destekli Geliştirici ve Güvenlik Otomasyon Aracı"
readme = "README.md"
requires-python = ">=3.8"
authors = [
{ name = "Geliştirici", email = "developer@example.com" }
]
classifiers = [
"Programming
Language :: Python :: 3",
"License :: OSI Approved :: MIT
License",
"Operating
System ::
OS Independent",
]
dependencies = [
"click>=8.0.0",
"litellm>=1.0.0",
"tiktoken>=0.5.0",
"pydantic>=2.0.0",
]
# 🚀 İşte terminale 'ai-cli'
komutunu kaydeden sihirli alan!
[project.scripts]
ai-cli = "src.cli:main"
Bu Yapılandırmada Ne Yaptık?
3. Adım: Yerel
Geliştirici Modunda Kurulum (Editable Install)
Yapılandırmayı tamamladıktan sonra projenizi
bilgisayarınıza bir Python paketi gibi kaydetmemiz gerekiyor. Ancak kod
üzerinde değişiklik yapmaya devam edeceğimiz için bunu düzenlenebilir (editable) modda kuracağız. Böylece koddaki
değişiklikleriniz anında terminal komutuna yansır, her seferinde yeniden kurmak
zorunda kalmazsınız.
Terminalinizi açın, pyproject.toml dosyasının
bulunduğu ana dizine gelin ve şu komutu çalıştırın:
pip install -e .
(Eğer sanal ortam kullanıyorsanız
- venv - sanal ortamın aktif olduğundan emin
olun.)
4. Adım: Artık
Hazırsınız! Terminalden Test Edin
Kurulum bittikten sonra terminalinizde python cli.py ... şeklinde dosya çağırma devri bitti! Artık
terminalin her yerinden projenizi küresel bir araç gibi çağırabilirsiniz:
Güvenlik ve Linter
Taraması İçin:
ai-cli lint -f src/linter.py
Otomatik Git Commit
Mesajı İçin:
ai-cli commit -e
Yardım Menüsünü Görmek İçin:
ai-cli --help