Xây app AI đầu tiênBuild your first AI app

Sáu bài 101, một app. Cho bản xấu nhất chạy từ đầu tới cuối trước. Six 101 lessons, one app. Get the ugliest version running end to end first.

Bài tổng kết (capstone): bot hỏi đáp tài liệu nội bộ, xây qua đúng sáu bước API, Prompt, RAG, Eval, Guardrail, Triển khai. Mỗi bước dùng lại một bài đã học, và cả sáu ghép thành một vòng khép kín.

The capstone: an internal-docs Q&A bot, built in exactly six steps: API, Prompt, RAG, Eval, Guardrail, Deploy. Each step reuses one lesson, and all six close into a single loop.

Request path: question, input guardrail, RAG, prompt, API, output guardrail, answer; deploy wraps everything; eval runs offline. 06Triển khai bọc toàn bộDeploy wraps everything HỏiAsk ĐápReply 05Guardrail vàoGuardrail in 03RAG 02Prompt 01API 05Guardrail raGuardrail out 04Evalchạy ngoài luồng, trên bộ câu hỏi cố địnhruns offline, on a fixed question set
Số là thứ tự xây, đường đi là thứ tự một request chạy qua. Hai thứ tự này khác nhau. Nét đứt nghĩa là không nằm trên đường đi của request. Bấm vào trạm để tới phần chi tiết. Numbers are build order; the line is the order a request travels. They differ. Dashed means off the request path. Click a station to jump to its details.

Trước hết: có cần làm app AI không?First: do you need an AI app at all?

Phần lớn dự án bot nội bộ thất bại vì đáng lẽ không nên làm. Bạn không cần app AI khi:

Most internal-bot projects fail because they shouldn't have been built. You don't need an AI app when:

  • Tài liệu dưới khoảng 20 trang và ít người hỏi. Một trang FAQ cộng Ctrl+F là đủ.
  • 80% câu hỏi lặp lại trong khoảng 20 câu. Viết sẵn 20 câu trả lời và ghim lên kênh chat.
  • Trả lời sai gây hậu quả pháp lý hoặc tài chính. Dùng tra cứu có cấu trúc hoặc chuyển người.
  • Tài liệu gốc mâu thuẫn hoặc lỗi thời. Dọn tài liệu trước, bot chỉ khuếch đại sự lộn xộn.
  • The docs are under roughly 20 pages and few people ask. A FAQ page plus Ctrl+F is enough.
  • 80% of questions repeat within about 20. Write 20 answers and pin them in the chat channel.
  • A wrong answer has legal or financial consequences. Use structured lookup or a human.
  • The source docs contradict each other or are outdated. Clean them first; a bot only amplifies the mess.

Phương án AI rẻ nhấtThe cheapest AI option

Nếu tổng tài liệu vừa với context window (đếm token, đừng đoán), bỏ qua RAG. Nhồi toàn bộ vào system prompt và bật prompt caching. Bạn bỏ được cả một pipeline dữ liệu.

If all the docs fit in the context window (count tokens, don't guess), skip RAG. Put everything in the system prompt and turn on prompt caching. You drop an entire data pipeline.

Chỉ chuyển sang RAG khi tài liệu không còn vừa, chi phí mỗi câu quá cao, hoặc cần phân quyền theo người hỏi.

Move to RAG only when the docs stop fitting, per-question cost is too high, or you need per-user permissions.

Chọn trong 30 giâyDecide in 30 seconds

  1. Có người thật hỏi lặp lại đủ nhiều để đáng tự động hoá?Do real people ask often enough to be worth automating?
    Không:No: FAQ tĩnh. Dừng.Static FAQ. Stop.
  2. Trả lời sai có gây hậu quả pháp lý hoặc tài chính?Would a wrong answer have legal or financial consequences?
    Có:Yes: tra cứu có cấu trúc hoặc chuyển người. Dừng.structured lookup or a human. Stop.
  3. Tổng tài liệu có vừa context window không?Do all the docs fit in the context window?

    Vừa: 01 API, 02 Prompt với toàn bộ tài liệu và prompt caching, 04 Eval, 05 Guardrail tối thiểu, 06 Triển khai.

    They fit: 01 API, 02 Prompt with all docs plus prompt caching, 04 Eval, minimal 05 Guardrail, 06 Deploy.

    Không vừa, hoặc cần phân quyền: đủ sáu bước, có 03 RAG.

    They don't, or you need permissions: all six steps, including 03 RAG.

Nhánh nào cũng vậy: Eval và Guardrail không bao giờ bị bỏ. Chỉ RAG là tuỳ chọn.Every branch: Eval and Guardrail are never skipped. Only RAG is optional.

Sáu bước, theo thứ tự xâySix steps, in build order

Ba bước đầu làm app trả lời được. Ba bước sau làm app đáng tin và dùng được. Mỗi bước xong khi đạt đúng tiêu chí ghi ở cuối thẻ.The first three make the app answer. The last three make it trustworthy and usable. Each step is done when it meets the criterion at the bottom of its card.

01

API

Gọi modelModel calls
[app] ─(system + messages)─► [model] ─(text + usage)─► [app]

Một lời gọi HTTP gửi tin nhắn, nhận văn bản và số token. Mọi thứ khác chỉ là chuẩn bị đầu vào và xử lý đầu ra cho lời gọi này.

One HTTP call: send messages, get text and token counts back. Everything else prepares input and handles output for this call.

Chọn gọi model qua API là đổi quyền kiểm soát hạ tầng và phí theo token lấy năng lực model hàng đầu ngay hôm nay mà không phải vận hành gì.

Calling a model via API trades infrastructure control and a per-token fee for top-tier capability today with nothing to operate.

Dùng cho
Đo chi phí, độ trễ thật; so hai model trên cùng 20 câu hỏi.
Được
Model mạnh sau vài dòng code, trả theo lượng dùng, đổi model bằng một tham số.
Mất
Dữ liệu rời hạ tầng của bạn; rate limit và lỗi tạm thời; hành vi đổi nếu gọi alias kiểu “latest”. Ghim đúng model ID (vd. claude-haiku-5-5, không có hậu tố ngày) trong config, chỉ đổi sau khi chạy lại Eval.
Xong khi
Script in ra câu trả lời và số token.
Use for
Measuring real cost and latency; comparing two models on the same 20 questions.
Gain
A strong model in a few lines, pay per use, switch models with one parameter.
Lose
Data leaves your infrastructure; rate limits and transient errors; behavior shifts behind a “latest”-style alias. Pin the exact model ID (e.g. claude-haiku-5-5, no date suffix) in config and change it only after re-running Eval.
Done when
A script prints the answer and token counts.

Dấu hiệu: bạn chưa biết một câu trả lời tốn bao nhiêu tiền và mất bao lâu.

Signal: you don't yet know what one answer costs or how long it takes.

02

Prompt

Gọi modelModel calls
system: vai trò · quy tắc · định dạng
user:   <documents>…</documents> + câu hỏi

Chỉ dẫn và ngữ cảnh gửi kèm câu hỏi. Đây là mã nguồn hành vi của app, viết bằng ngôn ngữ tự nhiên.

The instructions and context sent with the question. It's the app's behavior, written as natural-language source code.

Chọn điều khiển hành vi bằng prompt là đổi sự chắc chắn của code lấy tốc độ lặp tính bằng phút.

Controlling behavior through prompts trades the certainty of code for iteration measured in minutes.

Dùng cho
Ép trả lời ngắn, có nguồn, từ chối bằng một câu cố định khi thiếu thông tin.
Được
Sửa trong vài phút, không cần hạ tầng; prompt dài gần như miễn phí khi có caching.
Mất
Chỉ đề nghị, không bảo đảm; sửa lỗi A dễ sinh lỗi B; không thêm được kiến thức.
Xong khi
Với 5 đoạn dán tay, bot trả lời đúng định dạng và từ chối được câu ngoài tài liệu.
Use for
Forcing short, cited answers and a fixed refusal string when info is missing.
Gain
Fixes in minutes, no infrastructure; long prompts nearly free with caching.
Lose
Suggests, doesn't guarantee; fixing A breeds B; can't add knowledge.
Done when
Given 5 pasted passages, the bot answers in format and refuses off-doc questions.

Dấu hiệu: model có đủ thông tin nhưng trả lời sai cách.

Signal: the model has the information but answers the wrong way.

03

RAG

Tri thứcKnowledge
nạp:  tài liệu ► chunk ► embedding ► kho (+ quyền xem)
hỏi:  câu hỏi ► embedding ► top-k ► rerank ► prompt

Tìm vài đoạn tài liệu liên quan nhất rồi đặt vào prompt. Model trả lời từ đoạn được đưa vào, không từ trí nhớ. Chunk khởi đầu 512–1024 token, chồng lấn 10–15%, giống RAG 101.

Find the few most relevant passages and put them in the prompt. The model answers from them, not from memory. Start chunks at 512–1024 tokens with 10–15% overlap, as in RAG 101.

Chọn RAG là đổi một pipeline dữ liệu phải bảo trì lấy câu trả lời bám tài liệu mới nhất mà không nhồi cả kho vào mỗi request.

Choosing RAG trades a data pipeline to maintain for answers grounded in the latest docs without stuffing the whole collection into every request.

Dùng cho
Kho quá lớn cho context, tài liệu đổi thường xuyên, cần phân quyền theo người.
Được
Giảm bịa mạnh, cập nhật bằng cách nạp lại (re-index), chi phí gần như không theo kích thước kho.
Mất
Tìm sai đoạn là trả lời sai tự tin; yếu với mã số và tên riêng; thêm pipeline phải bảo trì.
Xong khi
Đoạn đúng nằm trong top-5 ở phần lớn câu của bộ Eval.
Use for
Collections too large for context, docs that change often, per-user permissions.
Gain
Far less fabrication, update by re-indexing, cost nearly flat with collection size.
Lose
Wrong passage, confidently wrong answer; weak on codes and names; another pipeline to run.
Done when
The right passage is in the top 5 for most Eval questions.

Dấu hiệu: model sai vì thiếu thông tin, không phải vì hiểu sai chỉ dẫn.

Signal: the model is wrong because it lacks information, not because it misread instructions.

04

Eval

Kiểm soátControl
bộ câu hỏi ► app ► chấm truy xuất (recall@k)
                   └► chấm trả lời (đúng · có nguồn · bám tài liệu)

Bộ câu hỏi cố định có đáp án, cùng script chấm tự động. Đây là unit test của app AI.

A fixed question set with expected answers plus an automatic grader. The unit tests of an AI app.

Chọn đầu tư vào Eval là đổi vài ngày viết bộ test lúc đầu lấy khả năng biết chắc mỗi thay đổi làm app tốt lên hay tệ đi.

Investing in Eval trades a few days of test-writing upfront for knowing whether each change makes the app better or worse.

Dùng cho
Quyết định đổi prompt, chunk hay model; bắt hồi quy (regression); khoanh lỗi ở truy xuất hay ở sinh.
Được
Cảm giác thành con số; kiểm chứng trong vài phút; bộ test lớn dần từ log thật.
Mất
Tốn công lúc đầu; chỉ đo được thứ nó chứa; LLM-as-judge có thiên lệch riêng.
Xong khi
Một lệnh in ra recall@5, tỷ lệ đúng, tỷ lệ từ chối đúng cho hai phiên bản.
Use for
Deciding on prompt, chunking, or model changes; catching regressions; locating errors.
Gain
Gut feeling becomes numbers; verify in minutes; the set grows from real logs.
Lose
Upfront effort; measures only what it contains; LLM judges have biases.
Done when
One command prints recall@5, accuracy, and correct-refusal rate for two versions.

Dấu hiệu: bạn đánh giá app bằng cách thử vài câu rồi nói "có vẻ ổn".

Signal: you judge the app by trying a few questions and saying "looks fine".

05

Guardrail

Kiểm soátControl
vào:   phạm vi · dữ liệu cá nhân · chèn lệnh
truy:  chỉ tài liệu người hỏi được xem
ra:    có nguồn? nguồn có thật? ► gửi / câu dự phòng

Các lớp kiểm tra bằng code bao quanh lời gọi model. Prompt xin model làm đúng, guardrail kiểm tra xem model có làm đúng không.

Layers of code checks around the model call. The prompt asks the model to behave; the guardrail checks that it did.

Chọn thêm guardrail là đổi một ít độ trễ và một tỷ lệ từ chối nhầm lấy giới hạn trên cho thiệt hại khi model sai.

Adding guardrails trades a little latency and some false refusals for an upper bound on damage when the model is wrong.

Dùng cho
Chặn trả lời không nguồn hoặc nguồn bịa, chặn lộ tài liệu ngoài quyền, chặn prompt injection.
Được
Trần thiệt hại cố định; kiểm tra bằng code gần như miễn phí; mỗi lần chặn là dữ liệu cho Eval.
Mất
Giảm chứ không xoá rủi ro; chặt quá thì từ chối nhầm; model phụ làm tăng độ trễ.
Xong khi
Mọi câu tấn công trong bộ test bị chặn mà tỷ lệ đúng không giảm đáng kể.
Use for
Blocking uncited or fake-cited answers, permission leaks, and prompt injection.
Gain
A fixed damage ceiling; code checks nearly free; every block is Eval data.
Lose
Reduces risk, doesn't remove it; too strict means false refusals; helper models add latency.
Done when
Every attack question in the test set is blocked without a real drop in accuracy.

Dấu hiệu: có một loại lỗi mà xảy ra dù một lần cũng không chấp nhận được.

Signal: there's a class of error that is unacceptable even once.

06

Triển khaiDeploy

Vận hànhOperations
người dùng ► web / Slack ► backend ► [05 → 03 → 02 → 01 → 05]
                                └► log · 👍/👎 · nạp lại tài liệu

Bọc pipeline thành dịch vụ có giao diện, log, trần chi phí và cách cập nhật tài liệu. Bản demo thành sản phẩm ở bước này.

Wrap the pipeline in a service with a UI, logs, a cost cap, and doc updates. This is where the demo becomes a product.

Chọn đưa lên production là đổi sự yên tĩnh của bản demo lấy dữ liệu thật về cách người dùng hỏi, thứ duy nhất cho biết app có giá trị.

Going to production trades the quiet of a demo for real data on how users ask, the only proof the app has value.

Dùng cho
Thu câu hỏi thật, đo số câu không còn đến tay phòng Nhân sự, phát hiện tài liệu lỗi thời.
Được
Streaming: chữ hiện sau chưa tới một giây, guardrail đầu ra chạy trên toàn văn rồi thay câu dự phòng nếu sai; log thật nuôi Eval; 👍/👎 gần như miễn phí; phát hành dần giới hạn sự cố.
Mất
Log là dữ liệu nhạy cảm; quên nạp lại là trả lời theo quy định cũ; chi phí có thể tăng vọt.
Xong khi
10 người dùng thật dùng một tuần, có log, có chi phí thật, lỗi đã vào bộ Eval.
Use for
Collecting real questions, measuring how many no longer reach HR, spotting stale docs.
Gain
Streaming shows text in under a second, then the output guardrail checks the full text and swaps in the fallback if needed; real logs feed Eval; 👍/👎 is nearly free; gradual rollout limits incidents.
Lose
Logs are sensitive; a missed re-index means outdated answers; costs can spike.
Done when
10 real users for a week, with logs, real cost, and failures added to Eval.

Dấu hiệu: Eval đã đạt mục tiêu và bạn bắt đầu tự nghĩ câu hỏi để thử.

Signal: Eval hit its targets and you've started inventing questions to try.

Bảng đánh đổiTrade-off table

BướcChi phí thêm mỗi câuĐộ trễ thêmĐộ khó vận hànhLoại lỗi nó sửaBỏ được ở bản đầu?
01 APIToàn bộ chi phí tokenPhần lớn độ trễThấpKhông có câu trả lời nàoKhông
02 PromptThấp, rẻ hơn nữa khi cacheKhông đáng kểThấpTrả lời sai cách, sai định dạngKhông
03 RAGThấp đến trung bình50–500 msCao nhấtThiếu thông tin, kho quá lớn, cần phân quyềnCó, nếu tài liệu vừa context
04 EvalKhông có lúc chạyKhông có lúc chạyTrung bìnhKhông biết mình đang saiKhông
05 GuardrailGần 0 nếu bằng codeVài ms tới vài trăm msTrung bìnhLỗi hiếm nhưng không chấp nhận đượcChỉ phần dùng model phụ
06 Triển khaiChi phí hạ tầng cố định, nhỏTuỳ hạ tầngTrung bìnhKhông biết người dùng thật cần gìKhông, nếu muốn có giá trị
StepAdded cost per questionAdded latencyOps difficultyError class it fixesSkippable in v1?
01 APIAll token costMost of the latencyLowNo answer at allNo
02 PromptLow, lower with cachingNegligibleLowWrong manner, wrong formatNo
03 RAGLow to medium50–500 msHighestMissing info, docs too large, permissionsYes, if docs fit in context
04 EvalNone at runtimeNone at runtimeMediumNot knowing you're wrongNo
05 GuardrailNear zero in codeA few ms to a few hundred msMediumRare but unacceptable errorsOnly the helper-model part
06 DeploySmall fixed infrastructureInfra-dependentMediumNot knowing what users needNo, if you want value

Anti-patterns

Sai lầmVì sao saiSửa thế nào
Dựng vector DB, agent, framework ngay ngày đầuTốn hàng tuần làm hạ tầng trước khi biết có cần khôngBắt đầu bằng nhồi context hoặc numpy, thêm công cụ khi Eval chỉ ra giới hạn
Đánh giá bằng "thử vài câu thấy ổn"Cảm tính không bắt được hồi quyBộ 30–50 câu cố định, chạy bằng một lệnh
Sửa prompt khi lỗi nằm ở truy xuấtĐoạn sai thì không prompt nào cứu đượcĐo recall@k trước, thấp thì sửa chunk và tìm kiếm
Bộ test thiếu câu không trả lời đượcKhông đo được độ bịaKhoảng 20% câu không có trong tài liệu
Lọc quyền sau khi model trả lờiTài liệu bị giới hạn quyền xem đã nằm trong promptLọc theo quyền trước khi tìm kiếm
Chunk không kèm tiêu đề mụcĐoạn mất ngữ cảnh, tìm saiGhép đường dẫn tiêu đề vào đầu mỗi chunk
Tin tuyệt đối LLM-as-judgeModel chấm có thiên lệch, điểm đẹp nhưng kết luận saiĐối chiếu 20–30 mẫu với người chấm trước
Gọi alias kiểu “latest” thay vì model ID đã ghimHành vi đổi mà không ai biết vì saoGhim đúng model ID trong config, nâng cấp qua Eval
Mở cho cả công ty ngayLỗi đầu tiên được hàng trăm người thấy10 người, rồi một phòng ban, rồi toàn công ty
Không có pipeline cập nhật tài liệuBot trả lời theo quy định cũ, rất tự tinJob nạp lại theo lịch hoặc sự kiện, hiện ngày cập nhật trong nguồn
MistakeWhy it's wrongFix
Vector DB, agents, and a framework on day oneWeeks of infrastructure before knowing it's neededStart with full context or numpy; add tools when Eval shows a limit
Judging by "tried a few, looks fine"Gut feeling can't catch regressionsA fixed 30–50 question set, one command
Tuning the prompt when retrieval is the bugNo prompt rescues the wrong passageMeasure recall@k first; if low, fix chunking and search
No unanswerable questions in the test setYou can't measure fabricationAbout 20% questions not in the docs
Filtering permissions after the answerRestricted docs are already in the promptFilter by permission before searching
Chunks without section headingsPassages lose context, retrieval misfiresPrepend the heading path to every chunk
Fully trusting LLM-as-judgeBiased judge, nice score, wrong conclusionCalibrate on 20–30 human-graded samples first
Calling a “latest”-style alias instead of a pinned model IDBehavior changes, nobody knows whyPin the exact ID in config; upgrade through Eval
Opening to the whole company at onceThe first bug is seen by hundreds10 people, then a department, then everyone
No doc update pipelineConfident answers from outdated rulesScheduled or event-driven re-index, show update dates in sources

Ba câu cần nhớThree things to remember

  1. Chạy được từ đầu tới cuối trước, làm tốt từng khâu sau.Run end to end first, perfect each stage later. Một vòng khép kín thô dạy bạn nhiều hơn một khâu hoàn hảo đứng riêng.A rough closed loop teaches more than one perfect stage alone.
  2. Không có Eval thì mọi thay đổi chỉ là đoán.Without Eval, every change is a guess. Viết bộ câu hỏi trước khi tinh chỉnh bất cứ thứ gì.Write the question set before tuning anything.
  3. Prompt đề nghị, guardrail bảo đảm.Prompts suggest, guardrails guarantee. Thứ gì không được phép sai thì phải kiểm tra bằng code.Anything that must never go wrong is checked in code.