1. Introdução ao LCEL
LCEL (LangChain Expression Language) é um framework simples e fácil de usar para construir cadeias complexas. Ele fornece uma interface unificada e primitivas compostas para facilitar a construção de cadeias. Cada objeto LCEL implementa a interface Runnable
, definindo um conjunto de métodos de invocação comumente utilizados (como invoke
, batch
, stream
, ainvoke
, etc.). Portanto, as cadeias de objetos LCEL também podem suportar automaticamente esses métodos de invocação, tornando a própria cadeia de cada objeto LCEL um objeto LCEL.
2. Invocação
2.1. Sem usar LCEL
Sem utilizar o LCEL, você pode usar o trecho de código a seguir para passar uma string de tópico e recuperar uma string de piada.
from typing import List
import openai
prompt_template = "Conta uma piada curta sobre {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("sorvete")
2.2. Usando o LCEL
Por outro lado, usando o LCEL, é possível alcançar a mesma funcionalidade de forma mais concisa. O trecho de código a seguir demonstra como construir facilmente uma cadeia usando objetos 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(
"Conta uma piada curta sobre {topic}"
)
output_parser = StrOutputParser()
model = ChatOpenAI(model="gpt-3.5-turbo")
chain = (
{"topic": RunnablePassthrough()}
| prompt
| model
| output_parser
)
chain.invoke("sorvete")
3. Streaming
3.1. Sem usar LCEL
O trecho de código a seguir demonstra como transmitir os resultados do processo sem usar o 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("sorvete")
3.2. Usando o LCEL
A transmissão dos resultados do processo usando o LCEL é mais conveniente. O trecho de código a seguir demonstra como fazer streaming com o LCEL.
for chunk in chain.stream("sorvete"):
print(chunk, end="", flush=True)
4. Processamento em Lote
4.1. Sem usar LCEL
O trecho de código a seguir demonstra como processar em paralelo um lote de entradas sem usar o 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(["sorvete", "espaguete", "dumplings"])
4.2. Usando o LCEL
O processamento em lote usando o LCEL é muito direto. O trecho de código a seguir demonstra como usar o LCEL para processamento em lote.
chain.batch(["sorvete", "espaguete", "dumplings"])