00 · Lộ trình AI agent mức senior — đọc gì, theo thứ tự nào, trả lời phỏng vấn ra sao
Series 9 bài này dành cho Senior Backend / Tech Lead ở công ty sản phẩm muốn đưa tính năng AI vào sản phẩm (stack Laravel + PostgreSQL) và dùng coding agent trong team. Mỗi bài trả lời đủ 10 mục: bài toán gốc, mô hình tư duy, internals, đảm bảo/giới hạn, failure modes (có lab), vận hành, so sánh, góc nhìn tech lead, anti-pattern, câu hỏi phụ. Trang này là bản đồ: đọc theo thứ tự nào, lab chạy ra sao, và một bài system design tổng hợp để luyện trả lời phỏng vấn.
Trang điều hướng — không phải bài về một công nghệ, nên không theo khung 10 mục. Nếu chưa từng gọi API LLM hay chưa biết agent loop là gì, đọc trước AI và AI agent từ số 0.
Bản đồ series
flowchart TB B0["Nền: AI agent từ số 0"] --> B1["01 LLM internals: token, KV cache, sampling"] B1 --> B2["02 Tool use và agent loop: giao thức, idempotency"] B1 --> B3["03 Context engineering: cache, context rot, compaction"] B2 --> B5["05 Workflow và multi-agent"] B3 --> B4["04 RAG với pgvector"] B2 --> B6["06 MCP chuyên sâu"] B2 --> B8["08 Bảo mật agent"] B6 --> B8 B4 --> B7["07 Eval và observability"] B5 --> B7 B7 --> B9["09 Vận hành production"] B8 --> B9 B3 --> B9
| Bài | Câu hỏi cốt lõi bài trả lời | Lab nổi bật (chạy thật) |
|---|---|---|
| 01 · LLM dưới nắp capo | Vì sao output đắt hơn input, vì sao temperature 0 không tất định, vì sao tiếng Việt đắt | Tiếng Việt có dấu 40 token vs tiếng Anh 12; float cộng khác thứ tự ra khác; KV cache nhanh ~7× |
| 02 · Tool use và agent loop | Agent là gì ở mức giao thức; làm sao không hoàn tiền hai lần | Crash sau side effect: khoá theo tool_use_id vẫn hoàn 2 lần khi retry từ đầu; khoá nghiệp vụ thì 1 |
| 03 · Context engineering | Quản lý context và prompt cache thế nào | Giờ hiện tại trong system prompt → chỉ 2% dùng lại cache; dọn context mỗi lượt tăng chi phí 1,7× |
| 04 · RAG với pgvector | RAG hỏng ở đâu, pgvector đủ tới đâu | Recall 0,81 ở ef_search mặc định; WHERE tenant 1% trả 0–2/10 dòng; build thiếu RAM chậm 8× |
| 05 · Workflow và multi-agent | Khi nào tách agent, trả giá bao nhiêu | 20 bước × 95% = 36%; fan-out 10 worker p50 4 s → 9,8 s; 20 worker → 43% bị 429 |
| 06 · MCP chuyên sâu | Giao thức trên dây, spec 2026-07-28, rủi ro | JSON-RPC thô; stateless server/discover; mô tả tool độc đi nguyên văn vào context |
| 07 · Eval và observability | Làm sao biết thay đổi là tốt hơn | Eval 50 câu chọn sai prompt 34% số lần; trace theo OTel GenAI |
| 08 · Bảo mật agent | Prompt injection, bộ ba chết người | CommonMark vẫn render ảnh rò dữ liệu; IDOR qua tool; SSRF với IP viết lạ; cổng taint |
| 09 · Vận hành production | Retry, timeout, capacity, chi phí | Timeout của SDK PHP không được áp; retry-after 12 s khoá worker; 1 lời gọi = 3 request |
Kế hoạch học 4 tuần
| Tuần | Đọc | Làm tay | Tự kiểm: nói được trong 2 phút |
|---|---|---|---|
| 1 | 01, 02 | Chạy lab tokenizer, sampling; chạy run_agent_loop_lab.sh, tự thêm một tool và một kịch bản crash | Agent loop ở mức giao thức; vì sao exactly-once không có; prefill vs decode |
| 2 | 03, 04 | Sửa cache_prefix.php thêm một "silent invalidator" của riêng bạn; chạy pgvector_lab.py, thử m/ef_construction khác | Prompt cache là prefix match; bẫy WHERE + HNSW và 3 cách xử lý |
| 3 | 05, 06, 08 | Chạy raw_client.py, đọc từng message; thêm một tool ghi vào ToolGate và phân loại nó | Khi nào KHÔNG dùng multi-agent; bộ ba chết người; MCP 2026-07-28 đổi gì |
| 4 | 07, 09 | Chạy run_retry_lab.sh; viết một bộ eval 30 câu cho một tính năng thật ở công ty cũ | Thiết kế trọn bài system design ở mục dưới trong 30 phút |
Bài system design tổng hợp: agent CSKH cho shop Laravel
Đề (hay gặp ở vòng tech lead): "Shop thương mại điện tử 50 000 đơn/ngày, stack Laravel + PostgreSQL + Redis. Thiết kế trợ lý CSKH trả lời tình trạng đơn, chính sách đổi trả, và xử lý yêu cầu hoàn tiền nhỏ." Số liệu dưới đây là ví dụ minh hoạ để luyện cách lập luận.
1. Làm rõ yêu cầu (đừng nhảy vào kiến trúc)
- Bao nhiêu hội thoại/ngày? Giả sử 5 000, cao điểm 3 lượt/giây. Kênh: web chat. Tiếng Việt.
- Hoàn tiền tự động tới ngưỡng nào? Giả sử ≤ 500 000đ và đơn đủ điều kiện; trên ngưỡng → nhân viên duyệt.
- SLO: TTFT p95 < 2 s; tỉ lệ tự giải quyết ≥ 60%; chi phí < 1 000đ/hội thoại; không một lần hoàn tiền trùng.
2. Chọn mức: workflow trước, agent chỗ cần
Router (một lần gọi model rẻ hoặc structured outputs) phân loại ý định: hỏi đơn / hỏi chính sách / hoàn-đổi / khác. Hỏi đơn là workflow (tool tra đơn + trả lời). Hỏi chính sách là RAG. Hoàn-đổi cần nhiều bước có điều kiện → agent với tool hẹp. Không multi-agent: luồng phụ thuộc chặt, không song song hoá được (bài 05).
3. Kiến trúc
flowchart LR
W["Web chat"] -->|"POST, nhận run_id"| API["Laravel (FPM)"]
API --> Q[("Queue llm")]
Q --> WK["Worker: LlmGateway + agent loop"]
WK -->|"stream"| RV["Reverb / SSE"] --> W
WK --> CL["Claude API (Opus/Sonnet theo route)"]
WK --> T1["Tool get_order (authz theo session)"]
WK --> T2["Tool search_policy (pgvector + FTS)"]
WK --> T3["Tool refund (idempotency key nghiệp vụ, ngưỡng, duyệt)"]
T1 --> PG[("PostgreSQL")]
T2 --> PG
T3 --> PAY["Cổng thanh toán (idempotency key)"]
WK --> TR[("agent_runs: checkpoint, usage, trace")]
WK --> H["Chuyển nhân viên"]
4. Quyết định then chốt và lý do
| Quyết định | Lý do | Bài |
|---|---|---|
| Chạy trong queue, stream qua Reverb | 3 lượt/s × ~10 s = 30 đồng thời (Little's law), không giữ FPM; TTFT thấp | 09 |
Guzzle timeout tường minh, maxRetries theo route, một tầng retry | Timeout của SDK không tự áp; tránh retry nhân chồng | 09 |
| System prompt + tool cố định, sắp theo tên; dữ liệu động ở cuối | Prompt cache — đòn bẩy chi phí lớn nhất | 03 |
Tool nhận order_id nhưng user lấy từ session | Chống IDOR qua agent | 08 |
Refund: khoá refund:{order_id}:{request_id}, truyền xuống cổng thanh toán, checkpoint trước khi chạy tool | At-least-once + idempotent; lab cho thấy khoá theo tool_use_id không đủ | 02 |
| Trên ngưỡng hoặc phiên đã đọc nội dung khách viết (ghi chú đơn, ảnh) → duyệt | Cắt bộ ba chết người, hành động không đảo ngược | 08 |
Chính sách qua RAG pgvector + FTS unaccent, trích dẫn nguồn, cho phép "không có thông tin" | Không để model "nhớ" chính sách (Air Canada); khách gõ không dấu | 04 |
| Render trả lời qua sanitizer allowlist ảnh + CSP | Chặn rò dữ liệu qua ảnh markdown | 08 |
max_iter 8, ngân sách token/hội thoại, phát hiện lặp | Chặn đuôi chi phí | 02, 09 |
| Eval 200 ca (outcome grader kiểm bảng refunds) chạy trong CI; review 30 transcript/tuần | Đổi prompt/model có số liệu | 07 |
| Trace OTel GenAI, dashboard chi phí/hội thoại, cache hit ratio, % chuyển người | Phát hiện "chi phí tăng im lặng" | 07, 09 |
5. Ước lượng chi phí (minh hoạ)
Giả định: mỗi hội thoại 4 lượt; tiền tố system + tool 6k token dùng chung mọi người (cache luôn ấm); mỗi lượt thêm ~1,5k token input mới (câu hỏi + tool result) và 300 token output. Trên Sonnet 5.5 ($2 input, $10 output, đọc cache $0,20, ghi cache 1,25× = $2,50 / 1M token):
- Đọc cache: 6k + 7,8k + 9,6k + 11,4k = 34,8k token × $0,20/1M ≈ $0,007
- Ghi cache phần mới: 1,5k + 3 × 1,8k = 6,9k token × $2,50/1M ≈ $0,017
- Output: 4 × 300 = 1,2k token × $10/1M = $0,012
→ ~$0,036/hội thoại (≈ 950đ ở tỉ giá ~26 000đ/USD); 5 000 hội thoại/ngày ≈ $180/ngày. Router đẩy câu hỏi đơn giản sang Haiku và rút gọn tool result sẽ kéo xuống. Con số thật
phải đo từ usage.
6. Rủi ro và phương án
- Nhà cung cấp sự cố → circuit breaker, chuyển nhân viên, trang trạng thái.
- Chất lượng giảm sau nâng model → canary + eval, rollback bằng cấu hình.
- Dữ liệu cá nhân → che trường không cần, chính sách lưu transcript, tuân thủ Luật Bảo vệ dữ liệu cá nhân (hiệu lực 1/1/2026).
- Exit strategy → gateway nội bộ + eval set; tool và RAG độc lập nhà cung cấp.
Checklist "nói được" trước buổi phỏng vấn
- Vẽ agent loop ở mức
tool_use/tool_result/stop_reasonvà nói 3 thứ harness phải làm (giới hạn vòng, lỗi thành dữ liệu, idempotency). - Giải thích prompt cache là prefix match và kể một silent invalidator.
- Kể bẫy WHERE + HNSW và cách xử lý.
- Nói khi nào KHÔNG dùng agent, KHÔNG dùng multi-agent, KHÔNG dùng RAG, KHÔNG dùng MCP.
- Định nghĩa bộ ba chết người và cách cắt; kể một sự cố công khai (EchoLeak, GitHub MCP, Supabase).
- Giải thích vì sao eval 50 câu không đủ phân biệt 82% và 86%.
- Nói Little's law cho việc đặt LLM vào hệ PHP-FPM.
- Nói exit strategy: gateway, eval set, dữ liệu gốc để embed lại.
Chạy lab
Toàn bộ lab nằm trong labs/ai/ của repo; output gốc đã chạy nằm trong labs/ai/out/. Không cần API key: agent loop dùng mock server
(mock_anthropic.py) nói đúng giao thức Messages API, nên SDK chính thức chạy thật nhưng "model" là kịch bản cố định.
# Python (tokenizer, sampling, KV cache, chi phí, pgvector, multi-agent, eval, OTel, MCP)
python3 -m venv .venv && . .venv/bin/activate
pip install numpy tokenizers anthropic mcp opentelemetry-sdk "psycopg[binary]"
# PHP (agent loop, retry/timeout, streaming, prompt cache, bảo mật)
cd labs/ai/php && composer install && cd ..
# Mock server
./mockctl.sh start cskh # policy: cskh | parallel | echo
./mockctl.sh stop
# PostgreSQL + pgvector tạm (xem phụ lục bài 04)
| Thư mục / file | Bài | Nội dung |
|---|---|---|
py/tokenizer_vi_en.py, py/sampling.py, py/kv_cache.py | 01 | Token tiếng Việt, sampling, float, KV cache |
php/agent_loop.php, php/run_agent_loop_lab.sh | 02 | Vòng lặp, max_iter, crash/resume, idempotency |
php/cache_prefix.php, py/context_cost.py | 03 | Silent invalidator, mô hình chi phí |
py/pgvector_lab.py, sql/hybrid_search_vi.sql | 04 | HNSW, lọc, FTS tiếng Việt, RRF |
py/multiagent_sim.py | 05 | Lỗi cộng dồn, fan-out, rate limit |
mcp/shop_server.py, mcp/raw_client.py, mcp/http_probe.sh | 06 | JSON-RPC thô, 2026-07-28, tool poisoning |
py/eval_stats.py, py/otel_agent_trace.py | 07 | Thống kê eval, trace GenAI |
php/security_lab.php | 08 | Ảnh markdown, IDOR, SSRF, taint |
php/retry_timeout.php, php/run_retry_lab.sh, php/stream_ttft.php | 09 | Retry, timeout, TTFT |
Giới hạn của series (đọc trước khi trích dẫn số liệu)
- Môi trường viết bài không có API key và không có Context7 MCP: hành vi model thật (có gọi đúng tool không, có bị injection không) chưa được verify — mỗi bài ghi rõ chỗ nào. Thông tin API/giá lấy từ tài liệu tham chiếu Claude API bản cache 2026-09-25 và mã nguồn SDK đã cài; nguồn ngoài tra bằng web ngày 2026-09-30.
- Lab PostgreSQL chạy trên PostgreSQL 16.13 + pgvector 0.6.0 (cluster tạm), không phải PostgreSQL 18.4 trong repo
postgresql-learningnhư quy ước — máy viết bài không có repo đó. pgvector bản mới (0.8+) có iterative scan xử lý bẫy lọc; bài 04 ghi rõ. - Giá, model, tính năng beta thay đổi nhanh — kiểm tra lại trang giá và migration guide trước buổi phỏng vấn.
Bắt đầu: 01 · LLM dưới nắp capo.