Prompt Engineering Vượt Trội: Biến Ý Tưởng Thành Code Hoàn Chỉnh Với Kỹ Thuật Chain-of-Thought
PROMPT ENGINEERING

Prompt Engineering Vượt Trội: Biến Ý Tưởng Thành Code Hoàn Chỉnh Với Kỹ Thuật Chain-of-Thought

Giới Thiệu Prompt Engineering Vượt Trội: Biến Ý Tưởng Thành Code Hoàn Chỉnh Với Kỹ Thuật Chain-of-Thought

Trong kỷ nguyên AI bùng nổ, khả năng giao tiếp hiệu quả với các mô hình ngôn ngữ lớn (LLMs) đã trở thành một kỹ năng tối quan trọng. Không chỉ dừng lại ở việc đưa ra câu hỏi đơn thuần, chúng ta cần một phương pháp tiếp cận tinh vi hơn để khai thác tối đa sức mạnh của AI, đặc biệt trong lĩnh vực phát triển phần mềm. Bài viết này sẽ giúp bạn hiểu rõ về prompt engineering nâng cao, tập trung vào kỹ thuật Chain-of-Thought (CoT), từ góc nhìn thực tế của một chuyên gia vibe coding và AI development. Chúng ta sẽ khám phá cách biến những ý tưởng phức tạp thành code hoàn chỉnh, có cấu trúc và hoạt động hiệu quả, thông qua việc hướng dẫn AI suy luận từng bước một.

Prompt Engineering Vượt Trội: Biến Ý Tưởng Thành Code Hoàn Chỉnh Với Kỹ Thuật Ch
Minh họa: Prompt Engineering Vượt Trội: Biến Ý Tưởng Thành Code Hoàn Chỉnh Với Kỹ Thuật Chain-of-Thought (Nguồn ảnh: naadispeaks.files.wordpress.com)

Chain-of-Thought: Chìa Khóa Mở Khóa Tiềm Năng AI

Kỹ thuật Chain-of-Thought (CoT) là một bước đột phá trong prompt engineering, cho phép các mô hình ngôn ngữ lớn giải quyết các vấn đề phức tạp bằng cách mô phỏng quá trình suy luận từng bước của con người. Thay vì chỉ yêu cầu mô hình đưa ra câu trả lời cuối cùng, CoT khuyến khích hoặc yêu cầu mô hình hiển thị các bước trung gian dẫn đến kết quả đó. Điều này không chỉ giúp cải thiện độ chính xác của câu trả lời mà còn làm cho quá trình suy luận của AI trở nên minh bạch và dễ hiểu hơn. Đối với lập trình, điều này có nghĩa là chúng ta có thể hướng dẫn AI không chỉ viết code mà còn giải thích lý do đằng sau các lựa chọn thiết kế, cấu trúc dữ liệu, và thuật toán.

AI coding tools
Công cụ AI coding hiện đại (Nguồn ảnh: www.makerstations.io)

Khi áp dụng Chain-of-Thought trong việc tạo code, chúng ta không chỉ yêu cầu "viết code", mà còn yêu cầu "hãy suy nghĩ từng bước về cách giải quyết vấn đề này, sau đó viết code dựa trên suy nghĩ đó". Ví dụ, thay vì chỉ hỏi "Viết một hàm Python để sắp xếp một danh sách", chúng ta sẽ yêu cầu "Hãy suy nghĩ về các thuật toán sắp xếp phổ biến, chọn một thuật toán phù hợp với hiệu suất trung bình, giải thích lý do lựa chọn, sau đó viết hàm Python cài đặt thuật toán đó và cung cấp một ví dụ sử dụng." Quá trình này giúp mô hình tạo ra code có chất lượng cao hơn, ít lỗi hơn và dễ bảo trì hơn, vì nó đã "hiểu" được bối cảnh và yêu cầu sâu hơn.

CoT đặc biệt hữu ích khi xử lý các tác vụ yêu cầu nhiều bước logic, như phân tích yêu cầu phức tạp, thiết kế kiến trúc phần mềm nhỏ, hoặc debug code. Bằng cách chia nhỏ vấn đề thành các bước nhỏ hơn, mô hình có thể tập trung vào từng phần một, giảm thiểu khả năng mắc lỗi. Đây là một ví dụ cơ bản về cách CoT có thể được áp dụng trong prompt engineering nâng cao để yêu cầu AI giải thích suy luận trước khi đưa ra kết quả, một kỹ thuật được gọi là "Zero-shot CoT" hoặc "Few-shot CoT" với các ví dụ cụ thể.

Một lợi ích không thể phủ nhận của CoT là khả năng debug và tinh chỉnh đầu ra. Khi AI hiển thị các bước suy luận, chúng ta có thể dễ dàng xác định xem AI đã đi chệch hướng ở đâu, từ đó điều chỉnh prompt để đạt được kết quả mong muốn. Điều này biến AI từ một "hộp đen" thành một đối tác có thể tương tác và học hỏi, mở ra cánh cửa cho prompt engineering nâng cao lên một tầm cao mới.

Hướng Dẫn Thực Hành: Xây Dựng Chain-of-Thought Cho Code Generation

Để triển khai Chain-of-Thought hiệu quả, chúng ta cần cấu trúc prompt một cách có hệ thống. Dưới đây là các bước và ví dụ cụ thể để biến ý tưởng thành code hoàn chỉnh.

Vibe coding workflow
Vibe coding trong thực tế (Nguồn ảnh: user-images.githubusercontent.com)

Bước 1: Xác định mục tiêu và yêu cầu

Bắt đầu bằng việc định nghĩa rõ ràng mục tiêu và các yêu cầu kỹ thuật. Hãy suy nghĩ về các thành phần chính của giải pháp.


Prompt: "Tôi cần một API endpoint trong Node.js sử dụng Express để quản lý danh sách công việc (todos). API này cần có các chức năng: lấy tất cả todos, thêm một todo mới, cập nhật trạng thái của một todo, và xóa một todo. Dữ liệu todos sẽ được lưu trữ trong một mảng trong bộ nhớ (in-memory) để đơn giản. Mỗi todo có cấu trúc { id: string, title: string, completed: boolean }. Hãy suy nghĩ từng bước về cách thiết kế API này, bao gồm cả các route, phương thức HTTP, và cách xử lý dữ liệu."

Trong prompt trên, chúng ta đã yêu cầu AI "suy nghĩ từng bước", đây là tín hiệu chính để kích hoạt cơ chế CoT. Chúng ta cũng cung cấp đầy đủ ngữ cảnh và cấu trúc dữ liệu mong muốn.

Bước 2: Hướng dẫn AI suy luận từng bước

AI sẽ bắt đầu quá trình suy luận. Nếu AI không tự động hiển thị các bước, bạn có thể thêm các câu như "Hãy chia nhỏ vấn đề thành các phần nhỏ hơn và giải thích cách bạn sẽ giải quyết từng phần." hoặc "Đầu tiên, hãy nghĩ về cấu trúc dữ liệu. Sau đó, nghĩ về các route API."


AI's Chain-of-Thought (tưởng tượng):
"Bước 1: Xác định cấu trúc dữ liệu.
  - Cần một mảng để lưu trữ todos.
  - Mỗi todo là một object với id, title, completed.
  - Cần một cơ chế để tạo id duy nhất (ví dụ: `uuid`).
Bước 2: Thiết kế các route API.
  - GET /todos: Lấy tất cả todos.
  - POST /todos: Thêm todo mới.
  - PUT /todos/:id: Cập nhật todo theo id.
  - DELETE /todos/:id: Xóa todo theo id.
Bước 3: Cài đặt logic cho từng route.
  - GET /todos: Trả về mảng todos.
  - POST /todos: Lấy title từ body, tạo id, completed mặc định là false, thêm vào mảng, trả về todo mới.
  - PUT /todos/:id: Tìm todo theo id, cập nhật các trường (ví dụ: completed), trả về todo đã cập nhật. Xử lý trường hợp không tìm thấy.
  - DELETE /todos/:id: Tìm todo theo id, xóa khỏi mảng, trả về thông báo thành công. Xử lý trường hợp không tìm thấy.
Bước 4: Cài đặt boilerplate Express.
  - Khởi tạo app, sử dụng middleware `express.json()`.
  - Lắng nghe trên một cổng."

Bước 3: Tạo code dựa trên suy luận

Sau khi AI đã trình bày suy luận, bạn có thể yêu cầu nó tạo code. Hoặc, nếu bạn đã yêu cầu nó suy luận trước khi viết code, nó sẽ tự động chuyển sang bước này. Dưới đây là ví dụ về code mà AI có thể tạo ra dựa trên suy luận trên:


// Import necessary modules
const express = require('express');
const { v4: uuidv4 } = require('uuid'); // For unique IDs

const app = express();
const PORT = 3000;

// Middleware to parse JSON bodies
app.use(express.json());

// In-memory data store for todos
let todos = [
    { id: uuidv4(), title: 'Learn Prompt Engineering', completed: false },
    { id: uuidv4(), title: 'Build a CoT AI app', completed: true }
];

// Route 1: Get all todos
app.get('/todos', (req, res) => {
    res.json(todos);
});

// Route 2: Add a new todo
app.post('/todos', (req, res) => {
    const { title } = req.body;
    if (!title) {
        return res.status(400).json({ message: 'Title is required' });
    }
    const newTodo = {
        id: uuidv4(),
        title,
        completed: false
    };
    todos.push(newTodo);
    res.status(201).json(newTodo);
});

// Route 3: Update a todo by ID
app.put('/todos/:id', (req, res) => {
    const { id } = req.params;
    const { title, completed } = req.body;
    const todoIndex = todos.findIndex(todo => todo.id === id);

    if (todoIndex === -1) {
        return res.status(404).json({ message: 'Todo not found' });
    }

    if (title !== undefined) {
        todos[todoIndex].title = title;
    }
    if (completed !== undefined) {
        todos[todoIndex].completed = completed;
    }

    res.json(todos[todoIndex]);
});

// Route 4: Delete a todo by ID
app.delete('/todos/:id', (req, res) => {
    const { id } = req.params;
    const initialLength = todos.length;
    todos = todos.filter(todo => todo.id !== id);

    if (todos.length === initialLength) {
        return res.status(404).json({ message: 'Todo not found' });
    }

    res.status(204).send(); // No content for successful deletion
});

// Start the server
app.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});

Bạn có thể thấy, code được tạo ra rất có cấu trúc, bao gồm cả xử lý lỗi cơ bản và sử dụng các thư viện phổ biến như uuid. Đây là kết quả trực tiếp của kỹ thuật prompt engineering nâng cao Chain-of-Thought.

Bước 4: Tinh chỉnh và lặp lại

Sau khi có code, hãy kiểm tra, chạy thử và tinh chỉnh. Nếu có bất kỳ vấn đề nào, hãy quay lại bước 1 hoặc 2, điều chỉnh prompt để làm rõ yêu cầu hoặc sửa đổi các bước suy luận của AI. Ví dụ, bạn có thể yêu cầu thêm validation cho input, hoặc chuyển sang sử dụng database thay vì in-memory array. Quá trình này là lặp đi lặp lại, và mỗi lần lặp sẽ giúp bạn trở thành một chuyên gia prompt engineering tốt hơn.

Tips và Best Practices cho Prompt Engineering Nâng Cao với CoT

Để tối ưu hóa việc sử dụng Chain-of-Thought trong prompt engineering nâng cao, hãy áp dụng các mẹo sau:

AI-assisted programming
Lập trình với sự hỗ trợ của AI (Nguồn ảnh: www.makerstations.io)
  1. Sử dụng từ khóa rõ ràng để kích hoạt CoT: Luôn bao gồm các cụm từ như "Hãy suy nghĩ từng bước", "Giải thích quá trình suy luận", "Phân tích vấn đề từng phần", "Đầu tiên, hãy làm X, sau đó Y, cuối cùng Z" trong prompt của bạn. Điều này sẽ khuyến khích mô hình tạo ra các bước trung gian.
  2. Cung cấp ngữ cảnh và ràng buộc chi tiết: Đừng ngần ngại cung cấp thông tin chi tiết về môi trường (Node.js, Python, React), thư viện (Express, Axios), cấu trúc dữ liệu, và các ràng buộc về hiệu suất hoặc bảo mật. Càng nhiều thông tin, AI càng có thể đưa ra các quyết định sáng suốt hơn trong quá trình suy luận.
  3. Chia nhỏ vấn đề phức tạp: Nếu yêu cầu quá lớn, hãy chia nó thành nhiều prompt nhỏ hơn. Ví dụ, thay vì yêu cầu "Viết toàn bộ ứng dụng web", hãy bắt đầu với "Thiết kế cơ sở dữ liệu", sau đó "Viết API cho X", rồi "Viết giao diện người dùng cho Y". Mỗi prompt có thể sử dụng CoT.
  4. Yêu cầu AI tự đánh giá: Đôi khi, bạn có thể thêm vào prompt yêu cầu AI tự kiểm tra lại code của mình hoặc chỉ ra các điểm yếu tiềm ẩn. Ví dụ: "Sau khi viết code, hãy chỉ ra bất kỳ trường hợp lỗi nào có thể xảy ra và cách cải thiện code."
  5. Sử dụng Few-shot Prompting với CoT: Nếu bạn có các ví dụ về cách giải quyết vấn đề tương tự bằng CoT, hãy bao gồm chúng trong prompt. Điều này sẽ giúp AI hiểu rõ hơn về định dạng và kiểu suy luận mà bạn mong muốn. Mặc dù ví dụ trên là Zero-shot CoT (không có ví dụ trước), việc cung cấp một vài ví dụ (Few-shot) có thể nâng cao đáng kể chất lượng.
  6. Kỳ vọng sự lặp lại: Prompt engineering không phải là một quá trình một lần duy nhất. Bạn sẽ cần lặp lại, điều chỉnh prompt dựa trên đầu ra của AI để đạt được kết quả tối ưu. CoT giúp quá trình lặp lại này hiệu quả hơn bằng cách làm rõ nơi AI "sai" trong suy nghĩ của nó.
  7. Tạo các tiêu chí đánh giá rõ ràng: Trước khi bắt đầu, hãy xác định các tiêu chí để đánh giá code được tạo ra (ví dụ: dễ đọc, hiệu quả, đáp ứng yêu cầu, có xử lý lỗi). Điều này giúp bạn có cơ sở để tinh chỉnh prompt.

So Sánh Chain-of-Thought với Các Kỹ Thuật Prompt Engineering Khác

Prompt engineering nâng cao không chỉ có Chain-of-Thought. Để hiểu rõ hơn về giá trị của CoT, hãy so sánh nó với các kỹ thuật khác:

1. Zero-shot Prompting (Prompt không ví dụ)

Đây là kỹ thuật cơ bản nhất, nơi bạn chỉ đưa ra một prompt mà không có bất kỳ ví dụ nào. Mô hình phải tự dựa vào kiến thức đã học để tạo ra câu trả lời. Ví dụ: "Viết hàm Python để tính giai thừa."

  • Ưu điểm: Đơn giản, nhanh chóng.
  • Nhược điểm: Hiệu quả thấp với các tác vụ phức tạp, dễ mắc lỗi, thiếu khả năng kiểm soát quá trình suy luận.
  • So với CoT: CoT là một dạng nâng cao của Zero-shot (Zero-shot CoT) khi bạn chỉ cần thêm "Hãy suy nghĩ từng bước" vào prompt. Điều này cải thiện đáng kể chất lượng mà không cần cung cấp ví dụ.

2. Few-shot Prompting (Prompt có ví dụ)

Kỹ thuật này bao gồm một vài cặp ví dụ (input-output) trong prompt để hướng dẫn mô hình về định dạng và kiểu câu trả lời mong muốn. Ví dụ: "Dịch từ tiếng Anh sang tiếng Việt. Anh: Hello -> Việt: Xin chào. Anh: Goodbye -> Việt: Tạm biệt. Anh: Thank you -> Việt: ..."

  • Ưu điểm: Cải thiện đáng kể hiệu suất so với Zero-shot, đặc biệt với các tác vụ cụ thể hoặc định dạng đầu ra đặc biệt.
  • Nhược điểm: Tốn không gian prompt, đôi khi khó tìm hoặc tạo ra các ví dụ phù hợp.
  • So với CoT: Few-shot CoT kết hợp cả hai bằng cách cung cấp các ví dụ bao gồm cả các bước suy luận. Điều này thường mang lại hiệu suất tốt nhất cho các tác vụ phức tạp, vì mô hình không chỉ học được định dạng mà còn học được cách suy nghĩ.

3. Self-Consistency (Tự nhất quán)

Kỹ thuật này yêu cầu mô hình tạo ra nhiều chuỗi suy luận khác nhau cho cùng một vấn đề, sau đó chọn câu trả lời phổ biến nhất hoặc phù hợp nhất. Điều này giúp giảm thiểu lỗi do một đường suy luận duy nhất bị sai lệch.

  • Ưu điểm: Nâng cao độ tin cậy và chính xác của kết quả, đặc biệt trong các tác vụ logic.
  • Nhược điểm: Tốn kém tài nguyên tính toán vì yêu cầu nhiều lần gọi mô hình.
  • So với CoT: Self-Consistency thường được áp dụng SAU khi CoT đã tạo ra các đường suy luận. CoT là cách để tạo ra các đường suy luận, còn Self-Consistency là cách để chọn ra đường suy luận tốt nhất từ nhiều đường được tạo ra.

Tóm lại, Chain-of-Thought (CoT) không phải là một kỹ thuật độc lập mà thường được tích hợp với Zero-shot hoặc Few-shot prompting để tạo ra một phương pháp prompt engineering nâng cao mạnh mẽ. Nó tập trung vào việc làm cho quá trình suy luận của AI minh bạch và có cấu trúc, điều này là cốt lõi để biến ý tưởng phức tạp thành code hoàn chỉnh một cách hiệu quả và đáng tin cậy.

Các Lưu Ý Quan Trọng

  • Chất lượng của prompt quyết định chất lượng đầu ra: Dù CoT mạnh mẽ đến đâu, nếu prompt ban đầu mơ hồ hoặc thiếu thông tin, AI vẫn sẽ gặp khó khăn. Hãy đầu tư thời gian để viết prompt rõ ràng, chi tiết và có cấu trúc.
  • Đừng kỳ vọng hoàn hảo ngay lập tức: AI vẫn có thể mắc lỗi hoặc bỏ sót các trường hợp biên. Prompt engineering là một quá trình lặp đi lặp lại. Hãy luôn sẵn sàng kiểm tra, debug và tinh chỉnh đầu ra.
  • Hiểu rõ khả năng của mô hình: Các mô hình khác nhau có khả năng CoT khác nhau. Các mô hình lớn hơn, tiên tiến hơn (như GPT-4) thường thực hiện CoT tốt hơn nhiều so với các mô hình nhỏ hơn.
  • Cẩn thận với "hallucination": AI đôi khi có thể tạo ra thông tin không chính xác hoặc không tồn tại, ngay cả khi sử dụng CoT. Luôn xác minh thông tin và code được tạo ra.
  • Vấn đề bảo mật và quyền riêng tư: Tránh đưa thông tin nhạy cảm hoặc bí mật vào prompt, đặc biệt khi sử dụng các mô hình AI công cộng. Dù các mô hình thường không lưu trữ dữ liệu người dùng lâu dài, việc cẩn trọng vẫn là ưu tiên hàng đầu.
  • Kiểm tra hiệu suất và tối ưu hóa: Code được tạo ra bởi AI có thể hoạt động đúng nhưng chưa chắc đã tối ưu về hiệu suất. Hãy luôn đánh giá và tối ưu hóa thủ công nếu cần.
  • Kết hợp với các công cụ khác: Prompt engineering không phải là giải pháp duy nhất. Hãy kết hợp với các công cụ phát triển truyền thống, IDE, và các quy trình CI/CD để tạo ra một quy trình phát triển toàn diện.

Câu Hỏi Thường Gặp

Chain-of-Thought có phải luôn là kỹ thuật tốt nhất để tạo code không?

Không phải lúc nào cũng vậy. Đối với các tác vụ đơn giản, trực tiếp (ví dụ: "Viết hàm tính tổng hai số"), Zero-shot prompting có thể đủ nhanh và hiệu quả. CoT trở nên vượt trội khi các yêu cầu phức tạp, đòi hỏi nhiều bước suy luận, lựa chọn thiết kế hoặc giải thích chi tiết.

Làm thế nào để biết AI đang thực sự sử dụng Chain-of-Thought hay chỉ "bắt chước" nó?

Khi bạn yêu cầu AI "suy nghĩ từng bước", mô hình sẽ tạo ra các bước trung gian. Mặc dù chúng ta không thể nhìn thấy "suy nghĩ" bên trong của AI, việc nó hiển thị các bước này cho thấy nó đã được huấn luyện để phân rã vấn đề theo cách đó. Chất lượng của các bước suy luận và code cuối cùng sẽ là chỉ số tốt nhất để đánh giá hiệu quả của CoT.

Có cần phải sử dụng các từ khóa cụ thể như "Hãy suy nghĩ từng bước" không?

Việc sử dụng các từ khóa rõ ràng như "Hãy suy nghĩ từng bước", "Giải thích quá trình của bạn", "Chia nhỏ vấn đề" là rất khuyến khích. Các mô hình ngôn ngữ lớn thường được huấn luyện trên các tập dữ liệu có chứa các chuỗi suy luận, và những từ khóa này giúp kích hoạt khả năng đó một cách hiệu quả nhất.

CoT có thể giúp debug code không?

Tuyệt đối có. Bằng cách cung cấp một đoạn code lỗi và yêu cầu AI "Hãy phân tích code này từng bước, tìm ra lỗi và đề xuất sửa chữa, giải thích lý do", bạn có thể sử dụng CoT để AI thực hiện quá trình debug một cách có hệ thống, thường là với độ chính xác đáng kinh ngạc.

Kết Luận

Prompt engineering nâng cao, đặc biệt là kỹ thuật Chain-of-Thought, đang định hình lại cách chúng ta tương tác với AI trong lĩnh vực phát triển phần mềm. Bằng cách hướng dẫn AI suy luận từng bước, chúng ta không chỉ nhận được code mà còn nhận được sự "hiểu biết" sâu sắc hơn về giải pháp. Điều này giúp biến những ý tưởng phức tạp thành các sản phẩm phần mềm hoàn chỉnh, chất lượng cao một cách hiệu quả hơn bao giờ hết.

Việc nắm vững CoT là một kỹ năng thiết yếu cho bất kỳ ai muốn khai thác tối đa tiềm năng của AI trong công việc hàng ngày. Hãy bắt đầu thực hành ngay hôm nay và khám phá cách bạn có thể nâng cao năng suất và chất lượng code của mình. Đừng quên truy cập vibe coding để tìm hiểu thêm về các xu hướng công nghệ mới nhất và các kỹ thuật phát triển AI tiên tiến.

Chia sẻ:

Câu hỏi thường gặp

Chain-of-Thought có phải luôn là kỹ thuật tốt nhất để tạo code không?
Không phải lúc nào cũng vậy. Đối với các tác vụ đơn giản, trực tiếp (ví dụ: "Viết hàm tính tổng hai số"), Zero-shot prompting có thể đủ nhanh và hiệu quả. CoT trở nên vượt trội khi các yêu cầu phức tạp, đòi hỏi nhiều bước suy luận, lựa chọn thiết kế hoặc giải thích chi tiết.
Làm thế nào để biết AI đang thực sự sử dụng Chain-of-Thought hay chỉ "bắt chước" nó?
Khi bạn yêu cầu AI "suy nghĩ từng bước", mô hình sẽ tạo ra các bước trung gian. Mặc dù chúng ta không thể nhìn thấy "suy nghĩ" bên trong của AI, việc nó hiển thị các bước này cho thấy nó đã được huấn luyện để phân rã vấn đề theo cách đó. Chất lượng của các bước suy luận và code cuối cùng sẽ là chỉ số tốt nhất để đánh giá hiệu quả của CoT.
Có cần phải sử dụng các từ khóa cụ thể như "Hãy suy nghĩ từng bước" không?
Việc sử dụng các từ khóa rõ ràng như "Hãy suy nghĩ từng bước", "Giải thích quá trình của bạn", "Chia nhỏ vấn đề" là rất khuyến khích. Các mô hình ngôn ngữ lớn thường được huấn luyện trên các tập dữ liệu có chứa các chuỗi suy luận, và những từ khóa này giúp kích hoạt khả năng đó một cách hiệu quả nhất.
CoT có thể giúp debug code không?
Tuyệt đối có. Bằng cách cung cấp một đoạn code lỗi và yêu cầu AI "Hãy phân tích code này từng bước, tìm ra lỗi và đề xuất sửa chữa, giải thích lý do", bạn có thể sử dụng CoT để AI thực hiện quá trình debug một cách có hệ thống, thường là với độ chính xác đáng kinh ngạc.
MỤC LỤC
MỤC LỤC