Kurs
GLM-5-Turbo, modelin çok adımlı yürütmeyi koordine ettiği aracı (agent) tarzı iş akışları için özel olarak tasarlanmıştır. Karmaşık talimatları anlama, araçları güvenilir şekilde çağırma ve sistemlerin tüketebileceği yapılandırılmış çıktılar üretme konusunda optimize edilmiştir.
Bu eğitimde, webde aktif olarak gezinip ilgili bilgileri çıkaran ve kullanıcı için temiz bir özet oluşturan gerçek zamanlı bir tarayıcı aracısı inşa edeceğiz. Eğitimin sonunda, uçuşların ötesinde, gerçek dünyadaki her türlü arama ve çıkarım görevine genişletebileceğiniz yeniden kullanılabilir bir mimariye sahip olacaksınız.
Aşağıdaki videoda GLM-5 Turbo projemizi çalışırken görebilirsiniz:
GLM-5-Turbo nedir?
GLM-5-Turbo, gerçek dünya aracı iş akışlarını desteklemek üzere tasarlanmıştır. Kullanıcılara görevine göre daha hızlı yanıtlar ile daha derin muhakeme arasında denge kurmalarını sağlayan birden fazla düşünme modu sunar.
Etkileşimli uygulamalar için ayrıca akış (streaming) çıkışı destekler; böylece yanıtlar, daha duyarlı bir kullanıcı deneyimi için token token iletilebilir.
Temel güçlü yönlerinden biri, modelin harici araçları güvenilir biçimde çağırmasına olanak tanıyan işlev çağırmadır (function calling). Model ayrıca JSON gibi yapılandırılmış çıktıları destekler; bu da aşağı akıştaki sistemler ve UI katmanlarıyla entegrasyonu kolaylaştırır.
Daha uzun iş akışları için GLM-5-Turbo, aynı bilgiyi tekrar tekrar işlemeye gerek kalmadan uzun etkileşimler boyunca performansı korumaya yardımcı olan bağlam önbelleğe almayı (context caching) içerir. Ayrıca MCP (Model Context Protocol) aracılığıyla harici sistemlerle entegrasyonu destekleyerek modelin ek araçlara ve veri kaynaklarına bağlanmasını sağlar.
Aracı iş akışları için tasarlandı
GLM-5-Turbo, özellikle görevlerin birden çok adım, araç ve uzun yürütme zincirleri içerdiği OpenClaw gibi aracı tarzı ortamlara derinlemesine optimize edilmiştir.
Bu optimizasyon birkaç kritik alanı iyileştirir:
- Araç çağırma güvenilirliği: Modelin doğru işlevleri tutarlı şekilde çağırmasını sağlar.
- Talimat parçalama: Modelin karmaşık görevleri daha küçük adımlara bölmesine olanak tanır.
- Uzun zincir yürütme kararlılığı: Çok adımlı aracılar için kritik önemdedir.
Pratikte, GLM-5-Turbo etkileşimli sistemler için yeterince hızlıdır ve aynı zamanda çok adımlı, araç çağırmalı senaryolarda güvenilirdir; bu da tam olarak tarayıcı aracıları inşa etmek için ihtiyaç duyduğumuz şeydir.
GLM-5-Turbo Örnek Projesi: Gerçek Zamanlı Bir Tarayıcı Aracısı Oluşturun
Bu eğitimde, hafif bir seyahat asistanı gibi davranan bir Streamlit uygulaması oluşturacağız. Kullanıcı şu türde bir sorgu sağlar: “Gelecek cuma-pazartesi SFO’dan JFK’ye en ucuz uçuşları bul.” Sistem ardından şunları yapar:
- Webde ilgili uçuş sayfalarını arar
- Bu sayfaları açar ve inceler
- Fiyat, süre ve aktarma gibi faydalı bilgileri çıkarır
- En iyi seçenekleri kullanıcı dostu bir formatta özetler
Yüksek seviyede, sistem birlikte çalışan dört bileşenden oluşur.
- İlki, Z.AI veya OpenRouter’a sohbet-tamamlama istekleri gönderen LLM katmanıdır (
llm_client.py). - İkincisi, arama, sayfa açma ve içerik çıkarma gibi eylemleri sunan tarayıcı araçları katmanıdır (
browser_tools.py). - Üçüncüsü, modeli ve araçları çok adımlı bir iş akışında birleştiren aracı döngüsüdür (
agent.py). - Son olarak, Streamlit arayüzü (
app.py) etkileşim ve görselleştirme için bir arayüz sağlar.
Tüm kaynak kodu: https://github.com/AashiDutt/GLM5_TURBO
Adım 1: Önkoşullar
Uygulamayı oluşturmadan önce aşağıdakilere sahip olduğunuzdan emin olun:
- Python 3.9+
- Bir GLM-5-Turbo API anahtarı (Z.AI veya OpenRouter)
- Tarayıcı otomasyonu için Playwright yüklü
Gerekli kütüphaneleri yükleyin:
pip install streamlit pandas python-dotenv requests playwright
playwright install chromium
app.py dosyası Streamlit, pandas, dotenv ve özel modülleri kullanır. browser_tools.py dosyası ise requests ve Playwright kullanır. API çağrıları llm_client.py içinde requests ile yapılır.
Şimdi, API anahtar(lar)ımızın bulunacağı bir .env dosyası oluşturmak için aşağıdaki komutu çalıştırın:
cp .env.example .env
Tercih ettiğiniz API uç noktasını seçin ve API anahtarını girin:
.env
PROVIDER=zai
# Direct Z.AI API
ZAI_API_KEY=Your Z.AI API key
ZAI_BASE_URL=https://api.z.ai/api/paas/v4/chat/completions
ZAI_MODEL=glm-5-turbo
# OpenRouter
OPENROUTER_API_KEY=Your OpenRouter API key
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1/chat/completions
OPENROUTER_MODEL=z-ai/glm-5-turbo
# Browser
HEADLESS=true
MAX_STEPS=10
Benzer şekilde, Playwright tarayıcısı browser_tools.py içindeki bu kurucu (constructor) ile başlatılır:
class BrowserTools:
def __init__(self, headless: bool = True) -> None:
self.playwright = sync_playwright().start()
self.browser = self.playwright.chromium.launch(headless=headless)
self.context = self.browser.new_context(viewport={"width": 1440, "height": 1100})
self.page = self.context.new_page()
Bu blok, aracının web ile etkileşim kurmak için kullandığı, Playwright ile tamamen kontrol edilen bir tarayıcı ortamını başlatır.
Playwright motorunu başlatır, bir Chromium tarayıcısı açar, izole bir tarayıcı oturumu oluşturur ve tüm eylemlerin gerçekleştiği yeni bir sayfa açar.
Bu kurulum, aracıya gerçek web sitelerinde gezinme, canlı içeriği gözlemleme ve gördüklerine göre karar verme olanağı tanır.
Adım 2: LLM istemcisini kurma
Sırada, hem doğrudan Z.AI kullanımını hem de aynı arayüzle OpenRouter’ı destekleyen LLMClient’imizi kuracağız. Sağlayıcıya özgü uç nokta kurucuda seçilir. Fiyatlandırma benzer olduğundan, bu demoda tercihinize göre her iki API’yi de kullanabilirsiniz.
Temel kurulum şöyledir:
class LLMClient:
def __init__(
self,
provider: str,
api_key: str,
model: str,
app_name: str = "GLM-5 Browser Agent Demo",
app_url: str = "http://localhost:8501",
) -> None:
self.provider = provider.lower().strip()
self.api_key = api_key
self.model = model
if self.provider == "zai":
self.url = os.getenv("ZAI_BASE_URL", "https://api.z.ai/api/paas/v4/chat/completions")
elif self.provider == "openrouter":
self.url = os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1/chat/completions")
Bu başlatıcı, arayüzü tutarlı tutarken uygun API uç noktasını (Z.AI veya OpenRouter) seçerek LLM istemcisini yapılandırır.
API anahtarını, modeli ve uç nokta URL’sini saklar; böylece sistemin geri kalanı, sağlayıcıya özgü farkları dert etmeden modeli çağırabilir.
Ardından create_chat_completion(), gerektiğinde araçları ekleyerek yükü (payload) oluşturur ve döndürülen araç çağrılarını ayrıştırır.
payload: Dict[str, Any] = {
"model": self.model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
"stream": False,
}
if tools:
payload["tools"] = tools
payload["tool_choice"] = "auto"
Yukarıdaki yük, konuşma bağlamı ve üretim parametreleri de dahil olmak üzere modele gönderilen isteği tanımlar. tools eklenip tool_choice="auto" etkinleştirildiğinde, modelin harici işlevleri ne zaman çağıracağına kendisinin karar vermesine olanak tanınır.
Adım 3: Tarayıcı araçlarını tanımlama
agent.py içinde, modelin çağırabileceği bir araç şeması tanımlarız. Bunlar search_web, open_url, open_search_result, extract_page, extract_flight_cards, click, type_text ve wait_for_text içerir.
İşte örnek bir araç tanımı:
{
"type": "function",
"function": {
"name": "search_web",
"description": "Search the public web for flight result pages or travel aggregators.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"max_results": {"type": "integer", "default": 8},
},
"required": ["query"],
},
},
}
Bu şema, aracın ne yaptığını, hangi girdileri beklediğini ve nasıl çağrılacağını modele anlatır. Araçları bu şekilde tanımlayarak, akışı sabitlemek yerine modelin webde ne zaman arama yapacağına dinamik olarak karar vermesine izin veririz.
Yürütme tarafında, bu araçlar browser_tools.py içinde uygulanır. Bu demo için DuckDuckGo’nun HTML uç noktasını kullanıp, takip eden gezinmeler için mevcut sonuç bağlantılarını sakladık.
def search_web(self, query: str, max_results: int = 8) -> Dict[str, Any]:
url = f"https://html.duckduckgo.com/html/?q={quote_plus(query)}"
headers = {"User-Agent": "Mozilla/5.0"}
resp = requests.get(url, headers=headers, timeout=30)
resp.raise_for_status()
html = resp.text
search_web() işlevi, ham HTML sonuçlarını getirip ayrıştırarak hafif bir web araması yapar ve ücretli bir arama API’sı ihtiyacını ortadan kaldırır. Ayrıca sonuçları dahili olarak saklar; böylece aracı daha sonraki adımlarda bu sonuçlarda gezinebilir.
Artık aracının web ile nasıl etkileşim kuracağını tanımladığımıza göre, sonraki adım, web araması aracılığıyla uçuş bilgilerini bu araçları kullanarak nasıl çıkardığını görmektir.
Adım 4: Uçuş bilgilerini çıkarmak
Model umut vaat eden bir kaynak bulduğunda onu incelemesi gerekir. Ham sayfa anlık görüntülerini çıkarmak için (Adım 3’teki) tarayıcı araçlarını kullanabiliriz.
Adım 4.1: Sayfaları açma ve çıkarma
Web sayfasını yüklemek ve başlık, URL ve görünür metinle bir anlık görüntü döndürmek için open_url() aracını kullanacağız.
def open_url(self, url: str) -> Dict[str, Any]:
self.page.goto(url, wait_until="domcontentloaded", timeout=45000)
self.page.wait_for_timeout(1200)
return self._page_snapshot()
Daha geniş kapsamlı çıkarım için, sayfa anlık görüntüsünü ve mevcut sayfadan toplanmış bir bağlantı kümesini döndüren aşağıdaki extract_page() aracını kullanacağız.
def extract_page(self, max_chars: int = 7000, link_limit: int = 20) -> Dict[str, Any]:
snapshot = self._page_snapshot(max_chars=max_chars)
snapshot["links"] = self._collect_links(limit=link_limit)
self.current_links = snapshot["links"]
return snapshot
Bu faydalıdır; çünkü model her zaman körlemesine tıklamak zorunda değildir. Bazen önce mevcut sayfa metnini ve erişilebilir bağlantıları inceleyip sonra bir sonraki hamleye karar verebilir.
Adım 4.2: Sezgisel uçuş çıkarımı
Demonun kilit parçası, görünür sayfa metnini alıp fiyat, saatler, süre ve aktarmaları tespit etmek için regex kalıpları kullanan extract_flight_cards() işlevidir.
İşte bu mantığın özeti:
money_pattern = re.compile(r"(?:\$|USD\s?)(\d{2,5})")
time_pattern = re.compile(r"\b\d{1,2}:\d{2}\s?(?:AM|PM|am|pm)?\b")
duration_pattern = re.compile(r"\b\d{1,2}\s?h\s?\d{0,2}\s?m?\b|\b\d{1,2}\s?hr\s?\d{0,2}\s?min?\b", re.I)
stop_pattern = re.compile(r"nonstop|1 stop|2 stops|3 stops", re.I)
Bu regex kalıpları, uçuşla ilgili yaygın sinyaller için birer algılayıcı gibi davranır. money_pattern, $299 veya USD 299 gibi biçimlerdeki fiyatları yakalarken time_pattern kalkış ve varış saatlerini tanımlar.
Benzer şekilde duration_pattern seyahat süresini çıkarır, stop_pattern ise uçuşun aktarmasız mı yoksa aktarmalı mı olduğunu algılar. Her kullanım durumu için benzer kalıplar oluşturabilirsiniz.
Bu sinyaller tanımlandıktan sonra, işlev metnin küçük parçalarını tarar ve anlamlı kombinasyonlar arar. Eşleşme bulunduğunda, yapılandırılmış bir uçuş kartı oluşturur:
card = {
"snippet": joined[:350],
"price_usd": int(price_match.group(1)),
"times": times[:2],
"duration": duration.group(0) if duration else None,
"stops": stops.group(0) if stops else None,
}
Yukarıdaki kod bloğu, ham metni bir uçuş seçeneğinin yapılandırılmış bir temsilene dönüştürür. Fiyatı çıkarır, saat girdilerini en ilgili olanlarla sınırlar ve eksik alanları ele alır. Bu, hata ayıklama için yararlı olan özgün bağlamı korur.
Çıkarım hazır olduğunda, aracı artık yapılandırılmamış sayfa içeriğini kullanılabilir verilere dönüştürebilir. Sırada, bu verilerin çok adımlı karar verme sürecini yönlendirmek üzere aracı döngüsünden nasıl aktığına bakacağız.
Adım 5: Aracı döngüsü
Gerçek aracı davranışı BrowserAgent sınıfında (agent.py içinde) yer alır. Bu sınıf, istemi ve araç şemasını modele gönderir, modelin bir araç çağırmak isteyip istemediğini kontrol eder, o aracı yürütür, araç sonucunu konuşmaya geri ekler ve nihai bir yanıt üretilene kadar devam eder.
İşte ana döngü:
for step in range(1, self.max_steps + 1):
assistant = self.llm.create_chat_completion(
messages=messages,
tools=TOOLS,
temperature=0.2,
max_tokens=2200,
enable_thinking=False,
)
if assistant.tool_calls:
...
result = self.tool_runner(tc.name, tc.arguments)
...
continue
final_content = assistant.content.strip()
if final_content:
yield {"type": "final", "step": step, "content": final_content}
return
Bu döngü demonun kalbidir.
Her adımda model, mevcut konuşma durumunu alır ve bir sonraki adımda ne yapacağına karar verir. Araç çağrıları dönerse, bunlar tool_runner kullanılarak yürütülür ve sonuçlar bir sonraki yineleme için döngüye geri beslenir.
Bu süreç, model bir araç çağırmak yerine nihai bir yanıt üretene kadar devam eder.
Döngü ayrıca sonsuz yürütmeyi önlemek için maksimum adım sınırını zorunlu kılar ve süreci kontrollü ve verimli tutar.
Adım 6: Araçları uygulamaya bağlama
app.py içinde, model tarafından talep edilen araç adlarını gerçek tarayıcı yöntemlerine eşliyoruz. Bu eşleme make_tool_runner() işleviyle uygulanır:
def make_tool_runner(browser: BrowserTools):
def run(name: str, args: Dict[str, Any]):
if name == "search_web":
return browser.search_web(**args)
if name == "open_url":
return browser.open_url(**args)
if name == "open_search_result":
return browser.open_search_result(**args)
if name == "extract_page":
return browser.extract_page(**args)
if name == "extract_flight_cards":
return browser.extract_flight_cards(**args)
Bu işlev, model ile tarayıcı arasında bir yönlendirici (dispatcher) olarak görev yapar. Model yalnızca araç adını ve argümanları döndürür; run() ise bunu BrowserTools örneği üzerinde bir işlev çağrısına çevirir.
Aracı artık araçları başarıyla çağırıp yürütebildiğine göre, her şeyi bir araya getirecek kullanıcı arayüzünü inşa etme zamanı.
Adım 7: Streamlit arayüzünü oluşturma
Streamlit arayüzü, tarayıcı aracısını etkileşimli bir uygulamaya dönüştürür. Kullanıcıdan seyahat ayrıntılarını toplar, aracıyı başlatır, ara adımları akış halinde gösterir ve sonunda en iyi uçuş seçeneklerinin yapılandırılmış bir tablosuyla birlikte bir özet sunar. Bu tam UI akışı app.py içinde uygulanır.
st.set_page_config(page_title="GLM-5 Browser Agent", page_icon="", layout="wide")
st.title("GLM-5-Turbo Real-Time Browser Agent")
st.subheader("Trip Request")
origin = st.text_input("Origin", value="SFO")
destination = st.text_input("Destination", value="JFK")
depart_date = st.date_input("Depart date")
return_date = st.date_input("Return date")
adults = st.number_input("Adults", min_value=1, max_value=9, value=1)
natural_request = st.text_area(
"Optional natural language request",
value="Find the cheapest reasonable flight options and summarize the best ones.",
height=120,
)
user_query = (
f"Find flight options from {origin} to {destination} for {adults} adult(s). "
f"Departure date: {depart_date}. Return date: {return_date}. "
f"User preference: {natural_request}"
)
run = st.button("Run browser agent", type="primary", use_container_width=True)
if run:
if not api_key:
st.error("Please enter an API key in the sidebar.")
st.stop()
llm = LLMClient(provider=provider, api_key=api_key, model=model)
event_box = st.container(border=True)
result_box = st.container(border=True)
all_events = []
with managed_browser(headless=headless) as browser:
agent = BrowserAgent(llm=llm, tool_runner=make_tool_runner(browser), max_steps=max_steps)
for event in agent.stream(user_query):
all_events.append(event)
with event_box:
if event["type"] == "status":
st.write(f"**Step {event['step']}** — {event['content']}")
elif event["type"] == "tool_call":
with st.expander(f"Step {event['step']} • Tool call: {event['tool']}", expanded=False):
st.json(event["arguments"])
elif event["type"] == "tool_result":
with st.expander(f"Step {event['step']} • Tool result: {event['tool']}", expanded=False):
st.json(event["result"])
elif event["type"] == "final":
st.success("Agent finished.")
final_event = next((e for e in reversed(all_events) if e["type"] == "final"), None)
final_text = final_event["content"] if final_event else ""
with result_box:
st.subheader("Final Answer")
parsed = parse_final_json(final_text)
if parsed:
st.markdown(render_final_markdown(parsed))
options_df = build_options_dataframe(parsed)
if not options_df.empty:
st.subheader("Top options table")
st.dataframe(
options_df,
use_container_width=True,
column_config={
"Link": st.column_config.LinkColumn("Link", display_text="Open source"),
},
)
else:
st.markdown(final_text)
Streamlit arayüzü bileşenleri şöyle bir araya getirir:
st.set_page_config()vest.title()çağrıları uygulamanın genel yerleşimini ve başlığını tanımlar;st.text_input(),st.date_input(),st.number_input()vest.text_area()gibi girdi bileşenleri ise seyahat ayrıntılarını toplar.- Kullanıcı
Run browser agentdüğmesine tıkladığında uygulama önce bir API anahtarının mevcut olup olmadığını kontrol eder, ardındanLLMClient’ı başlatır. Daha sonra ara aracı günlükleri ve nihai sonuçlar için ayrı kaplar oluşturur ve yönetilen bir Playwright tarayıcı oturumu açar. Bu oturum içindeBrowserAgentolayları akıtmaya başlar ve UI her durum güncellemesini, araç çağrısını ve araç sonucunu gösterir. - Aracı tamamladığında, uygulama son olayı çıkarır, döndürülen JSON’u ayrıştırır ve render eder. Özet,
render_final_markdown()ile gösterilirkenbuild_options_dataframe()yapılandırılmış uçuş seçeneklerini kaynak bağlantıları tıklanabilir bir tabloya dönüştürür.
Bu adım tamamlandığında her şeyi app.py olarak kaydedebilir ve uygulamayı şu komutla başlatabilirsiniz:
streamlit run app.py

Bu proje, gerçek tarayıcı arama sonuçlarını ve araç çağırmayı kullandığı için iyi bir demo olarak çalışır. Aynı zamanda hâlâ bir prototiptir. Uçuş siteleri dinamiktir, sayfalar gürültülü olabilir ve bazı platformlar bot karşıtı korumalar kullanır.
Mevcut çıkarım mantığı bilerek sezgisel bırakılmıştır; bu da sistemi basit ve anlaşılır tutar.
Daha da önemlisi, bu kurulum uçuşlarla sınırlı değildir. Birkaç küçük ayarlamayla—esas olarak istemleri ve çıkarım mantığını güncelleyerek—aynı mimariyi alışveriş, araştırma, haber toplama veya canlı bilgiyi gezinip özetlemeyi gerektiren herhangi bir görev için yeniden kullanabilirsiniz.
Sonuç
Bu eğitimde GLM-5-Turbo, Playwright ve Streamlit ile gerçek zamanlı bir tarayıcı aracısı oluşturduk. Model bir planlayıcı gibi davranır, tarayıcı araçları yürütme katmanı olarak işlev görür ve UI yapılandırılmış sonuçları kullanıcı dostu bir formata dönüştürür.
En önemli çıkarım, değerin yalnızca modelden gelmediğidir. Değer, modeli kontrollü bir araç katmanı ve bir aracı döngüsüyle birleştirmekten gelir.
Bununla birlikte, bu projeyi genişletmenin çeşitli yolları vardır. Siteye özel ayrıştırıcılar ekleyerek çıkarımı geliştirebilir, sistemi otellere veya seyahat planlarına genişletebilir ya da aktarmasız uçuşlar veya tercih edilen havayolları gibi kullanıcı tercihlerini entegre edebilirsiniz. Bunlar bu demoyu tam teşekküllü bir tarayıcı uzantısına dönüştürmenize yardımcı olabilir.
GLM-5-Turbo SSS
Bu GLM-5-Turbo projesini çalıştırmak için bir GPU’ya ihtiyacım var mı?
Hayır. Bu proje bir GPU gerektirmez çünkü modele API (Z.AI veya OpenRouter) üzerinden erişilir. Tüm ağır hesaplama sağlayıcının altyapısında gerçekleşir; yerel makineniz yalnızca UI ve tarayıcı otomasyonunu yürütür.
Neden bir uçuş API’si yerine tarayıcı aracısı kullanmalı?
API’ler daha güvenilir ve yapılandırılmıştır; ancak önceden tanımlanmış verilere sınırlıdır ve sıklıkla ücretli erişim gerektirir. Öte yandan bir tarayıcı aracısı şunları yapabilir:
- birden çok kaynağı dinamik olarak keşfetmek
- farklı sorgulara uyum sağlamak
- önceden entegre API’ler olmadan çalışmak
Ancak üretim sistemleri için hibrit bir yaklaşım (aracı ve API’ler) genellikle en iyi seçimdir.
Aracı neden bazı web sitelerinde bazen başarısız oluyor?
Birçok seyahat web sitesi şunları kullanır:
- dinamik JavaScript oluşturma
- bot karşıtı korumalar
- sık değişen yerleşimler
Bu demo genel tarayıcı otomasyonu ve sezgisel çıkarıma dayandığı için, tüm sitelerde tutarlı şekilde çalışmayabilir.
Neden nihai çıktı olarak JSON döndürmekten kaçındık?
JSON, dahili olarak hata ayıklama, yapılandırılmış işleme, sıralama ve filtreleme için kullanışlıdır. Ancak son kullanıcılar okunabilir özetleri tercih eder. Bu nedenle sistem, yapılandırılmış çıktıları kullanıcı dostu bir formata dönüştürür.
ML (Üretken Yapay Zekâ) alanında Google Developers Uzmanıyım, Kaggle 3x Expert unvanına sahibim ve 3+ yıllık teknoloji deneyimiyle Women Techmakers Elçisiyim. 2020'de bir sağlık teknolojileri girişiminin kurucu ortağı oldum ve Georgia Tech'te makine öğrenmesi alanında uzmanlaşarak bilgisayar bilimleri yüksek lisansı yapıyorum.

