Introduction to AI Agents: Tại sao Agents (tự làm việc) quan trọng hơn Chatbot
7/19/2026 · 15p đọc
title: "Introduction to AI Agents: Tại sao Agents (tự làm việc) quan trọng hơn Chatbot"
series: "AI-Native Solutions Architect: Từ Coder đến Kiến trúc sư AI"
season: "Season 3 — AI Agents & Platform Engineering"
order: 21
audience: "Software Engineer hướng tới Solutions Architect"
reading_time: "14 phút"
tags: ["ai-agents", "agentic-ai", "react", "tool-use", "function-calling", "autonomous-agents", "solutions-architect"]
Introduction to AI Agents: Tại sao Agents (tự làm việc) quan trọng hơn Chatbot
Một Pull Request mới được mở. Bạn dán diff vào ChatGPT hoặc Claude chat, hỏi "review giúp tôi đoạn code này". Model trả lời khá tốt — chỉ ra một vài vấn đề tiềm ẩn, gợi ý sửa. Nhưng để biết test có pass không, bạn phải tự copy lệnh, tự chạy, tự dán kết quả ngược lại vào chat để hỏi tiếp "test fail chỗ này, giờ sao". Rồi lại tự vào GitHub, tự viết comment, tự đăng. Ba, bốn vòng qua lại thủ công cho một việc mà bản thân nó không hề phức tạp về mặt logic — chỉ đơn giản là nhiều bước, và bạn là người duy nhất nối các bước đó lại với nhau.
Đây là giới hạn cố hữu của mọi chatbot, dù model nền có mạnh đến đâu. ChatGPT, Claude chat, hay bất kỳ giao diện hỏi-đáp nào đều được thiết kế cho một vòng lặp duy nhất: bạn nhập, nó xuất, kết thúc. Nó không tự chạy lệnh, không tự đọc kết quả, không tự quyết định bước tiếp theo dựa trên một quan sát vừa xảy ra trong thế giới thực. Muốn nó "biết" điều gì mới, bạn phải là người mang thông tin đó quay lại — thủ công, mỗi lần một câu.
Phần lớn công việc kỹ thuật thực tế không có dạng "hỏi một câu, nhận một câu trả lời". Review một PR đòi hỏi đọc diff, chạy test, diễn giải kết quả, rồi hành động (comment, approve, reject) — bốn bước phụ thuộc lẫn nhau, bước sau chỉ quyết định được khi biết kết quả bước trước. Đây chính là khoảng trống mà AI Agent được sinh ra để lấp: một hệ thống không chỉ trả lời, mà tự lập kế hoạch, tự gọi công cụ, tự quan sát kết quả, và tự lặp lại quy trình đó cho tới khi đạt mục tiêu — không cần bạn làm người chuyển tiếp thông tin ở giữa. Đây cũng là điểm khởi đầu của Season 3: từ đây, chúng ta không còn nói về "prompt tốt hơn" nữa, mà về cách thiết kế cả một hệ thống có khả năng hành động.
Vấn đề
Hãy hình dung rõ hơn quy trình review PR thủ công qua chatbot ở trên, tách thành từng bước:
- Bạn copy diff của PR, dán vào chat, hỏi "có vấn đề gì không".
- Model chỉ ra vài điểm nghi ngờ — nhưng nó không biết test có pass không, vì nó không truy cập được vào hệ thống CI thật.
- Bạn tự chạy
pnpm test, copy output, dán ngược lại: "đây là kết quả test, giờ sao". - Model diễn giải kết quả, gợi ý fix — nhưng không tự sửa code, không tự chạy lại test để xác nhận fix đúng.
- Bạn tự quyết định approve hay request changes, tự viết comment, tự đăng lên GitHub.
Không bước nào trong 5 bước này khó về mặt suy luận. Cái thiếu là khả năng tự hành động dựa trên kết quả quan sát được. Chatbot dừng lại đúng ở ranh giới của một lượt hỏi-đáp; mọi thứ xảy ra sau khi nó trả lời — chạy lệnh, đọc file, gọi API, đăng comment — đều phải do con người thực hiện và mang kết quả quay lại.
Vấn đề càng rõ khi số bước tăng lên hoặc kết quả một bước quyết định nhánh rẽ của bước sau. Nếu test pass, agent nên comment "LGTM". Nếu test fail, nó cần đọc thêm log lỗi, xác định file nào gây fail, rồi mới viết review chính xác. Một chatbot không có cơ chế "nếu X thì làm Y, nếu không thì đọc thêm rồi quyết định lại" — nó chỉ có một lượt input-output, không có trạng thái giữa các lượt, không có quyền tự gọi công cụ để lấy thêm thông tin khi cần.
Nói cách khác: chatbot là một hàm thuần túy f(input) -> output, không có side effect, không có bộ nhớ về hành động đã thực hiện, không có khả năng chủ động đi lấy dữ liệu mới. Còn phần lớn công việc kỹ sư thực sự làm hằng ngày — deploy, review, điều tra incident, migrate dữ liệu — đều là chuỗi hành động có trạng thái, phụ thuộc lẫn nhau, và cần điều chỉnh theo từng kết quả trung gian.
Kỹ thuật cốt lõi
Phân biệt rạch ròi Chatbot và Agent
| Tiêu chí | Chatbot | Agent |
|---|---|---|
| Mô hình xử lý | Input → Output, một lượt | Observe → Think → Act, lặp nhiều vòng |
| Trạng thái (state) | Không giữ trạng thái giữa các hành động thực (chỉ giữ lịch sử hội thoại) | Giữ trạng thái xuyên suốt: lịch sử hành động + kết quả quan sát được |
| Gọi công cụ (tool use) | Không tự gọi, hoặc gọi rồi dừng lại chờ người dùng | Tự quyết định gọi tool nào, khi nào, dựa trên mục tiêu |
| Điều kiện dừng | Kết thúc sau một câu trả lời | Tự đánh giá đã đạt mục tiêu chưa, hoặc chạm giới hạn bước |
| Vai trò con người | Người điều phối — mang thông tin qua lại giữa các lượt | Người đặt mục tiêu và giám sát — agent tự điều phối các bước |
| Phù hợp cho | Trả lời câu hỏi, giải thích, sinh nội dung một lần | Tác vụ nhiều bước, phụ thuộc kết quả trung gian, cần hành động thực |
Ranh giới quan trọng nhất trong bảng trên là dòng "Điều kiện dừng". Chatbot không có khái niệm "mục tiêu chưa đạt, cần làm tiếp" — nó chỉ có "đã trả lời xong lượt này". Agent thì ngược lại: nó được giao một mục tiêu (goal), không phải một câu hỏi, và nó tự chịu trách nhiệm xác định khi nào mục tiêu đó đã hoàn thành.
ReAct không còn là một kỹ thuật prompt — nó là kiến trúc của Agent
Ở Season 1 Bài 3, ReAct (Reasoning + Acting) được giới thiệu như một kỹ thuật prompting: xen kẽ giữa suy luận (Thought) và hành động thực (Action), rồi quan sát kết quả (Observation) trước khi suy luận tiếp. Lúc đó, ReAct là một lượt xử lý trong một cuộc hội thoại — bạn viết prompt yêu cầu model thể hiện chuỗi Thought-Action-Observation, và agent coding tool (Cursor, Claude Code) thực thi nó ngầm bên dưới UI chat.
Giờ đây, ở Season 3, chúng ta lật ngược góc nhìn: ReAct không phải là một kỹ thuật viết prompt hay, mà là kiến trúc vận hành cốt lõi của bất kỳ AI Agent nào. Một Agent, tách ra thành các thành phần, luôn có:
- Reasoning engine — chính là LLM, đóng vai trò "bộ não" quyết định bước tiếp theo dựa trên mục tiêu và lịch sử quan sát đã có.
- Tools — tập hợp hành động thực agent có quyền gọi: đọc file, chạy lệnh, gọi API, ghi database, gửi message.
- Memory/State — lịch sử các cặp Action-Observation đã xảy ra, để LLM không suy luận trong chân không mà dựa trên dữ liệu thật đã thu thập.
- Termination condition — điều kiện dừng: hoặc LLM tự đánh giá mục tiêu đã đạt, hoặc chạm giới hạn số bước cứng (sẽ nói kỹ ở phần Cạm bẫy).
flowchart LR
Goal["Mục tiêu được giao"] --> Think
Think["Think: LLM suy luận<br/>bước tiếp theo dựa trên<br/>goal + lịch sử Observation"] --> Decision{"Đã đạt<br/>mục tiêu?"}
Decision -->|Chưa| Act["Act: gọi Tool cụ thể<br/>(đọc file, chạy lệnh, gọi API...)"]
Act --> Observe["Observe: nhận kết quả<br/>thực từ Tool vừa gọi"]
Observe --> Think
Decision -->|Rồi, hoặc chạm<br/>MAX_STEPS| Done["Kết thúc: trả kết quả<br/>hoặc báo cáo lý do dừng"]
Khác biệt then chốt so với CoT hay ToT (đã học ở Bài 3): CoT và ToT suy luận thuần túy "trong đầu" model, dựa trên thông tin đã có sẵn trong prompt. Vòng lặp Agent thì grounding mỗi bước suy luận vào một quan sát thực vừa xảy ra ngoài đời — kết quả một lệnh chạy, nội dung một file vừa đọc, response một API vừa gọi. Đây là lý do Agent có thể xử lý những việc chatbot không thể: nó không đoán "test chắc sẽ pass" — nó chạy test thật và đọc kết quả thật trước khi kết luận.
Thực hành
Sơ đồ vòng lặp Agent cơ bản (dạng text)
┌─────────────────────────────────────────────────────────┐
│ │
│ [1] OBSERVE │
│ Quan sát trạng thái hiện tại: goal + lịch sử │
│ Action/Observation đã có từ các vòng trước. │
│ │ │
│ ▼ │
│ [2] THINK │
│ LLM suy luận: "Dựa trên những gì đã biết, bước │
│ tiếp theo cần làm gì để tiến gần hơn tới goal?" │
│ -> Quyết định: gọi tool nào, với tham số gì, │
│ HAY đã đủ để kết luận và dừng lại. │
│ │ │
│ ▼ │
│ [3] ACT │
│ Thực thi hành động: gọi tool cụ thể (đọc file, │
│ chạy lệnh, gọi API, ghi dữ liệu, gửi comment...) │
│ │ │
│ ▼ │
│ Kết quả hành động quay lại thành Observation mới │
│ ──────────────► quay lại bước [1] OBSERVE │
│ │
│ Vòng lặp dừng khi: (a) LLM xác nhận đã đạt goal, hoặc │
│ (b) đã chạm số bước tối đa (MAX_STEPS) — bắt buộc phải │
│ có giới hạn này, xem phần Cạm bẫy. │
│ │
└─────────────────────────────────────────────────────────┘
Ví dụ minh họa: Agent tự động review Pull Request
Bài toán cụ thể: mỗi khi có PR mới, một agent tự động lấy diff, chạy test liên quan, và đăng nhận xét vào PR — không cần kỹ sư ngồi chờ CI rồi tự viết comment.
Bước 1 — Định nghĩa tools mà agent được phép gọi:
// pr-review-agent.tools.ts
interface Tool {
name: string;
description: string;
execute: (args: Record<string, unknown>) => Promise<string>;
}
const tools: Tool[] = [
{
name: 'get_pr_diff',
description: 'Lấy diff code của Pull Request theo ID',
execute: async ({ prId }) => gitProvider.getDiff(prId as string),
},
{
name: 'run_tests',
description: 'Chạy test suite trên các đường dẫn module bị ảnh hưởng',
execute: async ({ paths }) => testRunner.run(paths as string[]),
},
{
name: 'post_pr_comment',
description: 'Đăng comment review vào Pull Request',
execute: async ({ prId, body }) =>
gitProvider.postComment(prId as string, body as string),
},
];
Bước 2 — System prompt định nghĩa mục tiêu và ràng buộc cho agent:
Bạn là một Code Review Agent tự động. Mục tiêu duy nhất: kiểm tra Pull
Request #{PR_ID}, chạy test liên quan, và đăng kết quả review vào PR
dưới dạng comment.
Quy trình bắt buộc:
1. Lấy diff của PR bằng tool get_pr_diff.
2. Xác định các file/module bị ảnh hưởng, chạy test tương ứng bằng
tool run_tests.
3. Dựa trên diff và kết quả test, viết review ngắn gọn: liệt kê vấn đề
tiềm ẩn (nếu có), xác nhận test pass/fail, đề xuất approve hoặc
request changes.
4. Đăng review đó vào PR bằng tool post_pr_comment.
Ràng buộc bắt buộc:
- KHÔNG được tự ý merge hay approve PR — chỉ đăng comment nhận xét,
quyết định cuối cùng thuộc về con người.
- KHÔNG lặp lại một hành động đã thực hiện thành công (đã chạy test
rồi thì không chạy lại trừ khi diff thay đổi).
- Nếu sau 3 bước vẫn chưa đủ thông tin để kết luận, DỪNG LẠI và báo
cáo lý do thay vì tiếp tục đoán.
- Mỗi bước phải nêu Thought (lý do) trước khi chọn Action (tool gọi).
Bước 3 — Vòng lặp Agent điều phối (rút gọn, minh họa cơ chế Observe-Think-Act):
// agent-loop.ts — vòng lặp Agent: Observe -> Think -> Act -> lặp lại
interface AgentStep {
thought: string;
action?: { tool: string; args: Record<string, unknown> };
observation?: string;
}
const MAX_STEPS = 8; // giới hạn cứng — không có nó, agent có thể chạy vô hạn
async function runAgent(
goal: string,
tools: Tool[],
llmCall: (prompt: string) => Promise<any>,
) {
const history: AgentStep[] = [];
let stepCount = 0;
while (stepCount < MAX_STEPS) {
stepCount++;
// THINK: đưa goal + toàn bộ lịch sử Observation cho LLM suy luận bước kế
const prompt = buildPrompt(goal, history);
const response = await llmCall(prompt);
if (response.type === 'final_answer') {
return { status: 'done', result: response.content, steps: stepCount };
}
// ACT: LLM chọn gọi một tool cụ thể với tham số cụ thể
const tool = tools.find((t) => t.name === response.action.tool);
if (!tool) {
history.push({
thought: response.thought,
observation: `Lỗi: tool "${response.action.tool}" không tồn tại`,
});
continue;
}
const observation = await tool.execute(response.action.args);
// OBSERVE: kết quả tool được ghi vào history, vòng lặp quay lại THINK
history.push({ thought: response.thought, action: response.action, observation });
}
// Chạm giới hạn số bước mà chưa đạt goal — bắt buộc dừng, không lặp mãi
return { status: 'max_steps_reached', history };
}
Bước 4 — Trace thực tế của một lần chạy (3 vòng Observe-Think-Act):
Thought 1: Cần lấy diff của PR #482 trước khi đánh giá bất cứ điều gì.
Action 1: get_pr_diff({ prId: "482" })
Observation 1: Diff thay đổi 3 file: orders.service.ts,
orders.controller.ts, orders.service.spec.ts. Thêm logic
tính discount theo tier khách hàng.
Thought 2: Đã có test file liên quan trong diff, nhưng cần chạy toàn
bộ suite của module orders để chắc chắn không phá vỡ test cũ.
Action 2: run_tests({ paths: ["src/modules/orders"] })
Observation 2: 42/45 test pass. 3 test fail: "should apply 10% discount
for gold tier" — expected 90, received 100.
Thought 3: Test fail cho thấy logic discount có bug thực sự (assertion
khớp với business rule đã có sẵn, không phải test lỗi thời).
Đủ thông tin để kết luận: request changes.
Action 3: post_pr_comment({
prId: "482",
body: "3/45 test fail trong module orders. Logic discount
tier 'gold' không được áp dụng — kiểm tra điều kiện if
trong calculateDiscount() ở orders.service.ts dòng ~87.
Đề xuất: fix logic rồi chạy lại suite trước khi merge."
})
Observation 3: Comment đã đăng thành công lên PR #482.
Kết quả: status = "done" sau 3 bước (dưới giới hạn MAX_STEPS = 8).
Điểm mấu chốt trong trace trên: agent không đăng comment ngay ở Thought 1 dựa trên "nhìn diff thấy có vẻ ổn" — nó buộc mình đi qua bước chạy test thật (Observation 2) trước khi kết luận. Đây chính là giá trị agent mang lại so với chatbot: hành động dựa trên dữ liệu thực thu thập được qua nhiều bước, không phải suy đoán một lần rồi dừng.
Cạm bẫy thường gặp
Xây agent cho việc không cần agent. Không phải mọi tác vụ nhiều bước đều cần một vòng lặp Observe-Think-Act với LLM ở giữa. Nếu quy trình là tuyến tính, xác định trước, không có nhánh rẽ phụ thuộc vào suy luận ngữ nghĩa (ví dụ: "lint code rồi build rồi deploy" — ba bước cố định, không cần LLM quyết định bước nào tiếp theo), một script CI/CD thông thường hoặc một chatbot gọi API tuần tự là đủ, rẻ hơn, nhanh hơn, và xác định (deterministic) hơn nhiều so với để một LLM tự quyết định từng bước. Agent chỉ đáng giá khi bước tiếp theo thực sự phụ thuộc vào việc diễn giải một kết quả không có cấu trúc cố định — ví dụ đọc hiểu nội dung một comment tự nhiên, diễn giải log lỗi để quyết định hướng debug. Trước khi thiết kế agent, tự hỏi: "quy trình này có nhánh rẽ nào cần suy luận ngữ nghĩa không, hay tôi chỉ đang dùng LLM để làm việc một if-else đã có thể viết tay?"
Agent loop vô hạn nếu không đặt giới hạn số bước rõ ràng. Đây là lỗi vận hành nghiêm trọng nhất và dễ bị bỏ qua nhất khi mới xây agent. Nếu LLM liên tục đánh giá "chưa đủ thông tin, cần thêm một bước nữa" — do prompt mơ hồ, do tool trả về kết quả không rõ ràng, hoặc do chính model có xu hướng lặp lại một hành động đã thất bại — vòng lặp có thể chạy đến khi hết ngân sách API, hết quota, hoặc treo tiến trình vô thời hạn. MAX_STEPS trong đoạn code ở trên không phải là chi tiết triển khai tùy chọn — nó là điều kiện an toàn bắt buộc, giống hệt timeout cho một network call. Ngoài giới hạn số bước cứng, nên bổ sung thêm cơ chế phát hiện lặp (nếu 2 Action liên tiếp giống hệt nhau về tool và tham số, dừng ngay và báo lỗi thay vì để agent thử lại vô nghĩa).
Cho agent quyền thực hiện hành động không thể hoàn tác mà không có approval gate. Ví dụ trên cố tình giới hạn agent chỉ được đăng comment, không được tự merge hay approve PR. Đây không phải sự thận trọng thừa — một agent với quyền merge trực tiếp, nếu suy luận sai ở Thought nào đó (ví dụ hiểu nhầm "3 test fail nhưng không liên quan" trong khi thực ra có liên quan), có thể đưa code lỗi thẳng vào production mà không ai kịp can thiệp. Nguyên tắc thiết kế: tool nào có side effect không thể hoàn tác (merge, deploy, xóa dữ liệu, gửi email cho khách hàng) nên có một bước con người xác nhận ở giữa, tách biệt khỏi các tool chỉ đọc hoặc chỉ tạo ra output có thể review trước (comment, draft, báo cáo).
🧭 Góc nhìn Solutions Architect
Nếu tôi bỏ agent này đi và thay bằng một kỹ sư làm thủ công từng bước, họ có thực sự cần "suy nghĩ" ở mỗi bước hay chỉ đang làm theo một checklist cố định — và nếu là checklist, tại sao tôi cần LLM ở đây thay vì một script? Giới hạn số bước và cơ chế phát hiện lặp của tôi đã được test với trường hợp xấu nhất (tool trả về lỗi liên tục) chưa, hay tôi chỉ mới test đường happy-path? Và hành động nào của agent này, nếu sai, sẽ không thể hoàn tác — tôi đã chặn đúng những hành động đó sau một approval gate của con người chưa?
🔗 Bài viết liên quan
- Advanced Prompting: Chain of Thought, Tree of Thoughts, ReAct — nền tảng kỹ thuật ReAct ở góc độ một prompt đơn lẻ, trước khi mở rộng thành kiến trúc Agent đầy đủ trong bài này.
- Tool Use & Function Calling — đi sâu vào cách thiết kế và triển khai tool interface mà agent gọi ở bước Act, phần vừa được minh họa rút gọn ở trên.
Bài trước: AI Integration Patterns · Bài tiếp theo: Framework cho Agents