1. مقدمة في LCEL

LCEL (لغة تعبير سلسلة) هي إطار عمل بسيط وسهل الاستخدام لبناء سلاسل معقدة. يوفر واجهة موحدة وأساسيات مركبة لتسهيل بناء السلاسل. ينفذ كل كائن LCEL واجهة Runnable، حيث يعرّف مجموعة من طرق الاستدعاء المستخدمة بشكل شائع (مثل invoke، batch، stream، ainvoke، إلخ). لذلك، يمكن لسلاسل كائنات LCEL أيضًا دعم هذه الطرق تلقائيًا، مما يجعل سلسلة كل كائن LCEL ذاته كائن LCEL.

2. الاستدعاء

2.1. بدون استخدام LCEL

بدون استخدام LCEL، يمكنك استخدام مقتطف الكود التالي لتمرير سلسلة موضوع واسترداد سلسلة نكتة.

from typing import List
import openai

prompt_template = "قل لي نكتة قصيرة عن {topic}"
client = openai.OpenAI()

def call_chat_model(messages: List[dict]) -> str:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", 
        messages=messages,
    )
    return response.choices[0].message.content

def invoke_chain(topic: str) -> str:
    prompt_value = prompt_template.format(topic=topic)
    messages = [{"role": "user", "content": prompt_value}]
    return call_chat_model(messages)

invoke_chain("آيس كريم")

2.2. باستخدام LCEL

بالمقابل، يمكن بواسطة LCEL تحقيق نفس الوظيفة بشكل أكثر إيجازًا. يوضح مقتطف الكود التالي كيفية بناء سلسلة بسهولة باستخدام كائنات LCEL.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

prompt = ChatPromptTemplate.from_template(
    "قل لي نكتة قصيرة عن {topic}"
)
output_parser = StrOutputParser()
model = ChatOpenAI(model="gpt-3.5-turbo")
chain = (
    {"topic": RunnablePassthrough()} 
    | prompt
    | model
    | output_parser
)

chain.invoke("آيس كريم")

3. التدفق

3.1. بدون استخدام LCEL

يوضح مقتطف الكود التالي كيفية تدفق نتائج المعالجة بدون استخدام LCEL.

from typing import Iterator

def stream_chat_model(messages: List[dict]) -> Iterator[str]:
    stream = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=messages,
        stream=True,
    )
    for response in stream:
        content = response.choices[0].delta.content
        if content is not None:
            yield content

def stream_chain(topic: str) -> Iterator[str]:
    prompt_value = prompt.format(topic=topic)
    stream = stream_chat_model([{"role": "user", "content": prompt_value}])
    for chunk in stream:
        print(chunk, end="", flush=True)

stream_chain("آيس كريم")

3.2. باستخدام LCEL

يوضح مقتطف الكود التالي كيفية تدفق باستخدام LCEL.

for chunk in chain.stream("آيس كريم"):
    print(chunk, end="", flush=True)

4. معالجة الدُفعة

4.1. بدون استخدام LCEL

يوضح مقتطف الكود التالي كيفية معالجة متوازية لدُفعة من المدخلات بدون استخدام LCEL.

from concurrent.futures import ThreadPoolExecutor

def batch_chain(topics: list) -> list:
    with ThreadPoolExecutor(max_workers=5) as executor:
        return list(executor.map(invoke_chain, topics))

batch_chain(["آيس كريم", "مكرونة", "فطائر"])

4.2. باستخدام LCEL

معالجة الدُفعة باستخدام LCEL مباشرة. يوضح مقتطف الكود التالي كيفية استخدام LCEL لمعالجة الدُفعة.

chain.batch(["آيس كريم", "مكرونة", "فطائر"])