47 điểm bởi GN⁺ 2025-03-24 | 4 bình luận | Chia sẻ qua WhatsApp
  • Việc hiểu cách các công cụ lập trình AI như Cursor, Windsurf và Copilot vận hành bên trong có thể giúp tăng năng suất và đảm bảo hiệu năng ổn định trong các codebase phức tạp
  • Nhiều người không hiểu rõ giới hạn của AI IDE và đối xử với chúng như công cụ truyền thống, từ đó gặp phải các vấn đề về hiệu năng
  • Bài viết này giải thích cách Cursor hoạt động bên trong, system prompt, cũng như cách tối ưu coding và các quy tắc của Cursor

Từ LLM đến coding agent

Mô hình ngôn ngữ lớn (LLM)

  • Về cơ bản, LLM hoạt động bằng cách dự đoán từ tiếp theo
  • Khi cung cấp prompt, LLM sẽ tạo phản hồi theo kiểu tự động hoàn thành
    • Các LLM đời đầu dựa trên decoder (ví dụ: GPT-2) cần prompt được viết theo cách cụ thể để tạo ra kết quả mong muốn
    • Prompt engineering là kỹ thuật “đánh lừa” mô hình để dẫn nó đến câu trả lời mong muốn
  • Sau khi instruction tuning được đưa vào, tính dễ sử dụng được cải thiện
    • Những lệnh như “hãy viết một PR để refactor phương thức Foo” có thể được thực hiện ngay
    • Trên thực tế, đây vẫn là một phiên bản mở rộng của quy trình tự động hoàn thành
  • Tool calling được bổ sung
    • Mô hình có thể thực hiện các tác vụ như đọc file, ghi file và chạy lệnh
    • Ví dụ: read_file('index.py') → client cung cấp nội dung file → mô hình tiếp tục công việc

Lập trình dựa trên agent

Các AI IDE như Cursor được cấu thành bằng một lớp wrapper phức tạp:

  • Fork của VSCode → bắt đầu từ nền tảng mã nguồn mở
  • Bổ sung UI chat và chọn LLM phù hợp (ví dụ: Sonnet 3.7)
  • Triển khai công cụ cho coding agent
    • read_file(full_path: str)
    • write_file(full_path: str, content: str)
    • run_command(command: str)
  • Tối ưu prompt
    • Thêm các chỉ dẫn như "bạn là một lập trình viên chuyên gia", "đừng phỏng đoán, hãy dùng công cụ"
      → Chỉ cần triển khai các bước trên thì thực tế vẫn có thể hoạt động, nhưng có thể phát sinh các vấn đề như lỗi cú pháp, ảo giác, và thiếu tính nhất quán

Chiến lược tối ưu và mẹo cho lập trình dựa trên agent

  • Để tạo ra một AI IDE tốt, cần hiểu những việc LLM làm tốt, đồng thời thiết kế prompt và công cụ cẩn thận theo đúng giới hạn của LLM.
    • Đơn giản hóa tác vụ chính và dùng các mô hình nhỏ hơn cho tác vụ phụ là cách hiệu quả
    • Có thể phân tán các tác vụ phức tạp để cải thiện hiệu năng và tính nhất quán
  • Bổ sung ngữ cảnh người dùng (dùng @file)

    • Người dùng rất có thể đã biết file hoặc ngữ cảnh phù hợp
    • Thêm cú pháp @file → đưa toàn bộ nội dung file hoặc thư mục vào để cung cấp ngữ cảnh
    • Mẹo: rất nên tích cực dùng @folder/@file → cung cấp ngữ cảnh rõ ràng để cải thiện tốc độ phản hồi và độ chính xác
  • Tối ưu tìm kiếm mã nguồn

    • Tìm kiếm code có thể phức tạp, đặc biệt là tìm kiếm theo ngữ nghĩa (ví dụ: “vị trí của mã xác thực”)
    • Lập chỉ mục codebase vào vector store (Vectorstore) → khi tìm kiếm, LLM sẽ tự động lọc và sắp xếp lại
    • Mẹo: comment và tài liệu mã nguồn rất quan trọng → giúp tăng hiệu quả của mô hình embedding
      • Thêm ở đầu file mô tả mục đích, ý nghĩa và thời điểm chỉnh sửa của file đó
  • Tối ưu ghi file

    • Viết ra mã hoàn hảo là việc khó và tốn kém
    • Thay vì toàn bộ file, hãy tạo semantic diff → chỉ cung cấp các đoạn mã đã thay đổi
    • Một mô hình apply riêng sẽ dựa trên semantic diff để ghi vào file thực tế → sửa các lỗi cú pháp
    • Mẹo: không thể truyền lệnh prompt trực tiếp cho mô hình apply → cung cấp toàn bộ file để tăng khả năng kiểm soát
    • Mẹo: mô hình apply có thể chậm và dễ lỗi khi chỉnh sửa file lớn → giữ kích thước file dưới 500 LoC
    • Mẹo: phản hồi từ linter là tín hiệu cực kỳ quan trọng → cần áp dụng linter mạnh
      • Có thể tận dụng phản hồi từ quá trình biên dịch và ngôn ngữ có hệ thống kiểu
    • Mẹo: dùng tên file mang tính định danh rõ ràng → thay vì page.js, hãy dùng các tên cụ thể như foo-page.js, bar-page.js
      • Cung cấp đầy đủ đường dẫn file trong tài liệu → loại bỏ sự mơ hồ cho công cụ chỉnh sửa
  • Sử dụng mô hình chuyên biệt cho agent

    • Nên dùng mô hình chuyên biệt cho agent, thay vì mô hình viết code thông thường
    • Đây là lý do các mô hình của Anthropic cho hiệu năng nổi bật trong những IDE như Cursor
    • Mẹo: đừng chỉ chọn mô hình viết code, hãy chọn mô hình được tối ưu cho IDE dựa trên agent
      • Có thể kiểm tra hiệu năng mô hình trên bảng xếp hạng WebDev Arena
  • Sử dụng công cụ tự sửa (chiến lược nâng cao)

    • "apply_and_check_tool" → chạy linter tốn chi phí + thu thập log console và ảnh chụp màn hình từ trình duyệt headless
    • MCP(Model Context Protocol) → tăng quyền tự chủ của agent và khả năng cung cấp ngữ cảnh

Phân tích chi tiết system prompt của Cursor

  • Prompt mới nhất của Cursor (March 2025) được trích xuất thông qua kỹ thuật prompt injection dựa trên MCP
    • Các prompt engineer của Cursor có năng lực viết prompt rất xuất sắc, ngay cả khi so với các AI IDE khác.
    • Phân tích cấu trúc prompt có thể giúp cải thiện hiệu năng sinh mã và năng lực thiết kế kiến trúc agent
  • Các thành phần prompt chính và ý nghĩa

    • Dùng các thẻ như "<communication>", "<tool_calling>"
      • Kết hợp Markdown và thẻ XML → dễ đọc với con người và dễ xử lý với LLM
    • "powered by Claude 3.5 Sonnet"
      • Tăng tính nhất quán của mô hình → ngăn LLM đưa ra thông tin sai về mô hình đang chạy
    • "the world's best IDE"
      • Ngăn LLM gợi ý sản phẩm khác khi xảy ra lỗi
    • "we may automatically attach some information…follow the USER's instructions…by the <user_query> tag."
      • Không truyền trực tiếp prompt của người dùng mà bọc vào thẻ đặc biệt để tránh nhầm lẫn
    • "Refrain from apologizing"
      • Tránh xin lỗi không cần thiết (bù cho đặc tính của mô hình Sonnet)
    • "NEVER refer to tool names when speaking"
      • Thêm lệnh không được nhắc đến tên công cụ → nhưng trên thực tế đôi khi mô hình vẫn bỏ qua
    • "Before calling each tool, first explain"
      • Giải thích trạng thái trước khi gọi công cụ → cải thiện trải nghiệm người dùng
    • "partially satiate the USER's query, but you're not confident, gather more information"
      • Tránh phản hồi quá sớm do quá tự tin → khuyến khích thu thập thêm thông tin
    • "NEVER output code to the USER"
      • Cấm xuất mã trực tiếp → chỉ cho phép sinh mã thông qua công cụ
    • "If you're building a web app from scratch, give it a beautiful and modern UI"
      • Khuyến khích tạo web app hấp dẫn chỉ bằng một prompt (phục vụ mục đích demo)
    • "you MUST read the the contents or section of what you're editing before editing it"
      • Bắt buộc đọc ngữ cảnh trước khi sửa code → tăng nhận thức ngữ cảnh
    • "DO NOT loop more than 3 times on fixing linter errors"
      • Giới hạn vòng lặp sửa lỗi → ngăn vòng lặp vô hạn
    • "Address the root cause instead of the symptoms."
      • Hướng đến việc sửa nguyên nhân gốc rễ thay vì triệu chứng
    • "DO NOT hardcode an API key"
      • Chỉ dẫn nhằm tăng cường bảo mật → ngăn hardcode
    • "codebase_search", "read_file", "grep_search", "file_search", "web_search"
      • Cung cấp nhiều công cụ tìm kiếm khác nhau để lấy đúng ngữ cảnh trước khi viết code
    • Yêu cầu "One sentence explanation…why this command needs to be run…"
      • Tăng tính logic khi xử lý đối số công cụ → áp dụng kỹ thuật cải thiện prompt
    • Công cụ "reapply""Calls a smarter model to apply the last edit"
      • Áp dụng lại chỉnh sửa gần nhất bằng mô hình cao cấp hơn → nâng chất lượng chỉnh sửa
    • Công cụ "edit_file""represent all unchanged code using the comment of the language you're editing"
      • Biểu diễn phần mã không thay đổi bằng comment của ngôn ngữ đang chỉnh sửa → tăng độ chính xác cho mô hình chỉnh sửa
  • Tận dụng prompt caching
    • System prompt và mô tả công cụ được giữ ở trạng thái tĩnh
    • Không có tùy biến theo codebase hay người dùng → có thể cải thiện chi phí và tốc độ xử lý bằng prompt caching

Cách viết và sử dụng hiệu quả các quy tắc của Cursor

  • Không có một đáp án tuyệt đối cho việc viết quy tắc Cursor, nhưng dựa trên kinh nghiệm viết prompt và hiểu biết về cấu trúc bên trong của Cursor, bài viết đưa ra một số mẹo hữu ích
  • Điều quan trọng là phải viết quy tắc như hướng dẫn kiểu bách khoa toàn thư, chứ không phải chỉ là mệnh lệnh đơn giản.
  • Khái niệm cốt lõi khi viết quy tắc

    • LLM gọi fetch_rules(…) dựa trên tên và mô tả của danh sách quy tắc
    • Quy tắc không được thêm vào system prompt mà chỉ được tham chiếu khi cần
    • Vì vậy, cách mô tả theo kiểu bách khoa toàn thư sẽ hiệu quả hơn là kiểu ra lệnh
  • Những điều cần tránh khi viết quy tắc

    • Không định nghĩa danh tính (identity)
      • Không dùng các mô tả như "bạn là chuyên gia TypeScript"
      • LLM đã biết danh tính của mình qua prompt tích hợp sẵn → có nguy cơ xung đột
    • Không cố ghi đè system prompt
      • Những lệnh như "đừng thêm comment", "hãy hỏi tôi trước khi viết code" → có thể gây rối trong việc sử dụng công cụ nội bộ
    • Tránh mệnh lệnh phủ định
      • Với LLM, mệnh lệnh tích cực như "hãy làm" hiệu quả hơn "đừng làm"
      • Ví dụ mệnh lệnh tích cực: "khi sửa file, hãy kiểm tra toàn bộ ngữ cảnh trước rồi mới chỉnh sửa"
  • Khuyến nghị khi viết quy tắc

    • Viết tên và mô tả quy tắc rõ ràng, trực quan
      • Chỉ với thông tin tối thiểu về codebase cũng phải có thể áp dụng quy tắc
      • Có thể viết các quy tắc trùng lặp → cải thiện độ chính xác khi tìm kiếm
    • Viết quy tắc theo kiểu bách khoa toàn thư
      • Thay vì mệnh lệnh cụ thể, hãy mô tả tình huống và mục đích
      • Khi cần, có thể liên kết thêm file mã để tăng ngữ cảnh
    • Dùng Cursor để viết bản nháp quy tắc
      • LLM rất giỏi trong việc viết ngữ cảnh cho các LLM khác
      • Ví dụ: "@folder/ tạo file Markdown mô tả các đường dẫn mã thường xuyên được chỉnh sửa và các định nghĩa liên quan"
    • Tránh viết quá nhiều quy tắc
      • Quá nhiều quy tắc là kém hiệu quả và thường phản ánh codebase thiếu trực quan
      • Một codebase lý tưởng là nơi agent có thể làm việc chỉ với số lượng quy tắc tối thiểu
  • Ví dụ về cách viết quy tắc hiệu quả

    • ✅ Mệnh lệnh quy tắc:
      • "đọc toàn bộ ngữ cảnh trước khi sửa file"
      • "khi sửa mã phía server, kiểm tra logic mã xác thực"
      • "khi có lỗi, hãy sửa nguyên nhân trước"
    • ❌ Mệnh lệnh quy tắc (nên tránh):
      • "đừng xóa comment"
      • "hãy hỏi tôi trước khi sửa"
      • "đừng sửa những đoạn mã không cần thiết"
  • Chiến lược cốt lõi khi viết quy tắc

    • Hãy viết quy tắc như mô tả tình huống, không phải mệnh lệnh
    • Dùng tên và mô tả trực quan → đạt hiệu năng tối đa với số lượng quy tắc tối thiểu
    • Tăng cường mô tả tình huống và liên kết mã thay vì đưa ra chỉ dẫn quá cụ thể

Kết luận

  • Việc Cursor bắt đầu từ một fork của VSCode, sử dụng prompt trên nền tảng mã nguồn mở và API mô hình công khai, nhưng vẫn được định giá gần 10 tỷ USD (khoảng 13 nghìn tỷ won) là điều đáng kinh ngạc
    • Hiện tại Cursor đang được định giá ở mức gấp 6 lần theo tiêu chí wrapper multiple
  • Cursor mang lại hiệu năng mạnh nhờ prompt được tối ưuhệ thống tool calling mạnh mẽ
  • Khả năng Cursor tự phát triển mô hình agent riêng là không cao
    • Thay vào đó, nhiều khả năng Anthropic sẽ tung ra sản phẩm cạnh tranh dựa trên Claude Code và Sonnet
  • Insight cốt lõi

    • Việc thiết lập đúng codebase, tài liệu hóa và quy tắc sẽ tiếp tục là kỹ năng quan trọng trong tương lai
    • Hiểu các chiến lược tối ưu của công cụ lập trình AI có thể giúp tăng năng suất và độ chính xác
    • Nếu Cursor không hoạt động đúng, rất có thể vấn đề nằm ở cách sử dụng

"Nếu Cursor không hoạt động, bạn cần xem lại cách dùng của mình."

4 bình luận

 
bluekai17 2025-03-26

Chắc phải thử áp dụng mới được.

 
ohyecloudy 2025-03-25

Dùng Cursor để viết bản nháp quy tắc
LLM rất mạnh trong việc viết ngữ cảnh cho các LLM khác

Thú vị thật. Chẳng lẽ vì chúng cùng uống một dòng nước sao?

 
linker 2025-03-25

Bài viết rất sâu sắc. Cảm ơn bạn.

 
nicewook 2025-03-25
  • Phân tích chi tiết system prompt của Cursor - thật ấn tượng.
  • Việc Anthropic có thể ra mắt một AI IDE khiến tôi đã thấy háo hức từ bây giờ.