
LangChain Expression Language (LCEL) là giao diện khai báo chuẩn để xây dựng và tổ hợp chuỗi xử lý LLM trong hệ sinh thái LangChain. Thay vì viết logic lồng nhau thủ công, LCEL cho phép định nghĩa pipeline như một biểu thức tuyến tính, từ đó tận dụng được streaming, async, batch, fallback và retry tự động mà không cần code boilerplate.
Tại sao cần LCEL?
Trước LCEL, các nhà phát triển thường dùng LLMChain hoặc SequentialChain — các class kế thừa phức tạp, khó mở rộng, và streaming chỉ hoạt động ở tầng cuối. LCEL giải quyết bằng cách làm cho mọi thành phần (prompt, model, parser, retriever, tool) đều implements giao diện Runnable thống nhất. Kết quả: một chuỗi prompt | model | parser tự động hỗ trợ .stream(), .abatch(), .with_fallbacks() mà không cần viết thêm một dòng code.
Giao diện Runnable là trái tim của LCEL. Mọi component trong LangChain hiện nay — từ ChatPromptTemplate, ChatOpenAI, StrOutputParser đến custom retriever, tool, hay lambda function — đều implement interface này. Sự thống nhất này cho phép tổ hợp (composition) trở nên tự nhiên: output của Runnable này trở thành input của Runnable kia thông qua toán tử pipe |.

Ba phương thức cốt lõi của Runnable
Mọi Runnable trong LCEL tuân thủ ba phương thức chính:
invoke(input)— chạy đồng bộ, trả về kết quả cuối cùngstream(input)— trả về async iterator cho token-by-token streamingbatch(inputs)— xử lý nhiều input cùng lúc, tận dụng concurrency pool
Ngoài ra còn có abatch (async batch), astream (async stream), with_config (gán metadata như run_name, tags), và with_fallbacks (chuỗi dự phòng khi thành phần chính lỗi). Tất cả các phương thức này đều được implement mặc định ở base class — developer chỉ cần implement invoke (hoặc stream nếu muốn tối ưu streaming).
Ví dụ: RAG chain hoàn chỉnh với LCEL
Đoạn code sau minh họa một chuỗi RAG (Retrieval-Augmented Generation) chuẩn production:
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template(
"Trả lời dựa trên ngữ cảnh:n{context}nnCâu hỏi: {question}"
)
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
parser = StrOutputParser()
# Retriever đã được cấu hình sẵn (vector store, similarity search)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
rag_chain = (
{"context": retriever | RunnableLambda(lambda docs: "nn".join(d.page_content for d in docs)),
"question": RunnablePassthrough()}
| prompt
| model
| parser
)
# Streaming token-by-token
for chunk in rag_chain.stream("Tóm tắt bài báo về LCEL"):
print(chunk, end="", flush=True)
Chuỗi trên tự động: lấy tài liệu liên quan, ghép ngữ cảnh, đưa vào prompt, gọi model, parse output — và streaming hoạt động ngay từ lần đầu chạy. Lưu ý RunnablePassthrough() chuyển input gốc (câu hỏi) thẳng đến prompt, trong khi retriever | RunnableLambda(...) biến đổi kết quả tìm kiếm thành string ngữ cảnh.

Tổ hợp nâng cao: Parallel, Branching, Fallback
LCEL cho phép chạy song song nhiều nhánh và gom kết quả nhờ RunnableParallel:
from langchain_core.runnables import RunnableParallel
# Chạy song song: tóm tắt + trích xuất thực thể + phân loại chủ đề
analysis_chain = RunnableParallel(
summary=prompt_summary | model | parser,
entities=prompt_entities | model | parser,
category=prompt_category | model | parser,
)
result = analysis_chain.invoke({"input": long_document})
# result = {"summary": "...", "entities": [...], "category": "..."}
Mỗi key trong RunnableParallel là một sub-chain độc lập. LCEL tự động chạy chúng song song (dùng thread pool) và gom kết quả thành dict. Điều này giảm latency đáng kể so với chạy tuần tự — ví dụ 3 lệnh gọi LLM song song mất ~2s thay vì ~6s.
Fallback chain đảm bảo độ bền: nếu model chính (gpt-4o) lỗi rate-limit, tự động chuyển sang model dự phòng (gpt-4o-mini):
robust_chain = (prompt | model).with_fallbacks([prompt | backup_model])
Khi chain đầu tiên raise exception, LCEL tự động thử chain kế tiếp trong danh sách fallback. Có thể chuỗi nhiều cấp: .with_fallbacks([chain2, chain3, chain4]).
LCEL vs LangGraph: Khi nào dùng cái nào?
LCEL phù hợp cho pipeline tuyến tính, đơn hướng, không cần state phức tạp. LangGraph (cùng tác giả LangChain) thiết kế cho workflow có vòng lặp, điều kiện, human-in-the-loop, và state persistence. Quy tắc đơn giản: nếu chuỗi xử lý có thể vẽ thành đường thẳng — dùng LCEL; nếu là đồ thị có chu trình — dùng LangGraph.
Ví dụ LCEL đủ dùng: RAG chain, summarization pipeline, structured output extraction, tool calling sequence. Ví dụ cần LangGraph: ReAct agent (think-act-observe loop), multi-agent debate, workflow cần checkpoint/resume, human approval step.
Triển khai production: LangServe
LCEL chain có thể expose thành REST API chỉ trong vài dòng code nhờ langserve:
from langserve import add_routes
from fastapi import FastAPI
app = FastAPI()
add_routes(app, rag_chain, path="/rag")
# Chạy: uvicorn main:app --reload
# Test: curl -X POST http://localhost:8000/rag/invoke -d '{"input": "Câu hỏi"}'
API tự động có endpoint /invoke, /stream, /batch, /stream_log — sẵn sàng cho frontend consume streaming SSE. stream_log đặc biệt hữu ích: trả về intermediate step (retriever result, prompt sent, model raw output) bên cạnh final answer — tuyệt vời cho debugging và observability.
Config và Observability
with_config cho phép gán metadata cho chain, sau đó dùng trong LangSmith tracing:
chain = (prompt | model | parser).with_config(
run_name="rag_chain_v2",
tags=["production", "rag"],
metadata={"version": "2.1", "team": "ml-platform"}
)
Kết hợp với langsmith tracing: mọi run tự động log input/output, latency, token usage, error — hỗ trợ A/B testing prompt, model, retriever config mà không cần custom logging.
Tóm tắt
LCEL đưa LangChain từ framework “viết chain tùy chỉnh” thành ngôn ngữ tổ hợp chuẩn cho LLM pipeline. Ưu điểm lớn: streaming tự động, async native, fallback declarative, và deploy API zero-config qua LangServe. Với bất kỳ dự án nào dùng LangChain hiện nay, LCEL là cách viết chain được khuyến nghị mặc định.
