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, LangGraphLangSmith 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 theogọ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"
}

1pJ6VnTG2J-58Ofw_KJAwPYNYzcn-f9vW

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 searchscore
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())

1-MR8PoGA9EPJ8AhP4NMc7bEA8flC0TDT

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ỗ.

1y0Nx6E8jHtl3eOcfMHVPIDRHuzKlyR5f

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

Nền tảng lý thuyết

Kiến trúc & thiết kế

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.