LCEL
Espero que eu tenha conseguido explicar bem o que
faz o LangChain e tenha
sido convincente sobre o por que
de usarmos uma ferramenta como ele, pois
agora vamos para o como
.
Na semana passada, exploramos alguns exemplos simples utilizando o Langchain. Dessa vez, vamos olhar para o abismo de mais uma abstração desnecessariamente complexa: o LangChain Expression Language (LCEL).
Não vou ficar reproduzindo exatamente o que é dito na documentação do LangChain. Se quiser ver a explicação canônica, vai até lá e leia. Aqui eu vou só explicar o motivo de eu seguir no meu material utilizando essa linguagem em vez de continuar no modo "antigo" de se trabalhar com o Langchain. Seguem os meus principais motivos:
- Suporte à chamadas assíncronas com mais facilidade;
- Linguagem mais sucinta para trabalhar com o
Streamable callback
; e - Material preparado para o futuro. É. Eu não quero ter que reescrever isso aqui =P
1. Chain simples
Vamos começar com o encadeamento mais simples possível:
input ---> [prompt] ---> [modelo] ---> output
Em todos os nossos exemplos, vamos usar majoritariamente o stream
, pois é o
que acredito fazer mais sentido para a nossa aplicação.
O protocolo utilizado como base para quase tudo no LCEL é o Runnable
. Com
ele, é possível encadear etapas de uma corrente e até mesmo executá-las de uma
forma relativamente sucinta. Vamos ver o exemplo mais básico:
- OpenAI
- Ollama
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
model = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_template(
"""
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. For each item, create a simple sentence
justifying this choice.
"""
)
chain = prompt | model
for s in chain.stream({"activity": "eat live fish"}):
print(s.content, end="", flush=True)
from langchain.llms import Ollama
from langchain.prompts import ChatPromptTemplate
model = Ollama(model="mistral")
prompt = ChatPromptTemplate.from_template(
"""
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. For each item, create a simple sentence
justifying this choice.
"""
)
chain = prompt | model
for s in chain.stream({"activity": "eat live fish"}):
print(s, end="", flush=True)
Para poder usar o código acima com a API da OpenAI, lembre-se de configurar a sua chave de API no sistema.
2. Encadeando múltiplos modelos
Agora vamos recriar o nosso exemplo com o tradutor
e o agente
:
- OpenAI
- Ollama
from langchain.chat_models import ChatOpenAI
from langchain.llms import Ollama
from langchain.prompts import ChatPromptTemplate
model1 = ChatOpenAI(model="gpt-3.5-turbo")
model2 = ChatOpenAI(model="gpt-4")
prompt1 = ChatPromptTemplate.from_template("""
Apenas traduza o texto a seguir:
{text}
"""
)
prompt2 = ChatPromptTemplate.from_template( """
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. Only respond with the list of 5 items, no
summarizing statement, forewords or warnings or even explanations are required.
"""
)
chain1 = prompt1 | model1
chain2 = {"activity": chain1} | prompt2 | model2
chain3 = {"text": chain2} | prompt1 | model1
for s in chain3.stream({"text": "caminhar na praia"}):
print(s.content, end="", flush=True)
print()
from langchain.llms import Ollama
from langchain.prompts import ChatPromptTemplate
model1 = Ollama(model="mistral")
model2 = Ollama(model="dolphin2.2-mistral")
prompt1 = ChatPromptTemplate.from_template("""
Apenas traduza o texto a seguir:
{text}
"""
)
prompt2 = ChatPromptTemplate.from_template( """
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. Only respond with the list of 5 items, no
summarizing statement, forewords or warnings or even explanations are required.
"""
)
chain1 = prompt1 | model2
chain2 = {"activity": chain1} | prompt2 | model1
chain3 = {"text": chain2} | prompt1 | model2
for s in chain3.stream({"text": "caminhar na praia"}):
print(s, end="", flush=True)
print()
3. Runnable passthroughs
Existe uma maneira alternativa de chamar o método stream
para aqueles que não
gostam do fato dele precisar de um dicionário para ser chamado. Se você está
entre essas pessoas, seus problemas foram resolvidos! Behold:
- Exemplo simples
- Encadeamento
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap, RunnablePassthrough
model = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_template(
"""
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. For each item, create a simple sentence
justifying this choice.
"""
)
chain = {"activity": RunnablePassthrough()} | prompt | model
for s in chain.stream("eat live fish"):
print(s.content, end="", flush=True)
from langchain.chat_models import ChatOpenAI
from langchain.llms import Ollama
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap, RunnablePassthrough
model1 = ChatOpenAI(model="gpt-3.5-turbo")
model2 = ChatOpenAI(model="gpt-4")
prompt1 = ChatPromptTemplate.from_template("""
Apenas traduza o texto a seguir:
{text}
"""
)
prompt2 = ChatPromptTemplate.from_template( """
You are now my personal travel agent. Act as someone who has immense travel
experience and knows the best places in the world to do certain activities. I
want to know where I should go to {activity}. Give the answers as a list of
items, no bigger than 5 items. Only respond with the list of 5 items, no
summarizing statement, forewords or warnings or even explanations are required.
"""
)
chain1 = {"text": RunnablePassthrough()} | prompt1 | model1
chain2 = {"activity": chain1} | prompt2 | model2
chain3 = {"text": chain2} | prompt1 | model1
for s in chain3.stream("caminhar na praia"):
print(s.content, end="", flush=True)
print()
Não coloquei como se usa o ollama com Runnable passthroughs, mas confio em vocês para fazer essa inferência sozinhos! =D