LangChain, LangGraph, LangSmith: Hiểu qua ví dụ build AI tool hỗ trợ HR
LangChain, LangGraph, LangSmith: Hiểu qua ví dụ build AI tool hỗ trợ HR
Bài viết này giải thích LangChain, LangGraph và LangSmith theo cách gần gũi, dễ hình dung, nhưng vẫn đủ sâu cho developer muốn build AI agent thật. Ví dụ xuyên suốt là một tool tên HR Copilot — trợ lý AI giúp team HR tìm ứng viên, chấm điểm CV, soạn email và theo dõi quy trình tuyển dụng.
Mở đầu: Vì sao chỉ gọi LLM là chưa đủ?
Giả sử bạn muốn build một tool AI cho team HR.
HR nhập vào một câu rất tự nhiên:
Tìm giúp tôi ứng viên phù hợp cho vị trí Senior Backend Go Developer,
ưu tiên AWS, MySQL và tiếng Nhật N2. Nếu phù hợp thì soạn email mời phỏng vấn.
Nghe qua thì giống một câu hỏi bình thường có thể copy vào ChatGPT. Nhưng nếu muốn biến nó thành một sản phẩm thật, tool phải làm nhiều hơn rất nhiều:
- hiểu HR đang muốn tuyển vị trí nào,
- lấy đúng JD liên quan,
- tìm CV trong database hoặc kho hồ sơ,
- đọc và chấm điểm từng ứng viên,
- giải thích vì sao ứng viên này phù hợp,
- soạn email mời phỏng vấn,
- dừng lại để HR duyệt trước khi gửi,
- cập nhật trạng thái ứng viên trong pipeline,
- và ghi lại toàn bộ quá trình để debug nếu AI trả lời sai.
Nói cách khác, đây không còn là chuyện “gọi một model và lấy câu trả lời”. Đây là một AI workflow có nhiều bước, có dữ liệu thật, có tool thật, có quyền hạn, có phê duyệt của con người và có nhu cầu theo dõi chất lượng.
Đó là lúc bộ ba LangChain — LangGraph — LangSmith trở nên hữu ích.
1. Ba công cụ này khác nhau thế nào?
Hãy tưởng tượng ta đang xây một “nhà máy nhỏ” để hỗ trợ HR tuyển dụng.
- LangChain giống các bộ phận máy: máy đọc CV, máy gọi LLM, máy tìm dữ liệu, máy trả JSON.
- LangGraph giống dây chuyền vận hành: bước nào chạy trước, khi nào rẽ nhánh, khi nào dừng chờ HR duyệt.
- LangSmith giống phòng điều khiển: xem agent đã chạy qua bước nào, sai ở đâu, tốn bao nhiêu tiền, chậm ở đoạn nào.
Nói ngắn gọn:
LangChain = AI biết dùng công cụ.
LangGraph = AI làm việc theo quy trình.
LangSmith = team nhìn thấy AI đã làm gì và sai ở đâu.
Hoặc theo góc nhìn kỹ thuật:
| Công cụ | Vai trò chính | Ví dụ trong HR Copilot |
|---|---|---|
| LangChain | Ghép LLM với prompt, tool, retriever, output parser | Chấm điểm CV theo JD và trả JSON |
| LangGraph | Điều phối workflow có state, nhánh, vòng lặp, human approval | Tìm CV → chấm điểm → soạn email → chờ HR duyệt → gửi |
| LangSmith | Trace, debug, evaluation, monitoring | Xem vì sao AI chọn ứng viên A thay vì B |
Một cách nhớ khác:
LangChain = khả năng
LangGraph = quy trình
LangSmith = niềm tin
2. Trước khi đi sâu: AI agent là gì?
Một chatbot bình thường thường chạy như sau:
User hỏi → LLM trả lời
Một AI agent thì khác. Agent không chỉ trả lời, mà có thể tự quyết định bước tiếp theo và gọi công cụ bên ngoài.
Ví dụ với HR Copilot:
HR yêu cầu tìm ứng viên
→ Agent hiểu yêu cầu
→ Agent gọi tool lấy JD
→ Agent gọi tool tìm CV
→ Agent đọc CV
→ Agent chấm điểm
→ Agent soạn email
→ Agent dừng lại chờ HR duyệt
Một agent thường có ba phần:
| Thành phần | Hiểu đơn giản | Ví dụ HR |
|---|---|---|
| Não | LLM suy luận và quyết định | “Ứng viên này thiếu AWS, nên điểm thấp hơn” |
| Giác quan | Đọc dữ liệu, tìm tài liệu, truy xuất thông tin | Search JD, đọc CV, lấy note ứng viên |
| Tay chân | Gọi tool/API để hành động | Gửi email, cập nhật ATS, post Slack |
Nhiều agent hiện đại chịu ảnh hưởng từ ý tưởng ReAct:
Suy nghĩ → Hành động → Quan sát kết quả → Suy nghĩ lại → ... → Trả lời
Trong ví dụ HR:
Suy nghĩ: Cần tìm ứng viên Backend Go.
Hành động: gọi search_candidates().
Quan sát: tìm được 10 CV.
Suy nghĩ lại: cần chấm điểm theo AWS, MySQL, tiếng Nhật.
Hành động tiếp: gọi score_candidate().
Với task đơn giản, vòng lặp này có thể viết bằng code thường. Nhưng khi workflow có nhiều bước, rẽ nhánh, dừng chờ người duyệt, resume sau vài giờ hoặc vài ngày, tự viết bằng while sẽ rất nhanh rối. Đây là lý do LangGraph tồn tại.
PHẦN I — HIỂU BA CÔNG CỤ QUA BÀI TOÁN HR
3. LangChain: bộ đồ nghề để nối LLM với thế giới bên ngoài
Nếu chỉ cần làm một việc rất đơn giản, bạn chưa chắc cần LangChain.
Ví dụ:
Tóm tắt CV này trong 5 dòng.
Trường hợp đó, gọi thẳng OpenAI / Anthropic / Gemini API cũng được.
Nhưng HR Copilot không đơn giản như vậy. Nó cần nhiều mảnh ghép:
- prompt để hướng dẫn model,
- model để suy luận,
- tool để gọi database ứng viên,
- retriever để tìm CV hoặc policy liên quan,
- output parser để trả kết quả dạng JSON,
- streaming, retry, fallback, batch nếu chạy ở production.
LangChain giúp chuẩn hóa các mảnh ghép đó để ta nối chúng thành một pipeline.
JD + CV
→ Prompt đánh giá
→ LLM
→ Structured Output
→ Backend lưu kết quả
3.1 LangChain giải quyết pain gì?
Khi mới thử AI, ta thường viết kiểu:
response = client.chat.completions.create(...)
Cách này ổn cho demo nhỏ. Nhưng khi app lớn dần, bạn sẽ gặp nhiều câu hỏi:
- Nếu muốn đổi model từ GPT sang Claude thì sao?
- Prompt có nhiều biến thì quản lý thế nào?
- Làm sao bắt LLM trả JSON đúng schema?
- Làm sao cho LLM gọi tool như
search_candidates()? - Làm sao ghép RAG vào để trả lời dựa trên dữ liệu thật?
- Làm sao stream kết quả, retry khi lỗi, fallback khi model fail?
LangChain không làm thay toàn bộ sản phẩm cho bạn. Nó cho bạn bộ linh kiện chuẩn hóa để build nhanh và gọn hơn.
3.2 Các mảnh ghép quan trọng trong LangChain
Model
Model là LLM bạn dùng: GPT, Claude, Gemini, Llama local...
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-opus-4-8")
result = llm.invoke("Tóm tắt CV này trong 5 bullet points")
Điểm hay là khi đổi provider, phần còn lại của pipeline ít bị ảnh hưởng hơn so với gọi API thủ công ở nhiều nơi.
Prompt Template
Prompt template giúp bạn viết prompt có biến, dễ tái sử dụng và dễ test.
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "Bạn là HR specialist có kinh nghiệm tuyển dụng IT."),
("user", "Đánh giá CV sau so với JD.\n\nCV:\n{cv}\n\nJD:\n{jd}")
])
Thay vì nối chuỗi thủ công ở nhiều chỗ, bạn có một template rõ ràng.
Structured Output
Với app thật, text tự do rất khó xử lý.
Ví dụ output tự do:
Ứng viên này khá phù hợp, có thể mời phỏng vấn.
Backend sẽ khó biết điểm là bao nhiêu, decision là gì, thiếu skill nào.
Output tốt hơn:
{
"match_score": 82,
"decision": "interview",
"strengths": ["Go", "AWS", "MySQL"],
"risks": ["Chưa rõ kinh nghiệm leadership"]
}
Structured output giúp AI trả về dữ liệu có hình dạng rõ ràng để backend dùng tiếp.
Tool
Tool là function/API mà agent có thể gọi.
Ví dụ:
search_candidates(skills=["Go", "AWS"], language="N2")
get_candidate_cv(candidate_id="C001")
send_email(to, subject, body)
update_pipeline_status(candidate_id, status)
LLM không tự biết database nội bộ của công ty. Tool chính là cầu nối để LLM chạm vào dữ liệu thật.
Retriever / RAG
RAG là pattern:
Câu hỏi
→ Tìm tài liệu liên quan
→ Đưa tài liệu vào prompt
→ LLM trả lời dựa trên tài liệu đó
Trong HR Copilot, RAG có thể dùng để tìm:
- JD liên quan,
- CV cũ,
- policy tuyển dụng,
- salary band,
- interview guideline,
- note lịch sử ứng viên.
Chain
Chain là pipeline tuyến tính.
chain = prompt | llm | output_parser
result = chain.invoke({"cv": cv_text, "jd": jd_text})
Tư duy rất đơn giản:
Input → Prompt → Model → Parser → Output
Chain rất hợp với tác vụ một đường thẳng: tóm tắt, phân loại, trích xuất thông tin, chấm điểm theo schema.
3.3 Ví dụ LangChain trong HR Copilot
Ví dụ chấm điểm CV theo JD:
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
class CandidateScore(BaseModel):
candidate_name: str
match_score: int = Field(ge=0, le=100)
level: str
strengths: list[str]
risks: list[str]
recommendation: str # "move_to_interview" | "hold" | "reject"
prompt = ChatPromptTemplate.from_messages([
("system", "Bạn là HR specialist tuyển dụng IT. Trả kết quả theo schema."),
("user", "Đánh giá CV sau so với JD.\n\nCV:\n{cv}\n\nJD:\n{jd}")
])
llm = ChatAnthropic(model="claude-opus-4-8").with_structured_output(CandidateScore)
chain = prompt | llm
result = chain.invoke({"cv": cv_text, "jd": jd_text})
Output mong muốn:
{
"candidate_name": "Nguyen Van A",
"match_score": 82,
"level": "middle",
"strengths": ["Go backend", "AWS", "MySQL"],
"risks": ["Chưa thấy kinh nghiệm leadership rõ ràng"],
"recommendation": "move_to_interview"
}
3.4 Khi nào chỉ cần LangChain?
LangChain là đủ nếu workflow còn đơn giản:
| Bài toán | Có cần LangGraph không? |
|---|---|
| Upload CV → tóm tắt JSON | Chưa cần |
| CV + JD → score | Chưa cần |
| Hỏi đáp policy tuyển dụng bằng RAG | Chưa cần |
| Soạn email draft từ template | Chưa cần |
Nhưng khi có nhiều bước, rẽ nhánh, phê duyệt, retry, resume, LangChain một mình bắt đầu chưa đủ. Lúc đó ta cần LangGraph.
4. LangGraph: khi agent không thể chạy theo một đường thẳng
LangChain rất hợp để ghép pipeline. Nhưng tuyển dụng không phải lúc nào cũng đi theo một đường thẳng.
Ví dụ workflow thật có thể là:
Tìm CV
→ Nếu không có ứng viên phù hợp: hỏi lại HR có muốn nới tiêu chí không
→ Nếu có ứng viên tốt: soạn email
→ Trước khi gửi: chờ HR duyệt
→ Nếu HR yêu cầu sửa email: quay lại bước soạn
→ Nếu HR duyệt: gửi email và cập nhật trạng thái
Đây là workflow có:
- nhiều bước,
- nhiều nhánh,
- trạng thái cần giữ lại,
- vòng lặp,
- bước chờ con người,
- khả năng dừng rồi chạy tiếp.
LangGraph giúp ta mô hình hóa workflow đó thành một graph.
LangGraph biến agent từ “một đoạn prompt thông minh”
thành “một quy trình có kiểm soát”.
4.1 Các khái niệm chính trong LangGraph
| Khái niệm | Hiểu đơn giản | Ví dụ HR |
|---|---|---|
| State | Dữ liệu dùng chung của workflow | JD, danh sách CV, score, email draft |
| Node | Một bước xử lý | search_candidates, score_candidates |
| Edge | Đường nối giữa các bước | search → score |
| Conditional Edge | Rẽ nhánh theo điều kiện | score cao → soạn email, không có CV → hỏi lại HR |
| Checkpoint | Lưu trạng thái để resume | Dừng chờ HR duyệt email |
| Interrupt | Dừng workflow để con người can thiệp | HR bấm Approve / Revise / Reject |
| Subgraph | Graph nhỏ trong graph lớn | Subgraph riêng cho “email approval” |
4.2 State: bộ nhớ làm việc của workflow
State là nơi LangGraph giữ dữ liệu trong suốt quá trình chạy.
Ví dụ:
from typing import TypedDict, List, Optional
class HRCopilotState(TypedDict):
user_request: str
job_id: Optional[str]
job_description: Optional[dict]
candidates: List[dict]
scored_candidates: List[dict]
top_candidates: List[dict]
email_draft: Optional[dict]
hr_approval_status: Optional[str]
final_result: Optional[str]
Nếu không có state, mỗi bước sẽ khó biết bước trước đã làm gì. Agent dễ bị mất ngữ cảnh hoặc phải truyền dữ liệu thủ công rất rối.
4.3 Node: mỗi bước là một function rõ ràng
Một node có thể là:
- một function Python bình thường,
- một lần gọi LLM,
- một lần gọi tool,
- hoặc một agent nhỏ hơn.
Ví dụ:
load_job_description
search_candidates
score_candidates
rank_candidates
generate_email_draft
wait_hr_approval
send_email
update_pipeline_status
Điểm tốt là workflow trở nên rất dễ đọc. Nhìn graph là biết agent đang được phép đi qua những bước nào.
4.4 Conditional edge: chỗ workflow rẽ nhánh
Trong HR Copilot, sau khi chấm điểm xong, ta có thể rẽ nhánh:
Nếu có ứng viên đạt ngưỡng → soạn email
Nếu không có ai đạt → trả report / hỏi lại HR
Sau khi HR duyệt email:
approved → gửi email
revise → soạn lại
rejected → dừng
Đây là lý do LangGraph mạnh hơn chain tuyến tính.
4.5 Human-in-the-loop: AI đề xuất, con người quyết định
Với tuyển dụng, không nên để AI tự gửi email hoặc tự reject ứng viên mà không có người duyệt.
Cách an toàn hơn:
AI tìm ứng viên
→ AI soạn email
→ HR duyệt
→ hệ thống mới gửi
Trong LangGraph, bước này có thể dùng interrupt() để dừng workflow.
from langgraph.types import interrupt
def wait_hr_approval(state: HRCopilotState):
decision = interrupt({"email_draft": state["email_draft"]})
return {"hr_approval_status": decision}
Workflow có thể dừng tại đây, chờ HR bấm Approve / Revise / Reject, rồi resume từ đúng chỗ đó.
4.6 Checkpoint: dừng rồi chạy tiếp
Nếu HR chưa duyệt email ngay thì sao?
Không vấn đề. LangGraph có checkpointer để lưu state. Agent có thể dừng hôm nay và tiếp tục ngày mai.
Ví dụ:
Ngày 1: AI tìm ứng viên, soạn email, dừng chờ HR duyệt.
Ngày 2: HR bấm Approve, workflow resume, gửi email, cập nhật pipeline.
Đây là điểm rất quan trọng khi build agent cho nghiệp vụ thật.
4.7 Ví dụ workflow LangGraph cho HR Copilot
START
→ parse_hr_request
→ load_job_description
→ search_candidates
→ filter_candidates
→ score_candidates
→ rank_candidates
→ select_top_candidates
→ generate_recommendation_report
→ need_email?
├── no → END
└── yes → generate_email_draft
→ wait_hr_approval
├── approved → send_email → update_pipeline_status → END
├── revise → revise_email → wait_hr_approval
└── rejected → END
Code rút gọn:
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt
builder = StateGraph(HRCopilotState)
builder.add_node("load_jd", load_jd_fn)
builder.add_node("search", search_candidates_fn)
builder.add_node("score", score_candidates_fn)
builder.add_node("rank", rank_candidates_fn)
builder.add_node("draft_email", generate_email_draft_fn)
builder.add_node("send_email", send_email_fn)
builder.add_node("update_status", update_pipeline_fn)
def wait_hr_approval(state: HRCopilotState):
decision = interrupt({"email_draft": state["email_draft"]})
return {"hr_approval_status": decision}
builder.add_node("wait_hr_approval", wait_hr_approval)
builder.add_edge(START, "load_jd")
builder.add_edge("load_jd", "search")
builder.add_edge("search", "score")
builder.add_edge("score", "rank")
def route_after_rank(state: HRCopilotState):
return "draft_email" if state["top_candidates"] else END
builder.add_conditional_edges("rank", route_after_rank, {
"draft_email": "draft_email",
END: END,
})
builder.add_edge("draft_email", "wait_hr_approval")
def route_after_approval(state: HRCopilotState):
return {
"approved": "send_email",
"revise": "draft_email",
"rejected": END,
}[state["hr_approval_status"]]
builder.add_conditional_edges("wait_hr_approval", route_after_approval, {
"send_email": "send_email",
"draft_email": "draft_email",
END: END,
})
builder.add_edge("send_email", "update_status")
builder.add_edge("update_status", END)
graph = builder.compile(checkpointer=MemorySaver())
4.8 Khi nào nên dùng LangGraph?
Dùng LangGraph khi bạn thấy các dấu hiệu này:
| Dấu hiệu | Ví dụ |
|---|---|
| Workflow nhiều bước | Search → score → rank → draft → approve → send |
| Có nhánh điều kiện | Nếu thiếu thông tin thì hỏi lại HR |
| Có vòng lặp | HR yêu cầu sửa email nhiều lần |
| Có state cần giữ | JD, CV, score, email draft |
| Có human approval | Trước khi gửi email hoặc update ATS |
| Cần resume | HR duyệt sau vài giờ hoặc vài ngày |
| Cần kiểm soát agent | Không để LLM tự quyết mọi thứ trong prompt |
Nếu task chỉ là prompt | model | parser, dùng LangGraph có thể hơi thừa. Nhưng nếu task là một quy trình nghiệp vụ thật, LangGraph rất đáng dùng.
5. LangSmith: nhìn thấy agent đã làm gì
Một vấn đề lớn của AI app là: khi nó trả lời sai, ta thường không biết sai ở đâu.
Ví dụ HR hỏi:
Vì sao AI lại chọn ứng viên A thay vì ứng viên B?
Nếu không có trace, bạn chỉ thấy kết quả cuối cùng. Bạn không biết:
- AI đã đọc đúng JD chưa,
- đã tìm đúng CV chưa,
- tool search có trả thiếu dữ liệu không,
- prompt chấm điểm có thiếu tiêu chí không,
- model có tự suy diễn quá đà không,
- chi phí request đó là bao nhiêu,
- bước nào chạy chậm nhất.
LangSmith giúp ghi lại toàn bộ hành trình đó.
User request
→ load_job_description
→ search_candidates
→ read_candidate_cv
→ score_candidate
→ generate_email_draft
→ wait_hr_approval
LangSmith không trực tiếp làm agent thông minh hơn. Nhưng nó giúp team nhìn thấy, debug, đánh giá và cải thiện agent theo thời gian.
5.1 Trace: camera quay lại toàn bộ request
Trace cho thấy từng bước agent đã đi qua:
Request input
→ load_job_description(job_id="GO-BE-2026")
→ search_candidates(skills=["Go", "MySQL", "AWS"])
→ read_candidate_cv(C001)
→ score_candidate(C001)
→ read_candidate_cv(C002)
→ score_candidate(C002)
→ rank_candidates
→ generate_summary
→ final_answer
Nếu kết quả sai, bạn có thể mở trace và kiểm tra:
| Câu hỏi debug | Có thể phát hiện |
|---|---|
| Agent gọi đúng tool chưa? | Gọi nhầm search_old_candidates thay vì search_candidates |
| Tool trả dữ liệu đúng chưa? | CV thiếu phần kinh nghiệm gần nhất |
| RAG lấy đúng tài liệu chưa? | Lấy nhầm JD Java thay vì JD Go |
| LLM chấm điểm có hợp lý không? | Ưu tiên sai tiêu chí |
| Bước nào chậm? | Vector search mất 4 giây |
| Request nào tốn token? | Prompt chứa quá nhiều CV không cần thiết |
5.2 Evaluation: đừng đánh giá AI bằng cảm giác
Khi build AI app, rất dễ nói:
Mình test thấy cũng ổn.
Nhưng “thấy ổn” không đủ cho production.
Bạn cần dataset test:
| Input | Expected behavior |
|---|---|
| “Đánh giá CV A cho JD Senior Go” | Trả score, strengths, risks, recommendation |
| “Gửi email reject ứng viên B” | Không gửi ngay, phải yêu cầu HR xác nhận |
| “Tìm ứng viên Java nhưng JD là Go” | Cảnh báo mismatch |
| “Ứng viên thiếu salary expectation” | Đánh dấu missing information |
| “Soạn email offer” | Dùng template chính thức và chờ approval |
LangSmith giúp chạy evaluation trên dataset đó để xem agent có bị hồi quy sau mỗi lần đổi prompt, đổi model, đổi retriever không.
Các kiểu evaluator thường gặp:
| Evaluator | Dùng khi nào |
|---|---|
| Human | Cần HR / expert chấm tay |
| Code | Có rule rõ ràng, ví dụ output phải có field match_score |
| LLM-as-judge | Muốn LLM khác chấm độ hợp lý của câu trả lời |
| Pairwise | So sánh output của prompt A và prompt B |
5.3 Monitoring: khi agent chạy thật
Khi đưa HR Copilot vào production, bạn cần theo dõi:
- latency,
- token usage,
- cost,
- error rate,
- tool failure,
- retrieval quality,
- feedback của HR,
- prompt version,
- model version,
- đường đi của agent trong graph.
Không có monitoring, team chỉ nghe được câu: “AI trả lời sai”. Có monitoring, team biết sai ở đâu và sửa đúng chỗ.
5.4 LangSmith không chỉ dùng cho LangChain
Một điểm đáng chú ý: LangSmith không bắt buộc app của bạn phải viết bằng LangChain.
Bạn có thể dùng LangSmith để quan sát app viết bằng nhiều framework hoặc SDK khác, nhờ nó hỗ trợ chuẩn tracing / observability như OpenTelemetry.
Nói đơn giản: LangSmith là lớp quan sát cho AI app, không phải chỉ là “log viewer của LangChain”.
PHẦN II — CASE STUDY: BUILD HR COPILOT
6. HR Copilot cần làm gì?
Hãy tưởng tượng công ty muốn build một tool nội bộ tên HR Copilot.
HR nhập:
Tìm giúp tôi ứng viên phù hợp cho vị trí Senior Backend Go Developer,
ưu tiên có AWS, MySQL, tiếng Nhật N2. Nếu phù hợp thì soạn email mời phỏng vấn.
Tool cần chạy như sau:
Hiểu yêu cầu
→ Lấy JD
→ Tìm ứng viên
→ Đọc CV và note cũ
→ Chấm điểm
→ Xếp hạng
→ Giải thích lý do chọn
→ Soạn email
→ Chờ HR duyệt
→ Gửi email
→ Cập nhật pipeline
→ Ghi trace
Đây là một ví dụ rất tốt để thấy vì sao cần cả ba công cụ:
| Lớp | Làm gì trong HR Copilot |
|---|---|
| LangChain | prompt, model, structured output, tool calling, RAG |
| LangGraph | workflow nhiều bước, state, nhánh, approval, resume |
| LangSmith | trace, debug, evaluation, monitoring |
7. Kiến trúc tổng thể
HR User
→ Web App / Slack Bot / Internal Tool
→ Backend API
→ AI Layer
├── LangChain
│ ├── Model
│ ├── Prompt
│ ├── Tool calling
│ ├── Retriever / RAG
│ └── Structured output
│
├── LangGraph
│ ├── State
│ ├── Nodes
│ ├── Edges
│ ├── Conditional routing
│ ├── Human approval
│ └── Checkpoint
│
└── LangSmith
├── Trace
├── Evaluation
├── Monitoring
└── Cost / latency tracking
→ Business Systems
├── Candidate DB
├── CV storage
├── JD database
├── Gmail / SMTP
├── Google Calendar
├── Slack
└── ATS / Google Sheet
8. Data model đơn giản
Để demo, ta có thể bắt đầu với ba nhóm dữ liệu:
Candidate
- id
- name
- email
- skills
- language_level
- years_of_experience
- current_status
- cv_url
- notes
JobDescription
- id
- title
- required_skills
- nice_to_have_skills
- language_requirement
- level
- salary_range
PipelineStatus
- candidate_id
- job_id
- status
- last_contacted_at
- interviewer
- next_action
Đừng thiết kế quá phức tạp từ đầu. Prototype chỉ cần đủ dữ liệu để chứng minh workflow chạy được.
9. Tool list cho HR Copilot
| Tool | Input | Output | Mục đích |
|---|---|---|---|
get_job_description |
job_id / keyword | JD detail | Lấy thông tin vị trí |
search_candidates |
skills, level, language | Candidate list | Tìm ứng viên |
get_candidate_cv |
candidate_id | CV text | Đọc CV |
get_candidate_notes |
candidate_id | Notes/history | Biết lịch sử liên hệ |
score_candidate |
CV + JD | Score JSON | Chấm điểm |
generate_email_draft |
candidate + JD | Email draft | Soạn email |
request_hr_approval |
draft + candidate | approval result | Chờ HR duyệt |
send_email |
to, subject, body | send result | Gửi email |
update_pipeline_status |
candidate_id, status | update result | Cập nhật ATS |
post_slack_summary |
channel, message | post result | Báo cáo cho team |
Nguyên tắc quan trọng: không phải tool nào agent cũng được gọi tự do.
| Tool | Rủi ro | Nên kiểm soát thế nào |
|---|---|---|
search_candidates |
Thấp | Cho phép |
get_candidate_cv |
Trung bình | Log access |
send_email |
Cao | Cần HR approval |
update_pipeline_status |
Cao | Cần approval hoặc role permission |
send_offer_letter |
Rất cao | Bắt buộc human approval |
10. Mockup luồng sử dụng
Màn 1 — HR nhập yêu cầu
┌─ HR Copilot ───────────────────────────────────────────────┐
│ │
│ HR ▸ Tìm ứng viên cho Senior Backend Go Developer, │
│ ưu tiên AWS / MySQL / tiếng Nhật N2. Nếu hợp thì │
│ soạn email mời phỏng vấn. [Gửi] │
│ │
│ ⏳ Agent đang chạy… │
│ ✓ Đã lấy JD: Senior Backend Go Developer │
│ ✓ Tìm thấy 3 ứng viên │
│ ✓ Chấm điểm xong │
│ ✓ 1 ứng viên đạt ngưỡng │
│ ⏸ Đã soạn email — đang chờ bạn duyệt │
│ │
└────────────────────────────────────────────────────────────┘
Màn 2 — Bảng ứng viên đã chấm điểm
┌─ Kết quả: Senior Backend Go Developer ─────────────────────┐
│ │
│ # Ứng viên Điểm Đề xuất Điểm mạnh │
│ ─ ───────────── ──── ─────────── ─────────────── │
│ 1 Nguyen Van A 92★ Mời PV Go, MySQL, AWS │
│ 2 Tran Thi B 64 Tạm giữ Go, MySQL │
│ 3 Le Van C 58 Tạm giữ AWS │
│ │
│ ▸ Vì sao chọn #1? │
│ Khớp 3/3 kỹ năng bắt buộc + N2 + 5 năm kinh nghiệm. │
│ Rủi ro: chưa rõ kinh nghiệm quản lý team. │
│ │
│ [ Xem CV đầy đủ ] [ Soạn email cho #1 ] │
└────────────────────────────────────────────────────────────┘
Màn 3 — HR duyệt email trước khi gửi
┌─ Duyệt email trước khi gửi ────────────────────────────────┐
│ Tới: a@example.com │
│ Tiêu đề: Invitation to interview - Senior Backend Go Dev │
│ ──────────────────────────────────────────────────────── │
│ Hi Nguyen Van A, │
│ Cảm ơn anh đã quan tâm vị trí Senior Backend Go Developer │
│ … nội dung do agent soạn … │
│ Best regards, HR Team │
│ ──────────────────────────────────────────────────────── │
│ [ ✓ Duyệt & Gửi ] [ ✎ Sửa lại ] [ ✗ Hủy ] │
└────────────────────────────────────────────────────────────┘
Ba nút này ánh xạ trực tiếp vào ba nhánh trong LangGraph:
approved → send_email → update_pipeline_status
revise → revise_email → wait_hr_approval
rejected → END
11. Lộ trình build prototype
Không nên build full HR Copilot ngay từ đầu. Nên đi từng version nhỏ.
| Version | Mục tiêu | LangChain | LangGraph | LangSmith |
|---|---|---|---|---|
| V1 — CV summarizer | Upload CV → JSON tóm tắt | model + prompt + structured output | Chưa cần | Bật trace |
| V2 — CV-JD matcher | CV + JD → score + strengths + risks | prompt + parser + model | Chưa cần | Eval dataset |
| V3 — Candidate search | Yêu cầu → search DB → top candidates | tool calling | Bắt đầu nếu nhiều bước | Trace tool calls |
| V4 — Interview email | Soạn email → HR duyệt → gửi | generate draft | Approval workflow | Trace + monitor |
| V5 — Full HR Copilot | Search → Evaluate → Recommend → Draft → Approve → Send → Update → Report | components | full orchestration | observability + eval |
Cách này giúp team có kết quả sớm, giảm rủi ro và dễ đo chất lượng.
12. Từ demo tới production: cần thay gì?
Một demo HR Copilot có thể dùng dữ liệu in-memory và fake email. Nhưng để chạy thật, cần thay dần từng phần.
| Mảng | Demo | Production |
|---|---|---|
| Dữ liệu | List / JSON in-memory | Postgres, MySQL, ATS, Google Sheet |
| CV storage | Text mẫu | S3, Google Drive, internal file storage |
| Tìm ứng viên | Lọc list bằng keyword | DB query + vector search |
| Chấm điểm | Rule đơn giản | LLM + structured output + evaluation |
| Gửi email | Print / fake list | Gmail API / SMTP |
| Cập nhật ATS | Fake update | API ATS / Google Sheet |
| Checkpointer | MemorySaver | SQLite / Postgres checkpointer |
| Giao diện | Console | Web app / Slack bot |
| Quan sát | print log | LangSmith trace |
| Phân quyền | Chưa có | Auth + role-based permission |
Nói ngắn gọn:
Prototype: chứng minh workflow đúng.
Production: thay mock bằng hệ thống thật, thêm permission, trace, eval, monitoring.
PHẦN III — SO SÁNH VÀ KHI NÀO DÙNG CÁI NÀO
13. Chain, Agent và Graph khác nhau ở đâu?
| Khái niệm | Hiểu đơn giản | Khi nào dùng |
|---|---|---|
| Chain | Pipeline thẳng | Prompt → Model → Parser |
| Agent | LLM tự quyết gọi tool nào | Cần tool calling linh hoạt |
| Graph | Workflow có state, node, edge, nhánh | Nhiều bước, approval, resume |
Ví dụ HR:
Chain:
CV + JD → LLM → Score JSON
Agent:
HR hỏi → agent tự quyết cần search JD, tìm CV, đọc note
Graph:
Search → Score → Rank → Draft Email → Wait Approval → Send → Update ATS
14. So sánh LangChain, LangGraph, LangSmith
| Tiêu chí | LangChain | LangGraph | LangSmith |
|---|---|---|---|
| Vai trò | Dựng app/agent từ component | Điều phối workflow agent có state | Quan sát, debug, đánh giá |
| Trừu tượng chính | Prompt, model, tool, retriever, parser, Runnable | Node, Edge, State, Checkpoint | Trace, Dataset, Evaluator, Metrics |
| Câu hỏi nó trả lời | “Dùng model/tool/data thế nào?” | “Agent đi qua bước nào?” | “Agent đã làm gì, sai ở đâu?” |
| App đơn giản | Rất hợp | Hơi thừa | Hữu ích nếu muốn trace |
| Workflow phức tạp | Một mình chưa đủ | Rất hợp | Rất cần |
| Human approval | Tự xử lý thêm | Hỗ trợ tốt | Quan sát được |
| Evaluation | Không phải trọng tâm | Không phải trọng tâm | Trọng tâm |
| Monitoring production | Không phải trọng tâm | Không phải trọng tâm | Trọng tâm |
15. Khi nào dùng gì?
Chỉ dùng LLM API trực tiếp
Dùng khi:
- task rất nhỏ,
- không cần tool,
- không cần RAG,
- không cần structured output phức tạp,
- không cần trace sâu.
Ví dụ:
Dịch email từ tiếng Nhật sang tiếng Việt.
Dùng LangChain
Dùng khi:
- cần prompt template,
- cần structured output,
- cần tool calling,
- cần RAG,
- cần pipeline rõ ràng.
Ví dụ:
CV + JD → score JSON
Dùng LangGraph
Dùng khi:
- workflow nhiều bước,
- có nhánh,
- có state,
- có human approval,
- cần resume,
- cần kiểm soát flow thay vì để prompt tự lo.
Ví dụ:
Tìm CV → chấm điểm → soạn email → HR duyệt → gửi email → update ATS
Dùng LangSmith
Dùng khi:
- muốn debug,
- muốn evaluation,
- muốn monitor cost/latency,
- muốn quan sát production,
- muốn biết agent sai ở đâu.
Ví dụ:
HR phản ánh AI chọn ứng viên sai → mở trace xem lỗi ở tool, prompt, RAG hay model.
16. Đặt LangChain / LangGraph giữa rừng framework
Ngoài bộ ba này còn nhiều framework khác. Mỗi framework có triết lý riêng.
| Framework | Triết lý chính | Hợp với |
|---|---|---|
| LangGraph | Graph / máy trạng thái | Workflow nhiều bước, state, approval |
| LlamaIndex | Dữ liệu và RAG | App hỏi đáp trên kho tài liệu lớn |
| Microsoft AutoGen | Multi-agent conversation | Nhiều agent trò chuyện / phối hợp |
| CrewAI | Vai trò và team agent | Mô phỏng team: researcher, writer, reviewer |
| DSPy | Khai báo và tối ưu prompt | Tự động tối ưu pipeline/prompt |
| Haystack | NLP/search pipeline | Search, RAG production theo pipeline |
La bàn chọn nhanh:
- Nặng về workflow có kiểm soát → LangGraph.
- Nặng về RAG / data retrieval → LlamaIndex hoặc LangChain retriever.
- Nặng về multi-agent hội thoại → AutoGen.
- Muốn diễn đạt theo vai trò trong team → CrewAI.
- Muốn tối ưu prompt tự động → DSPy.
Ghi chú: phần này chỉ nên xem như bản đồ định hướng. Khi chọn công nghệ cho production, vẫn nên kiểm tra tài liệu chính thức và thử prototype nhỏ.
PHẦN IV — DEEP DIVE NGẮN CHO DEVELOPER
Phần này dành cho người muốn hiểu sâu hơn. Nếu bạn chỉ cần build prototype, có thể đọc lướt.
17. ReAct: vòng lặp vừa nghĩ vừa làm
ReAct là một ý tưởng nền tảng của nhiều agent hiện đại.
Thay vì để model trả lời một lần, agent chạy theo vòng:
Reason → Act → Observe → Reason again
Trong HR Copilot:
Reason: Cần tìm ứng viên có Go, AWS, MySQL.
Act: gọi search_candidates().
Observe: có 12 ứng viên.
Reason: cần loại người thiếu tiếng Nhật N2.
Act: gọi filter_candidates().
Observe: còn 3 ứng viên.
Reason: chấm điểm và chọn người tốt nhất.
LangChain giúp implement tool calling. LangGraph giúp biến vòng lặp này thành workflow có kiểm soát.
18. Reflexion: agent biết rút kinh nghiệm
Reflexion là ý tưởng agent có thể tự ghi lại bài học sau mỗi lần chạy.
Ví dụ sau một lần chọn sai ứng viên, agent có thể lưu note:
Lần sau không nên chỉ dựa vào keyword AWS trong CV.
Cần kiểm tra xem ứng viên có kinh nghiệm production thật hay chỉ liệt kê skill.
Trong thực tế, phần “trí nhớ” này có thể được hiện thực bằng state, memory, checkpoint hoặc storage riêng.
LangGraph không tự biến agent thành “biết học” theo nghĩa huấn luyện lại model. Nhưng nó cung cấp hạ tầng state/checkpoint để lưu và dùng lại thông tin giữa các lượt chạy.
19. LangChain Runnable và LCEL
Nếu đi sâu vào LangChain, khái niệm quan trọng là Runnable.
Hiểu đơn giản, Runnable là giao diện chung cho các mảnh ghép có thể chạy được:
- prompt,
- model,
- parser,
- retriever,
- tool,
- function tự viết.
Các runnable thường có những cách gọi giống nhau:
| Method | Ý nghĩa |
|---|---|
invoke / ainvoke |
Chạy một input |
batch / abatch |
Chạy nhiều input |
stream / astream |
Stream kết quả |
LCEL cho phép nối runnable bằng dấu |:
chain = prompt | model | output_parser
Nói dễ hiểu: LangChain cố gắng làm cho các mảnh ghép AI có chung một “đầu nối”, để việc ghép pipeline gọn như xếp Lego.
20. LangGraph, Pregel và super-step
LangGraph lấy cảm hứng từ mô hình xử lý graph như Pregel / BSP.
Hình dung đơn giản, graph chạy theo từng “đợt”:
1. Xem node nào cần chạy
2. Chạy các node đó
3. Gộp kết quả vào state
4. Chuyển sang đợt tiếp theo
Cách chạy này giúp workflow có tính rõ ràng:
- node nào chạy,
- state được cập nhật lúc nào,
- checkpoint lưu ở đâu,
- khi resume thì quay lại mốc nào.
Với production, cần lưu ý: durable execution phụ thuộc vào checkpointer và cách triển khai hạ tầng. Prototype có thể dùng MemorySaver, nhưng production nên dùng storage bền hơn như SQLite/Postgres checkpointer.
21. LangSmith và OpenTelemetry
LangSmith có thể nhận trace từ nhiều app/framework khác nhau. Một lý do là nó hỗ trợ hướng tiếp cận observability dựa trên chuẩn như OpenTelemetry.
Ý nghĩa thực tế:
Bạn không bị bắt buộc phải viết app bằng LangChain mới dùng được LangSmith.
Nếu team đã có Datadog, Grafana hoặc hệ thống observability riêng, LangSmith có thể là lớp chuyên biệt cho AI trace/eval, còn hệ thống hiện tại tiếp tục dùng cho infra/app metrics.
PHẦN V — LỖI THƯỜNG GẶP VÀ KẾT LUẬN
22. Năm lỗi thường gặp khi build HR AI tool
Lỗi 1: Cho LLM quyết định quá nhiều
Không nên để LLM tự reject ứng viên hoặc tự gửi email.
Nên làm:
AI đề xuất → HR duyệt → hệ thống hành động
Lỗi 2: Không dùng structured output
Text tự do dễ đọc nhưng khó xử lý bằng backend.
Nên dùng JSON/schema cho những kết quả quan trọng:
{
"match_score": 82,
"recommendation": "move_to_interview",
"risks": ["Thiếu leadership experience"]
}
Lỗi 3: Không có trace
Khi AI sai, không có trace thì gần như chỉ đoán mò.
Nên bật LangSmith sớm, kể cả ở prototype.
Lỗi 4: Không có evaluation dataset
Đừng đánh giá AI bằng cảm giác. Hãy tạo dataset gồm các case:
- CV phù hợp,
- CV không phù hợp,
- thiếu thông tin,
- yêu cầu gửi email,
- yêu cầu cần approval,
- policy-sensitive.
Lỗi 5: Không kiểm soát quyền tool
Tool càng nguy hiểm càng cần kiểm soát.
search_candidates → có thể cho phép
get_candidate_cv → log access
send_email → cần approval
update_pipeline_status → cần approval / permission
send_offer_letter → bắt buộc human approval
23. Kết luận
Nếu chỉ nhớ một đoạn, hãy nhớ đoạn này:
LangChain giúp AI có khả năng.
LangGraph giúp AI làm việc theo quy trình.
LangSmith giúp team tin được, debug được và cải thiện được AI.
Với bài toán HR:
- Chỉ tóm tắt CV → LangChain là đủ.
- Cần tìm ứng viên, chấm điểm, soạn email, chờ duyệt → thêm LangGraph.
- Muốn biết vì sao agent sai, đo chất lượng, theo dõi cost/latency → dùng LangSmith.
Công thức thực dụng:
Prototype nhanh:
LangChain + LangSmith
Workflow có approval:
LangChain + LangGraph + LangSmith
Production agent:
LangChain components
+ LangGraph orchestration
+ LangSmith observability/evaluation
Điểm quan trọng nhất: AI không nên thay HR hoàn toàn.
AI nên đóng vai HR Copilot:
- làm nhanh phần lặp lại,
- tổng hợp thông tin,
- đề xuất ứng viên,
- soạn nháp email,
- giải thích lý do,
- còn con người vẫn giữ quyền quyết định ở các bước quan trọng.
Một agent tốt không phải là agent “tự làm tất cả”. Một agent tốt là agent làm đúng phần nên tự động hóa, biết dừng đúng lúc, và để con người kiểm soát những quyết định quan trọng.
Phụ lục A — Cheat sheet thuật ngữ
| Thuật ngữ | Giải thích ngắn | Ví dụ HR |
|---|---|---|
| LLM | Large Language Model | GPT/Claude đọc CV và sinh nhận xét |
| Prompt | Instruction gửi cho LLM | “Đánh giá CV này theo JD sau” |
| Prompt Template | Prompt có biến | {cv}, {jd}, {criteria} |
| Chain | Pipeline tuyến tính | Prompt → LLM → JSON |
| Tool | Function/API agent có thể gọi | search_candidates() |
| RAG | Search tài liệu rồi mới trả lời | Hỏi policy tuyển dụng nội bộ |
| Retriever | Thành phần tìm tài liệu liên quan | Search JD/policy/CV notes |
| Agent | LLM quyết định bước/tool tiếp theo | Tìm ứng viên rồi soạn email |
| State | Dữ liệu hiện tại của workflow | JD, candidates, score, email draft |
| Node | Một bước trong graph | score_candidates |
| Edge | Đường nối giữa các node | score cao → draft email |
| Conditional Edge | Rẽ nhánh theo điều kiện | approve → send, reject → stop |
| Checkpoint | Lưu trạng thái để resume | Chờ HR duyệt email |
| Trace | Log chi tiết toàn bộ execution | Xem agent đã gọi tool nào |
| Evaluation | Test chất lượng agent | Dataset CV/JD mẫu |
| Monitoring | Theo dõi production | cost, latency, error rate |
Phụ lục B — Nguồn tham khảo
Tài liệu chính thức
- LangChain GitHub: https://github.com/langchain-ai/langchain
- LangGraph Overview: https://docs.langchain.com/oss/python/langgraph/overview
- LangSmith Overview: https://docs.langchain.com/langsmith/home
- LangGraph Graph API: https://docs.langchain.com/oss/python/langgraph/graph-api
- LangGraph Persistence: https://docs.langchain.com/oss/python/langgraph/persistence
- LangGraph Subgraphs: https://docs.langchain.com/oss/python/langgraph/use-subgraphs
- LangSmith Observability: https://docs.langchain.com/langsmith/observability
- LangSmith Evaluation: https://docs.langchain.com/langsmith/evaluation
Nền tảng lý thuyết
- Yao et al. (2022), ReAct: Synergizing Reasoning and Acting in Language Models: https://arxiv.org/abs/2210.03629
- Shinn et al. (2023), Reflexion: Language Agents with Verbal Reinforcement Learning: https://arxiv.org/abs/2303.11366
- Xi, Chen et al. (2023), The Rise and Potential of LLM-Based Agents: A Survey: https://arxiv.org/abs/2309.07864
Kiến trúc & thiết kế
- LangChain Core — Runnable API: https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.Runnable.html
- LangChain — LCEL: https://python.langchain.com/docs/concepts/lcel/
- LangGraph GitHub: https://github.com/langchain-ai/langgraph
- LangGraph Pregel runtime: https://docs.langchain.com/oss/python/langgraph/pregel
- LangGraph Durable Execution: https://docs.langchain.com/oss/python/langgraph/durable-execution
- LangSmith OpenTelemetry: https://blog.langchain.com/opentelemetry-langsmith/
- LangSmith trace with OpenTelemetry: https://docs.langchain.com/langsmith/trace-with-opentelemetry
So sánh framework
- LangChain — AI Agent Frameworks: https://www.langchain.com/resources/ai-agent-frameworks
- Các bài so sánh framework từ cộng đồng như dev.to, theflyingbirds.in, aryaxai.com. Phần này chỉ nên dùng để tham khảo định hướng, không thay thế việc đọc tài liệu chính thức.