Cadeias ramificadas e paralelas
Crie estruturas RunnableParallel e RunnableBranch para executar várias cadeias simultaneamente ou encaminhar a entrada para diferentes cadeias com base em condições dinâmicas.
Cadeias ramificadas e paralelas é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.
Por que o processamento paralelo e as ramificações são importantes
Os pipelines de LLM do mundo real geralmente precisam fazer várias coisas ao mesmo tempo ou encaminhar as solicitações de maneiras diferentes com base no conteúdo. Cadeias paralelas executam várias ramificações simultaneamente, reduzindo a latência quando as tarefas são independentes. Cadeias com ramificações encaminham a entrada para diferentes cadeias especializadas com base em condições dinâmicas. A LCEL oferece suporte nativo aos dois padrões com RunnableParallel e RunnableBranch.
Fundamentos de RunnableParallel
RunnableParallel recebe um dicionário no qual cada chave corresponde a um componente executável. Quando invocado, ele executa todas as ramificações simultaneamente e retorna um dicionário em que cada chave contém o resultado da respectiva ramificação. É ideal quando você deseja gerar várias saídas a partir da mesma entrada — por exemplo, gerar um resumo e extrair palavras-chave simultaneamente.
from langchain_core.runnables import RunnableParallel
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
model = ChatOpenAI(model='gpt-4o-mini')
parser = StrOutputParser()
parallel = RunnableParallel(
summary=(
ChatPromptTemplate.from_template('Summarize: {text}') | model | parser
),
keywords=(
ChatPromptTemplate.from_template('Extract keywords from: {text}') | model | parser
)
)
result = parallel.invoke({'text': 'Long document text here...'})
print(result['summary'])
print(result['keywords'])Paralelismo com a forma abreviada de dicionário
A LCEL oferece uma forma abreviada conveniente: passar um dict simples como etapa em uma cadeia de tubos o encapsula automaticamente em RunnableParallel. Isso torna as ramificações paralelas naturais e elimina a instanciação explícita da classe. As chaves do dicionário tornam-se as chaves do resultado, e os valores são as ramificações executadas simultaneamente.
from langchain_core.runnables import RunnablePassthrough
# Dict shorthand creates RunnableParallel automatically
chain = (
RunnablePassthrough.assign(
sentiment=(
ChatPromptTemplate.from_template('Sentiment of: {review}')
| model | parser
),
aspects=(
ChatPromptTemplate.from_template('List aspects mentioned in: {review}')
| model | parser
)
)
)
result = chain.invoke({'review': 'Great battery but poor camera quality.'})
print(result['sentiment'])
print(result['aspects'])Entendendo RunnableBranch
RunnableBranch encaminha a entrada para diferentes cadeias com base em uma condição. Você fornece uma lista de pares (condition, runnable) e um componente executável padrão. A ramificação avalia as condições na ordem e executa a primeira ramificação correspondente. Isso permite o roteamento baseado na intenção — enviando consultas de atendimento ao cliente para uma cadeia de suporte e perguntas técnicas para uma cadeia de documentação.
from langchain_core.runnables import RunnableBranch
technical_chain = (
ChatPromptTemplate.from_template('Technical answer: {query}') | model | parser
)
general_chain = (
ChatPromptTemplate.from_template('General answer: {query}') | model | parser
)
branch = RunnableBranch(
(lambda x: 'error' in x['query'].lower() or 'bug' in x['query'].lower(),
technical_chain),
general_chain # default branch
)
result = branch.invoke({'query': 'I got a TypeError in my code'})
# Routes to technical_chain because 'error' is in the queryRoteamento semântico com classificação por LLM
Um padrão de roteamento mais flexível usa uma chamada de classificação por LLM para determinar qual ramificação utilizar. Primeiro, o roteador chama um modelo pequeno para classificar a intenção da entrada; depois, usa essa classificação para encaminhar a solicitação à cadeia especializada apropriada. Isso lida com casos sutis que a correspondência de palavras-chave não identifica, ao custo de uma chamada adicional à API.
from langchain_core.output_parsers import StrOutputParser
# Step 1: classify intent
classify_prompt = ChatPromptTemplate.from_template(
'Classify this query as exactly one of: billing, technical, general.\nQuery: {query}'
)
classifier = classify_prompt | model | StrOutputParser()
# Step 2: route based on classification
def route(classification_result: dict):
topic = classification_result['topic'].strip().lower()
if topic == 'billing':
return billing_chain
elif topic == 'technical':
return technical_chain
return general_chain
full_chain = (
RunnablePassthrough.assign(topic=lambda x: classifier.invoke(x))
| RunnableLambda(route)
)RAG paralelo: vários recuperadores
Em sistemas RAG avançados, pode ser necessário recuperar dados de várias fontes simultaneamente e combinar os resultados. RunnableParallel permite consultar ao mesmo tempo um banco de dados de produtos, um armazenamento de FAQ e um índice de documentação. Em seguida, uma etapa de combinação reúne os principais resultados antes de passar o contexto ao LLM, oferecendo ao modelo uma base de informações mais rica.
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
# Assume these retrievers are already set up
faq_retriever = faq_vectorstore.as_retriever(search_kwargs={'k': 3})
doc_retriever = doc_vectorstore.as_retriever(search_kwargs={'k': 3})
retrieval = RunnableParallel(
faq_results=faq_retriever,
doc_results=doc_retriever
)
def merge_docs(retrieved: dict) -> str:
all_docs = retrieved['faq_results'] + retrieved['doc_results']
return '\n\n'.join(d.page_content for d in all_docs)
pipeline = (
retrieval
| RunnableLambda(merge_docs)
| ChatPromptTemplate.from_template('Context: {context}\nAnswer: {question}')
| model | parser
)Cadeias condicionais com itemgetter
Quando precisar selecionar uma chave específica de um resultado paralelo ou passar apenas parte do contexto para a próxima etapa, o operator.itemgetter do Python funciona como um seletor Runnable leve. Isso é útil após uma etapa paralela, quando diferentes ramificações produzem chaves diferentes e você precisa extrair apenas a relevante para a próxima fase do processamento.
from operator import itemgetter
from langchain_core.runnables import RunnablePassthrough
# After a parallel step, extract just the summary
chain = (
RunnableParallel(
summary=summary_chain,
sentiment=sentiment_chain
)
| itemgetter('summary') # pass only the summary onward
| translate_chain
)
# itemgetter works because dict.__getitem__ is a valid transformMedindo o ganho de velocidade em paralelo
O principal benefício de RunnableParallel é a redução do tempo total de execução. Três chamadas sequenciais a LLM que levam 2 segundos cada demorariam 6 segundos no total. Em paralelo, elas são concluídas em aproximadamente 2 segundos — o tempo da ramificação mais lenta. No entanto, as chamadas paralelas multiplicam o uso de tokens de uma só vez; portanto, fique atento aos limites de taxa. Use max_concurrency em batch() ou defina limites de taxa por chave, se necessário.
import time
# Measure sequential time
start = time.time()
result1 = chain_a.invoke(input_data)
result2 = chain_b.invoke(input_data)
result3 = chain_c.invoke(input_data)
seq_time = time.time() - start
print(f'Sequential: {seq_time:.2f}s')
# Measure parallel time
start = time.time()
results = RunnableParallel(a=chain_a, b=chain_b, c=chain_c).invoke(input_data)
par_time = time.time() - start
print(f'Parallel: {par_time:.2f}s')
print(f'Speedup: {seq_time/par_time:.1f}x')Cadeias paralelas assíncronas
Para uma execução paralela realmente não bloqueante em aplicações assíncronas, use RunnableParallel.ainvoke(). Internamente, o LCEL usa asyncio.gather() para executar as ramificações simultaneamente no loop de eventos. Isso é especialmente importante em serviços FastAPI, nos quais cada manipulador de requisição é uma corrotina — usar a interface assíncrona evita o bloqueio do loop de eventos mesmo com várias chamadas simultâneas a LLM.
import asyncio
async def analyze_document(text: str) -> dict:
parallel = RunnableParallel(
summary=summary_chain,
keywords=keyword_chain,
sentiment=sentiment_chain
)
# All three chains run concurrently with asyncio.gather internally
result = await parallel.ainvoke({'text': text})
return result
# In FastAPI:
from fastapi import FastAPI
app = FastAPI()
@app.post('/analyze')
async def analyze(request: dict):
return await analyze_document(request['text'])Aninhando cadeias paralelas e sequenciais
Cadeias complexas frequentemente combinam etapas sequenciais e paralelas. Você pode aninhar RunnableParallel dentro de um encadeamento sequencial e vice-versa. Por exemplo: classificar a intenção (sequencialmente), executar a recuperação e a formatação do contexto em paralelo e, em seguida, gerar a resposta final (sequencialmente). O LangChain avalia o aninhamento corretamente, tornando cadeias sofisticadas legíveis sem uma confusão de retornos de chamada.
# Full pipeline: classify → parallel retrieval → generate
pipeline = (
RunnablePassthrough.assign(
intent=classify_chain # sequential: classify first
)
| RunnablePassthrough.assign(
context=RunnableParallel( # parallel: retrieve from both sources
faq=faq_retriever,
docs=doc_retriever
)
)
| format_context_chain # sequential: format merged context
| generate_answer_chain # sequential: call LLM
)Tratamento de erros nas ramificações
Quando uma ramificação de RunnableParallel falha, toda a invocação paralela gera uma exceção por padrão. Use .with_fallbacks() em cada Runnable de ramificação para tratar as falhas nesse nível de forma elegante. Para RunnableBranch, envolva cada ramificação em um bloco try-except dentro de um RunnableLambda ou use uma cadeia alternativa padrão para tratar erros de roteamento.
from langchain_core.runnables import RunnableParallel
# Wrap each branch with a fallback
safe_summary = summary_chain.with_fallbacks([
RunnableLambda(lambda x: 'Summary unavailable')
])
safe_sentiment = sentiment_chain.with_fallbacks([
RunnableLambda(lambda x: 'Sentiment unavailable')
])
robust_parallel = RunnableParallel(
summary=safe_summary,
sentiment=safe_sentiment
)
# Now one branch failing won't kill the entire parallel callVerificação rápida
Teste sua compreensão sobre ramificações e cadeias paralelas no LCEL.
Recapitulação da lição
Nesta lição, você aprendeu que RunnableParallel executa várias cadeias simultaneamente e retorna um dicionário de resultados, reduzindo a latência de chamadas independentes a LLM; RunnableBranch encaminha a entrada para diferentes cadeias especializadas com base em condições ou na classificação por uma LLM; e o aninhamento de etapas paralelas e sequenciais permite criar cadeias sofisticadas com vários caminhos que continuam legíveis. A seguir, exploraremos a transmissão gradual da saída no LangChain.
Aprenda Python com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 30
- Aulas
- 120
Perguntas Frequentes
A aula “Cadeias ramificadas e paralelas” é grátis?
Sim — o texto completo de “Cadeias ramificadas e paralelas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.
O que vou aprender em “Cadeias ramificadas e paralelas”?
Crie estruturas RunnableParallel e RunnableBranch para executar várias cadeias simultaneamente ou encaminhar a entrada para diferentes cadeias com base em condições dinâmicas. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Engineering Academy?
Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Cadeias ramificadas e paralelas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Engineering Academy?
Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Arquitetura do LangChain e abstrações principais
- Criando cadeias com LCEL
- Cadeias ramificadas e paralelas
- Transmitindo a saída em LangChain