LCEL Tanıtımı
LCEL (LangChain Expression Language), temel bileşenlerden karmaşık görev zincirleri oluşturmanıza izin veren güçlü bir iş akışı orkestrasyon aracıdır ve akış işleme, eş zamanlı işleme ve günlüğe alma gibi özellikleri destekler.
Temel Örnek: İstekte Bulunma + Model + Çıktı Ayrıştırıcı
Bu örnekte, LCEL (LangChain Expression Language) kullanarak prompt şablonu, model ve çıktı ayrıştırıcı gibi üç bileşeni bir araya getirerek "şaka anlatma" görevini uygulamak için tam bir iş akışı oluşturmayı göstereceğiz. Kod, zincirler oluşturmayı, farklı bileşenleri bağlamak için boru (|) sembolünü kullanmayı ve her bileşenin rolünü ve çıktı sonuçlarını tanıtmayı göstermektedir.
İlk olarak, prompt şablonunu ve modeli bir araya getirerek belirli bir konu hakkında şaka oluşturmayı gösterelim:
Gereksinimleri yükleyin
%pip install --upgrade --quiet langchain-core langchain-community langchain-openai
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("Bana {topic} ile ilgili bir şaka anlat")
model = ChatOpenAI(model="gpt-4")
output_parser = StrOutputParser()
chain = prompt | model | output_parser
chain.invoke({"topic": "dondurma"})
Çıktı
"Neden partilere dondurma çağırmaz? Çünkü sıcak olduğunda erir!"
Bu kodda, farklı bileşenleri bir zincir halinde birleştirmek için LCEL kullanıyoruz:
chain = prompt | model | output_parser
Buradaki |
sembolü, Unix boru işlemcisi'ne benzer şekilde farklı bileşenleri birbirine bağlar ve bir bileşenin çıktısını diğer bileşenin girdisi olarak iletilir.
Bu zincirde, kullanıcı girdisi prompt şablonuna iletilir, ardından prompt şablonunun çıktısı modele iletilir ve son olarak modelin çıktısı çıktı ayrıştırıcıya iletilir. Olup biteni daha iyi anlamak için her bir bileşene ayrı ayrı bakalım.
1. Prompt
prompt
, şablon değişkenlerini kabul eden bir BasePromptTemplate
'dir ve bir PromptValue
üretir. PromptValue
, dize üreten platformlar için mantık tanımlayan tüm dil modelleriyle kullanılabilir çünkü BaseMessage
üreten ve dize üreten mantığı tanımlar.
prompt_value = prompt.invoke({"topic": "dondurma"})
prompt_value
Çıktı
ChatPromptValue(messages=[HumanMessage(content='Bana dondurma ile ilgili bir şaka anlat')])
Aşağıda, prompt biçimli sonucu sohbet modelleri tarafından kullanılan mesaj biçimine dönüştürüyoruz:
prompt_value.to_messages()
Çıktı
[HumanMessage(content='Bana dondurma ile ilgili bir şaka anlat')]
Aynı zamanda doğrudan bir dizeye de dönüştürülebilir:
prompt_value.to_string()
Çıktı
'İnsan: Bana dondurma ile ilgili bir şaka anlat.'
2. Model
Şimdi, PromptValue
'yi model
e geçirelim. Bu örnekte, modelimiz ChatModel
'dir, bu da bir BaseMessage
çıktısı vereceği anlamına gelir.
Modeli doğrudan çağırmayı deneyin:
message = model.invoke(prompt_value)
message
Döndürür:
AIMessage(content="Neden partilere dondurma çağırmaz? Çünkü sıcak olduğunda erir!")
Eğer modelimiz bir LLM
türü olarak tanımlanmışsa, birden fazla dize çıktısı verecektir.
from langchain_openai.llms import OpenAI
llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm.invoke(prompt_value)
Model çıktısı:
'\n\nBot: Dondurma arabası neden bozuldu? Çünkü erimeye başladı!'
3. Çıktı Ayrıştırıcı
Son olarak, model
den gelen çıktıyı output_parser
'a iletelim, bu da bir BaseOutputParser
'dır, yani bir dize veya BaseMessage
'ı girdi olarak kabul eder. StrOutputParser
özellikle herhangi bir girdiyi basit bir dizeye dönüştürür.
output_parser.invoke(message)
Neden partilere dondurma çağırmaz? \n\nÇünkü sıcak olduğunda erir!
4. Tüm Süreç
Yürütme süreci şöyledir:
-
chain.invoke({"topic": "dondurma"})
çağrısını yapın, bu, tanımladığımız iş akışını başlatmak ve{"topic": "dondurma"}
parametresini geçerek "dondurma" ile ilgili bir şaka oluşturmak anlamına gelir. - Çağrı parametresi
{"topic": "dondurma"}
'ı zincirin ilk bileşeni olanprompt
'a geçirin, bu da görev şablonunu biçimlendirerekTell me a little joke about ice cream
görevini elde etmek için geçerli bir şekilde biçimlendirir. -
Tell me a little joke about ice cream
görevinimodel
(gpt4 modeli)'ye iletin. -
model
tarafından döndürülen sonucuoutput_parser
çıkış analizine ileterek model sonucunu biçimlendirir ve nihai içeriği döndürür.
Herhangi bir bileşenin çıktısına ilginiz varsa, herhangi bir zamanda zincirin daha küçük bir sürümünü test etmek için prompt
veya prompt | model
gibi bir şeyi deneyebilirsiniz:
input = {"topic": "dondurma"}
prompt.invoke(input)
(prompt | model).invoke(input)
RAG Arama Örneği
Şimdi, biraz daha karmaşık bir LCEL örneğini açıklamak istiyoruz. Soruları cevaplarken arka plan bilgisi eklemek için zincirler oluşturmak için geliştirilmiş bir geri alım örneğini çalıştıracağız.
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_openai.chat_models import ChatOpenAI
from langchain_openai.embeddings import OpenAIEmbeddings
vectorstore = DocArrayInMemorySearch.from_texts(
["harrison worked at kensho", "bears like to eat honey"],
embedding=OpenAIEmbeddings(),
)
retriever = vectorstore.as_retriever()
template = """Sadece aşağıdaki bağlam temel alınarak soruyu cevaplayın:
{context}
Soru: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI()
output_parser = StrOutputParser()
setup_and_retrieval = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parser
chain.invoke("harrison hangi şirkette çalıştı?")
Bu durumda, oluşturulmuş zincir şöyle:
chain = setup_and_retrieval | prompt | model | output_parser
Basitçe, yukarıdaki görev şablonu context
ve question
değerlerini yerine koymak için kullanır. Görev şablonunu oluşturmadan önce, cevap olarak kullanmak amacıyla ilgili belgeleri almak istiyoruz.
Bir test olarak, DocArrayInMemorySearch
'ü kullanarak bellek tabanlı bir vektör veritabanını taklit etmek için bir alır oluştururuz, sorgulara dayalı benzer belgeleri alabilen bir getirici tanımlarız. Bu da zincirlenebilir bir çalıştırılabilir bileşendir, ancak ayrı çalıştırmayı da deneyebilirsiniz:
retriever.invoke("harrison hangi şirkette çalıştı?")
Daha sonra, görev için girdiyi hazırlamak için RunnableParallel
'ı kullanırız, getiriciyi kullanarak belgeleri arar ve kullanıcının sorusunu RunnablePassthrough
kullanarak geçiririz:
setup_and_retrieval = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
)
Özetle, tam zincir şu şekildedir:
setup_and_retrieval = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parser
Süreç şöyledir:
- İlk olarak,
RunnableParallel
içerisinde iki girdi içeren bir nesne oluşturun. İlk giriş olancontext
getirici tarafından çıkarılan belge sonuçlarını içerecektir. İkinci giriş olanquestion
ise kullanıcının orijinal sorusunu içerecektir. Soruyu iletmek için bu girdiyi kopyalamak içinRunnablePassthrough
kullanırız. - Önceki adımda elde edilen sözlüğü
prompt
bileşenine iletin. Bu, kullanıcı girişini (yaniquestion
) ve elde edilen belgeleri (yanicontext
) kabul eder, bir görev oluşturur ve birPromptValue
çıktısı verir. -
model
bileşeni oluşturulan görevi alır ve OpenAI'nın LLM modeline değerlendirme için ileterek işletir. Model tarafından üretilen çıktı birChatMessage
nesnesidir. - Son olarak,
output_parser
bileşeni birChatMessage
alır, bunu Python dizesine dönüştürür veinvoke
yönteminden döndürür.