Rantai Bercabang dan Paralel
Bangun konstruksi RunnableParallel dan RunnableBranch untuk menjalankan beberapa rantai secara bersamaan atau mengarahkan masukan ke rantai yang berbeda berdasarkan kondisi dinamis.
Rantai Bercabang dan Paralel adalah pelajaran AI Engineering Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Engineering Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Engineering Academy mencakup 4 pelajaran total.
Mengapa Paralel dan Percabangan Penting
Pipeline LLM di dunia nyata sering kali perlu melakukan beberapa hal sekaligus atau merutekan permintaan secara berbeda berdasarkan konten. Rantai paralel menjalankan beberapa cabang secara bersamaan, sehingga mengurangi latensi ketika tugas-tugasnya tidak saling bergantung. Rantai bercabang merutekan input ke rantai khusus yang berbeda berdasarkan kondisi dinamis. LCEL mendukung kedua pola ini secara native melalui RunnableParallel dan RunnableBranch.
Dasar-Dasar RunnableParallel
RunnableParallel menerima kamus yang setiap kuncinya dipetakan ke sebuah Runnable. Saat dipanggil, komponen ini menjalankan semua cabang secara bersamaan dan mengembalikan kamus dengan setiap kunci berisi hasil cabangnya. Ini ideal saat Anda ingin menghasilkan beberapa output dari input yang sama—misalnya, membuat ringkasan dan mengekstrak kata kunci secara bersamaan.
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'])Paralel dengan Singkatan Dict
LCEL menyediakan singkatan yang praktis: meneruskan dict biasa sebagai langkah dalam rantai pipa akan otomatis membungkusnya dalam RunnableParallel. Dengan demikian, cabang paralel terasa alami dan pembuatan instance kelas secara eksplisit tidak diperlukan. Kunci dict menjadi kunci hasil, sedangkan nilainya adalah cabang yang dijalankan secara bersamaan.
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'])Memahami RunnableBranch
RunnableBranch merutekan input ke rantai yang berbeda berdasarkan suatu kondisi. Anda memberikan daftar pasangan (condition, runnable) dan sebuah runnable default. Cabang mengevaluasi kondisi sesuai urutan dan menjalankan cabang pertama yang cocok. Hal ini memungkinkan perutean berdasarkan maksud—mengirim kueri layanan pelanggan ke rantai dukungan dan pertanyaan teknis ke rantai dokumentasi.
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 queryPerutean Semantik dengan Klasifikasi LLM
Pola perutean yang lebih fleksibel menggunakan pemanggilan LLM pengklasifikasi untuk menentukan cabang yang digunakan. Router terlebih dahulu memanggil model kecil untuk mengklasifikasikan maksud input, lalu menggunakan hasil klasifikasi tersebut untuk merutekan input ke rantai spesialis yang sesuai. Cara ini menangani kasus bernuansa yang terlewat oleh pencocokan kata kunci, dengan konsekuensi satu pemanggilan API tambahan.
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 Paralel: Banyak Pengambil
Dalam sistem RAG tingkat lanjut, Anda mungkin perlu mengambil data dari beberapa sumber secara bersamaan lalu menggabungkan hasilnya. RunnableParallel memungkinkan Anda membuat kueri ke basis data produk, penyimpanan FAQ, dan indeks dokumentasi pada saat yang sama. Langkah penggabungan kemudian menyatukan hasil teratas sebelum meneruskan konteks ke LLM, sehingga model memperoleh basis informasi yang lebih kaya.
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
)Rantai Kondisional dengan itemgetter
Saat Anda perlu memilih kunci tertentu dari hasil paralel atau hanya meneruskan sebagian konteks ke langkah berikutnya, operator.itemgetter Python dapat digunakan sebagai pemilih Runnable yang ringan. Ini berguna setelah langkah paralel ketika cabang yang berbeda menghasilkan kunci yang berbeda dan Anda hanya perlu mengambil kunci yang relevan untuk tahap pemrosesan berikutnya.
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 transformMengukur Peningkatan Kecepatan Paralel
Manfaat utama RunnableParallel adalah mengurangi waktu berdasarkan jam dinding. Tiga pemanggilan LLM berurutan yang masing-masing memerlukan 2 detik akan memerlukan total 6 detik. Jika dijalankan secara paralel, semuanya selesai dalam sekitar 2 detik—waktu yang diperlukan cabang paling lambat. Namun, pemanggilan paralel melipatgandakan penggunaan token Anda secara bersamaan, jadi perhatikan batas laju. Gunakan max_concurrency di batch() atau tetapkan batas laju per kunci jika diperlukan.
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')Rantai Paralel Asinkron
Untuk eksekusi paralel yang benar-benar tidak memblokir dalam aplikasi asinkron, gunakan RunnableParallel.ainvoke(). Di balik layar, LCEL menggunakan asyncio.gather() untuk menjalankan cabang secara bersamaan pada loop peristiwa. Hal ini sangat penting dalam layanan FastAPI karena setiap pengendali permintaan merupakan coroutine—penggunaan antarmuka asinkron mencegah loop peristiwa terblokir, bahkan saat beberapa pemanggilan LLM berlangsung secara bersamaan.
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'])Menyarangkan Rantai Paralel dan Berurutan
Pipeline yang kompleks sering mencampurkan langkah berurutan dan paralel. Anda dapat menyarangkan RunnableParallel di dalam pipa berurutan, begitu pula sebaliknya. Sebagai contoh: klasifikasikan maksud secara berurutan, lalu jalankan pengambilan dan pemformatan konteks secara paralel, kemudian buat respons akhir secara berurutan. LangChain mengevaluasi penyarangan ini dengan benar, sehingga Anda dapat membangun pipeline canggih yang tetap mudah dibaca tanpa rangkaian callback yang berbelit-belit.
# 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
)Penanganan Kesalahan di Cabang
Ketika salah satu cabang RunnableParallel gagal, seluruh pemanggilan paralel secara bawaan akan memunculkan pengecualian. Gunakan .with_fallbacks() pada Runnable setiap cabang untuk menangani kegagalan tingkat cabang dengan baik. Untuk RunnableBranch, bungkus setiap cabang dalam try-except di dalam RunnableLambda, atau gunakan rantai pengganti bawaan untuk menangani kesalahan pengalihan.
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 callPemeriksaan Singkat
Uji pemahaman Anda tentang percabangan dan rantai paralel dalam LCEL.
Rangkuman Pelajaran
Dalam pelajaran ini, Anda mempelajari bahwa RunnableParallel menjalankan beberapa rantai secara bersamaan dan mengembalikan dict hasil, sehingga mengurangi latensi untuk pemanggilan LLM yang independen; RunnableBranch mengarahkan input ke rantai spesialis yang berbeda berdasarkan kondisi atau klasifikasi LLM; dan penyarangan langkah paralel serta berurutan memungkinkan Anda membangun pipeline multi-jalur yang canggih tetapi tetap mudah dibaca. Selanjutnya, kita akan mempelajari pengaliran output dalam LangChain.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Rantai Bercabang dan Paralel” gratis?
Ya — teks lengkap “Rantai Bercabang dan Paralel” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Engineering Academy, upgrade ke CoddyKit PRO. Kursus AI Engineering Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Rantai Bercabang dan Paralel”?
Bangun konstruksi RunnableParallel dan RunnableBranch untuk menjalankan beberapa rantai secara bersamaan atau mengarahkan masukan ke rantai yang berbeda berdasarkan kondisi dinamis. Kamu berlatih AI Engineering Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai AI Engineering Academy?
Tidak diperlukan pengalaman sebelumnya. AI Engineering Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Rantai Bercabang dan Paralel” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Engineering Academy ini?
Ya. Setiap pelajaran AI Engineering Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Arsitektur LangChain dan Abstraksi Inti
- Membangun Rantai dengan LCEL
- Rantai Bercabang dan Paralel
- Mengalirkan Keluaran di LangChain