- Tác giả

- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
AI Coding Assistant Hoạt Động Như Thế Nào? Từ LLM Đến Agent
Giới Thiệu
Ở bài trước, chúng ta đã điểm qua các công cụ AI lập trình phổ biến: GitHub Copilot, Cursor, Claude Code, OpenAI Codex, Google Antigravity, Kiro, Windsurf. Bề ngoài chúng rất khác nhau — có cái là extension, có cái là IDE, có cái chạy trong terminal. Nhưng bên trong, tất cả đều được xây dựng trên cùng một nền tảng kỹ thuật.
Hiểu nền tảng này không chỉ để "biết cho vui". Nó giải thích trực tiếp những hiện tượng bạn gặp hằng ngày:
- Tại sao AI đôi khi bịa ra một hàm không tồn tại?
- Tại sao session càng dài thì AI càng "quên" yêu cầu ban đầu?
- Tại sao cùng một câu hỏi, hai lần hỏi lại cho hai câu trả lời khác nhau?
- Tại sao agent đọc được file trong project nhưng lại không biết thư viện bạn vừa cài phiên bản mới nhất?
- Tại sao viết file
CLAUDE.mdhayAGENTS.mdlại giúp kết quả tốt hơn hẳn?
Sau bài này, bạn sẽ nắm được:
- LLM là gì và cách nó sinh ra code
- Token và context window — hai khái niệm quyết định chất lượng lẫn chi phí
- Cách AI tool thu thập context từ codebase (indexing, embedding, tìm kiếm)
- Tool calling — cách model "chạm" được vào file và terminal
- Vòng lặp agent (agent loop) — thứ biến một chatbot thành coding agent
- Cách tự viết một mini coding agent chỉ với khoảng 80 dòng Python
Yêu Cầu
- Biết lập trình cơ bản (ví dụ minh họa dùng Python)
- Đã đọc bài Introduction - Popular AI Coding Tools (khuyến khích)
- Nếu muốn chạy ví dụ: Python 3.10+ và một API key của Anthropic hoặc OpenAI
Bức Tranh Tổng Thể
Trước khi đi vào chi tiết, hãy nhìn kiến trúc chung của mọi AI coding assistant:
┌──────────────────────────────────────────────────────────────┐
│ AI Coding Tool (Client) │
│ (Copilot, Cursor, Claude Code, Codex CLI, Antigravity...) │
│ │
│ ┌────────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Giao diện │ │ Context │ │ Tool executor │ │
│ │ IDE / CLI │──▶│ builder │ │ (đọc/ghi file, │ │
│ └────────────┘ │ (prompt) │ │ chạy lệnh, MCP) │ │
│ └──────┬───────┘ └─────────▲─────────┘ │
│ │ request │ tool call │
└──────────────────────────┼─────────────────────┼─────────────┘
▼ │
┌──────────────────────────────────────┐
│ LLM (GPT, Claude, Gemini, ...) │
│ chạy trên server của nhà cung cấp │
└──────────────────────────────────────┘
Có hai phần tách biệt rõ ràng:
- Model (LLM): "bộ não" chạy trên server của OpenAI, Anthropic, Google... Model không trực tiếp đọc ổ cứng của bạn, không tự chạy được lệnh nào.
- Client (tool): phần mềm chạy trên máy bạn. Nó quyết định gửi gì cho model, nhận phản hồi, và thực thi các hành động mà model yêu cầu.
Đây là lý do cùng một model (ví dụ Claude) nhưng dùng qua Cursor, Copilot hay Claude Code lại cho trải nghiệm khác nhau: phần client — cách xây dựng context, bộ tool, system prompt — mới tạo nên sự khác biệt.
Bước 1: LLM — Cỗ Máy Dự Đoán Token Tiếp Theo
LLM Là Gì?
Large Language Model (LLM) là một mạng neural khổng lồ (hàng trăm tỷ tham số) được huấn luyện trên lượng văn bản cực lớn: sách, web, tài liệu, và đặc biệt là hàng tỷ dòng code từ các repository công khai.
Về bản chất, LLM chỉ làm một việc duy nhất: cho một chuỗi văn bản đầu vào, dự đoán token tiếp theo. Lặp lại việc này hàng nghìn lần, ta được một đoạn code hoàn chỉnh.
Input: def calculate_total(items):\n return
Model dự đoán token tiếp theo: " sum" (xác suất 62%)
" len" (xác suất 9%)
" reduce"(xác suất 4%)
...
→ chọn " sum", nối vào input, dự đoán tiếp: "(" → "item" → "." → "price" → ...
Vì đã "đọc" hàng triệu hàm tương tự, model học được các pattern: tên hàm calculate_total + tham số items thường đi kèm sum(item.price for item in items). Model không "hiểu" theo nghĩa con người, nhưng khả năng nhận diện pattern ở quy mô này đủ mạnh để giải quyết các bài toán lập trình phức tạp.
Các Giai Đoạn Huấn Luyện
| Giai đoạn | Mục đích | Kết quả |
|---|---|---|
| Pre-training | Học dự đoán token trên dữ liệu khổng lồ | Model biết ngôn ngữ, cú pháp, kiến thức chung |
| Instruction tuning | Học làm theo yêu cầu ("viết hàm...", "giải thích...") | Model trả lời đúng dạng câu hỏi |
| RLHF / RL | Học từ phản hồi của con người và từ môi trường (chạy test có pass không) | Model trả lời hữu ích hơn, code chạy đúng hơn, biết dùng tool |
Giai đoạn RL trên môi trường coding thực tế (giải issue, chạy test) là lý do các model đời mới làm agent tốt hơn hẳn so với vài năm trước.
Hệ Quả Thực Tế
1. Knowledge cutoff: Model chỉ biết dữ liệu đến thời điểm huấn luyện. Nếu framework ra phiên bản mới sau đó, model sẽ dùng API cũ. Giải pháp: đưa tài liệu mới vào context (copy docs, dùng MCP server tra tài liệu, hoặc cho agent tìm kiếm web).
2. Hallucination (ảo giác): Model dự đoán token "nghe hợp lý nhất", không phải token "đúng nhất". Nếu không có thông tin thật trong context, nó vẫn tự tin sinh ra một hàm user.getFullNameSafe() chưa từng tồn tại. Giải pháp: cho model đọc code thật, và quan trọng nhất — chạy code/test để kiểm chứng.
3. Tính ngẫu nhiên (non-deterministic): Ở mỗi bước, model chọn token dựa trên phân phối xác suất, có yếu tố ngẫu nhiên (điều khiển bởi tham số temperature). Vì vậy hỏi lại cùng một câu có thể ra kết quả khác. Đây không phải lỗi, mà là đặc tính.
Bước 2: Token Và Context Window
Token Là Gì?
Model không đọc từng ký tự hay từng từ, mà đọc token — các mảnh văn bản được cắt theo tần suất xuất hiện. Một token trung bình khoảng 3–4 ký tự tiếng Anh. Code thường tốn nhiều token hơn văn bản thường vì có nhiều ký tự đặc biệt và khoảng trắng; tiếng Việt có dấu cũng tốn token hơn tiếng Anh.
Thử đếm token bằng thư viện tiktoken của OpenAI:
# pip install tiktoken
import tiktoken
enc = tiktoken.get_encoding("o200k_base")
samples = {
"English": "Calculate the total price of all items in the cart",
"Tiếng Việt": "Tính tổng giá của tất cả sản phẩm trong giỏ hàng",
"Python": "def total(items):\n return sum(i.price for i in items)",
}
for label, text in samples.items():
tokens = enc.encode(text)
print(f"{label:12} | {len(text):3} ký tự | {len(tokens):3} token")
print(" ", [enc.decode([t]) for t in tokens][:12])
Giải thích:
get_encoding("o200k_base")lấy bộ tokenizer mà các model GPT đời mới sử dụng. Mỗi nhà cung cấp có tokenizer riêng, nên số token giữa GPT, Claude, Gemini sẽ hơi khác nhau, nhưng thứ tự độ lớn tương tự.- Vòng lặp in ra số ký tự, số token và các mảnh token đầu tiên để bạn thấy văn bản bị cắt như thế nào.
Context Window
Context window là số token tối đa model có thể "nhìn thấy" trong một lần xử lý — bao gồm cả input lẫn output. Các model hiện nay có context từ khoảng 200K đến hơn 1 triệu token.
Nghe thì nhiều, nhưng hãy xem một request của coding agent thực tế chứa những gì:
┌──────────────────────────────────────── Context window ───────┐
│ System prompt của tool (hướng dẫn, quy tắc an toàn) ~5-15K │
│ Định nghĩa các tool (read_file, edit, bash, MCP...) ~5-20K │
│ CLAUDE.md / AGENTS.md / rules của project ~1-5K │
│ Lịch sử hội thoại (các lượt trước) tăng dần │
│ Nội dung các file agent đã đọc tăng dần │
│ Output của các lệnh đã chạy (test log, build log) tăng dần │
│ Câu hỏi hiện tại của bạn nhỏ │
└───────────────────────────────────────────────────────────────┘
Một codebase trung bình dễ dàng vượt hàng triệu token, nên không bao giờ nhét được toàn bộ project vào context. Đây là bài toán cốt lõi mà mọi AI coding tool phải giải: chọn đúng những gì đưa vào context.
Vì Sao Session Dài Thì AI "Quên"?
- Context đầy: khi gần chạm giới hạn, tool phải compact (tóm tắt lịch sử cũ) hoặc cắt bỏ. Chi tiết trong yêu cầu ban đầu có thể bị mất khi tóm tắt.
- Context rot: ngay cả khi chưa đầy, context càng dài và càng nhiều thông tin nhiễu (log dài, file không liên quan) thì model càng dễ bỏ sót chi tiết quan trọng.
- Chi phí: mỗi lượt gửi lại toàn bộ context, nên session dài tốn token theo cấp số cộng. Các nhà cung cấp dùng prompt caching để giảm chi phí phần lặp lại, nhưng không loại bỏ hoàn toàn.
Bài học thực tế: mỗi task một session mới, dùng lệnh như /clear hoặc /compact khi chuyển chủ đề, và tránh để agent in ra những log dài vô ích.
Bước 3: Thu Thập Context Từ Codebase
Làm sao tool biết file nào liên quan đến câu hỏi "sửa lỗi đăng nhập bị timeout"? Có ba chiến lược chính, các tool thường kết hợp chúng.
Chiến Lược 1: Context Từ Editor (Autocomplete)
Với tính năng gợi ý code khi gõ (Copilot completion, Cursor Tab), tốc độ là ưu tiên số một — phải trả kết quả trong vài trăm mili giây. Tool sẽ lấy:
- Đoạn code trước và sau vị trí con trỏ
- Các tab đang mở, file vừa chỉnh sửa gần đây
- Các đoạn code tương tự trong project
Kỹ thuật này gọi là Fill-In-the-Middle (FIM): model được huấn luyện để điền vào chỗ trống giữa prefix và suffix.
<PREFIX>
def get_user(user_id: int) -> User:
user = db.query(User).filter(User.id == user_id).first()
<SUFFIX>
return user
<MIDDLE> ← model sinh phần này:
if user is None:
raise UserNotFoundError(user_id)
Autocomplete thường dùng model nhỏ, chuyên biệt để đảm bảo độ trễ thấp, khác với model lớn dùng cho chat và agent.
Chiến Lược 2: Semantic Search Với Embedding
Một số tool (như Cursor) index toàn bộ codebase: chia code thành các đoạn (chunk), chuyển mỗi đoạn thành một vector embedding — một dãy số biểu diễn "ý nghĩa" của đoạn code. Khi bạn hỏi, câu hỏi cũng được chuyển thành vector, rồi tool tìm các đoạn code có vector gần nhất.
Ví dụ minh họa ý tưởng (dùng embedding model miễn phí chạy local):
# pip install sentence-transformers numpy
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer("all-MiniLM-L6-v2")
# Giả lập các chunk code trong project
chunks = [
"def login(username, password): verify credentials and create session token",
"def send_invoice_email(order): render template and send via SMTP",
"class SessionStore: stores session in Redis with TTL expiration",
"def resize_image(path, width): use Pillow to resize uploaded avatar",
]
query = "fix login session expires too early"
chunk_vecs = model.encode(chunks, normalize_embeddings=True)
query_vec = model.encode(query, normalize_embeddings=True)
# Cosine similarity (vector đã normalize nên chỉ cần dot product)
scores = chunk_vecs @ query_vec
for idx in np.argsort(-scores):
print(f"{scores[idx]:.3f} {chunks[idx]}")
Giải thích:
model.encode(...)biến mỗi đoạn text thành vector 384 chiều.- Nhân vô hướng (
@) giữa các vector đã chuẩn hóa chính là cosine similarity — càng gần 1 càng giống nghĩa. - Kết quả: hàm
loginvà classSessionStoresẽ xếp đầu dù câu hỏi không chứa chính xác từ "SessionStore" hay "Redis". Đây là sức mạnh của tìm kiếm theo ngữ nghĩa so với tìm kiếm theo từ khóa.
Kỹ thuật lấy tài liệu liên quan rồi đưa vào prompt như thế này gọi là RAG (Retrieval-Augmented Generation).
Chiến Lược 3: Agentic Search — Để Model Tự Tìm
Các terminal agent như Claude Code và Codex CLI chủ yếu đi theo hướng khác: không cần index trước, mà cho model các công cụ tìm kiếm (grep, glob, ls, đọc file) và để model tự quyết định tìm gì, đọc file nào — giống hệt cách một developer mới vào dự án tìm hiểu code.
Bạn: "Sửa lỗi session hết hạn quá sớm"
Agent: grep -r "session" --include="*.py" -l → thấy auth/session.py, config/settings.py
Agent: đọc auth/session.py → thấy TTL lấy từ settings.SESSION_TTL
Agent: grep -n "SESSION_TTL" config/settings.py → SESSION_TTL = 60 (đơn vị giây!)
Agent: "Lỗi nằm ở đây: TTL đang là 60 giây thay vì 60 phút..."
| Tiêu chí | Semantic search (index) | Agentic search |
|---|---|---|
| Chuẩn bị | Cần index trước, cập nhật khi code đổi | Không cần chuẩn bị |
| Tốc độ tìm | Rất nhanh | Chậm hơn (nhiều bước) |
| Độ chính xác | Tốt cho câu hỏi mơ hồ | Rất tốt khi cần lần theo luồng code |
| Code luôn mới nhất | Phụ thuộc trạng thái index | Luôn đọc file hiện tại |
| Tốn token | Ít | Nhiều hơn |
Thực tế, nhiều tool kết hợp cả hai: dùng index để gợi ý điểm bắt đầu, rồi để agent tự đọc tiếp.
Chiến Lược 4: Context Do Bạn Cung Cấp
Đừng quên nguồn context quan trọng nhất: chính bạn.
- Tham chiếu file trực tiếp:
@src/auth/session.py(Cursor, Claude Code, Copilot đều hỗ trợ) - File hướng dẫn project:
CLAUDE.md,AGENTS.md,.cursor/rules,.github/copilot-instructions.md— được tự động đưa vào context ở mỗi session - Dán lỗi, stack trace, screenshot giao diện
Đây là lý do một câu prompt cụ thể ("sửa hàm refresh_token trong auth/session.py, test ở tests/test_session.py đang fail") cho kết quả tốt hơn nhiều so với "sửa lỗi đăng nhập".
Bước 4: Tool Calling — Cách Model "Chạm" Vào Máy Của Bạn
Như đã nói, model chỉ sinh ra text. Vậy làm sao Claude Code sửa được file hay chạy được npm test?
Câu trả lời là tool calling (còn gọi là function calling):
- Client gửi cho model danh sách tool kèm mô tả và JSON schema của tham số.
- Khi cần, model trả về một yêu cầu gọi tool có cấu trúc (tên tool + tham số) thay vì câu trả lời thông thường.
- Client thực thi tool trên máy bạn và gửi kết quả ngược lại cho model.
- Model đọc kết quả và quyết định bước tiếp theo.
Ví dụ định nghĩa một tool:
{
"name": "read_file",
"description": "Đọc nội dung một file trong project. Dùng khi cần xem code trước khi sửa.",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Đường dẫn tương đối tới file" }
},
"required": ["path"]
}
}
Và phản hồi của model khi muốn dùng tool:
{
"type": "tool_use",
"id": "toolu_01A...",
"name": "read_file",
"input": { "path": "auth/session.py" }
}
Giải thích:
descriptioncực kỳ quan trọng — model dựa vào đây để quyết định khi nào dùng tool.input_schemagiúp model sinh tham số đúng định dạng.- Model chỉ đề xuất gọi tool. Việc có thực thi hay không là do client quyết định — đây chính là nơi cơ chế permission hoạt động (Claude Code hỏi "Allow this command?", Codex chạy trong sandbox).
Bộ tool phổ biến của một coding agent:
| Nhóm tool | Ví dụ | Mục đích |
|---|---|---|
| Đọc / tìm kiếm | read_file, grep, glob, ls |
Hiểu codebase |
| Chỉnh sửa | edit_file (thay chuỗi), write_file |
Sửa và tạo code |
| Thực thi | bash / shell |
Chạy test, build, lint, git |
| Web | web_search, web_fetch |
Tra tài liệu mới |
| Mở rộng | MCP server (database, Jira, Figma, browser...) | Kết nối hệ thống bên ngoài |
| Điều phối | task / subagent |
Giao việc con cho agent khác |
MCP (Model Context Protocol) là chuẩn mở giúp bất kỳ ai cũng có thể viết thêm tool cho agent mà không phụ thuộc vào một tool cụ thể — chúng ta sẽ học kỹ ở Section 7.
Bước 5: Agent Loop — Trái Tim Của Coding Agent
Ghép tất cả lại, ta có vòng lặp agent:
┌─────────────────────────────────────────┐
│ 1. Gửi context + tools cho model │
└───────────────────┬─────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 2. Model trả lời │
└──────┬──────────────────────────┬───────┘
│ có tool_use │ chỉ có text
▼ ▼
┌───────────────────────────┐ ┌──────────────────┐
│ 3. Client thực thi tool │ │ 5. Kết thúc, │
│ (sau khi xin phép) │ │ trả lời người │
└─────────────┬─────────────┘ │ dùng │
▼ └──────────────────┘
┌───────────────────────────┐
│ 4. Thêm kết quả tool vào │
│ context → quay lại 1 │
└───────────────────────────┘
Chỉ đơn giản vậy thôi! Toàn bộ "trí thông minh" — lên kế hoạch, đọc file nào, sửa ra sao, chạy test, đọc lỗi, sửa lại — đều đến từ model ra quyết định ở bước 2. Client chỉ là một vòng while thực thi trung thực.
Điều làm agent mạnh hơn hẳn chatbot là feedback loop: agent chạy test, thấy fail, đọc lỗi, sửa, chạy lại. Nó không cần đúng ngay lần đầu, miễn là có tín hiệu để tự kiểm chứng.
Bước 6: Tự Viết Mini Coding Agent
Để thấy rõ agent loop đơn giản thế nào, hãy tự viết một coding agent tối giản với 3 tool: đọc file, ghi file, chạy lệnh shell.
mkdir mini-agent && cd mini-agent
python -m venv .venv && source .venv/bin/activate
pip install anthropic
export ANTHROPIC_API_KEY="sk-ant-..."
# mini_agent.py — một coding agent tối giản để học
import subprocess
import sys
from pathlib import Path
import anthropic
client = anthropic.Anthropic() # đọc ANTHROPIC_API_KEY từ biến môi trường
MODEL = "claude-sonnet-5-5"
SYSTEM_PROMPT = (
"Bạn là coding agent làm việc trong thư mục hiện tại. "
"Hãy đọc code trước khi sửa, sau khi sửa phải chạy lệnh để kiểm chứng. "
"Trả lời ngắn gọn bằng tiếng Việt."
)
TOOLS = [
{
"name": "read_file",
"description": "Đọc nội dung file.",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
{
"name": "write_file",
"description": "Ghi đè toàn bộ nội dung file (tạo mới nếu chưa có).",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}, "content": {"type": "string"}},
"required": ["path", "content"],
},
},
{
"name": "run_command",
"description": "Chạy một lệnh shell, ví dụ: ls, python test.py, pytest.",
"input_schema": {
"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"],
},
},
]
def execute_tool(name: str, args: dict) -> str:
"""Client thực thi tool mà model yêu cầu."""
try:
if name == "read_file":
return Path(args["path"]).read_text()
if name == "write_file":
Path(args["path"]).write_text(args["content"])
return f"Đã ghi {args['path']}"
if name == "run_command":
# Permission: hỏi người dùng trước khi chạy lệnh
if input(f"\n⚠️ Chạy lệnh `{args['command']}`? [y/N] ").lower() != "y":
return "Người dùng từ chối chạy lệnh này."
result = subprocess.run(
args["command"], shell=True, capture_output=True, text=True, timeout=60
)
return f"exit code: {result.returncode}\n{result.stdout}{result.stderr}"[-5000:]
return f"Tool không tồn tại: {name}"
except Exception as e: # trả lỗi về cho model tự xử lý
return f"Lỗi: {e}"
def run_agent(task: str) -> None:
messages = [{"role": "user", "content": task}]
while True: # ← AGENT LOOP
response = client.messages.create(
model=MODEL,
max_tokens=4096,
system=SYSTEM_PROMPT,
tools=TOOLS,
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "text":
print(f"\n🤖 {block.text}")
elif block.type == "tool_use":
print(f"\n🔧 {block.name}({block.input})")
output = execute_tool(block.name, block.input)
tool_results.append(
{"type": "tool_result", "tool_use_id": block.id, "content": output}
)
if response.stop_reason != "tool_use":
break # model không gọi tool nữa → hoàn thành
messages.append({"role": "user", "content": tool_results})
if __name__ == "__main__":
run_agent(" ".join(sys.argv[1:]))
Giải thích:
TOOLS: khai báo 3 tool vớidescriptionvàinput_schema— đây là "menu" model được phép dùng.execute_tool: phần client thực thi. Lệnh shell luôn hỏi xác nhận trước khi chạy — đây chính là cơ chế permission thu nhỏ. Output bị cắt còn 5.000 ký tự cuối để tránh làm đầy context.while True: agent loop. Mỗi vòng gửi toàn bộmessages(context ngày càng dài) cho model.stop_reason == "tool_use": model muốn gọi tool, ta thực thi rồi gửitool_result(kèmtool_use_idđể model biết kết quả thuộc lời gọi nào) và lặp tiếp. Nếu không, model đã xong việc.- Lỗi khi thực thi tool không làm sập chương trình mà được trả về cho model — model sẽ tự đọc lỗi và thử cách khác.
Chạy Thử
Tạo một file có bug:
# calc.py
def average(numbers):
return sum(numbers) / len(numbers) + 1
if __name__ == "__main__":
assert average([2, 4, 6]) == 4, "average sai"
assert average([]) == 0, "list rỗng phải trả 0"
print("All tests passed")
python mini_agent.py "Chạy calc.py, tìm và sửa bug cho đến khi tất cả assert pass"
Kết Quả
Output điển hình:
🔧 run_command({'command': 'python calc.py'})
⚠️ Chạy lệnh `python calc.py`? [y/N] y
🔧 read_file({'path': 'calc.py'})
🤖 Có 2 lỗi: hàm cộng thừa 1, và chưa xử lý list rỗng (ZeroDivisionError).
🔧 write_file({'path': 'calc.py', 'content': 'def average(numbers):\n if not numbers:\n return 0\n return sum(numbers) / len(numbers)\n...'})
🔧 run_command({'command': 'python calc.py'})
⚠️ Chạy lệnh `python calc.py`? [y/N] y
🤖 Đã sửa xong, tất cả assert đều pass.
Bạn vừa tự xây dựng phiên bản thu nhỏ của Claude Code hay Codex CLI. Các tool thương mại phức tạp hơn ở những điểm sau, nhưng vòng lặp cốt lõi y hệt:
| Thành phần | Mini agent | Tool thương mại |
|---|---|---|
| Sửa file | Ghi đè toàn bộ | Thay thế chính xác từng đoạn (diff), tiết kiệm token |
| Tìm kiếm | Không có | grep/glob tối ưu, semantic index |
| Permission | Hỏi mọi lệnh | Allowlist, sandbox, nhiều chế độ tự chủ |
| Quản lý context | Không | Auto compact, cắt output, prompt caching |
| Mở rộng | Không | MCP, skills, subagents, hooks |
| System prompt | 3 câu | Hàng nghìn từ, tinh chỉnh kỹ lưỡng |
Model Khác Nhau Thì Khác Gì?
Hầu hết tool cho phép chọn model. Vài khái niệm cần biết:
| Khái niệm | Ý nghĩa | Ảnh hưởng thực tế |
|---|---|---|
| Model lớn vs nhỏ | Lớn (Opus, GPT bản cao nhất, Gemini Pro) thông minh hơn; nhỏ (Haiku, Flash, mini) nhanh và rẻ | Dùng model lớn cho thiết kế, debug khó; model nhỏ cho task đơn giản, lặp lại |
| Reasoning / thinking | Model "suy nghĩ" (sinh token suy luận nội bộ) trước khi trả lời | Chính xác hơn với bài toán phức tạp, nhưng chậm và tốn token hơn |
| Context window | Giới hạn token mỗi request | Ảnh hưởng tới độ dài session và lượng code đọc được |
| Tốc độ (tokens/giây) | Tốc độ sinh output | Quan trọng với autocomplete và trải nghiệm tương tác |
Không có model "tốt nhất cho mọi việc". Nhiều tool có chế độ Auto để tự chọn model phù hợp cho từng request.
Xử Lý Lỗi Thường Gặp
Hiểu cơ chế bên trong giúp bạn chẩn đoán đúng nguyên nhân:
| Hiện tượng | Nguyên nhân gốc | Cách xử lý |
|---|---|---|
| AI dùng hàm/API không tồn tại | Hallucination, thiếu context thật | Cho agent đọc file liên quan, yêu cầu chạy code để kiểm chứng |
| Dùng cú pháp của phiên bản thư viện cũ | Knowledge cutoff | Ghi rõ version trong AGENTS.md, đưa link docs, dùng MCP tra tài liệu |
| Session dài, AI bỏ qua yêu cầu ban đầu | Context đầy, đã compact, context rot | Mở session mới cho task mới, ghi yêu cầu quan trọng vào file hướng dẫn |
| Agent đọc quá nhiều file không liên quan | Prompt mơ hồ, thiếu điểm bắt đầu | Chỉ rõ file bằng @path, mô tả phạm vi cụ thể |
| Mỗi lần hỏi ra kết quả khác | Tính ngẫu nhiên khi sinh token | Bình thường; cố định kết quả bằng test và review thay vì mong đợi output y hệt |
| Hết quota/chi phí tăng nhanh | Mỗi lượt gửi lại toàn bộ context, output tool dài | Session ngắn, dùng model nhỏ khi phù hợp, tránh in log dài |
Best Practices
- Coi model như một developer giỏi nhưng mới vào dự án — nó cần được cung cấp context, không tự biết convention của team.
- Luôn có cơ chế kiểm chứng — test, type checker, linter, build. Agent mạnh nhất khi có feedback loop rõ ràng.
- Quản lý context chủ động — một task một session; dùng file hướng dẫn cho thông tin lặp lại thay vì gõ lại mỗi lần.
- Đọc kỹ trước khi cho phép chạy lệnh — model chỉ đề xuất, bạn (và client) là người chịu trách nhiệm cuối cùng.
- Chọn model theo task — không phải lúc nào cũng cần model lớn nhất.
- Đừng tin tuyệt đối — code trông hợp lý không có nghĩa là đúng. Review như review code của đồng nghiệp.
Tổng Kết
Mọi AI coding assistant, dù là Copilot, Cursor, Claude Code hay Codex, đều xây dựng trên cùng một nền tảng:
- LLM dự đoán token tiếp theo dựa trên pattern học được — mạnh mẽ nhưng có knowledge cutoff, có thể hallucinate và mang tính ngẫu nhiên.
- Token và context window giới hạn lượng thông tin model nhìn thấy, quyết định cả chất lượng lẫn chi phí.
- Tool thu thập context bằng context từ editor, semantic search (RAG), agentic search, và context do bạn cung cấp.
- Tool calling cho phép model yêu cầu client đọc file, sửa code, chạy lệnh — client luôn là bên thực thi và kiểm soát quyền.
- Agent loop — một vòng lặp đơn giản "gọi model → chạy tool → gửi kết quả" — biến chatbot thành coding agent có khả năng tự kiểm chứng và tự sửa.
Nắm vững những khái niệm này, bạn sẽ hiểu vì sao các kỹ thuật trong những bài tiếp theo — viết prompt tốt, cung cấp context hiệu quả, viết AGENTS.md, dùng MCP và skills — lại có tác dụng.
Bài tiếp theo: AI Chatbots for Developers — khai thác ChatGPT, Claude, Gemini, Perplexity và Grok hiệu quả trong công việc lập trình hằng ngày.
