LCEL تعارف
LCEL (LangChain Expression Language) ایک طاقتور ورک فلو آرڈسٹریشن ٹول ہے جو آپ کو بُنیادی اجزاء سے مکمل ٹاسک چینز بنانے کی اجازت دیتا ہے اور اس میں پراکرتک فیچرز جیسے سٹریمنگ پروسیسنگ، متوازی پروسیسنگ، اور لاگنگ وغیرہ کی تعاون فراہم کرتا ہے۔
بنیادی مثال: Prompt + Model + Output Parser
اس مثال میں ہم آپ کو دکھائیں گے کے LCEL (LangChain Expression Language) کو کیسے استعمال کیا جاتا ہے تین اجزاء – پرامپٹ ٹیمپلیٹ، ماڈل، اور آؤٹپُٹ پارسر – کو ایک مکمل ورک فلو کے حصے کے طور پر اسٹاب ش کرنے کیلئے تا کے تصاویر بنایں کے تاس کی۔ اس کوڈ کا استعمال کرتے ہوئے دکھایا گیا ہے کہ کیسے چینز بنائیں جاتی ہین، پائپ سمبل |
کا استعمال کر کے مختلف اجزاء کو جوڑتے ہین، اور ہر اجزاء کا کردار اور آؤٹپُٹ کے نتائج کا مخصوص کردار کو متعارف کروایا گیا ہے۔
پہلے، چلتے ہیں کے ہم کس طرح پرامپٹ ٹیمپلیٹ اور ماڈل کو جوڑ کر ایک مخصوص موضوع پر مذاق بناتے ہین۔:
مسودے کول انسٹال کرو
%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("{مجھے وہ حالت بتاؤ جب میں {موضوع} کے بارے میں ٹارڈک مضمون پڑھ رہا تھا۔}")
model = ChatOpenAI(model="gpt-4")
output_parser = StrOutputParser()
chain = prompt | model | output_parser
chain.invoke({"topic": "ice cream"})
روپورٹ:
"مجے کیوں کسی موج پر ہر اسکا انوکھا وقت نہیں کیوں کہ یہ گرم ہوئے پر پگھل جاتا ہے!"
اس کوڈ میں ہم نے LCEL کا استعمال کر کے مختلف اجزاء کو ایک چین میں جوڑا ہے:
chain = prompt | model | output_parser
یہاں |
سمبل یونیکس پائپ آپریٹر کی طرح ہے، جو مختلف اجزاء کو ایک ساتھ جوڑتا ہے اور ایک اجزاء کا آؤٹپُٹ دوسرے اجزاء کے کیلئے ان پُٹ کے طور پر بھیجتا ہے
اس چین میں، یوزر ان پُٹ پرامپٹ ٹیمپلیٹ میں گئے، پھر پرامپٹ ٹیمپلیٹ کے آؤٹپُٹ کو ماڈل میں گیا، اور آخر میں ماڈل کا آؤٹپُٹ آؤٹپُٹ پارسر میں گیا۔ اس میں نظرانداز کریں کے ہر اجزاء کو علیحدہ کر کے م مخصوص کردار کو بہتر انداز میں سمجھنے کیلئے۔
1. پرامپٹ
prompt
ایک BasePromptTemplate
ہے جو ایک ٹیمپلیٹ متغیر ڈکشنری قبول کرتا ہے اور ایک PromptValue
پیدا کرتا ہے۔ PromptValue
ایک وراپڈ آبجیکٹ ہے جو پرامپٹ کو شامل کرتا ہے، جو کہ LLM
(اِن پُٹ کے طور پر ایک سٹرنگ فارم میں) یا ChatModel
(اس میں میسج سیکونیسیز کے فارم میں اِن پُٹ کے طور پر) کے لیئے پاس کیا جا سکتا ہے۔ یہ کسی بھی قسم کے لینگویج ماڈل کے ساتھ استعمال کیا جا سکتا ہے، کیوں کہ اس نے BaseMessage
ترتیب دینے کا لوجک ڈیفائن کیا ہوتا ہے، اور اس کو سٹرنگ بانانے کا راستہ بھی۔
prompt_value = prompt.invoke({"topic": "ice cream"})
prompt_value
روپورٹ
ChatPromptValue(messages=[HumanMessage(content='مجے وہ حالت بتاؤ جب میں موضوع کے بارے میں ٹارڈک مضمون پڑھ رہا تھا.')])
نیچے، ہم پرامپٹ-فارمیٹ کردہ نتیجے کو چیٹ ماڈلز میں استعمال ہونے والے میسج فارمیٹ میں تبدیل کرتے ہین:
prompt_value.to_messages()
روپورٹ
[HumanMessage(content='مجے وہ حالت بتاؤ جب میں موضوع کے بارے میں ٹارڈک مضمون پڑھ رہا تھا.')]
یہ سٹرنگ کے طور پر بھی سیدھے طور پر تبدیل کیا جا سکتا ہے:
prompt_value.to_string()
روپورٹ
'Human: مجے وہ حالت بتاؤ جب میں موضوع کے بارے میں ٹارڈک مضمون پڑھ رہا تھا.'
2. ماڈل
اگلے، PromptValue
کو model
میں پاس کریں۔ اس مثال میں، ہمارا model
ایک ChatModel
ہے، یعنی کہ یہ ایک BaseMessage
کو آوٹپُٹ کرے گا۔
ماڈل کو سیدھے طور پر بولانے کا کوشش کریں:
message = model.invoke(prompt_value)
message
ریٹرن کرتا ہے:
AIMessage(content="مجے کیوں کسی موج پر ہر اسکا انوکھا وقت نہیں کیوں کہ یہ گرم ہوئے پر پگھل جاتا ہے!")
اگر ہمارا model
ایک LLM
قسم کا ہوتا، تو یہ ایک سٹرنگ آوٹپُٹ کرتا۔
from langchain_openai.llms import OpenAI
llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm.invoke(prompt_value)
روپورٹ:
'\n\nبٹ: مجہے کیوں کسی ٹاکس گاڑی سے پاکی ڈاؤن ہوا؟ کیوں کہ یه میلٹ ڈاؤن رہا ہے!'
3. آؤٹپُٹ پارسر
آخر میں، ہمارے ماڈل
سے آؤٹپُٹ کو output_parser
میں پاس کریں، جو کے ایک BaseOutputParser
ہے، یعنی کے وہ ایک سٹرنگ یا BaseMessage
کو آوٹپُٹ کے طور پر قبول کرتا ہے۔ StrOutputParser
خاص طور پر کسی بھی ان پُٹ کو ایک سادہ سٹرنگ میں بدلتا ہے۔
output_parser.invoke(message)
مجے کیوں کسی موج پر ہر اسکا انوکھا وقت نہیں کیوں کہ یہ گرم ہوئے پر پگھل جاتا ہے!
4. تمام عمل
انجام پانے کا عمل مندرجہ ذیل ہے:
-
chain.invoke({"topic": "ice cream"})
کو بلائیں، جو ہم نے تعین کیا ہے اور پیرامیٹر{"topic": "ice cream"}
کو منتقل کرنا ہوتا ہے تاکہ "ice cream" کے بارے میں ایک لطیفہ پیدا ہو سکے۔ - پہلے چین کے پہلے کمپوننٹ
prompt
کو کال پیرامیٹر{"topic": "ice cream"}
سے گزاریں، جو پرامپت ٹیمپلیٹ کو فارمیٹ کرتا ہے اور پرامپٹTell me a little joke about ice cream
حاصل کرتا ہے۔ - پرامپٹ
Tell me a little joke about ice cream
کوmodel
(gpt4 model) کو گزاریں۔ -
model
کی طرف سے واپسی کردہ نتیجے کوoutput_parser
پرسر کرتا ہے، جو ماڈل نتیجے کو فارمیٹ کرتا ہے اور حتمی مواد واپس کرتا ہے۔
اگر آپ کسی کمپوننٹ کے افراطی نتائج سے دلچسپی رکھتے ہیں، تو آپ ہر وقت چین کا ایک چھوٹا سا ورژن ٹیسٹ کرسکتے ہیں، جیسے prompt
یا prompt | model
، تاکہ آپ بیچ کے نتائج دیکھ سکیں۔
input = {"topic": "ice cream"}
prompt.invoke(input)
(prompt | model).invoke(input)
RAG Search Example
اب، ہم ایک تھوڑی سی مشکل LCEL مثال کا وضاحت کریں گے۔ ہم سوالات کے جواب دیتے وقت کچھ پس منظر کی معلومات شامل کرنے کے لئے، مضبوط اندراج سے چینز کی تخلیق کرنے کے لئے مضبوط اندراج کا مثال دیں گے۔
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 = """محض مندرجہ ذیل سیاق و سباق کے بنیاد پر سوال کا جواب دیں:
{context}
Question: {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("where did harrison work?")
اس صورت میں، تشکیل شدہ چین:
chain = setup_and_retrieval | prompt | model | output_parser
سادہ طور پر، فوقی پرامپٹ ٹیمپلیٹ context
اور question
کو قبول کرتا ہے تاکہ وہ پرامپت بنا سکے۔ پرامپٹ ٹیمپلیٹ تخلیق سے پہلے، ہم چاہتے ہیں کہ متعلقہ دستاویزات حاصل کرنے کے لئے مضبوط اندراج سے دستاویزات کو حاصل کریں۔
ایک ٹیسٹ کے لئے، ہم DocArrayInMemorySearch
کا استعمال کرتے ہیں تاکہ memory-based vector ڈیٹا بیس کا جعلی بنا سکیں، ریٹریوور کو معین کرتے ہیں جو سوال کے بنیاد پر مماثل دستاویزات کو حاصل کر سکے۔ یہ بھی ایک chainable runnable کمپوننٹ ہے، لیکن آپ اسے علیحدہ طور پر بھی چلا سکتے ہیں:
retriever.invoke("where did harrison work?")
پھر ہم RunnableParallel
کا استعمال کرتے ہیں تاکہ پرامپٹ کے لئے اندراج تیار کریں، retretry کے ذریعہ مماثل دستاویزات کو تلاش کریں، اور RunnablePassthrough
کے ذریعہ صارف کا سوال منتقل کریں:
setup_and_retrieval = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
)
خلاصہ کے طور پر، مکمل چین کی تشکیل یہ ہے:
setup_and_retrieval = RunnableParallel(
{"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parser
عمل مندرجہ ذیل ہے:
- پہلے،
RunnableParallel
آبجیکٹ بنائیں جو دو اندراجات شامل کرتا ہے۔ پہلا اندراجcontext
وہ دستویزات شامل کرے گا جو ریٹریوور کے ذریعہ یاکساں کئے گئے نتائج ہیں۔ دوسرا اندراجquestion
صارف کا اصل سوال ہو گا۔ تاکہ سوال منتقل ہو، ہمRunnablePassthrough
کا استعمال کرتے ہیں۔ - پچھلے مرحلہ کی ڈکشنری کو
prompt
کمپوننٹ کو گزاریں۔ یہ صارف کا دخل (مثلاًquestion
) بھی قبول کرتا ہے اور حاصل شدہ دستاویزات (مثال کے طور پرcontext
) کو فارمیٹ کرتا ہے اورPromptValue
کو ابجیکٹ کو نکالتا ہے۔ - ماڈل کمپوننٹ حاصل شدہ پرامپٹ کو لے کر اسے OpenAI کے LLM ماڈل کو جانچنے کے لئے پاس کرتا ہے۔ ماڈل کی طرف سے حاصل شدے نتائج کا ایک
ChatMessage
خودرو بنا دیا جاتا ہے۔ - آخر میں،
output_parser
کمپوننٹ ایکChatMessage
لے گا، اسے Python سٹرنگ میں تبدیل کرے گا اورinvoke
میں سے اسے واپس دے گا۔