Thor ve Loki Gibi:LangChain ve LangGraph’ın Güçlü İş Birliği

Tıpkı ünlü kardeşler Thor ve Loki’nin Marvel evreninde birlikte çalışıp büyük maceralara atılmaları gibi, LangChain ve LangGraph da birlikte çalışarak güçlü ve dinamik yazılım çözümleri sunuyor. LangChain’in yeniliği olan LangGraph, LangChain’in üzerine inşa edilmiştir ve kullanıcılarına daha gelişmiş ajan çalışma zamanları sunmak için tasarlanmıştır. Bu kütüphane, döngüsel graphs oluşturmayı kolaylaştırarak yeni değerler katmaktadır. Bu, genellikle ajan çalışma zamanları oluştururken faydalıdır.
LangGraph, Dil Modelleri (LLM’ler) ile çok aktörlü, durumsal uygulamalar oluşturmak için geliştirilmiş bir kütüphanedir. Ajan ve çok ajanlı iş akışlarını oluşturmak için kullanılan bu kütüphane, LangChain üzerine inşa edilmiştir ve şu temel faydaları sunar: döngüler, kontrol edilebilirlik ve kalıcılık. LangGraph, döngü içeren iş akışlarını tanımlamanıza olanak tanır, bu da çoğu ajan mimarisi için hayati öneme sahiptir ve bu özelliğiyle DAG (Directed Acyclic Graph) tabanlı çözümlerden ayrılır. Ayrıca, uygulamanızın hem akış hem de durumu üzerinde ince ayar yapmanıza imkan tanıyan düşük seviyeli bir çerçevedir ve güvenilir ajanlar oluşturmak için kritiktir. Dahası, LangGraph yerleşik kalıcılık özelliklerine sahiptir, bu da insan-döngüde ve bellek özelliklerini mümkün kılar.
LangChain ekibi, bu yeni aracın kullanımını kolaylaştırmak için kapsamlı bir blog yazısı ve çeşitli not defterleri (notebooks) sağlamıştır. Bu kaynaklar, LangGraph’in potansiyelini tam anlamıyla keşfetmenize yardımcı olacak bilgilerle doludur.
Eğer siz de dil modelleme ve doğal dil işleme (NLP) alanında yeni araçları ve teknikleri keşfetmekten hoşlanıyorsanız, LangGraph sizin için mükemmel bir araç olabilir. Gelin, bu yeni ve heyecan verici teknolojiyi birlikte inceleyelim!
Basit Bir Graph Yapısı
Graphs, düğümler (nodes) ve bu düğümleri birbirine bağlayan kenarlardan (edges) oluşan matematiksel yapılardır. En basit haliyle, bir graph iki düğüm ve bu düğümleri birbirine bağlayan bir kenardan oluşur. Bu yapı, dil modelleri ve doğal dil işleme (NLP) uygulamalarında oldukça faydalıdır. Basit bir graphta, kullanıcıdan bir sorgu (query) alınır ve bu sorgu graphtan geçirilerek bir çıktı üretilir. Graph içindeki her düğüm, belirli bir işlemi veya fonksiyonu temsil eder. Düğümler arasında geçen kenarlar ise bu işlemlerin sırasını ve ilişkisini gösterir.
Düğümlerin İşlevi
Düğümleri, fonksiyonların çalıştırılabileceği yerler olarak düşünebiliriz. Her düğümde bir fonksiyon çalıştırılır ve bu fonksiyonun dönüş değeri bir sonraki düğüme iletilir. Bu şekilde, karmaşık işlemler basit adımlara bölünerek graph üzerinde ilerler.
Basit Fonksiyonlar ile Graph
Bu kavramı daha iyi anlamak için iki basit fonksiyon kullanan bir graph örneğini inceleyelim:
- Kullanıcı Girdisi: Kullanıcıdan bir dize (string) alırız. Örneğin, “Merhaba” dizesi.
- İlk Düğüm: Birinci fonksiyon, bu dizeye “Dünyalı” ekler. Bu durumda, ilk düğümden geçtikten sonra elde edilen sonuç “Merhaba Dünyalı” olur.
- İkinci Düğüm: İkinci düğümde, önceki düğümden gelen dizeye “Hey” eklenir. Sonuç olarak, ikinci düğümden geçtikten sonra elde edilen nihai sonuç “Hey Merhaba Dünyalı” olur.
Bu basit örnek, graphların nasıl çalıştığını ve her düğümde fonksiyonların nasıl işlediğini anlamamıza yardımcı olur. Her düğümde yapılan işlem, bir sonraki aşamaya geçerken belirli bir dönüş değeri üretir ve bu değer bir sonraki düğümde kullanılmak üzere iletilir. Bu süreç, dil modelleme ve NLP uygulamalarında graphların kullanımını daha etkili hale getirir.
Graphlar, dil modelleri ve NLP uygulamalarında güçlü bir araçtır. Düğümler ve kenarlarla yapılan bu yapı, karmaşık işlemleri basit adımlara böler ve her adımda belirli fonksiyonların çalıştırılmasını sağlar. Bu nedenle, LangGraph gibi araçlar, dil modelleriyle çalışırken graph yapılarını kullanarak daha esnek ve güçlü uygulamalar geliştirmenizi sağlar.

def function_1(input_1):
return input_1 + " Merhaba "
def function_2(input_2):
return input_2 + "Dunyali"
function_1(input_1)
: Bu fonksiyon,input_1
adında bir parametre alır ve bu parametreye ” Merhaba “ stringini ekler. Son olarak, bu yeni stringi döndürür.function_2(input_2)
: Bu fonksiyon,input_2
adında bir parametre alır ve bu parametreye “Dunyali” stringini ekler. Son olarak, bu yeni stringi döndürür.
langgraph.graph kütüphanesi kullanabilmeniz için aşağıdaki paketi yüklemeniz gerekmektedir.
!pip install langgraph
from langgraph.graph import Graph
# Define a Langchain graph
workflow = Graph()
workflow.add_node("node_1", function_1)
workflow.add_node("node_2", function_2)
workflow.add_edge('node_1', 'node_2')
workflow.set_entry_point("node_1")
workflow.set_finish_point("node_2")
app = workflow.compile()
Bu kod, LangChain kütüphanesini kullanarak bir dil graphı oluşturmayı ve derlemeyi gösteriyor.
from langgraph.graph import Graph
: LangChain kütüphanesindenGraph
sınıfını içe aktarır.workflow = Graph()
: Boş birGraph
örneği oluşturarak, bir dil graphı için temel bir yapı oluşturur.workflow.add_node("node_1", function_1)
:node_1
adında bir düğüm ekler ve bu düğümüfunction_1
işleviyle ilişkilendirir.function_1
daha önce tanımlanmış bir işlev olmalıdır.workflow.add_node("node_2", function_2)
:node_2
adında bir düğüm ekler ve bu düğümüfunction_2
işleviyle ilişkilendirir.function_2
daha önce tanımlanmış bir işlev olmalıdır.workflow.add_edge('node_1', 'node_2')
:node_1
ilenode_2
arasında bir kenar ekler. Bu, dil graphındaki işlevler arasındaki sıralamayı gösterir.workflow.set_entry_point("node_1")
: Dil graphının başlangıç noktasını belirler. Yani, graphınnode_1
düğümünden başlayacağını belirtir.workflow.set_finish_point("node_2")
: Dil graphının bitiş noktasını belirler. Yani, graphınnode_2
düğümünde sona ereceğini belirtir.app = workflow.compile()
: Oluşturulan dil graphını derler veapp
adlı bir uygulama nesnesine atar. Bu adım, graphı çalıştırmak için hazır hale getirir.
app.invoke("Hey")
Hey Merhaba Dunyali
Bu kod, oluşturulan dil graphı uygulamasını başlatmak ve bir girdi değeriyle çalıştırmak için kullanılır. invoke
yöntemi, dil graphı uygulamasını çalıştırır ve belirtilen girdi değerini başlangıç düğümüne ileterek işlemleri başlatır.
Örneğin, eğer function_1
işlevi “Merhaba” dizesini ekliyorsa ve function_2
işlevi “Dunyali” dizesini ekliyorsa, app.invoke("Hey")
kodu, graphtaki işlevlerin çalıştırılmasını başlatır. Bu durumda, “Hey” girdisi function_1
işlevine iletilir ve ardından function_2
işlevine iletilir. Sonuç olarak, çıktı “Hey Merhaba Dunyali” olacaktır.
input = 'Hey'
for output in app.stream(input):
# stream() yields dictionaries with output keyed by node name
for key, value in output.items():
print(f"Output from node '{key}':")
print("---")
print(value)
print("\n---\n")
Output from node 'node_1':
---
Hey Merhaba
Output from node 'node_2':
---
Hey Merhaba Dunyali
Bu kod, oluşturulan dil graphı uygulamasını belirli bir girdi ile çalıştırır ve her adımda oluşan çıktıları görüntüler. app.stream(input)
çağrısı, uygulamanın verilen girdi ile çalıştırılmasını başlatır ve her adımda oluşan çıktıları bir döngü aracılığıyla elde etmenizi sağlar.
Döngü, her adımda elde edilen çıktıları işler. Her çıktı, bir sözlük olarak temsil edilir, düğüm adıyla indekslenir ve bu düğümde gerçekleşen işlemin çıktısını içerir. Döngü, bu çıktıları düğüm adıyla birlikte yazdırır, böylece her adımda hangi çıktının hangi düğümden geldiği açıkça görülebilir.
LLM Çağrısı ile Graph Oluşturma
LLM (Large Language Model) çağrısı, büyük dil modellerini kullanarak metin üretmek veya anlamak için yapılan bir çağrıdır. Bu çağrı, genellikle dize işleme, metin oluşturma veya metin sınıflandırma gibi görevler için kullanılır.
Graphı oluştururken, node one
olarak adlandırdığımız bir düğüm oluştururuz. Bu düğüm, LLM’ye bir çağrı yapacak ve bir metin örneği alabilir. LLM bu metne dayalı olarak bir yanıt oluşturacak ve bu yanıtı node two
düğümüne ileteceğiz.
node one
‘da LLM’ye yapılan çağrı genellikle bir API çağrısı şeklinde olur. Örneğin, bir metin oluşturma görevi için GPT-3,GPT-3.5 gibi bir LLM servisi kullanılabilir. Bu çağrı sonucunda elde edilen metin yanıt, node two
‘ya geçirilir ve sonraki adımlarda bu metin üzerinde işlemler yapılabilir.
Sonuç olarak, bu yaklaşım, büyük dil modellerini kullanarak karmaşık metin işleme görevlerini gerçekleştirmek için graph tabanlı bir yaklaşım sunar. Bu sayede, dil modellerinin gücünden yararlanarak metin işleme uygulamaları geliştirebiliriz.

!pip install python-dotenv
from dotenv import load_dotenv
import os
#Load environment variables from .env file
load_dotenv()
# you can access open api key
os.environ['AZURE_OPENAI_API_KEY'] = os.environ.get("AZURE_OPENAI_API_KEY")
Bu kodu çalıştırdığınızda, AZURE_OPENAI_API_KEY değerini güvenli bir şekilde API anahtarlarınızı ve diğer duyarlı bilgilerinizi saklayabilir ve kullanabilirsiniz. Ben aşağıdaki örnekte model olarak gpt-3.5 turbo kullandım.
!pip install langchain langchain_openai
# Modeli kullanarak çağrı yapılması
response = llm.invoke('Hey dünyalı')
print(response)
content='Merhaba! Size nasıl yardımcı olabilirim?' response_metadata={'finish_reason': 'stop'} id='run-8936a285-717a-4e60-aaa5-af71baeda9a6-0'
def function_1(input_1):
response = llm.invoke(input_1)
return response.content
def function_2(input_2):
return "Agent söylüyor:" + input_2
function_1(input_1)
İlk işlev, kullanıcının girdisini alıp modele ileterek yanıt alır. İkinci işlev ise bu yanıtı işleyip belirli bir dize ekler.
function_1
: Kullanıcı girdisini alır, dil modeline gönderir ve modelin yanıtını döndürür. Girdi Parametresi: input_1
adında bir girdi alır.
- Dil Modeli Çağrısı:
llm.invoke(input_1)
çağrısı ile dil modeline (llm
nesnesi)input_1
girdisini gönderir. Bullm
nesnesi, bir önceki örnekte tanımladığımızAzureChatOpenAI
nesnesi olabilir. - Yanıtın Alınması:
invoke
yöntemi, dil modelinden bir yanıt alır. Bu yanıt genellikle metin tabanlı bir içerik olacaktır. - Yanıtın Dönülmesi:
response.content
döndürülür.
function_2(input_2)
function_2
: Modelin yanıtını alır ve bu yanıta “Agent söylüyor:” dizesini ekler.
- Girdi Parametresi:
input_2
adında bir girdi alır. - Dize Ekleme: “Agent söylüyor:” dizesini
input_2
girdisine ekler. - Yanıtın Dönülmesi: Yeni oluşturulan dizeyi döndürür.
LangChain kütüphanesi kullanarak işlevleri graph yapısında organize edebiliriz. Bu, verinin düğümler arasında akarak işlenmesini sağlar.
from langgraph.graph import Graph
#Define a Langchain Graph
workflow = Graph()
workflow.add_node("agent", function_1)
workflow.add_node("node_2", function_2)
workflow.add_edge('agent', 'node_2')
workflow.set_entry_point("agent")
workflow.set_finish_point("node_2")
app = workflow.compile()
Dil modelleri, doğal dil işleme görevlerinde güçlü araçlardır ve LangChain kütüphanesi bu modellerin graph yapıları içinde kullanımını kolaylaştırır.Bu kod, function_1
ve function_2
işlevlerini düğümler olarak ekler, düğümler arası bağlantıyı oluşturur ve graphı derler.
Graph yapısını kullanarak, kullanıcı girdisini işlemek ve modelin yanıtını almak için aşağıdaki adımları izleyebiliriz:
response = app.invoke("Hey Dünyalı!")
print(response) # "Agent söylüyor: Hello, how can I assist you?"
Bu adımda, graph yapı kullanılarak “Hey Dünyalı!” girdisi işlenir. İlk düğüm (function_1
), girdiyi modele iletir ve yanıt alır. İkinci düğüm (function_2
), bu yanıtı alır ve “Agent söylüyor:” dizesini ekler. Sonuç olarak, “Agent söylüyor:Merhaba! Size nasıl yardımcı olabilirim?” çıktısını elde ederiz.
input = "Hey Dünyalı!"
for output in app.stream(input):
# stream() yields dictionaries with output keyed by node name
for key, value in output.items():
print(f"Output from node '{key}':")
print("---")
print(value)
print("\n---\n")
# Son düğümün çıktısını ayrıca kontrol et
final_output = app.invoke(input)
print("Final Output:")
print(final_output)
Graph yapısının nasıl çalıştığını ve düğümler arasındaki veri akışını daha iyi anlamak için, her bir düğümün işleyişine bakalım. İlk olarak, graph uygulamamızı derledik ve “Hey Dünyalı!” girdisi ile çalıştırdık. Bunun sonucunda, şu şekilde bir çıktı elde ettik: “Agent söylüyor:Merhaba! Size nasıl yardımcı olabilirim?”
Her düğümün ne yaptığını adım adım inceleyelim:
- İlk Düğüm (Node 1): Kullanıcıdan gelen girdiyi (“Hey Dünyalı!”) aldı ve dil modeline iletti. Dil modeli, “Merhaba! Size nasıl yardımcı olabilirim?” yanıtını verdi.
- İkinci Düğüm (Node 2): İlk düğümden gelen yanıtı aldı ve bu yanıtın başına “Agent söylüyor:” ifadesini ekledi. Sonuç olarak, “Agent söylüyor:Merhaba! Size nasıl yardımcı olabilirim?” dizesini oluşturdu.
Bu yapı, her düğümde verinin nasıl işlendiğini ve bir sonraki düğüme nasıl iletildiğini göstermektedir. Graphın son çıktısı, her düğümün yaptığı işlemlerin birleşiminden oluşur ve beklediğimiz sonucu verir. Bu örnek, dil modeli yanıtlarının nasıl işlenip düzenlenebileceğini ve graph yapısının bu süreci nasıl yönettiğini açıkça göstermektedir.
Output from node 'agent':
---
Merhaba! Size nasıl yardımcı olabilirim?
---
Output from node 'node_2':
---
Agent söylüyor:Merhaba! Size nasıl yardımcı olabilirim?
---
Final Output:
Agent söylüyor:Merhaba! Size nasıl yardımcı olabilirim?
Daha Kompleks Bir Graph Örneği Üzerinde Çalışma Yapalım!
Bu senaryoda, Dil Modeli (LLM) ile etkileşimi geliştiriyoruz ve sadece basit bir çağrı yapmakla kalmayıp belirli bir görev de atıyoruz. Sadece “Nasılsınız?” gibi genel bir soru sormak yerine, kullanıcının sorgusundan belirli bilgileri çıkarmaya odaklanıyoruz, örneğin bir şehir adı.
İlk olarak, function_1
adında bir işlev tanımlıyoruz. Bu işlev, gelen cümledeki şehir ismini bulmak için bir dil modeli çağrısı yapacak. Ancak dikkat edilmesi gereken nokta, hava durumu bilgisi istenmediği için sadece şehir isminin döndürülmesi gerektiğidir. Daha sonra, function_2
adında başka bir işlev tanımlıyoruz. Bu işlev, function_1
tarafından döndürülen şehir ismini kullanarak bir yanıt oluşturuyor.
def function_1(input_1):
complete_query = "Verilen cümledeki şehir ismini bul ve bana ver. Hava durumunu sormuyorum. Sadece şehir ismini bana ver. Cümle:" + input_1
response = llm.invoke(complete_query)
return response.content
def function_2(input_2):
return "Agent söylüyor:" + input_2
from langgraph.graph import Graph
#Define a Langchain Graph
workflow = Graph()
workflow.add_node("agent", function_1)
workflow.add_node("node_2", function_2)
workflow.add_edge('agent', 'node_2')
workflow.set_entry_point("agent")
workflow.set_finish_point("node_2")
app = workflow.compile()
# Modeli kullanarak çağrı yapılması
response = app.invoke("İstanbul'da hava nasıl?")
print(response)
# Modeli kullanarak çağrı yapılması
response = app.invoke("İstanbul'da hava nasıl?")
print(response)
Agent söylüyor:İstanbul
Bu örnekte, dil modelini kullanarak belirli bir görevi gerçekleştirmek için nasıl kod yazabileceğimizi gördük. Bu yaklaşımı, daha karmaşık uygulamalarda da kullanabilir ve dil modellerini etkin bir şekilde entegre edebiliriz. Peki bunu gerçekten bir hava durumu API’sine bağlar ve sonuçları oradan almak istersek ne yaparız?
import os
from langchain_community.utilities import OpenWeatherMapAPIWrapper
os.environ["OPENWEATHERMAP_API_KEY"] = os.environ.get("OPENWEATHER_API_KEY")
weather = OpenWeatherMapAPIWrapper()
Bu kod parçacığı, OpenWeatherMapAPIWrapper adlı bir sınıfı kullanarak OpenWeatherMap API’sine erişim sağlamak için gereken ayarları yapar.
İlk olarak, os.environ["OPENWEATHERMAP_API_KEY"] = os.environ.get("OPENWEATHER_API_KEY")
satırı, ortam değişkenlerinden API anahtarını alır ve OpenWeatherMapAPIWrapper sınıfının kullanabileceği şekilde bir ortam değişkenine atanır. Bu adım, API anahtarını güvenli bir şekilde saklamamıza ve kullanmamıza olanak tanır.
Ardından, weather = OpenWeatherMapAPIWrapper()
satırıyla OpenWeatherMapAPIWrapper sınıfından bir örnek oluşturulur. Bu örnek, API’ye erişim sağlayacak ve hava durumu bilgilerini almak için kullanılabilir hale getirir.
OpenWeatherMap API’yi kullanabilmek için API anahtarına ihtiyacınız vardır. API anahtarınız yoksa, aşağıdaki adımları takip ederek bir tane oluşturabilirsiniz:
- OpenWeatherMap’in resmi web sitesine gidin: OpenWeatherMap.
- Ücretsiz bir hesap oluşturun veya mevcut bir hesabınıza giriş yapın.
- Hesabınıza giriş yaptıktan sonra, API anahtarınızı oluşturmak için API sekmesine gidin.
- API anahtarınızı almak için gerekli adımları takip edin. Anahtarınız oluşturulduktan sonra, bu anahtarı kullanarak API’ye erişebilirsiniz.
Bu kod parçacığını çalıştırmak için langchain_community
adlı pakete bağımlı olduğunuzu varsayalım. Bu paket, OpenWeatherMapAPIWrapper gibi API’leri kullanmak için kullanışlı araçlar sağlar. Ek olarak pyowm
paketini de yüklemeniz gerekir. Bu paket OpenWeatherMap API’sine erişmek için Python dilinde kullanılan bir kütüphanedir. OpenWeatherMap API’si ile hava durumu verilerine erişmek, sorgulamak ve işlemek için bu kütüphaneyi kullanabilirsiniz. Özellikle hava durumu uygulamaları veya hava durumu bilgisine ihtiyaç duyulan diğer uygulamalar geliştirirken pyowm
paketini kullanabilirsiniz. Bu paket, OpenWeatherMap API’sinin sunduğu hava durumu verilerini kolayca çekmenizi ve kullanmanızı sağlar.
!pip install pyowm
!pip install langchain_community
weather_data = weather.run("İstanbul")
print(weather_data)
Bu kod parçası, weather
adlı bir OpenWeatherMapAPIWrapper örneğini kullanarak İstanbul’un hava durumu verilerini almayı amaçlar.
İlk olarak, weather.run("İstanbul")
çağrısı ile weather
örneği üzerinde run
metodunu çağırıyoruz. Bu metod, belirtilen şehir için hava durumu verilerini almak için OpenWeatherMap API’sini kullanır. "İstanbul"
argümanı, hangi şehir için hava durumu verilerini almak istediğimizi belirtir. Sonrasında, weather_data
değişkenine bu metoddan dönen değeri atıyoruz. Bu değer, API’nin sağladığı hava durumu verilerini içerir.
Son olarak, print(weather_data)
satırıyla, aldığımız hava durumu verilerini ekrana yazdırıyoruz. Bu veriler genellikle sıcaklık, nem, rüzgar hızı gibi bilgileri içerir ve hava durumu bilgisine ilişkin genel bir görünüm sunar.
In İstanbul, the current weather is as follows:
Detailed status: broken clouds
Wind speed: 3.09 m/s, direction: 70°
Humidity: 54%
Temperature:
- Current: 28.68°C
- High: 31.09°C
- Low: 28.68°C
- Feels like: 29.72°C
Rain: {}
Heat index: None
Cloud cover: 75%
- Öncelikle, önceki sorguyu veya LLM’ye verilen önceki talimatı alıp bunu kullanmak istenmektedir.
- İkinci işlevde (function 2), önceki işlevden öğrenilen bilgi kullanılarak
weather run
komutu değiştirilmektedir.
def function_1(input_1):
complete_query = "Verilen cümledeki şehir ismini bul ve bana ver. Hava durumunu sormuyorum. Sadece şehir ismini bana ver. Cümle:" + input_1
response = llm.invoke(complete_query)
return response.content
def function_2(input_2):
weather_data = weather.run(input_2)
return weather_data
- Graphın nasıl kurulduğu ve ayarlandığı hala aynıdır, tek fark node2‘nin “tool” olarak çağrılmasıdır.
- Bu şekilde, node1 bilgisini alıp onu node2‘ye (bu durumda “tool” olarak adlandırılan) bağlamaktayız.
- Node’lara verilen isimlerin her durumda değiştirilmesi gerekmektedir.
from langgraph.graph import Graph
workflow = Graph()
#calling node 1 as agent
workflow.add_node("agent", function_1)
workflow.add_node("tool", function_2)
workflow.add_edge('agent', 'tool')
workflow.set_entry_point("agent")
workflow.set_finish_point("tool")
app = workflow.compile()
- Daha sonra, bu graphı derlemekteyiz ve soru sorduğumuzda şehir adını ayrıştırıp iletmeyi ummaktayız.
# Modeli kullanarak çağrı yapılması
response = app.invoke("İstanbul'da hava nasıl?")
print(response)
- Bu noktada, agent’ın “İstanbul” dediği ve ardından “tool”un bu bilgiyi aldığı, API çağrısını yaptığı ve bize bir şeyler döndürdüğü görülmektedir.
In İstanbul, the current weather is as follows:
Detailed status: scattered clouds
Wind speed: 3.6 m/s, direction: 80°
Humidity: 37%
Temperature:
- Current: 31.59°C
- High: 31.68°C
- Low: 24.48°C
- Feels like: 31.24°C
Rain: {}
Heat index: None
Cloud cover: 40%
input = "İstanbul'da hava nasıl?"
for output in app.stream(input):
# stream() yields dictionaries with output keyed by node name
for key, value in output.items():
print(f"Output from node '{key}':")
print("---")
print(value)
print("\n---\n")
# Son düğümün çıktısını ayrıca kontrol et
final_output = app.invoke(input)
print("Final Output:")
print(final_output)
Output from node 'agent':
---
İstanbul
---
Output from node 'tool':
---
In İstanbul, the current weather is as follows:
Detailed status: scattered clouds
Wind speed: 3.6 m/s, direction: 80°
Humidity: 37%
Temperature:
- Current: 31.59°C
- High: 31.68°C
- Low: 24.48°C
- Feels like: 31.24°C
Rain: {}
Heat index: None
Cloud cover: 40%
---
Final Output:
In İstanbul, the current weather is as follows:
Detailed status: scattered clouds
Wind speed: 3.6 m/s, direction: 80°
Humidity: 37%
Temperature:
- Current: 31.59°C
- High: 31.68°C
- Low: 24.48°C
- Feels like: 31.24°C
Rain: {}
Heat index: None
Cloud cover: 40%
Ancak, kullanıcının sadece sıcaklık sormasına rağmen, aldığımız geri dönüşün şehir için tam bir hava durumu raporu olduğunu fark ediyoruz. Bu durumu değiştirmek istiyoruz ve başka bir çağrı yaparak bu özel düğümün bilgilerini alıp kullanıcının sorusunu görmek ve sadece istenen bilgiyi yanıtlamak için bu özel düğümün sorumlu olduğu bir durum ortaya koyabiliriz.

Önceki paragraflarda bahsedilen sorun, kullanıcı girişinin (örneğin, “İstanbul’da hava nasıl?”) API’ye gönderilmeden önce düğümler arasında iletilmemesidir. Bu durumda, API’den gelen yanıtı almak mümkündür, ancak kullanıcının sorduğu sorunun hangi şehir için olduğu bilgisine erişmek mümkün olmayabilir.
Bu sorunu çözmek için önerilen çözüm, düğümler arasında veri iletimini sağlamaktır. LangChain’de, bu veri iletimi için sözlükler (dictionary) veya diziler (array) gibi veri tipleri kullanılabilir. Bu veri tipleri, düğümler arasında taşınabilir ve değiştirilebilir veri yapıları sağlar.
Örneğin, bir “agent state” sözlüğü oluşturulabilir ve bu sözlüğün içinde “messages” adında bir dizi bulunabilir. Bu dizi, kullanıcının sorduğu soruların ve API yanıtlarının saklandığı bir veri yapısı olabilir. Bu şekilde, her düğümde bu veri yapısına erişilerek, önceki düğümlerdeki verilere erişilebilir ve kullanıcının sorduğu sorunun hangi şehir için olduğu gibi bilgiler, düğümler arasında aktarılabilir.
Bu yaklaşımı kullanarak, her düğümde geçmiş verilere erişim sağlayabilir ve bu verileri kullanarak API çağrıları yapabiliriz. Bu da kullanıcıya daha tutarlı ve anlamlı yanıtlar verebilmemize olanak sağlar.
def function_3(input_3):
complete_query = "Göreviniz, kullanıcı sorgusuna göre kısa ve öz\
bir şekilde bilgi sağlamaktır. Kullanıcı sorgusu aşağıdadır:" + "user input"
response = model.invoke(complete_query)
return response.content
Bu kod parçası, belirli bir kullanıcı sorgusuna kısa ve öz bir şekilde yanıt vermek amacıyla kullanılabilecek bir işlevi tanımlamaktadır. İşlev, kullanıcı tarafından girilen sorguyu (örneğin, “İstanbul’da hava nasıl?”) alır ve bu sorguyu içeren bir metin oluşturur. Daha sonra, oluşturulan metni bir dil modeli (model
) üzerinden işlemek için invoke
metodunu kullanır ve sonuç olarak dil modelinden gelen yanıtı döndürür.
Özetle, bu işlev, kullanıcı sorgusunu alır, belirli bir metin formatında bir sorgu oluşturur, bu sorguyu bir dil modeline gönderir ve dil modelinden gelen yanıtı döndürür. Bu şekilde, kullanıcıya kısa ve öz bir şekilde bilgi sağlayabiliriz.
# assign AgentState as an empty dict
AgentState = {}
# messages key will be assigned as an empty array. We will append new messages as we pass along nodes.
AgentState["messages"] = []
Bu kod parçası, AgentState
adında bir boş sözlük (dictionary) oluşturur ve bu sözlüğün içine “messages” adında bir anahtar ekler, bu anahtara da boş bir dizi (array) atanır. Bu yapı, LangChain’in düğümler arasında veri iletimini sağlamak için kullandığı bir yapıdır.
AgentState
sözlüğü, düğümler arasında geçirilecek verileri saklamak için kullanılabilir. Örneğin, bir düğümde elde edilen bir bilgiyi, bir sonraki düğüme aktarmak için bu yapıyı kullanabiliriz. Bu sayede, her düğümde hangi bilgilerin aktarıldığını takip edebilir ve işlemleri tutarlı bir şekilde gerçekleştirebiliriz.
def function_1(state):
messages = state['messages']
user_input = messages[-1]
complete_query = "Verilen cümledeki şehir ismini bul ve bana ver. Hava durumunu sormuyorum. Sadece şehir ismini bana ver. Cümle:" + user_input
response = llm.invoke(complete_query)
state['messages'].append(response.content) # appending AIMessage response to the AgentState
return state
function_1
:
- Girdi:
state
(AgentState) sözlüğü. - İlk İşlem:
messages
anahtarını kullanarakstate
sözlüğündeki mesajları alır. - Kullanıcı Girdisi: Son kullanıcı girdisini (son mesajı) alır (
user_input = messages[-1]
). - Tam Sorgu Oluşturma: Kullanıcı girdisine dayalı olarak, şehir ismini bulmak için tam bir sorgu oluşturur (
complete_query
). - Dil Modeli Çağrısı: Bu sorguyu dil modeline gönderir (
llm.invoke(complete_query)
) ve yanıtı alır. - Yanıtı Ekleme: Alınan yanıtı
messages
dizisine ekler (state['messages'].append(response.content)
). - Dönüş: Güncellenmiş
state
sözlüğünü döner.
def function_2(state):
messages = state['messages']
agent_response = messages[-1]
weather = OpenWeatherMapAPIWrapper()
weather_data = weather.run(agent_response)
state['messages'].append(weather_data)
return state
function_2
:
- Girdi:
state
(AgentState) sözlüğü. - İlk İşlem:
messages
anahtarını kullanarakstate
sözlüğündeki mesajları alır. - Agent Yanıtı: Son agent yanıtını alır (
agent_response = messages[-1]
). - Hava Durumu API Çağrısı: OpenWeatherMapAPIWrapper sınıfından bir örnek oluşturur ve şehir adına göre hava durumu verilerini alır (
weather_data = weather.run(agent_response)
). - Yanıtı Ekleme: Alınan hava durumu verilerini
messages
dizisine ekler (state['messages'].append(weather_data)
). - Dönüş: Güncellenmiş
state
sözlüğünü döner.
def function_3(state):
messages = state['messages']
user_input = messages[0]
available_info = messages[-1]
agent2_query = "Göreviniz, kullanıcı sorgusuna ve internetteki mevcut bilgilere dayanarak bilgileri kısa ve öz bir şekilde sağlamaktır. \
Kullanıcı sorgusu aşağıdadır: " + user_input + " Mevcut bilgiler: " + available_info
response = llm.invoke(agent2_query)
return response.content
function_3
:
- Girdi:
state
(AgentState) sözlüğü. - İlk İşlem:
messages
anahtarını kullanarakstate
sözlüğündeki mesajları alır. - Kullanıcı Girdisi: İlk kullanıcı girdisini alır (
user_input = messages[0]
). - Mevcut Bilgi: En son alınan bilgiyi alır (
available_info = messages[-1]
). - Tam Sorgu Oluşturma: Kullanıcı girdisi ve mevcut bilgilere dayanarak, kısa ve öz bir yanıt oluşturmak için tam bir sorgu oluşturur (
agent2_query
). - Dil Modeli Çağrısı: Bu sorguyu dil modeline gönderir (
llm.invoke(agent2_query)
) ve yanıtı alır. - Dönüş: Dil modelinden alınan yanıtı döner (
return response.content
).
Kullanıcı sorgularını işlemek, şehir adını çıkarmak, hava durumu bilgilerini almak ve nihayetinde kullanıcının sorduğu soruya kısa ve öz bir yanıt vermek amacıyla bu iş akışı oluşturulmuştur.
Kullanıcı Sorgusunun Alınması ve Şehir Adının Çıkarılması
- İlk adımda (function_1), kullanıcıdan alınan sorgudan şehir adı çıkarılır.
- Bu adım, kullanıcının sorgusuna (örneğin, “İstanbul’da hava nasıl?”) odaklanarak şehir adını bulur ve yanıt olarak döner.
Hava Durumu Bilgilerinin Alınması:
- İkinci adımda (function_2), bir önceki adımda çıkarılan şehir adı kullanılarak hava durumu bilgileri OpenWeatherMap API’si aracılığıyla alınır.
- Bu adım, belirli bir şehir için hava durumu verilerini sağlar.
Kısa ve Öz Bir Yanıt Oluşturulması:
- Üçüncü adımda (function_3), kullanıcının orijinal sorgusu ve alınan hava durumu bilgileri kullanılarak kısa ve öz bir yanıt oluşturulur.
- Bu adım, kullanıcının sorduğu soruya en uygun ve net bir yanıtı sağlar.
İstanbul'da hava şu anda açık gökyüzüyle birlikte 27.68°C sıcaklıkta ve 10.8 m/s hızında esen 10°'lik bir rüzgarla devam ediyor. Nem oranı ise %65.
AgentState
kullanılarak verilerin her adımda izlenmesi ve saklanması sağlanır. Bu, her adımda elde edilen bilgilerin sonraki adımlara tutarlı bir şekilde aktarılmasını sağlar. AgentState
içerisindeki messages
dizisi, tüm iş akışının izlenebilirliğini sağlar. Her adımda eklenen mesajlar, iş akışının hangi aşamalardan geçtiğini ve hangi bilgilerin üretildiğini gösterir. Kullanıcının sorgusuna doğrudan ve net bir yanıt vermek, kullanıcı deneyimini iyileştirir. Kullanıcı sadece sorduğu sorunun yanıtını alır ve gereksiz bilgiden kaçınılır. Bu iş akışı, kullanıcıya daha tutarlı ve anlamlı yanıtlar vererek onların ihtiyaçlarını daha iyi karşılar.

Peki LangChain Agents mı yoksa LangGraph mı kullanmalıyım?
Büyük dil modellerinin (LLM) geliştirilmesi ve kullanımı, doğal dil işleme alanında önemli bir ilerleme kaydetmiştir. Bu bağlamda, LangChain ve LangGraph gibi çerçeveler, LLM tabanlı projelerde yaygın olarak kullanılmaktadır. Bu yazıda, her iki çerçevenin avantajları ve dezavantajları nesnel bir bakış açısıyla ele alınacaktır.
LangChain, özellikle büyük dil modelleri ile etkileşimde bulunmak için tasarlanmış bir çerçevedir. Başlıca özellikleri şunlardır:
- LangChain, LLM’nin belirli bir araç seti kullanarak planlama yapmasına olanak tanır. Bu, LLM’nin belirli görevleri yerine getirmek için hangi araçları ne zaman kullanacağını belirlemesini sağlar.
- Araç seti yaklaşımı sayesinde, farklı görevler için çeşitli araçların kolayca entegrasyonuna izin verir.
- Hızlı prototipleme ve denemeler için uygundur. Kullanıcıların hızlı bir şekilde çalışır prototipler geliştirmesine olanak tanır.
Ancak, LangChain’in bazı kısıtlamaları da bulunmaktadır:
- Ajanların dinamik ve serbest biçimli yapısı, üretim ortamlarında gerekli olan kontrol ve kısıtlamaları zorlaştırabilir.
- Verilerin güvenliğini sağlamak için ajanların veri erişimini sınırlamak zor olabilir.
LangGraph’ın Özellikleri ve Kullanım Alanları
- LangGraph, koşullu kenarlar ve döngüler kullanarak daha kontrollü bir işlem akışı sağlar. Bu, insan müdahalesi gerektiren durumlarda esneklik sağlar ve belirli adımlarda duraklamalar yapılmasına olanak tanır.
- Yürütme sırasında iletilen durumu kontrol etme yeteneği sunar. Bu, kullanıcı deneyimini iyileştirir ve süreç boyunca durum güncellemelerinin etkin bir şekilde iletilmesini sağlar.
- Daha kontrollü ve yapılandırılmış akışı sayesinde, LangGraph üretim ortamlarında kullanılmak için daha uygundur.
LangChain, hızlı prototipleme ve başlangıç geliştirmeleri için uygun bir çerçeve sunar. Araç seti yaklaşımı sayesinde esneklik sağlar ve LLM tabanlı projelerin hızlı bir şekilde hayata geçirilmesine yardımcı olur. Ancak, üretim ortamlarında gerekli olan kontrol ve veri güvenliği gereksinimlerini karşılamakta yetersiz kalabilir.
LangGraph ise daha kontrollü bir akış ve durum yönetimi sunarak, üretim ortamlarında kullanılmak üzere daha uygun bir çerçeve olarak öne çıkar. Kullanıcı müdahalesine izin veren ve süreç boyunca durum güncellemelerini etkin bir şekilde yöneten yapısı sayesinde, daha güvenli ve yapılandırılmış bir çalışma ortamı sağlar.
Sonuç olarak, hızlı prototipleme ve denemeler için LangChain tercih edilebilirken, üretim ortamlarında güvenlik ve kontrol gereksinimlerini karşılamak için LangGraph daha uygun bir seçenek olarak değerlendirilebilir. Bu iki çerçeve, farklı kullanım senaryolarına göre değerlendirilmelidir ve ihtiyaçlara göre uygun olan seçilmelidir.
Peki bence kim Thor, kim Loki? 😀
Thor, güç ve kuvvet sembolüdür, aynı zamanda hızlı ve doğrudan çözümler sunar. LangChain de bu özelliklere benzer şekilde, hızlı prototipleme ve dinamik planlama yetenekleriyle öne çıkar. Kullanıcılar, LangChain ile hızlıca sonuç alabilir ve projelerini hayata geçirebilirler. Ancak, bu süreçte kontrol eksikliği ve veri güvenliği gibi zorluklarla karşılaşabilirler.

Loki ise zekâ ve strateji sembolüdür, olayları daha ince detaylarıyla kontrol etmeyi tercih eder. LangGraph da benzer şekilde, daha kontrollü ve yapılandırılmış bir akış sunarak üretim ortamlarında güvenli ve esnek çözümler sağlar. LangGraph, kullanıcıların projelerinde daha fazla kontrol sahibi olmalarını ve süreç boyunca gerekli müdahaleleri yapabilmelerini sağlar.

LangChain’in gücü ve hızına (Thor) karşın, LangGraph’ın strateji ve kontrol yeteneklerini (Loki) vurgulamak mümkündür. İhtiyaçlarınıza ve projenizin gereksinimlerine göre, Thor’un gücünü mü yoksa Loki’nin zekâsını mı tercih edeceğinize karar verebilirsiniz. 🙂
Sevgiler,
Bir sonraki yazıda görüşmek üzere !
Kod
GitHub – KardelRuveyda/langgraph-exercises: My LangGraph Exercises 🦜🕸️
My LangGraph Exercises 🦜🕸️. Contribute to KardelRuveyda/langgraph-exercises development by creating an account on…github.com
Kaynakça
- https://langchain-ai.github.io/langgraph/
- https://blog.langchain.dev/langgraph/
- https://youtu.be/R8KB-Zcynxc?si=IS0C23dYnTZIEcRz
- https://youtu.be/qaWOwbFw3cs?si=RrDpn7u2EMxr7s1X
- https://youtu.be/PqS1kib7RTw?si=RTbV2YAo-4jOOVoc
- https://youtu.be/R-o_a6dvzQM?si=P4wqpG3TMl-_QBz0
- https://youtu.be/NZbgduKl9Zk?si=2OWNm45_-bYbLQTU
- https://www.softgrade.org/langchain-agents-vs-langgraph/