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. تمام عمل

انجام پانے کا عمل مندرجہ ذیل ہے:

  1. chain.invoke({"topic": "ice cream"}) کو بلائیں، جو ہم نے تعین کیا ہے اور پیرامیٹر {"topic": "ice cream"} کو منتقل کرنا ہوتا ہے تاکہ "ice cream" کے بارے میں ایک لطیفہ پیدا ہو سکے۔
  2. پہلے چین کے پہلے کمپوننٹ prompt کو کال پیرامیٹر {"topic": "ice cream"} سے گزاریں، جو پرامپت ٹیمپلیٹ کو فارمیٹ کرتا ہے اور پرامپٹ Tell me a little joke about ice cream حاصل کرتا ہے۔
  3. پرامپٹ Tell me a little joke about ice cream کو model (gpt4 model) کو گزاریں۔
  4. 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

عمل مندرجہ ذیل ہے:

  1. پہلے، RunnableParallel آبجیکٹ بنائیں جو دو اندراجات شامل کرتا ہے۔ پہلا اندراج context وہ دستویزات شامل کرے گا جو ریٹریوور کے ذریعہ یاکساں کئے گئے نتائج ہیں۔ دوسرا اندراج question صارف کا اصل سوال ہو گا۔ تاکہ سوال منتقل ہو، ہم RunnablePassthrough کا استعمال کرتے ہیں۔
  2. پچھلے مرحلہ کی ڈکشنری کو prompt کمپوننٹ کو گزاریں۔ یہ صارف کا دخل (مثلاً question) بھی قبول کرتا ہے اور حاصل شدہ دستاویزات (مثال کے طور پر context) کو فارمیٹ کرتا ہے اور PromptValue کو ابجیکٹ کو نکالتا ہے۔
  3. ماڈل کمپوننٹ حاصل شدہ پرامپٹ کو لے کر اسے OpenAI کے LLM ماڈل کو جانچنے کے لئے پاس کرتا ہے۔ ماڈل کی طرف سے حاصل شدے نتائج کا ایک ChatMessage خودرو بنا دیا جاتا ہے۔
  4. آخر میں، output_parser کمپوننٹ ایک ChatMessage لے گا، اسے Python سٹرنگ میں تبدیل کرے گا اور invoke میں سے اسے واپس دے گا۔