Bạn yêu cầu Claude Code: “fix bug login bị 500 error”. Claude không trả lời ngay. Nó đọc file, grep code, sửa logic, chạy test, đọc lỗi, sửa tiếp, cho đến khi test pass. Một câu prompt, mười phút, năm chục tool calls.
Đây không phải “LLM trả lời câu hỏi” theo nghĩa truyền thống. Đây là LLM Agent: một LLM được cấp tools, được phép lặp lại, được phép thay đổi kế hoạch dựa trên kết quả. Mạnh hơn chat đơn thuần một bậc.
Bài này mở mental model của agent: ReAct loop, tool use, planning, các pitfall thường gặp.
Dành cho: dev đã build qua chat-style LLM app, muốn hiểu agent (Claude Code, Cursor agent mode, LangChain agent) hoạt động bên dưới như thế nào.
Mental model: agent là gì
Một chat LLM thông thường:
User: câu hỏi
LLM: câu trả lời
Kết thúc.
Một agent:
User: nhiệm vụ
LLM: think -> action (tool call)
Tool: kết quả
LLM: think -> action
Tool: kết quả
LLM: think -> action
... (lặp lại) ...
LLM: trả lời cuối cùng
Điểm khác biệt:
- Agent lặp lại nhiều turn thay vì 1 turn
- Agent có thể gọi tool (function, API, code execution)
- Agent tự quyết định bao giờ dừng (khi nhiệm vụ xong hoặc bí)
Agent về bản chất là một loop của LLM call + tool execution + state update, được điều khiển bằng prompt template và parsing logic.
Phần 1: ReAct, pattern cơ bản
ReAct (Reasoning + Acting, Google 2022) là pattern phổ biến nhất cho agent. Mỗi step có 3 phần:
Thought: tôi cần làm gì tiếp theo?
Action: gọi tool nào với input gì?
Observation: tool trả về gì?
Lặp lại cho đến khi LLM xuất Answer: ... thay vì Action:.
Ví dụ cụ thể, agent có 2 tool: search(q) và add(a, b).
User: Tổng dân số của 3 nước đông dân nhất là bao nhiêu?
Thought: Tôi cần biết 3 nước đông dân nhất và dân số mỗi nước. Search.
Action: search("3 nước đông dân nhất thế giới 2024")
Observation: India 1.42B, China 1.41B, USA 0.33B
Thought: Tổng cộng các số.
Action: add(1.42, 1.41)
Observation: 2.83
Action: add(2.83, 0.33)
Observation: 3.16
Thought: Đã đủ thông tin, trả lời.
Answer: Tổng dân số 3 nước đông dân nhất (India, China, USA) là 3.16 tỷ.
LLM tự quyết định step nào tool nào. Code runner chỉ:
- Parse output của LLM để lấy
Action:(hoặcAnswer:) - Execute tool tương ứng
- Append
Observation:vào prompt - Lặp lại LLM call
Phần 2: Code ReAct loop tối giản
Không cần framework, ReAct loop chỉ 40 dòng Python:
import re
import json
from openai import OpenAI
client = OpenAI()
# Tools là pure function, không dùng eval, an toàn
def tool_search(query):
# Mock, thực tế gọi search API hoặc vector DB
return f"[Mock kết quả search cho: {query}]"
def tool_add(a, b):
return float(a) + float(b)
TOOLS = {
"search": tool_search,
"add": tool_add,
}
SYSTEM = """Bạn là một agent giải nhiệm vụ. Format output mỗi step:
Thought: [suy nghĩ về việc tiếp theo]
Action: tool_name
Action Input: {"key": "value"}
hoặc khi xong:
Answer: [câu trả lời cuối]
Tools có sẵn:
- search: input {"query": str}
- add: input {"a": float, "b": float}
"""
def parse_action(text):
m_action = re.search(r"Action:\s*(\w+)", text)
m_input = re.search(r"Action Input:\s*({.*?})", text, re.DOTALL)
if m_action and m_input:
return m_action.group(1), json.loads(m_input.group(1))
return None, None
def parse_answer(text):
m = re.search(r"Answer:\s*(.+)", text, re.DOTALL)
return m.group(1).strip() if m else None
def react_agent(user_msg, max_steps=10):
messages = [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": user_msg}
]
for step in range(max_steps):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
stop=["Observation:"]
)
out = resp.choices[0].message.content
ans = parse_answer(out)
if ans:
return ans
tool, args = parse_action(out)
if not tool or tool not in TOOLS:
return "Agent bí."
observation = TOOLS[tool](**args)
messages.append({"role": "assistant", "content": out})
messages.append({
"role": "user",
"content": f"Observation: {observation}"
})
return "Quá nhiều step."
40 dòng. Đây là essence của mọi agent framework, dù LangChain hay AutoGPT hay Claude Code đều cùng pattern. Khác biệt nằm ở:
- Cách parse (function calling thay vì regex)
- Số tool và độ phức tạp
- Memory management (lưu state qua nhiều turn)
- Error handling
Phần 3: Function calling, ReAct chuẩn hoá
Regex parse output dễ vỡ. OpenAI / Anthropic đẻ ra function calling (tool use): LLM trả về tool name và arguments dưới dạng JSON, không phải text tự do.
tools = [
{
"type": "function",
"function": {
"name": "search",
"description": "Tìm thông tin trên web",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "add",
"description": "Cộng hai số",
"parameters": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
},
"required": ["a", "b"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
if msg.tool_calls:
for call in msg.tool_calls:
tool_name = call.function.name
args = json.loads(call.function.arguments)
result = TOOLS[tool_name](**args)
# Append tool result vào messages
Function calling đáng tin hơn nhiều so với regex. Hỗ trợ bởi GPT-4, Claude, Gemini, Llama-3.1+. Mặc định dùng function calling khi có thể.
Phần 4: Planning, agent biết nghĩ trước
ReAct là reactive: agent quyết định từng bước dựa trên observation gần nhất. Có một cách khác: planning, agent lập kế hoạch nhiều bước trước rồi execute.
Pattern Plan-and-Execute:
User: nhiệm vụ phức tạp
Plan step (LLM call 1):
1. Search X
2. Phân tích Y
3. Tính Z
4. Tổng hợp
Execute step (LLM call 2, 3, 4):
Thực hiện step 1, get observation
Thực hiện step 2 với observation từ step 1
...
Replan step (nếu observation không như dự tính):
Sửa plan, tiếp tục
Lợi ích: agent có “big picture”, không bị lost trong từng step. Tốt cho nhiệm vụ phức tạp 10+ step.
Nhược: thêm latency (extra LLM call cho planning). Không phù hợp task ngắn.
Anthropic Claude và OpenAI o1 family có pattern internal kiểu này: “think” trước khi action.
Phần 5: Multi-agent, khi một agent không đủ
Một agent có thể bí với task quá rộng. Giải pháp: multi-agent system, mỗi agent có vai trò riêng.
Pattern phổ biến:
Supervisor + workers:
Supervisor agent: nhận nhiệm vụ, chia thành subtasks
|
|--> Worker A (chuyên về code)
|--> Worker B (chuyên về search)
|--> Worker C (chuyên về data analysis)
|
Supervisor: gộp kết quả workers, trả lời
Writer + reviewer:
Writer: viết draft
Reviewer: critique
Writer: sửa
Reviewer: approve
Chain of agents:
Researcher -> Analyst -> Writer -> Editor
Frameworks hỗ trợ: LangGraph, CrewAI, AutoGen, Claude SDK team mode.
Pitfall multi-agent: token cost tăng tuyến tính theo số agent + số turn. Một task có thể tốn $0.5-2 trong khi single agent chỉ $0.05.
Quy tắc: bắt đầu với single agent + tools. Chỉ scale lên multi-agent khi single agent rõ ràng không đủ.
Phần 6: LangChain agent, framework giúp gì và không giúp gì
LangChain là framework phổ biến nhất cho agent. Có lợi ích, có chi phí.
Code LangChain agent đơn giản:
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import Tool
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
llm = ChatOpenAI(model="gpt-4o-mini")
def safe_add(text_input):
parts = text_input.split(",")
return str(float(parts[0]) + float(parts[1]))
tools = [
Tool(
name="search",
func=lambda q: f"[search: {q}]",
description="Tìm thông tin trên web. Input: chuỗi truy vấn."
),
Tool(
name="add",
func=safe_add,
description="Cộng hai số. Input: 'a, b' với a, b là số."
)
]
prompt = PromptTemplate.from_template("""
Bạn là agent. Tools: {tools}
Sử dụng format:
Thought: ...
Action: tên_tool
Action Input: ...
Observation: ...
... lặp lại ...
Final Answer: ...
Tool names: {tool_names}
Question: {input}
{agent_scratchpad}
""")
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({"input": "Tổng dân số 3 nước đông dân nhất?"})
LangChain giúp:
- Abstraction sẵn cho ReAct, tool use, memory
- Tích hợp 100+ tool, vector DB, model providers
- Debug UI (LangSmith)
LangChain không giúp:
- Hiệu năng (overhead abstraction lớn)
- Hiểu cơ chế bên dưới (bạn vẫn cần đọc code mới biết nó làm gì)
- Predictability (mỗi version thay đổi API)
Quy tắc thực tế:
- POC nhanh: LangChain OK
- Production agent quan trọng: viết loop của riêng bạn (30-100 dòng), control mọi thứ
- Hybrid: dùng LangChain cho phần dễ (tool registry, memory), tự code phần khó (loop logic, error handling)
Phần 7: Pitfall sống còn
Pitfall 1: Agent loop vô tận.
LLM hallucinate tool result, hoặc bị stuck loop “search X -> không thấy -> search X lại”. Cost token tăng theo cấp số nhân.
Fix:
- Đặt
max_stepscứng (10-20) - Đặt budget token cứng cho mỗi request
- Detect lặp lại: nếu 2 step liên tiếp có cùng action, force break
- Timeout wall-clock (30s, 60s)
Pitfall 2: Tool description mơ hồ.
Description tool là cách LLM biết khi nào dùng tool. Nếu description sơ sài, LLM gọi sai tool hoặc bỏ qua tool đúng.
Bad:
search: tìm thông tin
Good:
search(query: str): Tìm thông tin trên Wikipedia. Dùng khi cần fact, định nghĩa, lịch sử. KHÔNG dùng cho tính toán hoặc câu hỏi yes/no chung. Trả về snippet text.
Detail càng nhiều càng tốt, kèm ví dụ khi nào dùng / khi nào không.
Pitfall 3: Không validate tool input.
LLM có thể truyền input bất kỳ vào tool. Nếu tool có power (shell exec, file write, http request), input bậy gây side effect ngoài ý muốn.
Fix: sandbox mọi tool có side effect:
- Số học: parse safely, không chạy code tuỳ ý
- Shell: whitelist commands, deny dangerous ops
- File write: chỉ trong workspace cụ thể
- HTTP: chỉ allowed domains
Agent giống user untrusted. Apply principle of least privilege.
Pitfall 4: Context bloat.
Mỗi step append observation vào messages. Sau 20 step, context dài 30k tokens, LLM “lost in middle”, quên nhiệm vụ ban đầu.
Fix:
- Truncate old observations nếu không cần
- Summarize history sau N step
- Tách “scratchpad” (chi tiết) khỏi “task state” (chỉ những gì cần)
- Dùng model context dài (Claude 200k) nếu phù hợp
Pitfall 5: Test agent bằng cảm tính.
Như RAG, agent cũng cần evaluation set. Câu hỏi: “Trên N task test, agent hoàn thành đúng bao nhiêu %?”
Build 20-50 test task có expected outcome. Chạy agent, check kết quả. Mỗi lần đổi prompt / tool / model, đo lại. Nếu không đo, không biết đang tốt hay tệ.
Phần 8: Khi nào dùng agent, khi nào không
Agent là tool mạnh nhưng đắt và khó debug. Quy tắc:
Dùng agent khi:
- Task cần nhiều step không xác định trước
- Cần tool use (search, code exec, API call)
- Có thể replan dựa trên observation
- User chấp nhận latency 30s-5min cho task phức tạp
Không dùng agent khi:
- Task đơn giản, 1-2 step rõ ràng (dùng chat thường + RAG)
- Latency yêu cầu thấp (chat realtime)
- Có thể giải bằng workflow cố định (DAG, không cần LLM “nghĩ”)
- Cost yêu cầu thấp (agent đắt gấp 5-50 lần chat thường)
Anti-pattern: nhồi agent vào mọi feature vì “agentic AI hot”. Workflow cố định + một LLM call thường đủ và tốt hơn.
Cheatsheet
| Khái niệm | Bản chất |
|---|---|
| Agent | LLM + loop + tools |
| ReAct | Thought / Action / Observation pattern |
| Function calling | LLM trả tool call dưới dạng JSON chuẩn |
| Planning | Lập kế hoạch nhiều step trước khi execute |
| Multi-agent | Nhiều LLM phối hợp, mỗi agent role riêng |
| Supervisor-worker | 1 agent điều phối, nhiều worker chuyên biệt |
| Tool description | Bản hướng dẫn cho LLM biết khi nào gọi tool |
Quy tắc 80/20:
- 80% chất lượng agent phụ thuộc tool design (description + signature)
- 15% phụ thuộc prompt template
- 5% phụ thuộc LLM model
Khi agent fail, debug theo thứ tự: tool design, prompt, model.
Lời kết
Agent là pattern thay đổi cách dev tương tác với LLM. Từ “hỏi-trả lời” sang “giao việc, kiểm tra kết quả”. Hiểu agent bên dưới giúp bạn build được hệ thống tự động hoá thực sự, không chỉ chatbot.
Nhưng nhớ: agent là dao hai lưỡi. Power lớn đi kèm cost lớn và độ phức tạp lớn. Luôn cân nhắc workflow đơn giản hơn trước khi reach for agent.
Hands-on cho bạn:
- Code ReAct loop ở Phần 2 với OpenAI API hoặc Claude. Đổi tools thành cái bạn quan tâm (file read, git status, curl an toàn).
- Build evaluation set 10-20 task cụ thể với expected outcome. Đo success rate.
- Thử chuyển từ regex parsing sang function calling, so sánh reliability.
- Thử đưa cùng task cho Claude Code hoặc Cursor agent mode. Quan sát patterns: chúng decompose task thế nào, gọi tool nào.
- Thử multi-agent (LangGraph hoặc viết tay): writer + reviewer cho một blog post draft. Đo cost và quality vs single agent.
Bài tiếp theo: Mixture of Experts (MoE): Mixtral, DeepSeek architecture. Chuyển từ inference / application sang architecture. MoE là kiến trúc model có thể có 670 tỷ params mà mỗi forward pass chỉ “kích hoạt” 37 tỷ. Trick đẹp nhất của 2024 trong scaling LLM.