Ba cách build AI agent bằng Python: CrewAI, OpenAI Agents SDK, LangGraph
Cùng một coding agent bốn tool được build lại bằng CrewAI, OpenAI Agents SDK và LangGraph, kèm bảng so sánh và cách chọn framework.
✓ Đã duyệt độc lập · cập nhật 21/10/2026 · 32 min
1. Ba framework, đi từ đơn giản tới phức tạp
Tim mở đầu video bằng lời hứa: bạn sẽ học cách build AI agent bằng Python, thông qua ba framework thuộc nhóm phổ biến nhất hiện có (theo video đăng ngày 23/09/2026): CrewAI, OpenAI Agents SDK và LangGraph. Thứ tự đi sẽ là từ đơn giản nhất tới phức tạp nhất. Qua đó bạn thấy chính xác ngoài kia có những công cụ nào, chúng hoạt động ra sao, build với chúng như thế nào, và cuối cùng là nên chọn cái nào.

Anh nói rõ mục tiêu: không phải viết lại từng dòng code từ con số không, mà là đưa cho bạn một cái nhìn tổng quan ở mức high level. Có cái nhìn đó rồi, bạn mới ra được quyết định tốt nhất và đi sâu vào đúng framework hợp với thứ mình đang muốn build.
Video này đến sau một video trước của Tim, trong đó anh chỉ cách làm agent hoàn toàn từ đầu bằng Python thuần, không dùng framework nào. Video lần này là bước "lên cấp" (level up): bắt đầu nhìn vào các framework, thứ mạnh hơn và cho phép build những agent thật sự thú vị. Anh nói mình đã chuẩn bị một loạt demo, và từ đây đi thẳng vào nội dung.
2. Cùng một agent, cùng bốn tool, chỉ đổi framework
Cách Tim làm trong video là cho bạn xem cùng một AI agent được build ba lần, với ba framework khác nhau. Như vậy bạn so được độ phức tạp, tính năng của từng cái, và cuối cùng biết mình nên dùng framework nào.
Trên màn hình là một slide có tiêu đề "Ranked by capability, not hype" (xếp theo năng lực, không theo độ hot). Đầu tiên là CrewAI. Theo Tim (theo video đăng ngày 23/09/2026), đây có lẽ là cách đơn giản nhất để build AI agent, ít nhất là loại agent có chút độ phức tạp và có tính năng. Với nó, bạn gần như chỉ cần mô tả thứ mình muốn bằng ngôn ngữ tự nhiên, và đó là lý do thanh "capability" (năng lực) và "effort" (công sức) của nó được xếp như trên slide.

list_files, read_file, write_file và run_command (tool này hỏi xin phép trước khi chạy). Dòng dưới giải thích đây là "nhóm đối chứng": tool và task không đổi, thứ duy nhất đổi là framework bọc quanh chúng.Tiếp theo là OpenAI Agents SDK, phức tạp hơn một chút nhưng vẫn tương đối dễ dùng (theo video đăng ngày 23/09/2026). Cuối cùng là LangGraph, chắc chắn là phức tạp nhất, khó hiểu nhất, nhưng cũng mạnh nhất, và là thứ bạn có lẽ sẽ chọn khi cần một agent chuẩn production (production-grade).
Agent mà cả ba phiên bản cùng build sẽ có quyền dùng bốn tool. Tim giải thích vì sao cần tool: thứ làm cho một agent trở thành agent là nó thật sự tương tác được với thế giới bên ngoài. Nó gọi được function, gọi được API. Nó không chỉ là một AI model. Model sẽ cấp năng lượng cho agent và đóng vai bộ não; nhưng khi build một agent, thứ bạn thật sự làm là trao năng lực cho model, rồi mô tả bạn muốn nó hoạt động thế nào, muốn nó làm gì, task nào nó phải hoàn thành.
Với cả ba agent, bốn năng lực đó là: liệt kê file (list files), đọc file (read file), ghi file (write file) và chạy lệnh (run command). Chỉ với bốn thứ đó, chúng đã hoạt động được như một coding agent đầy đủ: viết script, build cả một ứng dụng, đọc xem trong một repo đang có gì. Rồi bạn sẽ thấy chúng chạy ra sao.
3. CrewAI: mô tả agent như một tin tuyển dụng
Bắt đầu với CrewAI. Tim cho xem trên màn hình đại khái CrewAI trông thế nào, rồi nói anh sẽ nhảy vào code editor và cho xem vài ví dụ build agent bằng framework này. Nhìn chung, theo Tim (video đăng ngày 23/09/2026), CrewAI là framework đơn giản nhất trong danh sách. Tất nhiên còn rất nhiều framework khác, nhưng đây là ba trong số những cái phổ biến nhất.
Trong CrewAI (theo video đăng ngày 23/09/2026), về cơ bản bạn mô tả một agent giống hệt như mô tả bằng ngôn ngữ tự nhiên. Bạn cho nó một role (vai trò), một goal (mục tiêu), có thể cho nó một backstory (kiểu như một system prompt, hay context khác), cho nó quyền dùng một danh sách tool, cho nó một LLM, rồi chỉ việc chạy agent. Nó sẽ đi làm điều bạn yêu cầu.

coder với role, goal, backstory, bốn tool và model openai/gpt-5-mini, rồi Crew(agents=[coder], tasks=[task]) và crew.kickoff(). Cột phải ghi: đọc như một tin tuyển dụng, không loop, không schema, không message list; tool là các hàm có decorator; kickoff() chạy mọi thứ.Nên nó rất thẳng thắn. Theo video đăng ngày 23/09/2026, bạn có thể ghép nhiều agent với nhau. Lý do nó được gọi là "crew" (một đội) là vì nó được thiết kế để xử lý nhiều agent, chạy chúng cùng lúc và giao việc (delegate task) qua lại giữa chúng.
Tim chuyển sang VS Code để xem CrewAI thực sự trông thế nào. Anh nói thật là anh không thấy có giá trị gì khi ngồi viết từng dòng code một. Đây không phải một tutorial từng bước đầy đủ; anh chỉ muốn bạn thấy những thứ này hoạt động ra sao để có hiểu biết ở mức high level.
4. Cài đặt, API key, model và tool là một hàm Python
Muốn dùng CrewAI, trước hết bạn phải cài nó. Tim nói bạn chỉ cần gõ lệnh cài như sau, rồi nó được cài và bạn dùng được:
pip install crewai
Bạn cũng cần một API hay một nhà cung cấp LLM nào đó. Trong trường hợp của Tim, anh dùng OpenAI. Anh đã tạo một file biến môi trường (environment variable file, file .env) và khai báo OpenAI API key của mình trong đó. Bạn có thể dùng gần như bất kỳ LLM nào mình muốn, kể cả LLM chạy local (theo video đăng ngày 23/09/2026), nhưng khi đó phải chỉnh lại một chút ở chỗ khai báo model.
Ở đầu chương trình chỉ là các lệnh import. Tim chỉ ra một đoạn sẽ xuất hiện ở mọi file trong video: đó là đoạn nạp file biến môi trường để đọc được API key. Còn phần import của CrewAI thì rất gọn: import Agent, Crew và Task, cộng với decorator tool. Sau đó khai báo model, ở đây là GPT-5 mini, trên màn hình viết là MODEL = "openai/gpt-5-mini".
Tiếp theo là bốn tool đã được viết sẵn. Trong CrewAI (theo video đăng ngày 23/09/2026), một tool chỉ là một hàm Python. Bạn "trang trí" hàm đó bằng @tool (decorator lấy từ CrewAI như vừa import), và decorator này sẽ tự động chuyển hàm thành thứ mà agent có thể gọi được.
Một điểm quan trọng, và bạn sẽ thấy nó ở gần như mọi framework (theo video đăng ngày 23/09/2026): khi viết các hàm này, bạn nên khai báo kiểu (type) của tham số và của giá trị trả về. Lý do là đằng sau, các framework này truyền cho model một thứ gọi là schema của hàm, mô tả input là gì và output phải là gì. Nhờ vậy model hiểu cách sinh ra đoạn code, hay đúng hơn là đoạn JSON hoặc config, để thực sự gọi các hàm đó. Tim nói bạn sẽ hiểu ý anh ngay sau đây, nhưng hãy nhớ: mặc định các model không làm được gì cả. Ta bọc chúng trong các agent framework để chúng làm được những việc như gọi tool, và đó chính là phần việc framework chịu trách nhiệm.
5. Định nghĩa agent, task và crew
Quay lại code. Như đã nói, có bốn tool: list files, read file, write file và run command. Với mỗi tool, ta có thể đặt cho nó một cái tên, hay một mô tả về việc nó làm, và thông tin đó nằm trong decorator. Phần còn lại sẽ được CrewAI tự động nạp vào (theo video đăng ngày 23/09/2026) rồi truyền cho agent.
Còn về việc tạo agent, Tim nói đây đúng là tất cả những gì bạn cần làm. Rất thẳng. Và đó là lý do, theo Tim (theo video đăng ngày 23/09/2026), đây là một trong những framework dễ dùng nhất. Ta định nghĩa agent bằng class Agent, cho nó một role, một goal, một backstory, một danh sách các tool có sẵn (chính là những hàm vừa được gắn decorator tool), khai báo model, và bật verbose mode. Verbose mode chỉ có nghĩa là nó sẽ cho ta xem nó đang "nghĩ" gì; bạn có thể đặt thành False nếu không muốn thấy hết các bước trung gian.

agent.py trong thư mục 01_crewai: khối coder = Agent(...) được khoanh lại, bên dưới là hàm main() hỏi "What should the agent do?", tạo một Task, đưa vào Crew rồi gọi kickoff().Đoạn định nghĩa agent trên màn hình:
coder = Agent(
role="Coding Assistant",
goal="Complete the user's task using your tools, then summarize what you did.",
backstory="A careful developer working inside the user's project folder.",
tools=[list_files, read_file, write_file, run_command],
llm=MODEL,
verbose=True,
)Để chạy agent, ta dùng một khối code như bên dưới. Ta cần tạo một task: mọi thứ trong CrewAI đều được gói trong task (theo video đăng ngày 23/09/2026). Bạn có thể có nhiều task, nhưng với mỗi task, phải định nghĩa mô tả của task (description), output mong đợi (expected output), và agent làm nó. Agent này phải khớp với một trong các agent đã định nghĩa ở trên.
Khi đã có các task (lát nữa Tim sẽ cho xem trường hợp nhiều task), bạn chỉ việc truyền chúng vào một instance của Crew: khai báo các agent đã viết (ở đây là coder), các task muốn chạy, rồi "kick off" cái crew. result bằng kết quả của crew, và nó sẽ thực thi crew, tức chạy AI agent, rồi trả kết quả về.
def main():
request = input("What should the agent do? ")
task = Task(
description=request,
expected_output="A short summary of what was done.",
agent=coder,
)
crew = Crew(agents=[coder], tasks=[task])
result = crew.kickoff()
print(f"\n{result}")Tất nhiên ta có thể đặt nó trong một vòng while để chạy nhiều lần. Nhưng điểm Tim muốn bạn để ý (theo video đăng ngày 23/09/2026): ta không cần lo về session hay memory. Không cần lo về vòng lặp. Ta chỉ định nghĩa thứ mình muốn, kick off, và nó chạy.
6. Chạy thử: "summarize the current dir"
Tim chạy code để cho thấy ý anh. Chương trình hỏi: bạn muốn agent làm gì? Anh gõ "summarize the current dir", tức tóm tắt thư mục hiện tại.
Vì verbose mode đang bật, ta thấy nó báo: agent đã bắt đầu, tôi sẽ liệt kê các tool này, tôi sẽ gọi tool này. "Okay, whatever", Tim nói. Ta thấy trong thư mục có CrewAI, Agents SDK, và nó muốn đọc hết những thứ đó. Nó đang đi qua từng bước và cho ta xem chính xác nó đang làm gì. Về bản chất, nó chỉ lặp đi lặp lại: gọi các tool khác nhau, đưa kết quả cho LLM, và cuối cùng sẽ đưa ra một bản tóm tắt và trả lời.
Câu trả lời khá dài. Model nói: tôi đã liệt kê thư mục project và đọc các file đọc được, rồi đưa ra gần như toàn bộ nội dung.
Nên nó không hẳn là một bản tóm tắt, và Tim nói một phần vì anh đang dùng một model khá tệ của OpenAI (nhận xét trong video đăng ngày 23/09/2026). Nhưng điểm chính là: nó đã chạy, agent đã thực thi, nó đọc được code của ta, và anh hoàn toàn có thể bảo nó viết code, nó cũng làm được.
7. Multi-agent với CrewAI: Tech Lead lập plan, coder build
Tiếp theo, Tim xem nhanh một ví dụ agent nâng cao hơn một chút vẫn bằng CrewAI, trước khi chuyển sang Agents SDK và LangGraph.
Ở file crew.py này, ta cũng import vài thứ từ file agent viết ở trước: nhớ đoạn code có list file, read file và agent coder chứ. Lại import CrewAI, lại nạp file biến môi trường, lại có model. Và lần này, Tim đã dựng một hệ multi-agent bằng CrewAI, để cho thấy chạy nó dễ đến mức nào.
Lần này có một planner agent. Ta tạo thêm một agent thứ hai, vì agent coder đã được import từ file trước. Bên trong, role là Tech Lead, rồi đến goal và backstory. Để ý phần tool: Tim chỉ cho nó quyền dùng những tool không phá huỷ gì (non-destructive), tức đọc và liệt kê file. Cùng model, và cũng bật verbose.
planner = Agent(
role="Tech Lead",
goal="Break the user's request into a short, concrete build plan.",
backstory="A pragmatic tech lead who writes plans a junior dev can follow.",
tools=[list_files, read_file],
llm=MODEL,
verbose=True,
)Đi tiếp xuống dưới, chương trình hỏi: crew nên build gì? Ta đưa mô tả vào một plan_task. Task này giao cho planner agent, và yêu cầu của người dùng được chèn vào.
![Code hàm main của crew.py với plan_task, build_task có context=[plan_task] và Crew hai agent](../photos/-RTgK6qX6A8-1043.jpg)
main() của crew.py: plan_task giao cho planner, yêu cầu một plan đánh số tối đa 5 bước; build_task giao cho coder với context=[plan_task] (chú thích trong code: coder nhận output của planner); rồi Crew(agents=[planner, coder], tasks=[plan_task, build_task]).Sau khi có plan, ta chuyển plan đó cho coding agent. Task thứ hai có mô tả "Follow the plan exactly and build it" (làm đúng theo plan và build), output mong đợi là một bản tóm tắt ngắn về những gì đã build và file nào đã đổi. agent bằng coder, context bằng plan task. Tức ta có thể đưa thêm context, và context đó chính là output của task phía trên.
Rồi tương tự, để chạy crew, Tim chỉ đưa hai agent và hai task theo đúng thứ tự muốn chúng chạy. Theo Tim (theo video đăng ngày 23/09/2026), đó là mức độ dễ dàng khi build một hệ multi-agent chạy tuần tự (sequential). Tất nhiên bạn cũng có thể build những hệ phức tạp hơn với nhiều agent khác nhau.
8. Game Tetris và vì sao CrewAI đơn giản
Nhưng điểm Tim nhấn mạnh: ta không xử lý vòng lặp. Ta không xử lý memory. Ta không làm gì phức tạp cả. Ta chỉ mô tả, gần như bằng lời thường, những gì muốn các agent làm. Kiểu: đây là các agent, đây là task ta muốn chúng hoàn thành, cứ chạy đi. Thế thôi. Đó là cách ta thiết lập để nó chạy, và đó là lý do đây là một trong những framework đơn giản nhất (theo video đăng ngày 23/09/2026).
Tim chạy thử, gõ yêu cầu: build một game Tetris đơn giản bằng Python dùng Pygame, rồi bấm Enter. Ta thấy nó bắt đầu với agent Tech Lead: tạo plan, đó là bước một. Nó đi qua, đọc hết mọi thứ rồi tạo plan. Sau đó nó sẽ gọi sang agent kia, tức coder agent, nơi agent bắt đầu chạy tool, và ta sẽ thấy các file thật sự xuất hiện trong thư mục khi nó viết code.
Plan đã ra, và giờ là agent "coding assistant" với task "follow the plan exactly". Tim chỉ vào output: đây là plan. Nó được chuyển sang agent coder và bắt đầu build. Thật vậy, đã có một file config.py được viết ra trong thư mục, và sẽ còn thêm file nữa.
"Perfect", Tim nói. Nó đã xong: giờ có thêm main.py, cùng với config.py, cả game đã được viết. Anh nói anh không thực sự quan tâm nó có cho ra một game chạy được hay không; mục đích là cho bạn thấy các agent này hoạt động và vận hành ra sao. Anh xoá các file đó đi và chuyển sang framework tiếp theo.
Vậy là xong phần CrewAI, và bạn thấy sự đơn giản của nó. Tất nhiên (theo video đăng ngày 23/09/2026) có thể vào sâu và làm những thứ nâng cao hơn, nhưng giờ Tim muốn chuyển sang Agents SDK.
9. OpenAI Agents SDK: hàm của bạn, vòng lặp của họ
Agents SDK đến từ OpenAI. Theo Tim (theo video đăng ngày 23/09/2026), nó đặc biệt hợp nếu bạn muốn làm việc với các model của OpenAI, điều này hiển nhiên. Nhưng nó cũng là một điểm giữa khá dễ chịu giữa CrewAI và một thứ như LangGraph, mà lát nữa bạn sẽ thấy là phức tạp hơn nhiều. Anh nói không cần đi qua nhiều slide, nhảy thẳng vào code luôn.

@function_tool, agent có name, instructions, model, tools, và chạy bằng Runner.run_sync(agent, user_input, session=session). Cột phải ghi (theo slide trong video đăng ngày 23/09/2026): một decorator, SDK tự đọc type hint và docstring để viết JSON schema; session chính là message list, lưu trong SQLite và gửi lại tự động; vòng lặp là của họ, nhưng hành xử đúng như vòng lặp tự viết bằng Python thuần ở video trước.Bắt đầu với agent cơ bản. Phần đầu luôn giống nhau: import những tính năng cần dùng từ framework, nạp OpenAI API key và khai báo model muốn dùng.
Giống như trước, ta có các hàm. Lần này decorator trông hơi khác một chút, nhưng về bản chất y hệt CrewAI (theo video đăng ngày 23/09/2026): ta chỉ gắn decorator cho những hàm muốn coi là tool để truyền cho agent. Không có gì nhiều để giải thích ở đó.
Tiếp theo là khai báo agent. Khi khai báo, ta có name, instructions, model và tools, rất giống trước. Trên màn hình, instructions của agent "Mini coding agent" là:
agent = Agent(
name="Mini coding agent",
instructions=(
"You are a coding agent running in the user's terminal. "
"Use your tools to complete the user's task, then briefly summarize what you did. "
"The working directory is the folder the user launched you from."
),
model=MODEL,
tools=[list_files, read_file, write_file, run_command],
)10. Session và memory, rồi một game oẳn tù tì
Khác biệt duy nhất, xét thực tế trong ví dụ đơn giản này, là ta phải tự xử lý session và memory. Tim giải thích: khi bạn gửi một request tới LLM, nó không nhớ được gì về những điều đã nói trước đó. Muốn nó nhớ, phải có lịch sử session, hay lịch sử hội thoại, thứ thường được truyền vào như một phần của prompt, và đó là lý do context length cứ tăng dần. Nên trong OpenAI Agents SDK (theo video đăng ngày 23/09/2026), bạn thấy ngay là ta phải tự quản phần này.
Nó không quá phức tạp, và SDK có sẵn tính năng để làm việc này (theo video đăng ngày 23/09/2026): ở đây ta khai báo một SQLite session. Rồi có một vòng while để chat với agent, và lần này ta gọi Runner.run_sync. Tim nói nó chỉ trông phức tạp hơn một chút vì ta có thể chạy agent theo kiểu bất đồng bộ (asynchronous) hoặc đồng bộ (synchronous).
Ta truyền agent, input của người dùng, và với tham số session, ta truyền chính cái session vừa tạo. Framework sẽ tự động nối thêm vào đó (theo video đăng ngày 23/09/2026) và để nó lớn dần khi ta chat với agent, nhờ vậy agent nhớ được các câu trả lời trước.
def main():
session = SQLiteSession("mini-agent")
print("Mini agent ready. Type 'exit' to quit.")
while True:
user_input = input("\nYou: ")
if user_input.strip().lower() in ("exit", "quit"):
break
result = Runner.run_sync(agent, user_input, session=session)
print(f"\nAgent: {result.final_output}")Tim nói sẽ chạy thử ngay, rồi cho xem một ví dụ nâng cao hơn để thấy vì sao ta có thể dùng một framework như thế này. Nhưng điểm chính là (theo video đăng ngày 23/09/2026): gần như y hệt CrewAI. Khác biệt duy nhất là ta phải quản session, và ta được trao nhiều quyền kiểm soát hơn một chút so với framework kia.
Anh chạy file. Màn hình báo "Mini agent ready. Type 'exit' to quit." Anh làm một việc tương tự lần trước: bảo nó build một game oẳn tù tì (rock, paper, scissors) đơn giản bằng Python. Nó đã tạo game: file rps.py nằm ngay đó. Cuộn qua thì thấy một phiên bản dạng text đơn giản, và việc này hoàn tất trong một khoảng thời gian rất ngắn.
Ví dụ đó chưa nói lên được nhiều, nên Tim đóng nó lại, thoát khỏi file, và mở một ví dụ nâng cao hơn, nơi framework được dùng nhiều hơn và lộ ra thêm năng lực.
11. Handoff guardrail: structured output và agent kiểm tra an toàn
Ví dụ tiếp theo là một hệ agent phức tạp hơn, gồm bốn agent khác nhau có thể giao việc cho nhau. Nó tên là handoff_guardrail vì còn có một guardrail agent kiểm tra xem một task có mang tính phá huỷ (destructive) không. Nếu có, nó sẽ không cho đi tiếp phần triage còn lại.
Tim lưu ý ta đang phức tạp hơn một chút: có một handoff prompt, có thêm vài import khác từ agents, và cũng import những thứ đã viết ở file trước, nên hãy nhớ điều đó. Cuộn xuống, lại thấy phần nạp API key, và rồi đến phần đầu tiên bạn cần chú ý.
Thứ đang thấy trên màn hình là một Pydantic model. Đây là thứ ta có thể dùng để ép output của một LLM phải theo một định dạng cụ thể. Cái này gọi là structured output, nhìn thấy ngay ở tham số output_type. Theo Tim (video đăng ngày 23/09/2026), nó rất phổ biến và cực kỳ hữu ích cho agent, nhất là khi bạn tự code chúng. Về bản chất, mỗi khi agent này trả lời, câu trả lời sẽ theo đúng định dạng này, là một object Python. Nhờ đó ta kiểm được một thứ có destructive hay không, và lý do vì sao.
Rồi ta dựng guardrail agent. Đây là agent đó: tên là "Safety check", đây là instructions, đây là output type đã khai báo, và model muốn chạy. Về cơ bản ta đang kiểm tra: nếu ta yêu cầu xoá thứ gì đó, đừng cho đi tiếp, và chỉ cần báo rằng việc này là phá huỷ.

handoff_guardrail.py (chú thích: "a tiny agent that screens every request first"): class SafetyCheck với hai trường is_destructive và reasoning, agent "Safety check" dùng nó làm output_type, và hàm block_destructive gắn @input_guardrail trả về GuardrailFunctionOutput với tripwire_triggered.class SafetyCheck(BaseModel):
is_destructive: bool
reasoning: str
guardrail_agent = Agent(
name="Safety check",
instructions=(
"Decide if the request asks to delete files, wipe folders, "
"or run destructive shell commands. Refactoring existing code is fine."
),
output_type=SafetyCheck,
model=MODEL,
)
@input_guardrail
async def block_destructive(ctx, agent, user_input) -> GuardrailFunctionOutput:
check = await Runner.run(guardrail_agent, user_input, context=ctx.context)
return GuardrailFunctionOutput(
output_info=check.final_output,
tripwire_triggered=check.final_output.is_destructive,
)Sau đó là một guardrail function. Theo video đăng ngày 23/09/2026, đây là thứ có thể đặt vào một chuỗi agent (agent chain) để được gọi. Trong hàm guardrail này bạn có thể đặt bất cứ thứ gì mình muốn; ở đây Tim đã dùng một LLM, hay đúng hơn là một agent, để phát hiện thứ gì đó có destructive hay không. Nếu có, hàm trả về rằng nó destructive. Tức là: lấy task, xem nó có phá huỷ không; nếu có, ta kích hoạt guardrail function này để nó không cho đi tiếp; ngược lại thì cho đi tiếp. Tim nói bạn sẽ hiểu khi anh bắt đầu chạy.
12. Triage, coder, explainer và chạy thử guardrail
Đi xuống tiếp là ba agent khác nhau: một coder agent, một explainer agent và một triage agent. Prompt sẽ bắt đầu từ triage agent, và việc của nó là định tuyến (route) sang một agent cụ thể tuỳ theo task là gì.
Trong triage agent có name, có instructions, và cái RECOMMENDED_PROMPT_PREFIX mà bạn thấy ở đây là thứ có thể import vào. Rê chuột lên thì thấy nó bắt đầu bằng "# System context" và "You are part of a multi-agent system". Về bản chất, nó giải thích cho agent biết rằng nó là một phần của một hệ multi-agent và có thể chuyển việc (hand off) cho agent khác. Nó lấy thẳng từ OpenAI Agents SDK (theo video đăng ngày 23/09/2026).
Tiếp theo, ta khai báo hai handoff, tức hai agent có thể giao việc cho: coder hoặc explainer. Rồi đến input guardrail, một guardrail có sẵn trong framework (theo video đăng ngày 23/09/2026): ta gọi hàm block_destructive, rồi xem có kích hoạt guardrail hay không. Nếu kích hoạt, ta dừng ngay tại đó. Nếu không, ta cho triage agent làm việc.

handoffs=[coder, explainer] và input_guardrails=[block_destructive]. Trong terminal, yêu cầu "Delete all the files in this directory." bị trả về "[guardrail]: Blocked. That request looked destructive."Hai agent còn lại, coder và explainer, mỗi agent có một handoff_description để triage hiểu nên dùng cái nào. Rồi vẫn vậy: tools, model, bạn hiểu rồi. Trên màn hình, coder có mô tả "Writes, edits, and runs code.", còn explainer là "Explains the codebase without changing anything." và chỉ có hai tool đọc: list_files, read_file.
Phần cuối khai báo triage agent trên màn hình:
instructions=(
f"{RECOMMENDED_PROMPT_PREFIX}\n\n"
"Route the user. Hand off build/edit/run requests to the Coder. "
"Hand off questions about the code to the Explainer."
),
model=MODEL,
handoffs=[coder, explainer],
input_guardrails=[block_destructive],
)Cuối file, việc duy nhất là chạy flow: chạy triage agent với input của người dùng rồi in ra câu trả lời. Nếu "tripwire" bị kích hoạt, ta báo kiểu: này, yêu cầu này đã bị chặn.
Tim chạy file để cho xem nó hoạt động thế nào. Anh thử một yêu cầu như "Delete all the files in this directory" (xoá hết file trong thư mục này) và hy vọng guardrail sẽ chặn. "Perfect": guardrail chạy, và nó không cho đi tiếp vì đã bị chặn.
Rồi anh hỏi một thứ như "summarize the contents of the current directory" (tóm tắt nội dung thư mục hiện tại), để xem trước hết nó giao cho agent nào và câu trả lời ra sao. Câu trả lời hiện ra, và nó ghi rằng chính explainer agent đang trả lời.
Tiếp theo anh hỏi: "Can you write me a simple README file or some kind of markdown file that just has this summary inside of it?" (viết cho tôi một file README đơn giản, hay một file markdown, chỉ chứa bản tóm tắt này). Lần này lẽ ra nó phải sang coder agent, agent có quyền tạo file, rồi tạo file đó trong thư mục. Nhưng vì lý do nào đó, nó không đi thẳng sang coder agent. Tim copy câu hỏi và dán lại để thử cho chắc là nó chạy. Lúc dán thì mọi thứ rối tung, vì câu được dán vào thành nhiều dòng.
"Anyways", Tim nói, các bạn hiểu ý rồi: framework này trông như vậy. Bạn để ý là phần hệ multi-agent đã phức tạp hơn một chút. Giờ anh chuyển sang LangGraph.
13. LangGraph: framework phức tạp nhất, và là nơi bạn tự vẽ vòng lặp
Framework tiếp theo là LangGraph, framework phức tạp nhất trong danh sách (theo video đăng ngày 23/09/2026). Tim nói điều đó không có nghĩa là bạn không thể làm thứ gì đơn giản với nó, chỉ là nó khó hiểu hơn một chút vì phần graph và cách agent chảy (flow) qua graph.
Anh có những tutorial đầy đủ về LangGraph trên kênh của mình nếu bạn muốn học kỹ, vì video này, một lần nữa, chỉ là tổng quan ở mức high level. Hãy nhớ là anh đang cố cho bạn thấy các cách khác nhau để làm agent.

agent (gọi model với state), nếu có tool call thì sang node tools (chạy tool, nối kết quả) rồi quay lại agent, không có tool call thì END. Cột phải: node là hàm, edge là luồng, và sơ đồ này không phải ẩn dụ mà chính là code add_node, add_edge; state là tường minh; checkpoint "thay đổi mọi thứ" vì state được lưu sau mỗi bước.Theo Tim, LangGraph là framework sẵn sàng cho production nhất, và nó có rất nhiều use case production (theo video đăng ngày 23/09/2026). Rất nhiều người dùng nó. Còn LangChain là một lớp wrapper dễ dùng hơn một chút của LangGraph. Anh quyết định không đưa LangChain vào video này vì mọi thứ trong LangChain về bản chất chỉ là lớp bọc bên trên LangGraph, thứ bạn sắp thấy đây.
Trong LangGraph, bạn tự tạo và tự quản vòng lặp của mình. Theo Tim (theo video đăng ngày 23/09/2026), ở các framework vừa xem, vòng lặp agentic (agentic loop), nơi diễn ra việc gọi tool và cả quá trình đó, gần như được tự động hoá sẵn cho bạn. Bạn có thể hook vào và thay đổi vài thứ, nhưng ở LangGraph, bạn thực sự tự thiết kế nó hoàn toàn. Điều đó cho bạn quyền kiểm soát trọn vẹn để quyết định chính xác flow vận hành của agent.
Theo video đăng ngày 23/09/2026, nó cũng cho bạn observability, khả năng ghi log, và một cách để lặp lại các task khác nhau hoặc quay lại một trạng thái đã checkpoint, thứ mà Tim gọi là rất, rất mạnh. Anh muốn cho xem code trông thế nào, và bạn sẽ thấy ngay độ phức tạp.
Mở file agent.py của LangGraph: một loạt import, gồm chat models, messages, tools, checkpoint và graph. Thứ cần chú ý nhất là graph, vì đó là thứ ta đang tạo và là lý do ta dùng framework này. Như mọi khi, nạp API key, rồi đến system prompt. Docstring đầu file ghi: "Level 3: LangGraph. The agent is a graph you draw yourself: nodes, edges, and state."
14. Tool, model và các node cập nhật state
Tương tự trước, ta có các tool, và cũng chỉ việc gắn decorator tool. Phần này gần như giữ nguyên ở mọi framework (theo video đăng ngày 23/09/2026). Nhưng để ý: giờ ta phải tự tạo danh sách tool, một dictionary ánh xạ tên tới từng tool. Model cũng phức tạp hơn một chút: ta khởi tạo một chat model rồi "bind" các tool vào nó.
TOOLS = {t.name: t for t in [list_files, read_file, write_file, run_command]}
model = init_chat_model(MODEL).bind_tools(list(TOOLS.values()))Có model rồi. Và thay vì tạo một agent chung chung, thứ ta thực sự làm là tạo các node khác nhau cho hình dạng của vòng lặp agent. Có một agent node, một tool node, và một điều kiện should continue, một kiểu node nữa.
Tim nói anh sẽ không giải thích toàn bộ LangGraph, nhưng về cơ bản (theo video đăng ngày 23/09/2026), LangGraph hoạt động bằng cách bạn tạo các node, giữa chúng có các edge, và bạn cập nhật state trên mỗi edge, tức mỗi kết nối giữa các node. Ý tưởng là ta bắt đầu từ agent node: để ý là nó nhận vào một state và trả về một phiên bản đã cập nhật của state đó. Tool node cũng vậy: nhận state, trả về state đã cập nhật. Và chính cách bạn xử lý state quyết định output và flow của graph.
Tim thừa nhận nghe còn mơ hồ, vì đang ở mức high level, và nó chưa nên "vào" 100% đâu; bạn sẽ thấy rõ khi các edge được nối lại. Nhưng (theo video đăng ngày 23/09/2026) mọi thứ ở đây được làm thủ công hơn nhiều, và điều đó, một lần nữa, cho ta nhiều quyền kiểm soát hơn hẳn.
def agent_node(state: MessagesState):
reply = model.invoke([SystemMessage(SYSTEM_PROMPT)] + state["messages"])
return {"messages": [reply]}15. Nối các edge, checkpoint và chạy agent LangGraph
Giờ xem phần build graph. Trong graph, ta tạo một StateGraph, rồi thêm các node vào: agent node và tool node. Sau đó là một edge: nối node START với agent node, nghĩa đơn giản là graph bắt đầu ở đây. Ta bắt đầu bằng cách nhận một state rồi gọi model chạy với system prompt cộng các message đang có trong state. Lấy câu trả lời và trả nó về.
Tiếp theo là tool node. Ở các framework trước (theo video đăng ngày 23/09/2026), tool được xử lý tự động cho ta, nhưng ở đây ta phải tự gọi tool bằng tay. Ta kiểm: trong các message, hay trong câu trả lời vừa nhận từ model, có tool call nào không? Nếu model muốn gọi tool, ta tự invoke tool đó. output bằng tool có tên này, invoke với các tham số này; kiểm xem có lỗi gì không (trên màn hình, chú thích ghi: trả lỗi về cho model để nó tự phục hồi thay vì làm sập graph), rồi nối kết quả trở lại vào state, để ta thấy tool đã thực sự trả về gì. Cứ thế đi qua, gọi hết các tool, trả kết quả về.
Rồi đến một conditional edge (edge có điều kiện). Conditional edge này quay về agent: agent, tools, agent. Nhưng ta chỉ quay về agent, tức tiếp tục vòng lặp hay graph này, nếu should_continue trả về đúng. should_continue kiểm tra: có tool call nào không, hay vừa rồi có tool call nào được chạy không? Nếu không, ta kết thúc. Nên "tools" và END là hai kết quả có thể có của conditional edge này. Rồi lại một edge nữa, tools về agent, và bạn hiểu ý rồi.

should_continue (còn tool call thì đi "tools", không thì END) và build_graph: hai node agent, tools; edge START sang agent; conditional edge từ agent; edge ("tools", "agent") đang được khoanh; cuối cùng compile(checkpointer=checkpointer). Chú thích ghi: "the graph: you draw the agent loop as edges".def build_graph(checkpointer=None):
builder = StateGraph(MessagesState)
builder.add_node("agent", agent_node)
builder.add_node("tools", tool_node)
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue, ["tools", END])
builder.add_edge("tools", "agent")
return builder.compile(checkpointer=checkpointer)Tim công nhận nó hơi phức tạp, nhưng về cơ bản ta đang tự build toàn bộ flow của agent và khai báo chính xác cách đi giữa các state. Và ta có toàn quyền kiểm soát mọi thứ làm bên trong các hàm này (theo video đăng ngày 23/09/2026).
Xuống phần gọi chạy: ta build graph ra. Bản thân thứ này là một graph, nó đã được compile, và ta build nó bằng cách gọi hàm đó. Ta tạo một checkpoint, thứ sẽ lưu toàn bộ state diễn ra trong graph (chú thích trên màn hình: checkpointer lưu state sau mỗi node, memory là "miễn phí"). Ta có một thread ID, vì thực ra có thể chạy song song, có nhiều agent cùng lúc (theo video đăng ngày 23/09/2026). Rồi một vòng while đơn giản, trong đó ta invoke graph: graph.invoke với message của người dùng và config, và đi qua quá trình đó.
Tim chạy để cho xem nó trông thế nào, dù nhắc lại là nó chưa "vào" 100% đâu. Điểm chính là ta có nhiều quyền kiểm soát hơn hẳn, ta tự build graph. Nếu bạn đã từng build agent, bạn sẽ quý việc hook được vào tất cả các thành phần này. Nó cũng cho phép route giữa các task khác nhau, làm hệ multi-agent, và làm bất cứ gì bạn muốn với độ linh hoạt gần như không giới hạn (nhận định của Tim, theo video đăng ngày 23/09/2026).
Anh test bằng yêu cầu: build một game oẳn tù tì đơn giản bằng Python trong thư mục hiện tại. "Perfect": nó đã build game RPS ngay đó, mở ra là thấy. Rồi để ý là nó đang hỏi xin phép anh để thực sự chạy lệnh: một lệnh Python chạy file RPS với cờ --help. Anh trả lời "no", và nói anh tin đó là vì anh đã build sẵn bước hỏi xin phép thẳng vào tool run command. Agent sẽ kết thúc, báo lại: đây là những gì tôi đã làm, và ta có thể chat tiếp với nó.
Tim nói đó là phiên bản "đơn giản" của LangGraph, nghe buồn cười vì nó vẫn phức tạp. Giờ đến ví dụ có human in the loop.
16. Multi-agent graph: graph lồng trong graph
Tim đi qua một ví dụ LangGraph nâng cao hơn. Đây là một hệ multi-agent, giống thứ đã làm với Agents SDK: có một triage node đọc yêu cầu rồi chọn một route.
Mỗi "specialist" chính là vòng lặp agent vừa có trong agent.py, được compile và thả vào thành một node duy nhất. Nên nó giống như một graph trong một graph. Reviewer có thể gửi việc ngược về cho coder, nên graph có một chu trình (cycle) thật sự. Tim chỉ vào sơ đồ mà AI đã vẽ ra trong docstring: Start, triage, explainer, end; hoặc đi coder, tới reviewer, qua lại, bạn hiểu ý.

multi_agent.py trong thư mục 03_langgraph: docstring "The LangGraph party trick: a multi-agent graph you can actually see", cụm "compiled and dropped in as a single node" được khoanh lại, và sơ đồ ASCII của các route."""The LangGraph party trick: a multi-agent graph you can actually see.
A triage node reads the request and picks a route. Each specialist is the
agent loop from agent.py, compiled and dropped in as a single node.
The reviewer can send work back to the coder, so the graph has a real cycle.
START -> triage -> explainer -> END
-> coder -> reviewer -> END
^ |
+-----------+ (changes requested)
"""Ta import, nạp file biến môi trường, và import file trước (trên màn hình là import agent as base), nên hãy nhớ điều đó. Rồi có MAX_REVISIONS, số lần tối đa được đi qua lại giữa các node; trong code nó bằng 2.
Đây là state: có route hiện tại, cờ approved, và số lần revision. Nó sẽ đóng vai state chung dùng về sau.
class State(MessagesState):
route: str # set by triage: "coder" or "explainer"
approved: bool # set by the reviewer
revisions: int # how many times the reviewer sent work backTiếp theo là một hàm tạo specialist. Về cơ bản, nó cho phép ta build một subgraph riêng cho từng agent: agent, tools, agent, điều kiện có tiếp tục không. Chính xác là thứ đã có trong agent.py, chỉ là được gói trong một hàm riêng.
Rồi ta tạo hai specialist: một coder và một explainer. Ta truyền vào mô tả, hay prompt, truyền tên, và truyền các tool muốn cho nó dùng. Trên màn hình, coder có thêm câu "If you receive reviewer feedback, fix exactly what it asks for." và đủ bốn tool; explainer có prompt "You explain the codebase. Read files as needed and answer the question. Never write or run anything." và chỉ có list_files, read_file.
Đi xuống là một kiểu route, tức structured output cho triage agent: trên màn hình là class Route với trường agent chỉ nhận "coder" hoặc "explainer", và trường reason. Rồi đến triage model: lần này ta dùng with_structured_output, gắn nó vào chat model. Structured output là Route, và method là function calling.
triage_model = init_chat_model(base.MODEL).with_structured_output(Route, method="function_calling")
17. Triage, reviewer và vòng lặp sửa bài với game Tetris
Rồi có một triage node. Tim biết là phức tạp, anh chỉ đang lướt nhanh một ví dụ nâng cao. Triage node gọi triage model với system message, truyền state vào, rồi quyết định: ta sẽ đi tới agent nào, route sẽ là gì? Ta truy cập được decision.agent, và lý do là vì agent nằm sẵn trong structured output kia. Trên màn hình, system message của triage là "Route the user's latest request. coder: anything that builds, edits, or runs code. explainer: questions about the code that change nothing."
Tiếp theo là pick_specialist: nó chỉ lấy state và đi tới route tương ứng. Rồi đến reviewer. Với reviewer, lại có một structured output, là Review, gồm approved hoặc feedback. Reviewer model ở ngay đây. Rồi có reviewer node, nơi ta thực sự invoke message, kiểm xem có approved không, và tuỳ vào đó trả về một state khác. Sau đó có hàm after_review.
class Review(BaseModel):
approved: bool
feedback: str
reviewer_model = init_chat_model(base.MODEL).with_structured_output(Review, method="function_calling")
def reviewer_node(state: State):
review = reviewer_model.invoke([
SystemMessage(
"You are the code reviewer. Look at what the coder just did in this conversation: "
"the files it wrote and the commands it ran. Approve if the work meets the user's "
"request and has no obvious bugs. Otherwise reject with short, specific feedback."
),
*state["messages"],
])Rồi ta build một graph đầy đủ với mọi node được nối lại. Có state graph; thêm triage agent; rồi node coder, node explainer, node reviewer. Tim lưu ý các node này chưa được nối với nhau, ta mới chỉ khai báo chúng trong graph. Rồi ta nói muốn có một edge: bắt đầu từ triage agent. Một conditional edge chọn specialist, đi sang coder hoặc explainer: đó là quá trình triage. Rồi một edge nữa từ coder sang reviewer, và một conditional edge nơi reviewer quyết định sẽ kết thúc hay gửi về lại coder. Sau đó là checkpoint, và tiếp tục.
builder.add_edge(START, "triage")
builder.add_conditional_edges("triage", pick_specialist, ["coder", "explainer"])
builder.add_edge("explainer", END)
builder.add_edge("coder", "reviewer")
builder.add_conditional_edges("reviewer", after_review, ["coder", END])
return builder.compile(checkpointer=checkpointer)Rồi ta chạy toàn bộ graph, và nó cho phép đi qua lại giữa các agent dựa trên điều model quyết định là cần làm. Đây là hệ nâng cao hơn (theo video đăng ngày 23/09/2026): ta kiểm soát được ở mọi state, thêm được bất kỳ edge nào muốn, và đã tạo ra nhiều sub-agent bên trong chuỗi agent này.
multi_agent.py: triage chọn explainer hoặc coder; việc của coder đi qua reviewer, được duyệt thì kết thúc, chưa đạt thì quay về coder.Tim chạy code và yêu cầu: "Write a Tetris game in Python using PyGame and review it and make sure it's accurate" (viết game Tetris bằng Python dùng PyGame, review nó và đảm bảo nó chính xác). Lẽ ra giờ nó sẽ triage sang coding agent. Coding agent được nối sẵn, nên mỗi lần xong việc nó phải đi tới reviewer agent. Anh tìm cho bạn ngay đây: có node coder, reviewer. Nó đã triage xong. "Boom", nó đi sang coder. Ta chờ coder xong, rồi sẽ đi sang reviewer. Reviewer sẽ đưa feedback, quay về coder, và tiếp tục flow đó.
18. Bảng so sánh và nên chọn framework nào
"Perfect": nó viết xong. Reviewer vừa nói approved rồi báo: này, tôi xong rồi. Nó đi tới đây và đưa ra câu trả lời. Nhìn vào thư mục thì thấy có test_tetris.py cũng như tetris.py ("nếu tôi nói cho đúng", Tim nói), và cả game đã được viết. Trên màn hình, log ghi coder đã write_file(test_tetris.py), run_command(python test_tetris.py) sau khi hỏi xin phép, rồi "[reviewer] approved". Vậy là xong LangGraph.
Giờ Tim làm một bản tóm tắt tổng thể ba framework vừa xem, bằng một bảng so sánh nhanh. Tất cả các đánh giá dưới đây là của Tim theo video đăng ngày 23/09/2026.

CrewAI (theo video đăng ngày 23/09/2026): rất nhanh, và làm được multi-agent team. Tuy nhiên, theo Tim, nó không có guardrail dựng sẵn, không có chuyện tạm dừng chờ người duyệt (human approval), hay sống sót khi bị restart giữa chừng một task. Ta có thể thêm những thứ đó, nhưng kém trực quan hơn so với các framework kia. Còn việc kiểm soát chính vòng lặp agentic cũng vậy: phần lớn bị lấy đi và framework lo hết (trên slide, ô này ghi "black box"). Một lần nữa, không có nghĩa là ta không làm được những việc đó, chỉ là chúng không được hỗ trợ sẵn trong framework.
Agents SDK (theo video đăng ngày 23/09/2026): nhanh, không phải nhanh nhất, nhưng vẫn khá nhanh để build một agent. Có handoff. Vòng lặp là của họ, nhưng ta hook vào được. Nó có guardrail dựng sẵn ngay bên trong. Tạm dừng chờ người duyệt? Làm được, nhưng không linh hoạt bằng (slide ghi "inside one turn", trong một lượt). Còn sống sót qua restart giữa task thì không, nó không có khả năng đó.
LangGraph (theo video đăng ngày 23/09/2026): chắc chắn là chậm nhất, phức tạp nhất, khó build nhất, nhưng làm được team với bất kỳ kích thước, hình dạng nào. Ta tự vẽ và tự kiểm soát vòng lặp. Ta tự build guardrail của mình. Ta có thể "đóng băng" nó ở bất cứ đâu muốn, checkpoint nó, hand off, làm task khác, và thật sự có mức kiểm soát tối đa, nhất là khi đưa lên production.
Vậy nên dùng cái nào? Câu trả lời của Tim (theo video đăng ngày 23/09/2026):
- CrewAI rất hợp cho prototype, demo, tool nội bộ, những thứ tương đối đơn giản để build. Trên slide: bạn muốn có agent ngay hôm nay và không quan tâm bên trong nó chạy thế nào; nhãn "weekend projects".
- Agents SDK: rất nhiều sản phẩm thật dùng được nó. Code sạch, vòng lặp "trung thực" (honest loop), guardrail, handoff, đủ thứ. Slide đóng khung nó và gắn nhãn "the default choice" (lựa chọn mặc định).
- LangGraph là thứ dùng khi bạn muốn build những hệ agentic phức tạp hơn nhiều để đưa lên production, nơi bạn cần xử lý state, cần quan tâm từng bước, và chấp nhận build một thứ sẽ tốn nhiều thời gian hơn hẳn. Slide ghi: agent CHÍNH LÀ sản phẩm, có bước duyệt, task chạy lâu, state phải sống sót qua sự cố; nhãn "production workflows".
Dòng cuối trên slide "Which one should you use?" là một lời khuyên: bắt đầu ở mức thấp nhất giải quyết được vấn đề của bạn; bạn luôn có thể leo lên, còn leo xuống thì là viết lại từ đầu.
Tim kết thúc video: anh hy vọng nó hữu ích và hẹn gặp ở video sau.
Nguồn và liên kết 7 nguồn
- Tên gốc: How to Build AI Agents in Python - 3 Ways
- Sự kiện: YouTube
- Video gốc: https://www.youtube.com/watch?v=-RTgK6qX6A8 youtube.com
- Kênh YouTube Tech With Tim (Tim Ruscica): youtube.com/channel/UC4JX40jDee_tINbkjycV4Sg youtube.com
- Tài liệu CrewAI (Agent, Task, Crew, tool): docs.crewai.com, repo github.com/crewAIInc/crewAI docs.crewai.com
- OpenAI Agents SDK cho Python: tài liệu chính thức, các trang Sessions (có
SQLiteSession), Guardrails (input guardrail và tripwire) và Handoffs (cóRECOMMENDED_PROMPT_PREFIX); repo github.com/openai/openai-agents-python openai.github.io - LangGraph: tổng quan trong tài liệu LangChain, repo github.com/langchain-ai/langgraph docs.langchain.com