0

[Vibe Coding Thực Chiến #03] Prompt Engineering Cho Dân Dev: Giao Việc Cho AI Thế Nào Để Không Nhận Về "Một Đống Rác"?

Tác giả: Lee
Series: Vibe Coding Thực Chiến Cùng EzyPlatform (#03)
Hạ tầng thực nghiệm: VPS Ubuntu 22.04 LTS (157.66.47.xxx) | Domain: https://1576647xxx-admin.interdata.io.vn
Bộ công cụ: VS Code + Extension youngmonkeys.ezyarticle + Claude Code CLI / ChatGPT Codex


bài viết số #02, chúng ta đã cùng nhau dựng xong một "bàn làm việc" hoàn chỉnh: VPS Ubuntu chạy mượt mà, VS Code kết nối thông suốt qua extension và né sạch 3 bẫy lỗi kinh điển khi cài đặt.

Bàn làm việc đã sẵn sàng, máy chủ đã thông suốt. Bây giờ là lúc chúng ta bắt tay vào việc quan trọng nhất của một lập trình viên Vibe Coding: Ra lệnh cho AI sinh mã nguồn.

Thế nhưng, đây cũng chính là nơi mà 80% anh em dev "vỡ mộng" và nản lòng nhất!

Bao nhiêu lần bạn hí hửng gõ một câu prompt thật dài, mong chờ AI sinh ra một trang web lung linh, để rồi nhận về:

  • Một file code dài 2.000 dòng "nồi lẩu thập cẩm", nhồi nhét cả CSS, JS, HTML lẫn lộn 😣.
  • AI tự ý import thêm các thư viện lạ hoắc mà bạn không hề yêu cầu.
  • Sửa được cái nút bên trái thì vỡ tan nát cái banner bên phải 😡.
  • Và cay đắng nhất: lưu file vào hệ thống thì CMS báo lỗi cấu trúc, F5 trình duyệt là vỡ giao diện!

Tại sao lại như vậy? Có phải AI còn quá kém? Không hề! Vấn đề nằm ở chỗ: Chúng ta đang giao việc cho AI theo kiểu "người dùng phổ thông" chứ không phải theo tư duy của một Kỹ sư phần mềm.

Hôm nay, mình sẽ cùng bạn giải mã tận gốc rễ vấn đề này và trang bị Framework Prompt 3 Tầng — bí kíp giúp bạn thuần hóa AI, biến nó thành một "Junior Dev mẫn cán" chỉ sinh code chuẩn đét theo đúng kiến trúc của dự án!


1. Bẫy "Mega-Prompt": Thảm họa bắt nguồn từ đâu?

Rất nhiều bạn khi mới làm quen với AI thường mắc một thói quen chết người gọi là Mega-Prompt (Prompt tham lam):

"Hãy viết cho tôi một trang web thương mại điện tử hoàn chỉnh có giao diện bán hàng, giỏ hàng, thanh toán qua cổng VNPay, hệ thống database MySQL và trang admin quản trị đơn hàng."

Nhìn thì có vẻ rất chi tiết, nhưng dưới góc nhìn xử lý ngôn ngữ lớn (LLM), đây là một cơn ác mộng:

Thảm họa Mega-Prompt vs Tư duy Chia nhỏ để trị So sánh sự khác biệt: Mega-Prompt dẫn tới quá tải ngữ cảnh và ảo giác, trong khi Chia nhỏ để trị mang lại codebase sạch sẽ, dễ bảo trì.

Hậu quả tất yếu của Mega-Prompt:

  1. Quá tải Context Window: LLM có giới hạn về khả năng chú ý (Attention Mechanism). Khi bạn nhồi nhét quá nhiều phạm trù (UI + Database + Payment + Auth) vào một prompt, AI sẽ bị "nhiễu" và bắt đầu bỏ quên các thỏa thuận kỹ thuật ở phần trước.
  2. Ảo giác mã nguồn (Hallucination): Để hoàn thành khối lượng công việc khổng lồ trong một lượt phản hồi, AI sẽ "đốt cháy giai đoạn" bằng cách bịa ra các hàm giả định, tự import thư viện thừa thãi hoặc sinh code sơ sài.
  3. File phình to nghìn dòng (Spaghetti Code): AI sẽ nhổ ra một file index.html duy nhất dài dằng dặc, trộn lẫn HTML, CSS inline và các hàm JS thao tác DOM chằng chịt:

Hậu quả của Mega-Prompt: File code spaghetti khổng lồ Hậu quả khi prompt tham lam: Một file code hơn 2.000 dòng lẫn lộn, hoàn toàn không tương thích với cấu trúc của CMS.

Đoạn code này đem chạy file đơn lẻ thì có vẻ chạy được, nhưng khi đưa vào một hệ sinh thái thực tế như EzyPlatform thì lập tức trở thành vô dụng!


2. Tư duy "Chia nhỏ để trị" (Divide and Conquer) trong Vibe Coding

Để AI làm việc hiệu quả, bạn phải chuyển dịch tư duy từ "bắt AI xây cả ngôi nhà" sang "yêu cầu AI đúc từng viên gạch chuẩn chỉ".

Quy trình phân rã tính năng (Feature Decomposition) chuẩn của một Vibe Coder gồm 4 chặng:

[Chặng 1: Spec & Wireframe]  -->  Xác định cấu trúc trang tổng thể & Design System
        ↓
[Chặng 2: Component UI]      -->  Tách từng block độc lập (Hero Section, Features, Pricing, Footer)
        ↓
[Chặng 3: Client State]      -->  Thêm tương tác JavaScript cục bộ (Accordion, Tabs, Modal)
        ↓
[Chặng 4: API & Database]    -->  Đấu nối dữ liệu động qua Backend API / GraphQL

Khi chia nhỏ như vậy:

  • AI chỉ phải tập trung giải quyết duy nhất một bài toán cụ thể trong phạm vi 50–100 dòng code.
  • Khả năng xảy ra lỗi hay ảo giác giảm xuống gần như bằng 0.
  • Bạn kiểm soát và nghiệm thu được chất lượng của từng component ngay lập tức trên VPS.

3. Framework Prompt 3 Tầng Dành Riêng Cho Developer

Sau hàng trăm giờ thực chiến và thử nghiệm với nhiều model khác nhau (Claude 3.7 Sonnet, ChatGPT o3-mini, Codex), mình đúc kết ra một bộ khung câu lệnh chuẩn mực gồm 3 Tầng không thể thiếu:

Framework Prompt 3 Tầng Dành Riêng Cho Developer Cấu trúc 3 tầng: Role & Scope khóa ranh giới, Constraints khóa công nghệ, Output Format ép khuôn mã nguồn.

3.1. Tầng 1: Role & Scope (Vai trò & Phạm vi hẹp)

  • Mục đích: Định danh chuyên môn kỹ thuật và vẽ ranh giới làm việc cho AI, ngăn AI "nhiệt tình quá mức" mà sinh lan man sang các phần khác.
  • Mẫu câu thực tế:

    "Bạn là Senior Frontend UI Engineer. Nhiệm vụ của bạn là xây dựng duy nhất component Hero Section cho trang giới thiệu dịch vụ. Tuyệt đối không sinh phần Navigation Bar, không sinh Footer và không xử lý logic backend."

3.2. Tầng 2: Technical Constraints & Context (Ràng buộc công nghệ)

  • Mục đích: Khóa chặt "hộp cát công nghệ" (Sandbox) để AI không tự ý thêm các thư viện kỳ quặc hoặc dùng sai chuẩn giao diện.
  • Mẫu câu thực tế:

    "Ràng buộc kỹ thuật bắt buộc tuân thủ:
    - CSS Framework: Chỉ sử dụng Tailwind CSS (utility classes via CDN), không dùng CSS inline.
    - Bảng màu: Dark Mode hiện đại, nền chủ đạo slate-900, điểm nhấn màu gradient Indigo và Emerald.
    - Thư viện ngoài: KHÔNG sử dụng jQuery, KHÔNG dùng React/Vue, chỉ dùng Vanilla JavaScript nếu có tương tác.
    - Responsive: Mobile-first, hiển thị hoàn hảo trên cả màn hình 375px và 1440px."

3.3. Tầng 3: Expected Output Format (Chuẩn đầu ra 4 file EzyArticle)

  • Mục đích: Đây là tầng "ăn tiền" nhất! Thay vì để AI tự quyết định định dạng file, bạn ép AI phải nhả ra mã nguồn chia đúng 4 file riêng biệt theo chuẩn của EzyPlatform.
  • Mẫu câu thực tế:

    "Định dạng đầu ra bắt buộc phải tách thành 4 khối mã nguồn riêng biệt:
    1. content.html: Chỉ chứa markup HTML của thẻ <section> component (TUYỆT ĐỐI KHÔNG chứa thẻ <!DOCTYPE>, <html>, <head>, <body>).
    2. head.html: Chứa link nạp Tailwind CSS CDN và Google Fonts Inter.
    3. foot.html: Chứa mã JavaScript tương tác (nếu có).
    4. meta.json: File cấu hình metadata gồm: slug, title, pageType: 'PAGE', status: 'DRAFT'."


4. "Vũ khí bí mật": Mớm ngữ cảnh tự động bằng file RULES.md

Nếu mỗi lần chat với AI bạn lại phải copy-paste cả một đoạn prompt dài 3 tầng ở trên thì cực kỳ mất công và mỏi tay.

Giải pháp của dân chuyên nghiệp là: Tạo một "Mỏ neo ngữ cảnh" (Context Anchor) cố định ngay trong thư mục dự án!

Hầu hết các công cụ hỗ trợ AI hiện nay (Cursor, Claude Code, Antigravity CLI, GitHub Copilot) đều có cơ chế tự động nạp các file quy tắc (như .cursorrules hoặc RULES.md) trước khi bắt đầu xử lý prompt của bạn.

Tạo file RULES.md tại root project của bạn:

File RULES.md trong VS Code File RULES.md đặt tại root project: AI tự động đọc và tuân thủ 100% quy chuẩn kiến trúc của dự án.

Nội dung file RULES.md mẫu mà mình đang dùng trực tiếp trong dự án này:

# Vibe Coding Rules for EzyPlatform Project

Khi được yêu cầu tạo hoặc chỉnh sửa bất kỳ trang/component nào trong thư mục `pages/[page-name]`:

1. BẮT BUỘC TÁCH THÀNH 4 FILE CHUẨN:
   - `content.html`: Chỉ chứa nội dung UI component (thẻ <section>, <div>). Tuyệt đối KHÔNG sinh các thẻ bao ngoài: <!DOCTYPE html>, <html>, <head>, <body>.
   - `head.html`: Nạp link CDN CSS (Tailwind CSS, Font Awesome) và thẻ <style> bổ trợ.
   - `foot.html`: Nạp script JavaScript logic tương tác hoặc thư viện animation CDN.
   - `meta.json`: Khai báo metadata:
     {
       "slug": "[page-name]",
       "title": "[Page Title]",
       "pageType": "PAGE",
       "contentType": "HTML",
       "status": "DRAFT"
     }

2. RÀNG BUỘC THIẾT KẾ:
   - Giao diện: Hiện đại, phong cách Dark Mode (nền slate-900, slate-950).
   - Công nghệ: Tailwind CSS utility classes. Không dùng jQuery, không dùng inline style.
   - Tương thích: Theme Freestyle với Empty Layout trên EzyPlatform.

Nhờ có file RULES.md này làm "bảo kê", từ nay về sau câu prompt của bạn sẽ trở nên cực kỳ ngắn gọn:

"Hãy tạo component Hero Card giới thiệu khóa học Vibe Coding, có tiêu đề gradient và 2 nút kêu gọi hành động."

AI sẽ tự động áp dụng toàn bộ luật trong RULES.md: tự chia 4 file, tự né thẻ <html>, tự nạp Tailwind CDN và trả về kết quả chuẩn đét!


5. Thực chiến đối đầu: Bad Prompt vs Good Prompt

Để bạn thấy rõ sự khác biệt "một trời một vực", hãy cùng xem AI xử lý yêu cầu tạo một Hero Section thực tế:

Khi dùng Prompt ngây thơ (Bad Prompt):

  • Câu lệnh: "Viết cho tao trang chủ giới thiệu ứng dụng Vibe Coding xịn sò"
  • Kết quả: Nhận về một file index.html 800 dòng lộn xộn. Thử sync lên VPS qua extension EzyArticle:
    • Header bị nuốt mất vì đè lên layout theme mặc định.
    • Các icon không hiển thị vì AI tự bịa link CDN hỏng.
    • Không thể tách để tái sử dụng ở các trang khác.

Khi dùng Framework 3 Tầng + RULES.md (Good Prompt):

  • Kết quả: AI tự động tạo thư mục pages/hero-card/ chia tách 4 file sạch bóng, mỗi file chỉ từ 10 đến 50 dòng:

Thư mục 4 file modular chuẩn chỉ trong VS Code Cấu trúc thư mục sạch bóng: Mỗi file đảm nhận đúng 1 trách nhiệm duy nhất (Single Responsibility).

Mở file content.html bấm chuột phải chọn EzyArticle: Preview Page, kết quả hiển thị trên VPS thật ngay lập tức:

Preview Hero Card thành công trên VPS Giao diện Hero Section hiển thị hoàn hảo trên domain VPS cá nhân chỉ sau 15 giây gõ lệnh!

=> Giao diện Dark mode sang trọng, responsive mượt mà, typography chuẩn chỉ, và quan trọng nhất: Hoàn toàn sạch bóng bug! 🎉


6. 3 bẫy lỗi kinh điển khi prompt AI & Cách né trong 1 nốt nhạc 😡

Dù đã có framework, trong quá trình làm việc bạn vẫn sẽ gặp phải 3 tình huống oái oăm này:

Bẫy lỗi #1: Trôi ngữ cảnh (Context Drift) khi phiên chat quá dài 😣

  • Hiện tượng: Lúc đầu AI sinh code rất chuẩn, nhưng sau khi chat qua lại khoảng 20-30 câu, AI bắt đầu "quên bài": sinh lại thẻ <html> thừa, dùng lại CSS inline cũ.
  • Nguyên nhân: Khi lịch sử trò chuyện quá dài, các chỉ dẫn ban đầu bị đẩy ra xa khỏi vùng tập trung (Attention) của model.
  • Cách né (Recommend 👍):
    • Tách session chat: Mỗi session chỉ làm duy nhất một component. Xong Hero Section thì mở session chat mới để làm Features Section.
    • Luôn nhắc AI: "Nhớ đọc lại file RULES.md trước khi sinh code."

Bẫy lỗi #2: AI tự chế thêm thư viện ngoài (Dependency Hallucination) 😡

  • Hiện tượng: Bạn bảo AI làm hiệu ứng cuộn mượt (scroll animation), AI tự động ném thêm link CDN thư viện wow.js hay aos.css lạ hoắc vào head.html. Khi load trang thì bị lỗi chặn mạng hoặc xung đột script.
  • Nguyên nhân: AI học từ hàng triệu trang web cũ trên Internet và có xu hướng lôi các thư viện thời xưa vào code.
  • Cách né (Bí kíp 💡):
    • Khóa chặt ở Tầng 2 (Constraints): "Chỉ dùng CSS transition thuần hoặc JavaScript gốc (Vanilla JS), cấm tuyệt đối import bất kỳ thư viện animation bên ngoài nào."

Bẫy lỗi #3: AI nhầm lẫn giữa thân trang và khung HTML toàn cục ⚠️

  • Hiện tượng: Trong file content.html, AI tiện tay bọc toàn bộ mã nguồn bên trong một thẻ <main> hoặc <body> với class đè height: 100vh, làm hỏng thanh cuộn của trang web.
  • Nguyên nhân: AI quen thói quen viết trang web độc lập (Standalone page).
  • Cách né (Lưu ý ⚠️):
    • Trong prompt luôn ghi rõ: "Mã HTML trong content.html chỉ là một block con (Component), chỉ bọc ngoài cùng bằng một thẻ <section> duy nhất."

7. Cheatsheet Prompt 3 Tầng Dành Cho Bạn (Copy & Dùng Ngay) 📋

Dưới đây là mẫu khung prompt chuẩn mực mà bạn có thể lưu vào sổ tay (Bookmark) để tái sử dụng cho mọi dự án:

[ROLE & SCOPE]
Bạn là Senior UI/UX Frontend Engineer.
Nhiệm vụ: Xây dựng duy nhất component [TÊN_COMPONENT] (ví dụ: Pricing Table, Hero Banner, Testimonials).
Phạm vi: Chỉ tập trung vào component này, không viết navigation, không viết footer, không viết backend.

[CONSTRAINTS]
- CSS: Sử dụng 100% Tailwind CSS utility classes (CDN).
- Giao diện: Dark Mode hiện đại, nền slate-900, điểm nhấn màu [MÀU_CHỦ_ĐẠO].
- Responsive: Mobile-first, hiển thị hoàn hảo trên Mobile, Tablet và Desktop.
- Thư viện: Không dùng React/Vue, không dùng jQuery, chỉ dùng Vanilla JS nếu cần tương tác.

[OUTPUT FORMAT]
Trả về mã nguồn chia tách thành 4 khối riêng biệt:
1. `content.html`: Thân component bọc trong 1 thẻ <section> duy nhất.
2. `head.html`: Nạp link CDN Tailwind CSS và font chữ.
3. `foot.html`: JavaScript logic tương tác (nếu có).
4. `meta.json`: Metadata theo mẫu: {"slug": "[slug-trang]", "title": "[Tieu De]", "pageType": "PAGE", "status": "DRAFT"}

8. Tổng kết & Kỳ tiếp theo

Prompt Engineering trong lập trình không phải là "học cách nói chuyện hoa mỹ với AI", mà thực chất là: Kỹ năng chuyển hóa Requirement và Architecture thành các ràng buộc kỹ thuật chuẩn xác.

🎯 3 điểm cốt lõi cần nhớ từ bài viết này:

  1. Nói không với Mega-Prompt: Luôn phân rã bài toán thành từng component độc lập (Divide and Conquer).
  2. Thuộc lòng Framework 3 Tầng: Role & Scope ➔ Technical Constraints ➔ Expected Output Format.
  3. Neo ngữ cảnh bằng RULES.md: Để AI tự động tuân thủ cấu trúc 4 file của EzyPlatform mà không cần bạn phải nhắc lại nhiều lần.

Ở bài viết tiếp theo, khi đã nắm vững nghệ thuật ra lệnh cho AI, chúng ta sẽ bước sâu hơn vào "trái tim" của hệ thống EzyPlatform:

👉 [Vibe Coding Thực Chiến #04] Giải Phẫu Kiến Trúc EzyPlatform: Hiểu Đúng Cấu Trúc Để "Chỉ Huy" AI Chuẩn Xác!

Chúng ta sẽ mổ xẻ cơ chế Page Fragments, luồng render template Thymeleaf, và cách cấu hình REST API / GraphQL để chuẩn bị cho việc kết nối dữ liệu thật!


💬 Góc thảo luận: Anh em đã bao giờ "tăng xông" vì một câu prompt nhả ra đống code rác chưa? Kinh nghiệm phân rã task của anh em khi dùng AI là gì? Hãy để lại bình luận bên dưới để cùng đàm đạo nhé!

Nếu thấy bài viết này hữu ích và giúp bạn tiết kiệm được hàng tá token vô ích, đừng quên bấm Upvote 👍Bookmark (Clip) 🔖 bài viết nhé. Cảm ơn anh em rất nhiều!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí