Tra cứu nhanh: Lĩnh vực 4 — Prompt Engineering & Structured Output
System Prompt
Ví dụ code cụ thể tốt hơn mô tả bằng văn xuôi. Thay vì viết "dùng tên biến rõ ràng", hãy cho xem một đoạn code before/after.
Hiệu chỉnh mức độ nghiêm trọng: Không có ví dụ về điều gì cấu thành "nghiêm trọng" so với "nhỏ nhặt", mô hình sẽ coi mọi vấn đề đều quan trọng như nhau. Hãy cung cấp 2-3 ví dụ hiệu chỉnh cho thấy các mức độ nghiêm trọng bằng mẫu code cụ thể.
Cấu trúc một system prompt theo trình tự:
- Vai trò và bối cảnh (mô hình là ai, đang làm gì)
- Quy tắc và ràng buộc (phải làm gì/không được làm gì)
- Đặc tả định dạng output
- Ví dụ hiệu chỉnh (mức độ nghiêm trọng, giọng điệu, mức độ chi tiết)
Quy tắc chính: System prompt là cách hiệu quả nhất về chi phí để kiểm soát hành vi — chúng được cache và tái sử dụng qua nhiều yêu cầu nhờ prompt caching.
Structured Output — tool_use So Với Text
| Phương Pháp | Đảm Bảo | Dùng Khi |
|---|---|---|
tool_choice forced | Schema được API thực thi bắt buộc | Bạn cần structured output được đảm bảo mỗi lần |
tool_choice: auto | Mô hình có thể dùng hoặc không dùng tool | Agentic loop nơi phản hồi bằng văn bản cũng hợp lệ |
| JSON dựa trên prompt | Không có ràng buộc schema | Chỉ dùng cho trường hợp đơn giản, làm prototype |
Mẫu hình ưa dùng của đề thi: Định nghĩa một tool có mục đích duy nhất là cấu trúc hóa output (ví dụ: extract_entities), rồi buộc dùng nó bằng tool_choice: { type: "tool", name: "extract_entities" }. Điều này đảm bảo phản hồi khớp với schema của bạn.
Vì sao tool_use tốt hơn JSON dựa trên prompt:
- Schema được API xác thực, không phải qua xử lý hậu kỳ
- Không có rủi ro JSON dị dạng, thiếu trường, hoặc dư trường
- Hoạt động được với streaming (các chunk có cấu trúc)
Thiết Kế Schema Cho Structured Output
- Đặt các trường optional hoặc nullable khi dữ liệu có thể bị thiếu. Nếu một trường là bắt buộc nhưng dữ liệu lại không tồn tại, mô hình sẽ bịa đặt một giá trị để thỏa mãn schema.
- Dùng
enumcho các lựa chọn bị ràng buộc để ngăn giá trị tự do. - Giữ schema phẳng nhất có thể — schema lồng sâu làm tăng lỗi trích xuất.
- Thêm trường
descriptioncho mỗi thuộc tính — chúng hướng dẫn mô hình biết cần trích xuất gì.
Quy tắc ngăn bịa đặt: Nếu một trường có thể không có giá trị thực, hãy đặt nó là nullable: true hoặc required: false. Điều này cho phép mô hình trả về null thay vì tự bịa ra dữ liệu.
Ví Dụ Few-Shot
Khi nào dùng few-shot: Khi chỉ dùng hướng dẫn tạo ra output không nhất quán. Ví dụ few-shot minh họa chính xác định dạng và cách lập luận bạn mong muốn.
Thực hành tốt nhất:
- 2-4 ví dụ là điểm cân bằng tốt nhất. Nhiều hơn làm tăng chi phí context; ít hơn có thể không bao phủ đủ trường hợp biên.
- Đưa lý luận vào ví dụ, không chỉ cặp đầu vào → đầu ra. Cho thấy vì sao câu trả lời lại như vậy.
- Bao phủ trường hợp biên — ít nhất một ví dụ nên minh họa hành vi ở ranh giới.
- Đặt ví dụ trong system prompt để hưởng lợi từ caching, hoặc trong tin nhắn người dùng để biến đổi theo từng yêu cầu.
Lợi ích giảm dần: Đi từ 0 lên 2 ví dụ tạo ra tác động lớn nhất. Đi từ 4 lên 8 ví dụ hiếm khi cải thiện chất lượng và tốn thêm context.
Prompt Chaining
Các pipeline nhiều bước, mỗi bước là một prompt tập trung với một trách nhiệm duy nhất.
Mẫu hình: Bước 1 (trích xuất) → Bước 2 (xác thực) → Bước 3 (định dạng) → Bước 4 (tổng hợp)
Ưu điểm:
- Mỗi bước có một prompt nhỏ hơn, tập trung hơn — độ chính xác cao hơn ở mỗi bước
- Kết quả trung gian có thể được xác thực trước khi tiếp tục
- Từng bước riêng lẻ có thể được retry mà không cần chạy lại toàn bộ chuỗi
- Có thể dùng model khác nhau cho từng bước (tối ưu chi phí)
Khi nào chain vs. dùng một prompt duy nhất: Chain khi nhiệm vụ có các giai đoạn riêng biệt với yêu cầu khác nhau. Dùng một prompt duy nhất khi nhiệm vụ gắn kết và định dạng output đơn giản.
Mẫu Hình Retry — retry-with-error-feedback
Khi output không qua được xác thực, hãy gửi lại: prompt gốc + output thất bại + lỗi xác thực cụ thể.
Original: "Extract all dates from this contract" Failed output: { dates: ["2024-01-15", "next Tuesday"] } Error: "dates[1] is relative ('next Tuesday'), not absolute. All dates must be ISO 8601 format."
Mô hình thấy được nó đã tạo ra gì, điều gì sai, và có thể sửa một cách cụ thể. Không bao giờ chỉ nói "thử lại đi" — luôn kèm theo lỗi cụ thể.
Khi nào retry vs. leo thang:
- Retry: lỗi xác thực, sai định dạng, thiếu trường — mô hình có thể tự sửa
- Leo thang: thất bại lặp lại (>2 lần retry), độ tin cậy dưới ngưỡng, cách hiểu sai về cơ bản
Batch API
| Thuộc Tính | Giá Trị |
|---|---|
| Tiết kiệm chi phí | Rẻ hơn 50% so với đồng bộ |
| Độ trễ | Lên đến 24 giờ (không đảm bảo nhanh hơn) |
| Trường hợp dùng | Khối lượng công việc lớn, chịu được độ trễ |
| Không dùng cho | Yêu cầu thời gian thực, tương tác, hoặc hướng tới người dùng trực tiếp |
Điểm thi quan trọng: Batch API là để tăng thông lượng và tiết kiệm chi phí, không phải để tăng tốc độ. Nếu câu hỏi đề cập "thời gian thực" hoặc "hướng tới người dùng", Batch API là sai.
Giới Hạn Của Self-Review
Một mô hình không thể review hiệu quả output của chính nó trong cùng một phiên. Nó vẫn giữ nguyên lý luận đã tạo ra output ban đầu và có xu hướng thiên vị xác nhận lại nó.
Cách khắc phục: Dùng một instance model riêng biệt (cuộc hội thoại mới, không chia sẻ lịch sử) để review. Instance review chỉ thấy output, không thấy lý luận đã tạo ra nó.
Với input lớn: Dùng các lượt xử lý theo từng tệp (phân tích mỗi tệp độc lập) cộng với một lượt tích hợp xuyên tệp (tổng hợp các phát hiện). Đây là biện pháp giảm thiểu "pha loãng chú ý" — xử lý mọi thứ trong một lượt duy nhất khiến mô hình bỏ sót chi tiết.
Quy Tắc Quyết Định Cho Kỳ Thi
| Nếu câu hỏi nói... | Đáp án khả năng cao là... |
|---|---|
| "tuân thủ schema được đảm bảo" | tool_choice forced với một tool cụ thể |
| "output đôi khi sai định dạng" | Thêm ví dụ few-shot (2-4 ví dụ) |
| "mô hình bịa đặt dữ liệu bị thiếu" | Đặt các trường schema thành optional/nullable |
| "xác thực thất bại, cần sửa" | retry-with-error-feedback (gốc + thất bại + lỗi) |
| "giảm 50% chi phí", "xử lý số lượng lớn" | Batch API |
| "thời gian thực", "hướng tới người dùng" | KHÔNG dùng Batch API — hãy dùng đồng bộ |
| "chất lượng output không nhất quán" | Ví dụ few-shot hoặc prompt chaining |
| "review output của chính nó" | Instance riêng biệt (không phải cùng phiên) |
| "tài liệu lớn, thiếu chi tiết" | Lượt xử lý theo từng tệp + tích hợp xuyên tệp |
| "chỉ dùng hướng dẫn mà không hiệu quả" | Thêm ví dụ few-shot |
Các Bẫy Thi Thường Gặp
| Bẫy | Đáp Án Đúng |
|---|---|
| "Dùng JSON dựa trên prompt cho production" | Sai — hãy dùng tool_choice forced để đảm bảo schema |
| "Chỉ cần nói 'thử lại' khi xác thực thất bại" | Sai — phải kèm gốc + output thất bại + lỗi cụ thể |
| "Batch API để có phản hồi nhanh hơn" | Sai — Batch API đánh đổi độ trễ để lấy chi phí thấp hơn |
| "Review output trong cùng cuộc hội thoại" | Sai — review cùng phiên bị thiên vị; hãy dùng instance riêng biệt |
| "Thêm hơn 10 ví dụ few-shot để có kết quả tốt nhất" | Sai — 2-4 ví dụ là điểm cân bằng tốt nhất; lợi ích giảm dần sau đó |
| "Trường bắt buộc ngăn được bịa đặt dữ liệu" | Sai — trường bắt buộc GÂY RA bịa đặt khi dữ liệu bị thiếu |
| "Một prompt lớn xử lý được mọi thứ" | Sai — hãy chain các prompt khi nhiệm vụ có các giai đoạn riêng biệt |