Hai QA engineer cùng hỏi AI một câu tương tự nhau về cùng một bug, nhưng người viết prompt có "kiến trúc" (architecture) rõ ràng nhận được phân tích sắc bén, đúng trọng tâm — còn người viết prompt tùy hứng nhận được một đoạn văn chung chung không dùng được. Sự khác biệt không nằm ở model dùng, mà nằm ở cách prompt được thiết kế. Bài này tập trung vào ba trụ cột: role framing (định hình vai trò), cấu trúc chỉ dẫn (imperative/constrained/step-by-step), và kiểm soát output.
Role Framing Cải Thiện Chất Lượng Output AI Cho QA Như Thế Nào?
Vì Sao Role Framing Có Hiệu Quả
Role framing (định hình vai trò — gán cho AI một "nhân cách" hoặc vị trí chuyên môn cụ thể trước khi giao việc) hoạt động vì LLM được huấn luyện trên khối lượng văn bản khổng lồ, trong đó văn bản viết bởi các chuyên gia có "dấu vân tay" ngôn ngữ khác với văn bản viết bởi người mới. Khi bạn nói "Bạn là một Senior QA Automation Engineer với 8 năm kinh nghiệm về API testing", bạn không "thuyết phục" được AI trở nên giỏi hơn về mặt năng lực — nhưng bạn đang lái model về vùng phân bố xác suất (probability distribution) gần với văn bản chuyên gia hơn: dùng thuật ngữ chính xác hơn, cân nhắc edge case kỹ hơn, giả định ít hơn, hỏi lại khi thiếu thông tin nhiều hơn.
Hiệu ứng này đặc biệt rõ với các task QA vì domain có nhiều "mức độ chuyên môn" khác nhau — một câu hỏi về test case có thể được trả lời ở mức junior (chỉ test happy path) hoặc senior (test boundary, security, race condition, data integrity). Role framing là cách rẻ nhất để "kéo" câu trả lời lên mức chuyên môn mong muốn.
Role Frame Nên Có Gì
Một role frame hiệu quả không chỉ là một câu chức danh — nó cần các thành phần:
1. Chức danh + số năm kinh nghiệm: "Senior QA Engineer với 10 năm kinh nghiệm" (số năm cụ thể kéo output về mức độ chi tiết tương ứng, dù đây chỉ là tín hiệu ngôn ngữ không phải năng lực thật).
2. Chuyên môn cụ thể: "chuyên về performance testing hệ thống fintech" thay vì chỉ "QA engineer" chung.
3. Bối cảnh làm việc: "đang làm việc tại một công ty xử lý giao dịch tài chính, nơi mọi lỗi liên quan đến số tiền đều là nghiêm trọng (critical)."
4. Thái độ/phong cách làm việc mong muốn: "luôn nghi ngờ happy-path testing là chưa đủ, ưu tiên tìm edge case trước khi kết luận."
Ví dụ role frame đầy đủ:
Bạn là một Senior QA Engineer với 10 năm kinh nghiệm, chuyên sâu về testing hệ thống
thanh toán (payment systems) trong ngành fintech. Bạn luôn ưu tiên tìm race condition,
lỗi rounding số tiền, và edge case liên quan đến trạng thái giao dịch (pending/failed/
reversed) trước khi coi một tính năng là "đã test đủ". Bạn không bao giờ chỉ đưa ra
happy-path test case khi được yêu cầu viết test.
Role Frame Theo Từng Chuyên Môn QA
Các chuyên môn QA khác nhau cần role frame khác nhau vì mỗi mảng có "bản năng nghề nghiệp" riêng:
- Manual/Exploratory testing: "Bạn là một exploratory tester kinh nghiệm, áp dụng heuristic testing (như SFDPOT — Structure, Function, Data, Platform, Operations, Time) để tìm ra hành vi bất ngờ mà test case viết sẵn không phát hiện được."
- Test automation: "Bạn là automation engineer chuyên Playwright/Selenium, luôn viết test độc lập (không phụ thuộc thứ tự chạy), tránh sleep cứng (hard-coded wait), và ưu tiên locator ổn định (data-testid) hơn CSS selector dễ vỡ."
- Performance testing: "Bạn là performance test engineer, luôn nghĩ về throughput, p95/p99 latency, và điểm nghẽn (bottleneck) tài nguyên trước khi đưa ra kết luận về khả năng chịu tải."
- Security testing: "Bạn là security tester theo tư duy OWASP, mặc định nghi ngờ mọi input từ người dùng, và luôn kiểm tra injection, broken access control, và data exposure trước khi coi một API là an toàn."
Role Framing Trong Câu Lệnh vs. Trong System Prompt
Có hai cách đặt role frame: inline (viết trực tiếp trong mỗi câu lệnh/message) hoặc system prompt (đặt một lần ở cấu hình hệ thống, áp dụng cho toàn bộ session).
- System prompt role framing phù hợp khi bạn dùng công cụ có hỗ trợ custom instruction/system prompt riêng (như Custom GPT, Claude Project, hay file cấu hình của coding agent) — đặt một lần, áp dụng nhất quán cho mọi câu hỏi sau đó trong session, tiết kiệm việc phải lặp lại role frame mỗi lần.
- Inline role framing phù hợp khi bạn cần đổi "vai" linh hoạt trong cùng một cuộc hội thoại — ví dụ lúc hỏi về automation, lúc hỏi về security, không muốn một role cố định chi phối toàn bộ session.
Trong thực tế làm việc theo agentic workflow (dùng coding agent có file cấu hình như CLAUDE.md hay AGENTS.md), role frame nên đặt ở system-level cho vai trò "mặc định" của team (ví dụ toàn bộ AGENTS-QA.md định hình AI là QA automation engineer của dự án), còn inline dùng cho các câu hỏi đặc thù, tạm thời trong ngày.
Mẹo: Đừng chỉ nói "Bạn là QA engineer" — hãy thêm một câu về "điều bạn KHÔNG chấp nhận được" (ví dụ "không chấp nhận test case chỉ cover happy path"). Câu phủ định này thường hiệu quả hơn câu khẳng định trong việc ngăn AI trả về output hời hợt.
Cấu Trúc Prompt Nào Hiệu Quả Nhất — Imperative, Constrained, Step-by-Step?
Cấu Trúc 1: Imperative (Lệnh Trực Tiếp)
Cấu trúc imperative là dạng ra lệnh thẳng, ngắn gọn, không giải thích dài dòng: "Viết 5 test case cho tính năng đăng nhập bằng OTP." Ưu điểm: nhanh, phù hợp khi task đơn giản, rõ ràng, bạn đã biết chính xác mình cần gì. Nhược điểm: AI phải tự đoán các ràng buộc ngầm (định dạng, mức độ chi tiết, phạm vi) — dễ ra kết quả lệch kỳ vọng nếu task có nhiều cách hiểu.
Phù hợp với: task lặp lại quen thuộc, đã có "khuôn" sẵn trong đầu bạn, không cần AI tự quyết định gì thêm.
Cấu Trúc 2: Constrained (Có Ràng Buộc)
Cấu trúc constrained thêm các ràng buộc rõ ràng về phạm vi, định dạng, số lượng, những gì PHẢI có và KHÔNG được có:
Viết test case cho tính năng đăng nhập bằng OTP với các ràng buộc sau:
- Chỉ viết test case ở mức API (không viết UI test)
- Bắt buộc có ít nhất 2 test case về OTP hết hạn (expired) và 2 test case về OTP sai
quá số lần cho phép (rate limiting)
- Định dạng: Given-When-Then, mỗi test case đánh số
- Không viết test case về giao diện responsive hoặc UI styling
- Giả định OTP có hiệu lực 5 phút, giới hạn 5 lần thử sai
Ràng buộc là công cụ mạnh nhất để ngăn AI "lan man" — đặc biệt hữu ích khi bạn đã từng bị AI trả về những thứ không liên quan (ví dụ hỏi test API nhưng AI lại chèn cả UI test).
Cấu Trúc 3: Step-by-Step (Chain of Thought)
Cấu trúc step-by-step (còn gọi là chain-of-thought — chuỗi suy luận từng bước) yêu cầu AI trình bày quá trình suy nghĩ theo trình tự trước khi đưa kết luận cuối. Hữu ích với các task cần lập luận phức tạp, nhiều bước — như phân tích root cause của một bug khó, hoặc lập kế hoạch test cho một tính năng lớn nhiều phụ thuộc.
Phân tích bug sau theo từng bước:
Bước 1: Liệt kê tất cả thông tin đã biết từ log (trích dẫn dòng cụ thể)
Bước 2: Đưa ra 3 giả thuyết khả dĩ về nguyên nhân, xếp theo thứ tự khả năng cao thấp
Bước 3: Với mỗi giả thuyết, chỉ ra bằng chứng ủng hộ và bằng chứng phản bác trong log
Bước 4: Kết luận giả thuyết khả năng cao nhất, đề xuất bước debug tiếp theo để xác nhận
Cấu trúc này buộc AI "chậm lại", giảm khả năng nhảy thẳng đến kết luận sai dựa trên pattern-matching nông. Với các model có chế độ suy luận mở rộng (extended thinking/reasoning mode), yêu cầu step-by-step vẫn hữu ích vì nó định hình cấu trúc của output cuối, không chỉ quá trình suy luận nội bộ.
Kết Hợp Các Cấu Trúc
Ba cấu trúc trên không loại trừ nhau — prompt chuyên nghiệp thường kết hợp cả ba: imperative để mở đầu rõ mục tiêu, constrained để khoanh phạm vi, step-by-step để định hình quá trình suy luận khi cần độ tin cậy cao:
Viết test plan cho tính năng chuyển tiền liên ngân hàng. [imperative]
Ràng buộc:
- Chỉ cover luồng chuyển tiền qua API, không cover UI
- Bắt buộc có test case về idempotency (gọi lại API với cùng request ID)
- Bắt buộc có test case về timeout giữa hệ thống và ngân hàng đối tác [constrained]
Trước khi viết test case, hãy:
1. Liệt kê các trạng thái (state) khả dĩ của một giao dịch
2. Với mỗi trạng thái, xác định điểm chuyển tiếp có rủi ro cao nhất
3. Từ đó suy ra danh sách test case cần có [step-by-step]
Khi Nào Dùng Cấu Trúc Nào
| Tình huống | Cấu trúc nên dùng |
|---|---|
| Task quen thuộc, lặp lại, đã rõ khuôn mẫu | Imperative |
| Task có nguy cơ AI "lan man" sang phạm vi không mong muốn | Constrained |
| Task cần lập luận, phân tích, root cause | Step-by-step |
| Task quan trọng, độ rủi ro cao (production bug, security) | Kết hợp cả ba |
Mẹo: Khi không chắc dùng cấu trúc nào, hãy hỏi ngược lại chính mình câu này: "Nếu tôi giao task này cho một tester junior mà không giải thích thêm, họ có làm đúng ý tôi không?" Nếu câu trả lời là "không", nghĩa là bạn cần thêm constrained hoặc step-by-step — vì AI cũng gặp đúng vấn đề mơ hồ như một junior sẽ gặp.
Làm Sao Kiểm Soát Định Dạng và Cấu Trúc Output AI Cho QA?
Kỹ Thuật Chỉ Định Định Dạng Output
Cách hiệu quả nhất để kiểm soát định dạng là chỉ định rõ và cho ví dụ mẫu (template), không chỉ mô tả bằng lời:
Trả về kết quả dưới dạng bảng markdown với đúng các cột sau:
| ID | Test Case | Precondition | Steps | Expected Result | Priority |
Không thêm giải thích trước hoặc sau bảng.
Với các use case cần output máy đọc được (để đưa vào script, import vào test management tool), yêu cầu JSON với schema cụ thể:
Trả về kết quả dưới dạng JSON theo đúng schema sau, không thêm text nào ngoài JSON:
{
"test_cases": [
{
"id": "string",
"title": "string",
"priority": "high|medium|low",
"steps": ["string"],
"expected_result": "string"
}
]
}
Kiểm Soát Độ Dài và Độ Sâu Output
Không chỉ định dạng, bạn cũng cần kiểm soát độ dài và độ sâu — nếu không, AI có xu hướng viết dài dòng, lặp lại ý, hoặc quá súc tích thiếu chi tiết cần thiết. Kỹ thuật thực tế:
- Chỉ định số lượng cụ thể: "Đưa ra đúng 5 test case, không hơn không kém" thay vì "đưa ra một số test case".
- Chỉ định giới hạn từ/câu cho mỗi phần: "Mỗi expected result không quá 2 câu."
- Yêu cầu độ sâu bằng ví dụ đối chiếu: "Viết ở mức độ chi tiết tương đương ví dụ tôi đưa ra dưới đây" kèm 1 ví dụ mẫu cụ thể — hiệu quả hơn nhiều so với mô tả trừu tượng như "viết chi tiết."
Các Dạng Output Cho Sản Phẩm QA Thường Gặp
Mỗi loại deliverable QA có "hình dạng" output tối ưu riêng:
- Test case: bảng hoặc danh sách có cấu trúc Given-When-Then, luôn có cột Priority và Precondition.
- Bug report: cấu trúc cố định Title → Steps to Reproduce → Expected → Actual → Environment → Severity/Priority — yêu cầu AI tuân thủ đúng thứ tự này giúp report nhất quán và dễ import vào Jira/tool quản lý bug.
- Test plan: outline có heading phân cấp (Scope → Approach → Risk Areas → Test Cases theo nhóm → Out of Scope).
- Impact analysis (phân tích tác động thay đổi code): bảng liệt kê Module bị ảnh hưởng → Mức độ rủi ro → Test case cần chạy lại/viết thêm.
Mẹo: Luôn kèm MỘT ví dụ output mẫu ngắn (few-shot) ngay trong prompt khi bạn cần định dạng chính xác, đặc biệt với JSON schema phức tạp — mô tả bằng lời dễ bị AI hiểu sai cấu trúc lồng nhau, nhưng một ví dụ cụ thể loại bỏ gần hết sự mơ hồ.
Kiến Trúc Prompt Nào Hiệu Quả Nhất Cho Sinh Test Case và Phân Tích Bug?
Kiến Trúc Sinh Test Case
Một kiến trúc prompt sinh test case đáng tin cậy thường theo trình tự: Role → Context (requirement/API spec) → Constraint (phạm vi, số lượng) → Format → Yêu cầu tự kiểm tra (self-check):
[Role] Bạn là Senior QA Engineer chuyên về API testing cho hệ thống e-commerce.
[Context] Đây là spec của API tạo đơn hàng:
POST /api/orders
Body: { "items": [...], "shipping_address": {...}, "payment_method": "string" }
Business rule: đơn hàng phải có ít nhất 1 item, tổng giá trị tối thiểu 10,000đ để
được miễn phí ship, payment_method chỉ nhận "COD", "CREDIT_CARD", "E_WALLET".
[Constraint] Viết 10 test case bao gồm: happy path, validation lỗi từng field,
boundary cho ngưỡng miễn phí ship, và payment_method không hợp lệ. Không viết
test case về UI.
[Format] Trả về bảng markdown: ID | Test Case | Input | Expected Result | Priority
[Self-check] Sau khi viết xong, tự rà lại và bổ sung nếu thiếu test case nào về
boundary value cho ngưỡng 10,000đ (chính xác 10,000đ, 9,999đ, 10,001đ).
Bước self-check ở cuối là "vũ khí bí mật" ít người dùng — nó buộc AI tự phản biện chính output của mình trước khi bạn phải làm điều đó.
Kiến Trúc Phân Tích Bug
Kiến trúc phân tích bug hiệu quả theo trình tự: Role → Log/Evidence → Step-by-step reasoning → Kết luận có phân loại độ tin cậy:
[Role] Bạn là Senior QA Engineer chuyên debug hệ thống backend Node.js.
[Evidence] Đây là log lỗi (kèm log thực tế), đây là đoạn code liên quan (kèm code),
đây là bug report từ người dùng (kèm mô tả).
[Reasoning] Phân tích theo các bước:
1. Trích các dòng log liên quan trực tiếp đến lỗi (quote chính xác)
2. Đưa ra tối đa 3 giả thuyết về nguyên nhân gốc (root cause)
3. Với mỗi giả thuyết, đối chiếu với code — chỉ rõ dòng code nào ủng hộ/phản bác
[Conclusion] Kết luận giả thuyết khả năng cao nhất, và gán mức độ tin cậy
(cao/trung bình/thấp) — nếu mức độ tin cậy không cao, đề xuất cụ thể cần thêm
thông tin/log gì để xác nhận.
Yêu cầu AI tự gán "mức độ tin cậy" cho kết luận là kỹ thuật quan trọng — nó ngăn AI đưa ra kết luận chắc nịch một cách giả tạo khi bằng chứng thực ra còn mỏng.
Kiến Trúc Kết Hợp Cho PR Review / Phân Tích Tác Động
Khi review pull request hoặc phân tích tác động thay đổi code lên test coverage, kiến trúc cần kết hợp cả hai hướng trên — vừa cần đọc hiểu code (như phân tích bug), vừa cần sinh output có cấu trúc (như test case):
[Role] Bạn là Senior QA Engineer làm nhiệm vụ review PR để đánh giá rủi ro test.
[Context] Đây là diff của PR (kèm diff), đây là danh sách test case hiện có
liên quan đến module này (kèm danh sách tên test).
[Reasoning từng bước]
1. Xác định các hàm/method bị thay đổi trực tiếp trong diff
2. Với mỗi hàm, xác định test case hiện có nào đang cover nó (dựa trên danh sách
test đã cho) — nếu không có test nào cover, đánh dấu "GAP"
3. Với mỗi thay đổi logic (không phải chỉ đổi tên biến/refactor thuần), đánh giá
mức độ rủi ro (cao/trung bình/thấp) dựa trên: thay đổi có ảnh hưởng luồng tiền/
dữ liệu quan trọng không, có thay đổi điều kiện rẽ nhánh không.
[Output] Bảng: Hàm thay đổi | Test hiện có | Rủi ro | Đề xuất test bổ sung (nếu có)
Kiến trúc này thể hiện rõ nguyên tắc chung: prompt phức tạp = ghép các "khối" (Role, Context, Reasoning, Output) đã học ở trên theo đúng thứ tự phù hợp với bản chất của task, không phải viết một đoạn văn dài tùy hứng.
Mẹo: Khi ghép nhiều "khối" kiến trúc vào một prompt dài, luôn đặt tên rõ cho từng khối bằng heading hoặc label (như ví dụ trên dùng [Role], [Context]...) — không chỉ giúp bạn dễ maintain prompt template, mà còn giúp AI "phân vùng" đúng vai trò của từng đoạn, giảm khả năng nhầm context với instruction.