Course Content
LangChain Mastery
7 sections · 109 lessons
Write a function to implement a parallel chain execution in LangChain.
What you need to know
1from langchain_core.runnables import RunnableParallel2from langchain_core.output_parsers import StrOutputParser, JsonOutputParser34def build_review_analysis(llm):5 return RunnableParallel(6 summary=summary_prompt | llm | StrOutputParser(),7 sentiment=sentiment_prompt | llm | StrOutputParser(),8 entities=entity_prompt | llm | JsonOutputParser(),9 )1011analysis = build_review_analysis(llm)12analysis.invoke({"text": review})13# {"summary": "...", "sentiment": "negative", "entities": {...}}All three prompts use {text}. invoke runs the branches in a thread pool; ainvoke runs them as asyncio tasks, which is the better choice inside an async web server.
The dict shortcut
chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llmA dict at the start of or inside a pipeline becomes a RunnableParallel. Here, retrieval and passing the question through run together, and the dict feeds the prompt.
Partial failure
By default, if one branch raises, the whole parallel step raises and you lose the other results. When a missing branch is acceptable:
safe_entities = (entity_prompt | llm | JsonOutputParser()).with_fallbacks( [RunnableLambda(lambda x: {})])Now a failed entity extraction returns an empty dict, and the summary and sentiment still come back.
Limits
- Rate limits: three branches means three times the request rate. With
batchon top, concurrency multiplies again. - Independence: branches cannot see each other's output. If one needs another's result, that part is a sequence.
- Threads: sync branches share a thread pool; very large fan-outs are better done async.
A real-life example
An e-commerce marketplace analyses 50,000 product reviews a day for its seller dashboard: a one-line summary, a sentiment label, and product aspects mentioned (delivery, packaging, quality). Run one after another, each review took about 4.5 seconds. With the three branches in a RunnableParallel, it took about 1.8 seconds, the time of the slowest branch. Combined with abatch at a concurrency of 20, the daily job dropped from 9 hours to under 2. The team added an empty-dict fallback to the aspects branch, which failed on about 0.5% of reviews written in mixed scripts, so those reviews still got a summary and sentiment.
Follow-up questions to expect
- "Does
RunnableParallelreduce cost?" — No. It reduces waiting time only; each branch is still a paid call. - "How do you stream a parallel step?" —
streamyields chunks tagged with their branch key, so you can fill each part of a UI as it arrives. - "How do you limit concurrency inside a big parallel batch?" — Set
max_concurrencyin the config; it applies across the whole run.