1. การแนะนำเกี่ยวกับ LCEL

LCEL (LangChain Expression Language) เป็นโครงสร้างที่ง่ายและใช้ง่ายสำหรับการสร้างเส้นเชือดที่ซับซ้อน มันมีอินเตอร์เฟซที่เป็นไปได้และหลายฟังก์ชันเบื้องต้นเพื่อทำให้การสร้างเส้นเชือดเป็นเรื่องง่ายขึ้น แต่ละอ็อบเจ็กต์ของ LCEL นำไอ้มพลีเมนท์ของ Runnable interface ซึ่งกำหนดชุดของเมทอดที่ใช้บ่อย (เช่น 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 เป็นไปได้ง่ายมากขึ้น รายการโค้ดต่อไปนี้สาธิตถึงวิธีการสตรีมด้วย 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(["ไอศครีม", "สปาเก็ตตี้", "เกี้ยว"])