Mục lục
- Mục tiêu bài học
- LangChain là gì
- Cấu trúc package
- Cài đặt
- Hello world — gọi LLM qua LangChain
- 5 khái niệm cốt lõi
- Runnable — protocol thống nhất
- Preview LCEL: compose chain với pipe operator
- Khi nào dùng LangChain
- Khi nào không nên dùng
- Alternatives
- Common pitfalls
- Stability và version management
- Tóm tắt
- Bài tiếp theo
Mục tiêu bài học
Sau bài này bạn sẽ:
- ✅ Hiểu LangChain giải quyết bài toán gì và tại sao nó tồn tại
- ✅ Biết cấu trúc package hiện tại (0.3.x) và cách cài đúng
- ✅ Gọi được LLM qua LangChain bằng ví dụ hello world
- ✅ Nắm 5 khái niệm cốt lõi: Chat Model, Prompt Template, Output Parser, Retriever, Tool
- ✅ Hiểu Runnable protocol và tại sao nó quan trọng
- ✅ Biết khi nào nên và không nên dùng LangChain
LangChain là gì
LangChain là framework để build ứng dụng LLM. Có hai bản song song: Python (langchain) và JavaScript/TypeScript (langchain.js). Cả hai cùng maintainer và cùng philosophy nhưng API khác nhau.
Vấn đề LangChain giải quyết: khi bạn xây app LLM, bạn thường cần kết hợp nhiều thành phần — gọi LLM, format prompt, parse output, search vector DB, gọi tool, quản lý context. Viết code raw cho từng nhà cung cấp (OpenAI, Anthropic, Google, Cohere...) nghĩa là mỗi khi đổi provider phải sửa code ở nhiều nơi. LangChain cung cấp abstraction layer để các component này giao tiếp qua interface chung.
Mục tiêu thực tế:
- Đổi
ChatOpenAIsangChatAnthropichoặcChatGoogleGenerativeAImà không rewrite business logic. - Compose chain phức tạp (prompt → LLM → parser → retriever → LLM → output) bằng code có cấu trúc rõ ràng.
- Tích hợp sẵn với 100+ vector DB, document loader, tool mà không phải viết adapter thủ công.
LangChain phát triển rất nhanh từ 2022. Đến 2025, project đã trải qua nhiều lần refactor lớn. Phiên bản hiện tại là 0.3.x (2024–2025). Trước 0.1 (tháng 1/2024) là legacy codebase — nếu bạn tìm thấy code dùng LLMChain hay from langchain.chat_models import ChatOpenAI, đó là code cũ, không dùng làm mẫu.
Cấu trúc package
Từ phiên bản 0.1, LangChain tách thành nhiều package độc lập. Cách cũ gói hết mọi thứ vào một package gây conflict dependency nghiêm trọng. Cách mới cho phép cài chỉ những gì cần:
| Package | Vai trò | Ghi chú |
|---|---|---|
langchain-core |
Abstraction cốt lõi: Runnable, BaseMessage, BaseChatModel, BasePromptTemplate |
Bắt buộc, tự động kéo vào khi cài langchain |
langchain |
Chain cổ điển, agent (cũ), memory, output parser cao cấp | Thường cần trong project thực tế |
langchain-community |
Integration cộng đồng: Wikipedia, Notion, Spotify, SerpAPI, nhiều tool khác | Cài khi cần integration cụ thể |
langchain-openai |
OpenAI provider: ChatOpenAI, OpenAIEmbeddings |
Cài riêng nếu dùng OpenAI |
langchain-anthropic |
Anthropic provider: ChatAnthropic |
Cài riêng nếu dùng Claude |
langchain-google-genai |
Google provider: ChatGoogleGenerativeAI |
Cài riêng nếu dùng Gemini |
langchain-text-splitters |
Chunking utilities: RecursiveCharacterTextSplitter, TokenTextSplitter |
Chi tiết ở bài 22 |
langgraph |
Stateful multi-step agent, graph-based workflow | Module 5 của series này |
Điểm quan trọng: langchain-openai không nằm trong langchain core. Nếu bạn chỉ pip install langchain rồi from langchain_openai import ChatOpenAI, Python báo ModuleNotFoundError. Phải cài pip install langchain-openai riêng.
Tương tự, langchain-anthropic, langchain-google-genai đều là package riêng — cài theo nhu cầu, không phải tất cả cùng lúc.
Cài đặt
Cài theo nhu cầu thực tế của project:
# Bộ tối thiểu: LangChain + OpenAI provider
pip install langchain langchain-openai
# Nếu dùng thêm Anthropic (Claude)
pip install langchain-anthropic
# Nếu dùng ChromaDB làm vector store
pip install langchain-chroma
# Nếu dùng text splitter (thường cần trong RAG)
pip install langchain-text-splitters
# Cài đầy đủ cho project RAG điển hình
pip install langchain langchain-openai langchain-chroma langchain-text-splitters
Kiểm tra version sau cài:
import langchain
import langchain_core
print(langchain.__version__) # 0.3.x
print(langchain_core.__version__) # 0.3.x
Version pin trong production: LangChain có nhiều breaking change giữa các minor version. Khi đưa vào production, lock version chính xác:
# requirements.txt
langchain==0.3.14
langchain-core==0.3.50
langchain-openai==0.2.14
langchain-chroma==0.1.4
Số version ví dụ — kiểm tra số thực tế qua pip show langchain và ghi vào requirements.txt trước khi deploy.
Hello world — gọi LLM qua LangChain
Đây là ví dụ đơn giản nhất — gọi OpenAI GPT-4o-mini qua ChatOpenAI:
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
# API key đọc từ env: OPENAI_API_KEY
# Không hard-code key vào code
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
response = llm.invoke([
SystemMessage(content="Bạn là trợ lý kỹ thuật."),
HumanMessage(content="FastAPI là gì?"),
])
print(response.content)
# Output: FastAPI là một web framework hiện đại ...
print(type(response))
# Output:
Một số điểm cần chú ý:
ChatOpenAIimport từlangchain_openai, không phải từlangchain.SystemMessagevàHumanMessageimport từlangchain_core.messages..invoke()trả vềAIMessage, không phải string. Lấy nội dung quaresponse.content.OPENAI_API_KEYphải set trong environment —ChatOpenAIđọc tự động quaos.environ. Nếu thiếu, lúc gọi.invoke()sẽ báoAuthenticationError.
Đổi provider không cần sửa phần còn lại
# Thay ChatOpenAI bằng ChatAnthropic
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-3-5-haiku-20241022", temperature=0)
# ANTHROPIC_API_KEY phải set trong env
response = llm.invoke([
SystemMessage(content="Bạn là trợ lý kỹ thuật."),
HumanMessage(content="FastAPI là gì?"),
])
print(response.content)
# Code phần còn lại không đổi
Đây là điểm mạnh chính của LangChain: ChatOpenAI và ChatAnthropic đều implement BaseChatModel, nên .invoke() có signature giống nhau.
Streaming
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
for chunk in llm.stream([HumanMessage(content="Giải thích Docker trong 3 câu.")]):
print(chunk.content, end="", flush=True)
print() # newline cuối
5 khái niệm cốt lõi
Module 4 sẽ đào sâu từng khái niệm trong các bài 20–25. Đây là giới thiệu nhanh để bạn có mental model đúng trước khi bắt đầu.
1. Chat Model
Wrapper cho LLM provider. Ví dụ: ChatOpenAI, ChatAnthropic, ChatGoogleGenerativeAI. Tất cả đều implement BaseChatModel với unified API:
.invoke(messages)— gọi đồng bộ, trả vềAIMessage..stream(messages)— generator trả từng chunk..batch(list_of_messages)— gọi nhiều request song song..ainvoke(),.astream(),.abatch()— async variants.
2. Prompt Template
ChatPromptTemplate là template có variable, fill giá trị khi gọi. Tách riêng logic "cấu trúc prompt" khỏi "dữ liệu runtime":
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "Bạn là chuyên gia về {domain}. Trả lời ngắn gọn, dùng ví dụ thực tế."),
("user", "{question}"),
])
# Format prompt với data cụ thể
messages = prompt.format_messages(domain="FastAPI", question="Middleware là gì?")
3. Output Parser
Convert output từ AIMessage sang Python object phù hợp:
StrOutputParser: tríchAIMessage.contentthành string thuần.JsonOutputParser: parse JSON string trong response thành dict.PydanticOutputParser: validate và parse thành Pydantic model.
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
# StrOutputParser: dùng khi chỉ cần text
parser_str = StrOutputParser()
text = parser_str.invoke(response) # response là AIMessage
# text là str
# JsonOutputParser: khi prompt yêu cầu LLM trả JSON
parser_json = JsonOutputParser()
data = parser_json.invoke(response) # data là dict
4. Retriever
Interface chuẩn để lấy document từ bất kỳ nguồn nào (vector DB, ElasticSearch, BM25...). Method duy nhất quan trọng: .invoke(query: str) -> list[Document]. Bạn không cần biết retriever đang kết nối với vector DB nào — code business logic không thay đổi khi swap ChromaDB sang Pinecone. Chi tiết ở bài 23.
5. Tool / Agent
Tool là function Python mà LLM có thể "gọi" thông qua function calling. Agent là loop: LLM quyết định dùng tool nào → Python chạy tool → kết quả về cho LLM → lặp đến khi có câu trả lời. Chi tiết ở bài 25.
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""Trả về thời tiết hiện tại của thành phố. city là tên thành phố tiếng Anh."""
# Thực tế gọi weather API ở đây
return f"Hà Nội: 32°C, có mây"
Runnable — protocol thống nhất
Runnable là interface cốt lõi trong langchain-core. Mọi component đều implement nó: Chat Model, Prompt Template, Output Parser, Retriever, Tool.
Methods trên mọi Runnable:
| Method | Mô tả |
|---|---|
.invoke(input) |
Gọi đồng bộ, trả về một kết quả |
.stream(input) |
Generator, yield từng chunk khi có |
.batch(inputs) |
Gọi song song nhiều input, trả về list kết quả |
.ainvoke(input) |
Async version của invoke |
.astream(input) |
Async generator |
.abatch(inputs) |
Async parallel batch |
Vì tất cả component có cùng interface, bạn có thể compose chúng bằng | operator (LCEL — chi tiết bài 20). Output của component trước là input của component sau:
# prompt | llm | parser là một chain hợp lệ
# vì prompt trả ra messages, llm nhận messages và trả AIMessage,
# parser nhận AIMessage và trả string
chain = prompt | llm | parser
result = chain.invoke({"domain": "Docker", "question": "Volume là gì?"})
# result là string
.batch() tự động gửi nhiều request song song (dùng ThreadPoolExecutor nội bộ với sync, asyncio.gather với async version):
questions = [
{"question": "FastAPI là gì?"},
{"question": "Pydantic là gì?"},
{"question": "Uvicorn là gì?"},
]
# Gửi 3 request song song
results = chain.batch(questions)
# results là list[str], length 3
Preview LCEL: compose chain với pipe operator
LCEL (LangChain Expression Language) là cách compose component bằng | operator. Đây là preview ngắn — bài 20 sẽ đi vào chi tiết.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "Bạn là trợ lý kỹ thuật trả lời ngắn gọn, tối đa 2 câu."),
("user", "{question}"),
])
# Compose 3 component thành 1 chain
chain = prompt | llm | StrOutputParser()
# Gọi chain
answer = chain.invoke({"question": "FastAPI là gì?"})
print(answer)
# Output: FastAPI là web framework Python hiện đại...
Ở đây:
prompt.invoke({"question": "FastAPI là gì?"})trả về listChatMessage.- Kết quả đó được truyền vào
llm.invoke(messages), trả vềAIMessage. StrOutputParser().invoke(ai_message)trả về string.
LCEL còn hỗ trợ streaming đầu-cuối, async, parallel branch, và nhiều tính năng khác — bài 20 sẽ đào sâu.
Khi nào dùng LangChain
LangChain phù hợp khi:
1. Cần swap LLM provider linh hoạt
POC với nhiều model (GPT-4o, Claude 3.5, Gemini 1.5...) để so sánh chất lượng và chi phí. Chỉ đổi một dòng khởi tạo, không sửa phần còn lại.
2. Build chain có nhiều bước
Ví dụ: nhận câu hỏi → phân loại intent → route sang chain khác → tìm kiếm vector DB → build context → gọi LLM → parse output → trả kết quả. Viết code raw cho luồng này cần nhiều boilerplate. LCEL làm cấu trúc rõ ràng hơn.
3. Tích hợp với 100+ integration sẵn có
Document loader cho PDF, Word, web page, Notion, GitHub. Vector store wrapper cho ChromaDB, Pinecone, Qdrant, Weaviate, pgvector. Tool cho Google Search, Wikipedia, SQL, code execution. Viết adapter thủ công cho từng integration là công sức lớn.
4. Team cần code style nhất quán
Khi nhiều developer cùng build LLM features, LangChain cung cấp convention chung — cách đặt tên, cách compose, cách handle error. Giảm thời gian code review và onboarding.
Khi nào không nên dùng
1. Use case đơn giản
Nếu app của bạn chỉ là: nhận input → gọi OpenAI API → trả về response, code thuần OpenAI SDK dễ đọc và dễ debug hơn nhiều:
# Code thuần — rõ ràng hơn cho case đơn giản
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "FastAPI là gì?"}]
)
print(response.choices[0].message.content)
Thêm LangChain vào đây tạo ra thêm dependency, thêm abstraction layer, và không mang lại lợi ích gì.
2. Performance critical
LangChain có overhead từ callback system, type checking, và Pydantic validation trên mỗi bước. Overhead này thường không đáng kể so với latency LLM call (100–2000ms), nhưng nếu bạn build inference service cần p99 latency thấp nhất, code thuần SDK sẽ có ít overhead hơn.
3. Cần full control trong production
LangChain thay đổi API thường xuyên giữa minor version. Module path thay đổi, behavior thay đổi, class bị deprecated. Mỗi lần upgrade cần đọc migration guide cẩn thận và chạy test đầy đủ. Team muốn kiểm soát hoàn toàn code path từ đầu đến cuối sẽ thấy điều này là gánh nặng.
4. Team đã có abstraction riêng
Nếu team đã viết một thin wrapper đơn giản quanh OpenAI SDK và nó đang hoạt động tốt, không cần migrate sang LangChain chỉ để follow trend.
Alternatives
| Framework | Tập trung vào | Ngôn ngữ | Ghi chú |
|---|---|---|---|
| LlamaIndex | RAG, data ingestion, index types | Python | Abstraction khác với LangChain, ít opiniated hơn về chain composition |
| Haystack | Pipeline-based, NLP-first | Python | Document-centric, phù hợp enterprise search |
| Semantic Kernel | Plugin-based agent | C# / Python | Microsoft, tích hợp tốt với Azure OpenAI |
| Code thuần | Gọi SDK trực tiếp + wrapper nhỏ | Bất kỳ | Đủ cho nhiều production use case, dễ debug, không có breaking change bên ngoài |
Không có lựa chọn "đúng nhất". LangChain phổ biến nhất về ecosystem và tài liệu cộng đồng (2025). LlamaIndex thường được chọn khi RAG là focus chính. Code thuần + 1 file abstraction nhỏ là lựa chọn hợp lý khi bạn không muốn phụ thuộc vào framework bên ngoài.
Common pitfalls
1. Import sai path
Đây là lỗi phổ biến nhất khi đọc tutorial cũ (trước 0.1):
# SAI (import path cũ, trước 0.1)
from langchain.chat_models import ChatOpenAI # DeprecationWarning / ImportError
from langchain.prompts import ChatPromptTemplate # tương tự
from langchain.output_parsers import StrOutputParser # tương tự
# ĐÚNG (từ 0.1+)
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
2. Thiếu API key
ChatOpenAI đọc OPENAI_API_KEY từ environment khi khởi tạo. Nếu key chưa set, lỗi xảy ra lúc .invoke() (không phải lúc import), báo openai.AuthenticationError: 401. Luôn set trước khi chạy:
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
3. Mix phiên bản legacy và mới
Cài langchain==0.0.350 (rất cũ, 0.0.x) bên cạnh langchain-openai sẽ gây xung đột langchain-core dependency. Nếu thấy runtime error lạ liên quan đến class không tồn tại hoặc attribute missing, chạy:
pip install --upgrade langchain langchain-core langchain-openai
4. Dùng LLMChain (legacy)
LLMChain bị deprecated từ 0.1.17. Không dùng nó trong code mới:
# SAI (deprecated)
from langchain.chains import LLMChain
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(question="...")
# ĐÚNG (LCEL)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"question": "..."})
5. Quên rằng .invoke() trả AIMessage, không phải string
response = llm.invoke([HumanMessage(content="Hello")])
# SAI — response là AIMessage, không phải str
print(response) # In cả object
print(response + " world") # TypeError
# ĐÚNG
print(response.content) # str
# Hoặc dùng StrOutputParser trong chain
Stability và version management
LangChain nổi tiếng là một trong những project Python có nhiều breaking change nhất tính theo tốc độ phát triển. Một số thực tế:
- Giữa 0.0.x và 0.1: toàn bộ cấu trúc package được tách ra (
langchain-core, provider packages riêng). - Giữa 0.1 và 0.2: agent API refactor, nhiều class bị deprecated.
- Giữa 0.2 và 0.3: tiếp tục cleanup deprecated code, thêm structured output API.
Chiến lược an toàn khi dùng trong production:
Lock version trong requirements.txt
langchain==0.3.14
langchain-core==0.3.50
langchain-openai==0.2.14
Không dùng langchain>=0.3 hoặc langchain~=0.3 trong production — minor version mới có thể có breaking change.
Kiểm tra DeprecationWarning trước khi upgrade
# Chạy test với warnings bật
python -W all -m pytest tests/
# Hoặc trong code
import warnings
warnings.filterwarnings("error", category=DeprecationWarning)
Đọc migration guide trước khi upgrade major version
LangChain duy trì migration guide tại https://python.langchain.com/docs/versions/migrating_*. Khi upgrade từ 0.2 lên 0.3, đọc guide này trước khi chạy pip install --upgrade.
Tóm tắt
- LangChain là orchestration framework để build LLM app, phiên bản hiện tại 0.3.x (2025).
- Cấu trúc tách package:
langchain-core(abstraction),langchain(chain/memory), provider riêng (langchain-openai,langchain-anthropic...). - Cài
pip install langchain langchain-openaicho bộ tối thiểu với OpenAI. Provider không có tronglangchaincore. Runnablelà interface chung:.invoke(),.stream(),.batch(), async variants. Mọi component đều implement.- 5 khái niệm cốt lõi: Chat Model, Prompt Template, Output Parser, Retriever, Tool.
- LCEL (
prompt | llm | parser) là cách compose chain — bài 20 đào sâu. - Phù hợp khi cần swap provider, build chain phức tạp, dùng integration sẵn có. Không phù hợp khi use case đơn giản hoặc cần full control.
- Lock version trong production. Không dùng code legacy (
LLMChain, import path cũ).
Bài tiếp theo
Bài 20: LCEL (LangChain Expression Language) — chuỗi component với pipe operator — đào sâu vào LCEL: cách compose chain, xử lý branching, parallel step, streaming đầu-cuối, và async chain.
