Lần đầu tôi đọc một bài hướng dẫn prompt engineering, tôi nghĩ: đây là kỹ năng tôi có thể học trong một buổi chiều. Đọc xong, viết thử vài prompt, thấy ổn, tự cho mình là hiểu. Sau đó tôi build một feature thật — chatbot trả lời câu hỏi về sản phẩm — và mất ba tuần để làm nó không bị embarrassing. Khoảng cách giữa "hiểu prompt engineering" và "viết được prompt tốt cho production" lớn hơn bất kỳ bài tutorial nào thừa nhận.
ByteByteGo vừa có bài tổng hợp về các kỹ thuật prompt engineering — zero-shot, few-shot, chain-of-thought, role prompting, prompt chaining. Đọc bài đó, tôi thấy nội dung chính xác về mặt kỹ thuật. Nhưng cũng thiếu vài thứ mà chỉ biết được sau khi đã build thứ gì đó thật sự và failed đủ lần. Bài này là phần bổ sung đó.
Năm kỹ thuật — và thứ bài tutorial không nói về mỗi cái
Đưa instruction, không đưa example. Model dùng training knowledge để hiểu và thực hiện. Đây là cách hầu hết mọi người bắt đầu — và cũng là cách hầu hết mọi người stuck khi kết quả không như ý.
Điều tôi học được: zero-shot thất bại không phải vì thiếu example — mà vì instruction mơ hồ. Lần đầu tôi viết "classify this customer feedback as positive, negative, or neutral," tôi không định nghĩa gì cả. "Neutral" nghĩa là gì? Feedback vừa tích cực vừa tiêu cực thì là gì? Model phải đoán. Và nó đoán khác nhau mỗi lần. Trước khi nghĩ đến few-shot, hãy chắc chắn instruction của bạn đủ cụ thể để chính bạn có thể làm theo được.
Cung cấp 2–5 ví dụ trước khi đưa ra task thật. Model học pattern từ example và áp dụng vào input mới. Hiệu quả khi output format phức tạp hoặc khi behavior mong muốn khó describe bằng lời.
Cái này hay bị dùng sai: người ta thêm example vào khi model làm sai, hy vọng example sẽ "correct" model. Thường không work. Nếu model làm sai, thêm example cho đúng thứ sai đó — model học làm đúng thứ đó, nhưng có thể bắt đầu sai ở thứ khác. Vấn đề gốc rễ thường là instruction không rõ, không phải thiếu example. Sửa instruction trước, example sau.
"Think step by step." Yêu cầu model show reasoning trước khi đưa ra kết luận. Cải thiện đáng kể với reasoning tasks, math, logic. Giảm hallucination vì model phải justify từng bước.
CoT có một trade-off mà bài tutorial hay underplay: nó chậm hơn và tốn token hơn đáng kể. Trong production, với latency requirement nghiêm ngặt, bạn không thể dùng CoT cho mọi request. Tôi hay dùng nó trong offline processing — phân tích batch, generation offline — và dùng zero-shot cho real-time user-facing responses. Biết khi nào không cần CoT quan trọng không kém biết khi nào cần.
Gán persona cho model: "act as an experienced data engineer," "you are a patient first-grade teacher." Ảnh hưởng đến tone, vocabulary, level of detail, và góc nhìn của response.
Role prompting work tốt hơn nhiều khi bạn specific về role thay vì chung chung. "Act as a teacher" cho kết quả mediocre. "Act as an encouraging middle school math teacher who knows this student struggles with fractions and responds in simple language without condescending" cho kết quả tốt hơn hẳn. Càng nhiều context về role, model càng có ít chỗ để tự đoán.
Chia task phức tạp thành nhiều prompt nhỏ, output của prompt trước làm input cho prompt sau. Mỗi bước đơn giản, dễ debug, dễ monitor. Có thể dùng model khác nhau cho từng bước.
Đây là kỹ thuật underrated nhất trong danh sách — và là thứ tôi recommend nhất với người đang build AI features thật. Một mega-prompt xử lý mọi thứ nghe hay trên giấy. Trong thực tế, khi nó fail, bạn không biết fail ở bước nào. Khi nó tốt, bạn không biết tại sao tốt và không reproduce được. Chain cho phép bạn test từng bước độc lập, version control từng bước, và swap ra bước nào không work mà không break toàn bộ pipeline.
Thứ tôi thực sự dùng hàng ngày
Đọc bài tutorial về prompt engineering và thực sự prompt engineering trong production là hai thứ khác nhau. Đây là những gì tôi thực sự áp dụng — không phải những gì tôi biết về lý thuyết.
Đặt thông tin quan trọng ở đầu prompt, không phải cuối. Một commenter trong bài gốc dẫn một observation hay: model có xu hướng "lạc" nếu context quá dài và câu hỏi nằm ở cuối. Ngoài ra, phần đầu của prompt được cache hiệu quả hơn — với bài toán cần nhiều requests trên cùng system prompt, đặt system prompt ở đầu và ổn định giúp tiết kiệm đáng kể. Tôi đã đổi cấu trúc prompt theo hướng này và thấy consistency tốt hơn rõ rệt.
XML tags cho structured output đáng tin cậy hơn "respond in JSON." Tôi đã mất nhiều giờ debug vì model trả về JSON với trailing comma, comment trong JSON, hoặc text trước và sau JSON block. XML tags với schema rõ ràng — và validation programmatic phía sau — ổn định hơn nhiều. Nếu bạn cần structured output, define schema chính xác, validate bằng code, không chỉ hy vọng model làm đúng.
Tách reasoning khỏi structured output thành hai bước riêng. Bước một: chain-of-thought để model reason, không yêu cầu format cụ thể. Bước hai: dùng reasoning đó làm context, yêu cầu model produce structured output với strict schema. Bạn vừa có accuracy của CoT vừa có reliability của structured output — thay vì phải chọn một trong hai. Tốn thêm một API call, nhưng failure rate giảm đáng kể.
Version control prompt như code. Prompt không phải config. Prompt là behavior của system. Nếu bạn không version control prompt, bạn không biết tại sao output thay đổi sau một lần "chỉnh nhỏ." Tôi maintain prompt trong file riêng, với comment giải thích tại sao từng đoạn tồn tại, và dùng git history để trace thay đổi. Một prompt tốt có history của nó, không phải tự nhiên xuất hiện.
Thứ bài tutorial hay bỏ qua
Bài ByteByteGo có phần "Common Pitfalls" khá tốt, nhưng còn một pitfall nữa mà tôi không thấy ai nói đủ thẳng:
Overfitting prompt vào test cases của bạn. Bạn viết prompt, test với 10 examples, kết quả tốt, deploy. Rồi trong production, user nhập thứ hơi khác một chút — và prompt fail theo cách không ai dự đoán. Prompt engineering không phải chỉ là viết prompt work với test set của bạn. Nó là viết prompt work với distribution thật của input từ user thật.
Cách tôi combat vấn đề này: sau khi deploy, lấy 50–100 production requests thật (anonymized), chạy lại qua prompt, review kết quả. Rất nhiều lần tôi tìm thấy pattern thất bại mà test set không cover. Eval set từ production data quan trọng hơn eval set bạn tự tạo.
Một thứ khác: prompt engineering không phải giải pháp cho mọi vấn đề accuracy. Đôi khi output không tốt không phải vì prompt sai — mà vì task vượt quá capability của model, hoặc vì model không có đủ information trong context. Trước khi tiếp tục tune prompt, hãy hỏi: với người thông minh nhất bạn biết, nếu họ chỉ có thông tin trong prompt này, họ có làm được task không? Nếu không — vấn đề là context, không phải prompting technique.
Prompt tốt nhất là prompt đơn giản nhất mà vẫn cho kết quả bạn cần. Mọi thứ thêm vào đều là debt bạn phải maintain.
Điều thay đổi cách tôi nghĩ về prompting
Có một chuyển dịch trong cách tôi nghĩ về prompt engineering xảy ra sau khoảng 6 tháng làm việc với LLMs: tôi ngừng nghĩ về nó như "writing prompts" và bắt đầu nghĩ về nó như "designing interfaces."
Prompt là interface giữa intent của bạn và behavior của model. Như mọi interface design, nó cần rõ ràng, nhất quán, và fault-tolerant — nghĩa là không chỉ work trong điều kiện lý tưởng mà còn degrade gracefully khi input không như kỳ vọng. Bạn không thể control mọi thứ user sẽ input. Bạn chỉ có thể design prompt đủ robust để handle khoảng biến động đó.
Từ cái nhìn đó, tất cả các kỹ thuật — few-shot, CoT, chaining — đều là tools để làm interface robust hơn theo những chiều khác nhau. Few-shot giảm ambiguity về format. CoT giảm ambiguity về reasoning path. Chaining giảm cognitive load của một single prompt quá phức tạp. Không có kỹ thuật nào magic. Chúng đều là cách trade-off khác nhau giữa complexity, cost, latency, và reliability.
Hiểu trade-off đó — không phải chỉ biết tên kỹ thuật — là thứ phân biệt người biết prompt engineering và người làm được prompt engineering trong production.
Prompt là interface giữa intent của bạn và behavior của model. Bạn không thể control mọi thứ user sẽ input. Bạn chỉ có thể design prompt đủ robust để handle khoảng biến động đó.