Featured image of post Prompt Engineering: Mô hình tư duy 'Đạo diễn & Diễn viên'

Prompt Engineering: Mô hình tư duy 'Đạo diễn & Diễn viên'

Tại sao 'hãy ngắn gọn' lại cho kết quả tệ hơn 'trả lời trong 3 gạch đầu dòng'? Hướng dẫn chuyên sâu về system prompt, few-shot, chain-of-thought và structured output.

Hai kỹ sư. Cùng model. Cùng task. Người này ra kết quả xuất sắc. Người kia nhận rác.

Sự khác biệt không phải ở model. Mà ở prompt.

Prompt Engineering là kỹ năng giao tiếp chính xác với LLM. Đây không phải kỹ năng mềm — đây là một ngành kỹ thuật nghiêm túc với các kỹ thuật có thể đo lường và tái tạo.

Đây là Hướng dẫn chuyên sâu về Prompt Engineering.


Phần 1: Nền tảng (Mô hình tư duy)

Đạo diễn và Diễn viên

Hãy nghĩ LLM như Diễn viên linh hoạt nhất trên đời. Họ có thể đóng bất kỳ vai nào, nhận bất kỳ tính cách nào, theo bất kỳ kịch bản nào.

Bạn là Đạo diễn.

Đạo diễn tệ nói: “Hãy diễn hay vào.” Diễn viên không biết phải làm gì.

Đạo diễn giỏi nói: “Bạn đang đóng vai thám tử thập niên 1920. Mệt mỏi với đời, mỉa mai, nhưng xuất sắc. Nói bằng câu ngắn, mạnh. Không bao giờ phá vai.”

Cùng diễn viên đó sẽ cho màn trình diễn hoàn toàn khác nhau dựa trên chỉ đạo. Prompt của bạn chính là sự chỉ đạo đó.


Phần 2: Điều tra (Các kỹ thuật cốt lõi)

1. System Prompt (Thiết lập sân khấu)

System prompt định nghĩa vai trò cố định và ràng buộc cho toàn bộ cuộc trò chuyện.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from openai import OpenAI
client = OpenAI()

SYSTEM = """Bạn là senior Python code reviewer tại một công ty fintech.
Nhiệm vụ của bạn:
- Review code về tính đúng đắn, bảo mật và hiệu năng.
- Thẳng thắn và cụ thể. Không khen ngợi trừ khi thực sự xuất sắc.
- Format feedback: [CRITICAL] / [WARNING] / [SUGGESTION]
- Giới hạn: chỉ 5 điểm quan trọng nhất."""

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": f"Review code này:\n```python\n{code}\n```"}
    ]
)

Quy tắc cho system prompt tốt:

  • Định nghĩa vai trò (“Bạn là…”).
  • Định nghĩa rõ định dạng output.
  • Định nghĩa ràng buộc (“Không quá 5 mục”, “Không bao giờ nói X”).
  • Định nghĩa đối tượng (“Giải thích cho quản lý không biết kỹ thuật”).

2. Few-Shot Learning (Chỉ cho thấy, không kể)

Thay vì giải thích bạn muốn gì, hãy chỉ ra ví dụ.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FEW_SHOT_PROMPT = """Phân loại phản hồi khách hàng là POSITIVE, NEGATIVE, hoặc NEUTRAL.

Ví dụ:
Phản hồi: "Giao hàng cực nhanh, thích lắm!"
Phân loại: POSITIVE

Phản hồi: "Hàng bị hỏng khi nhận, rất thất vọng."
Phân loại: NEGATIVE

Phản hồi: "Đã nhận hàng."
Phân loại: NEUTRAL

Giờ phân loại:
Phản hồi: "{feedback}"
Phân loại:"""

Few-shot đáng tin cậy hơn nhiều so với zero-shot cho task phân loại, định dạng và trích xuất.

3. Chain-of-Thought (Buộc model suy luận)

Với task suy luận phức tạp, bảo model suy nghĩ từng bước trước khi trả lời.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ❌ ZERO-SHOT: Model nhảy thẳng đến câu trả lời (thường sai)
prompt = "17 có phải số nguyên tố không? Trả lời: "

# ✅ CHAIN-OF-THOUGHT: Model suy luận trước
prompt = """17 có phải số nguyên tố không?
Hãy suy nghĩ từng bước:
1. Số nguyên tố không có ước nào ngoài 1 và chính nó.
2. Kiểm tra chia hết: 17/2 = 8.5 (không), 17/3 = 5.67 (không), 17/4 = 4.25 (không)
3. Chỉ cần kiểm tra đến √17 ≈ 4.1
4. Không tìm thấy ước nào.
Kết luận: Có, 17 là số nguyên tố."""

Chỉ cần thêm “Hãy suy nghĩ từng bước” đã cải thiện đáng kể độ chính xác với toán, logic và task nhiều bước.

4. Structured Output (Thuần hóa JSON hoang dã)

Đừng bao giờ parse output LLM bằng string manipulation. Dùng structured output.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pydantic import BaseModel
from openai import OpenAI

client = OpenAI()

class KetQuaPhanTich(BaseModel):
    cam_xuc: str           # "POSITIVE" | "NEGATIVE" | "NEUTRAL"
    do_tin_cay: float      # 0.0 đến 1.0
    van_de_chinh: list[str]

response = client.beta.chat.completions.parse(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "Bạn là chuyên gia phân tích phản hồi."},
        {"role": "user", "content": f"Phân tích: '{feedback}'"}
    ],
    response_format=KetQuaPhanTich  # JSON hợp lệ đảm bảo
)

ket_qua = response.choices[0].message.parsed
print(ket_qua.cam_xuc)       # "NEGATIVE"
print(ket_qua.do_tin_cay)    # 0.95
print(ket_qua.van_de_chinh)  # ["hàng bị hỏng", "không được hoàn tiền"]

Phần 3: Chẩn đoán (Lỗi Prompt thường gặp)

Vấn đềNguyên nhânCách sửa
Format output không nhất quánKhông chỉ định formatThêm hướng dẫn format rõ ràng + few-shot.
Model bỏ qua ràng buộcRàng buộc ở cuối promptĐặt ràng buộc quan trọng ở đầu system prompt.
Hallucination về sự kiệnModel đoán vượt kiến thứcThêm: “Nếu không chắc, nói ‘Tôi không biết’. Không được đoán.”
Quá dài dòngKhông giới hạn độ dàiThêm: “Trả lời tối đa 3 câu.”
Prompt injectionUser ghi đè hướng dẫnWrap input: [USER INPUT]\n{input}\n[END USER INPUT]

Phần 4: Giải pháp (Pattern Prompt cho Production)

Framework COSTAR

Cấu trúc prompt quan trọng với 6 yếu tố:

1
2
3
4
5
6
C — Context:   "Bạn đang giúp developer junior debug lỗi Python."
O — Objective: "Xác định nguyên nhân gốc rễ của lỗi."
S — Style:     "Giải thích như cho trẻ 5 tuổi với khái niệm, kỹ thuật với code."
T — Tone:      "Kiên nhẫn, khích lệ, không bao giờ coi thường."
A — Audience:  "Developer có 1 năm kinh nghiệm."
R — Response:  "Format: [Nguyên nhân] → [Giải thích] → [Code sửa]"

Versioning Prompt (Quản lý Prompt như Code)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# prompts/v2/code_reviewer.py
SYSTEM_PROMPT_V2 = """..."""  # Có version, đã test, theo dõi trên Git

def eval_prompt(prompt: str, test_cases: list) -> float:
    correct = sum(
        run_prompt(prompt, tc["input"]) == tc["expected"]
        for tc in test_cases
    )
    return correct / len(test_cases)

score_v1 = eval_prompt(SYSTEM_PROMPT_V1, test_cases)  # 0.72
score_v2 = eval_prompt(SYSTEM_PROMPT_V2, test_cases)  # 0.89

Mô hình tư duy chốt hạ

1
2
3
4
5
6
7
System Prompt     → Bản tóm tắt của Đạo diễn. Thiết lập vai trò cố định.
Few-Shot          → Chỉ cho thấy, không kể. 3 ví dụ tốt hơn 3 đoạn giải thích.
Chain-of-Thought  → "Hãy suy nghĩ từng bước." Buộc lý luận trước kết luận.
Structured Output → Schema Pydantic = JSON đảm bảo hợp lệ. Không hack parse.

temperature=0     → Tất định. Cho task thực tế và đánh giá.
temperature=0.7   → Sáng tạo. Cho tạo nội dung.

Hãy đối xử với prompt như code: version nó, test với eval, review trong PR, và không bao giờ ship thay đổi prompt lên production mà không có benchmark.

Được tạo với sự lười biếng tình yêu 🦥

Subscribe to My Newsletter