AI Engineering Academy · Les

Vertakkende en parallelle chains

U bouwt RunnableParallel- en RunnableBranch-constructies om meerdere chains gelijktijdig uit te voeren of invoer op basis van dynamische voorwaarden naar verschillende chains te routeren.

Les 3 van 413 stappen

Vertakkende en parallelle chains is een gratis AI Engineering Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject AI Engineering Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus AI Engineering Academy bevat in totaal 4 lessen.

Waarom parallelle uitvoering en vertakkingen belangrijk zijn

Echte LLM-pijplijnen moeten vaak meerdere dingen tegelijk doen of verzoeken op basis van hun inhoud verschillend routeren. Parallelle ketens voeren meerdere vertakkingen gelijktijdig uit, waardoor de latentie afneemt wanneer taken onafhankelijk zijn. Vertakkende ketens routeren invoer naar verschillende gespecialiseerde ketens op basis van dynamische voorwaarden. LCEL ondersteunt beide patronen standaard met RunnableParallel en RunnableBranch.

De basis van RunnableParallel

RunnableParallel accepteert een dictionary waarin elke sleutel aan een Runnable is gekoppeld. Bij een aanroep worden alle vertakkingen gelijktijdig uitgevoerd en wordt een dictionary geretourneerd waarin elke sleutel het resultaat van zijn vertakking bevat. Dit is ideaal wanneer u meerdere uitvoerwaarden uit dezelfde invoer wilt genereren — bijvoorbeeld tegelijk een samenvatting genereren en trefwoorden extraheren.

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'])

Parallel uitvoeren met verkorte dict-notatie

LCEL biedt een handige verkorte notatie: wanneer u een gewone dict als stap in een pipe-keten doorgeeft, wordt deze automatisch verpakt in RunnableParallel. Hierdoor voelen parallelle vertakkingen natuurlijk aan en hoeft u de klasse niet expliciet te instantiëren. De sleutels van de dict worden de resultaatsleutels en de waarden zijn de vertakkingen die gelijktijdig worden uitgevoerd.

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'])

RunnableBranch begrijpen

RunnableBranch routeert invoer naar verschillende ketens op basis van een voorwaarde. U geeft een lijst met paren (condition, runnable) en een standaard-Runnable op. De vertakking evalueert de voorwaarden in volgorde en voert de eerste overeenkomende vertakking uit. Zo wordt routering op basis van intentie mogelijk — vragen aan de klantenservice gaan naar een ondersteuningsketen en technische vragen naar een documentatieketen.

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 query

Semantische routering met LLM-classificatie

Bij een flexibeler routeringspatroon bepaalt een LLM-aanroep voor classificatie welke vertakking moet worden gebruikt. De router roept eerst een klein model aan om de intentie van de invoer te classificeren en gebruikt die classificatie vervolgens om naar de juiste gespecialiseerde keten te routeren. Dit verwerkt genuanceerde gevallen die zoekopdrachten op trefwoorden missen, in ruil voor één extra API-aanroep.

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)
)

Parallelle RAG: meerdere retrievers

In geavanceerde RAG-systemen kunt u tegelijk gegevens uit meerdere bronnen ophalen en de resultaten samenvoegen. Met RunnableParallel kunt u tegelijkertijd een productdatabase, een FAQ-opslag en een documentatie-index doorzoeken. Een samenvoegstap combineert vervolgens de beste resultaten voordat de context aan de LLM wordt doorgegeven, waardoor het model een rijkere informatiebasis krijgt.

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
)

Voorwaardelijke ketens met itemgetter

Wanneer je een specifieke sleutel uit een parallel resultaat moet selecteren of slechts een deel van de context aan de volgende stap wilt doorgeven, werkt Python's operator.itemgetter als een lichte selecterende Runnable. Dit is handig na een parallelle stap wanneer verschillende vertakkingen verschillende sleutels opleveren en je alleen de relevante sleutel voor de volgende verwerkingsfase wilt extraheren.

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 transform

Parallelle versnelling meten

Het belangrijkste voordeel van RunnableParallel is een kortere verstreken tijd. Drie opeenvolgende aanroepen naar een LLM die elk 2 seconden duren, nemen in totaal 6 seconden in beslag. Parallel zijn ze in ongeveer 2 seconden klaar: de tijdsduur van de traagste vertakking. Parallelle aanroepen verhogen echter je tokengebruik in één keer, dus houd rekening met snelheidslimieten. Gebruik max_concurrency in batch() of stel indien nodig snelheidslimieten per sleutel in.

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')

Asynchrone parallelle ketens

Gebruik voor echt niet-blokkerende parallelle uitvoering in asynchrone toepassingen RunnableParallel.ainvoke(). Onder water gebruikt LCEL asyncio.gather() om de vertakkingen gelijktijdig in de gebeurtenislus uit te voeren. Dit is vooral belangrijk in FastAPI-services waarin elke aanvraagafhandelaar een coroutine is: dankzij de asynchrone interface blokkeer je de gebeurtenislus niet, zelfs niet bij meerdere gelijktijdige LLM-aanroepen.

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'])

Parallelle en opeenvolgende ketens nesten

Complexe pijplijnen combineren vaak opeenvolgende en parallelle stappen. Je kunt RunnableParallel nesten binnen een opeenvolgende pipe en andersom. Je kunt bijvoorbeeld eerst de intentie classificeren (opeenvolgend), daarna ophalen en context opmaken (parallel) en vervolgens het uiteindelijke antwoord genereren (opeenvolgend). LangChain verwerkt de nesting correct, zodat je geavanceerde pijplijnen leesbaar blijven zonder een wirwar aan callbacks.

# 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
)

Foutafhandeling in vertakkingen

Wanneer één vertakking van een RunnableParallel mislukt, genereert de volledige parallelle aanroep standaard een uitzondering. Gebruik .with_fallbacks() op afzonderlijke branch-Runnables om fouten op vertakkingsniveau netjes af te handelen. Voor RunnableBranch kun je elke vertakking in een try-except-blok binnen een RunnableLambda plaatsen of een standaardterugvalketen gebruiken om routeringsfouten af te handelen.

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 call

Korte controle

Test je begrip van vertakkingen en parallelle ketens in LCEL.

Samenvatting van de les

In deze les heb je geleerd dat RunnableParallel meerdere ketens gelijktijdig uitvoert en een woordenboek met resultaten teruggeeft, waardoor de latentie van onafhankelijke LLM-aanroepen afneemt; dat RunnableBranch invoer op basis van voorwaarden of LLM-classificatie naar verschillende gespecialiseerde ketens routeert; en dat je met het nesten van parallelle en opeenvolgende stappen geavanceerde pijplijnen met meerdere paden kunt bouwen die leesbaar blijven. Hierna bekijken we gestreamde uitvoer in LangChain.

Gratis beginnen

Leer Python met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Vertakkende en parallelle chains” gratis?

Ja — de volledige tekst van “Vertakkende en parallelle chains” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus AI Engineering Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus AI Engineering Academy bevat in totaal 4 lessen.

Wat leer ik in “Vertakkende en parallelle chains”?

U bouwt RunnableParallel- en RunnableBranch-constructies om meerdere chains gelijktijdig uit te voeren of invoer op basis van dynamische voorwaarden naar verschillende chains te routeren. Je oefent met AI Engineering Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met AI Engineering Academy te beginnen?

Ervaring vooraf is niet nodig. AI Engineering Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “Vertakkende en parallelle chains”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over AI Engineering Academy?

Ja. Elke les over AI Engineering Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. LangChain-architectuur en kernabstracties
  2. Chains bouwen met LCEL
  3. Vertakkende en parallelle chains
  4. Streaming output in LangChain
← Terug naar AI Engineering Academy