Hướng dẫn xây dựng AI Coding Agent riêng cho nhu cầu lập trình đặc thù
Bài viết chia sẻ hành trình xây dựng một AI Coding Agent riêng biệt để giải quyết các vấn đề lập trình ngách mà các LLM phổ thống chưa đáp ứng được. Tác giả hướng dẫn quy trình từ việc thiết kế Prompt, phát triển VS Code Extension cho đến tối ưu hóa giới hạn ngữ cảnh nhằm đảm bảo hiệu suất làm việc.

Hầu hết các lập trình viên hiện nay đều tận dụng các công cụ hỗ trợ lập trình AI. Tuy nhiên, sẽ ra sao khi bạn làm việc trong một lĩnh vực đặc thù (niche), nơi mà các Mô hình Ngôn ngữ Lớn (LLM) không chỉ thiếu kiến thức mà những kiến thức chung chúng có lại hoàn toàn sai đối với trường hợp của bạn?
Đây chính là vấn đề tôi gặp phải khi phát triển Power Platform Code Apps. Đây là các ứng dụng React đầy đủ được lưu trữ trên Power Platform, do đó chúng yêu cầu bộ SDK và các lệnh CLI đặc thù. Các mô hình như Opus 4.6 hoạt động khá tốt xét đến tính "ngách" của nó, nhưng hãy tưởng tượng khi bạn xây dựng thêm những thứ tùy chỉnh (bespoke) trên nền tảng ngách đó. Đó chính là gì tôi đã làm: tôi không dùng React mà muốn xây dựng bằng thuần Vanilla JavaScript (trước khi bạn chê, tôi biết tôi nên dùng React và Typescript, nhưng hãy nhớ rằng tôi có chút "độc lạ"). Điều này đồng nghĩa với việc không có tài liệu hay hướng dẫn đào tạo nào cả. Hơn nữa, vì sử dụng Vanilla JavaScript, dữ liệu đào tạo hiện có liên tục dẫn LLM đi sai hướng. Vì vậy, tôi đã quyết định tạo ra một AI Coding Agent của riêng mình.
Nhìn chung, có 3 cách để sở hữu một mô hình chuyên biệt hơn:
- Tự xây dựng từ đầu (Build your own)
- Tinh chỉnh (Fine‑tune) hoặc chưng cất (distil) một mô hình hiện có (tùy chọn có bổ sung học tập tăng cường)
- Sử dụng Prompt (Prompt)
Bạn có thể đoán được lựa chọn của tôi rồi đấy, đúng là cách dễ dàng nhất: Sử dụng Prompt.
Nội dung bài viết sẽ bao gồm:
- Tổng quan về Prompt
- Nền tảng triển khai
- Cách thức thực hiện
- Bài học kinh nghiệm
1. Tổng quan về Prompt
Nếu bạn đã nắm vững kiến thức này, hãy bỏ qua phần này, nhưng tôi muốn cung cấp cái nhìn nhanh về toàn bộ cấu trúc (stack) của một Prompt.
Có nhiều tầng trong một Prompt, mỗi tầng cao hơn và quan trọng hơn:
Model System Prompt (Prompt hệ thống của mô hình)
Đây là tầng cao nhất, thường được thêm bởi chủ sở hữu mô hình, dùng cho các vấn đề như bảo mật và tính pháp lý. Nó bao gồm các quy tắc như:
- Không chia sẻ cách thực hiện hành vi bất hợp pháp
- Không khuyến khích các hành vi gây hại
- Không chia sẻ thông tin bảo mật của mô hình (Danh sách không đầy đủ)
Application System Prompt (Prompt hệ thống ứng dụng)
Tầng tiếp theo, đây là những gì ứng dụng bạn sử dụng thêm vào. Nó bao phủ các công cụ cụ thể mà ứng dụng cung cấp và các mẫu/cơ chế mà nhà thiết kế ứng dụng tìm thấy để cải thiện hiệu suất. Ví dụ:
- Công cụ này đọc thư mục cục bộ
- Tài nguyên này cung cấp thông tin về x
- Khi xử lý CLI, đảm bảo xác thực được kiểm tra trước (Ví dụ mang tính lý thuyết, vì đây thường là bí mật thương mại)
Instruction.md (Tệp hướng dẫn)
Các tệp hướng dẫn là chỉ dẫn cụ thể cho dự án, thường bao gồm:
- Quy ước đặt tên
- Cấu trúc thư mục
- Nguyên tắc thiết kế
- Kỹ năng nào được sử dụng khi nào
- Bất kỳ bài học nào mà LLM đã học được (bạn có thể thiết lập để agent tự cập nhật tệp)
Điều này giúp đảm bảo dự án nhất quán và dễ đọc/dễ bảo trì hơn.
Skill.md (Tệp kỹ năng)
Các tệp này làm mờ ranh giới giữa prompt và ngữ cảnh. Chúng là nguồn hướng dẫn/kiến thức cụ thể cho các tình huống cụ thể. Bằng cách tách chúng khỏi phần hướng dẫn chính, LLM sẽ tự quyết định khi nào thêm chúng vào (giống như ngữ cảnh/hướng dẫn động). Ví dụ:
- Thiết kế Frontend (Frontend-design)
- Làm việc với tệp PowerPoint
- Thiết kế Canvas
- Biểu thức Power Automate
Hướng dẫn (Instructions) và Kỹ năng (Skills) do Anthropic tạo ra và được thiết kế cho Claude Code, nhưng các công cụ và mô hình khác cũng có thể sử dụng, mặc dù kết quả có thể ít nhất quán hơn về hệ thống phân cấp.
Your Prompt (Prompt của bạn)
Và cuối cùng là prompt mà bạn gửi đi, cùng với bất kỳ ngữ cảnh bổ sung nào.
2. Nền tảng (Platform)
Có một vài cách tôi có thể tiếp cận vấn đề này, nhưng những cách tôi cân nhắc nhiều nhất là:
- CLI Wrapper (Đóng gói CLI)
- VS Code Extension (Tiện ích mở rộng VS Code)
- GitHub Copilot Extensions
Tôi sử dụng GitHub Copilot nên bạn có thể hiểu tại sao các lựa chọn của tôi lại như vậy. Với kinh nghiệm về VS Code Extensions và việc tôi thích viết kết hợp code cùng với agent, việc xây dựng trên nền tảng này là hợp lý nhất, mặc dù một ngày nào đó tôi muốn thử CLI Wrapper.
Sử dụng GitHub Copilot để xây dựng AI Agent
Xây dựng trên VS Code có những lợi thế tuyệt vời:
- Xác thực tích hợp sẵn với GitHub Copilot
- Terminal tích hợp sẵn
- Có thể có giao diện người dùng tùy chỉnh (Custom UI)
- Mở rộng vượt ra ngoài văn bản với các nút bấm, v.v.
- Không cần hosting/backend
- Phân phối miễn phí trên VS Code Marketplace
Vì vậy, một khi đã quyết định nền tảng, bước tiếp theo là bắt tay vào xây dựng.
3. Cách thức thực hiện
AI Coding Agent của tôi sẽ có 3 lợi thế chính so với GitHub Copilot đơn thuần:
- Các lệnh CLI dựa trên giao diện người dùng đơn giản hóa
- System Prompt - được xây dựng cụ thể để đảm bảo LLM không sử dụng kiến thức JavaScript chung để đi lệch hướng
- Các tệp Skill (Skill files) - tất cả những bài học rút ra từ việc triển khai CodeApp JS
Các lệnh CLI dựa trên giao diện người dùng đơn giản hóa
Để Code Apps hoạt động, chúng yêu cầu Power Platform CLI, giúp xác thực, tạo kết nối và triển khai lên môi trường Power Platform. Vì vậy, để việc lập trình trở nên LowCode hơn và dễ dàng hơn, tôi muốn trừu tượng hóa các lệnh đó và tích hợp chặt chẽ hơn.
Để làm điều này, tôi đã xây dựng một loại quy trình dựa trên việc nhấn nút, bao gồm các bước:
- Thiết lập các tệp CodeApp JS
- Xác thực với tenant (khách thuê)
- Liệt kê và chọn môi trường (cập nhật cả tệp cấu hình)
- Tạo kết nối dựa trên đoạn mã đã viết
- Triển khai ứng dụng
System Prompt và Skill.md
Đây là nơi giá trị code được tạo ra nhiều nhất. Tôi gộp chúng lại vì chúng được tạo ra theo cùng một cách, điểm khác biệt duy nhất là System Prompt luôn được sử dụng còn Skills thì cụ thể cho từng nhiệm vụ.
Để tạo ra các prompt và kỹ năng phù hợp, tôi đã loại như "đào tạo" mô hình, và ý tôi là tôi đã xây dựng rất nhiều ứng dụng. Trong quá trình đó, tôi đảm bảo đọc lý do (reasoning) đằng sau từng câu trả lời, và mỗi khi gặp lỗi, tôi sẽ đưa giải pháp vào các tệp.
Nhìn vào việc sử dụng GitHub Copilot của tôi, bạn có thể đoán được những ngày tôi đang kiểm tra/đang học không?
Thống kê sử dụng GitHub Copilot trong quá trình phát triển
Việc này tốn thời gian, nhàm chán và tốn kém, nhưng bằng cách làm việc như vậy, ý tưởng là chỉ mắc lỗi một lần duy nhất.
Đó chính là "bí mật" thực sự, tất cả những gì tôi làm là học từ kinh nghiệm và sau đó ghi chép lại để agent biết phải làm gì và không được làm gì.
Tôi nghĩ quy trình đào tạo/học hỏi này là chìa khóa cho tất cả sự phát triển AI, bao gồm cả Copilot Studio. Bạn cần kiểm tra, kiểm tra, kiểm tra và kiểm tra, với mỗi lần kiểm tra tạo ra một sự điều chỉnh/tweaking cho hướng dẫn hoặc prompt của bạn. Cách tiếp cận lặp lại này cải thiện kết quả và tính nhất quán từ các LLM của bạn.
4. Bài học kinh nghiệm
Có một vài điều chắc chắn đã làm khó tôi, và lớn nhất là việc xử lý ngữ cảnh/cấu trúc Prompt (context/prompt stack). Tôi nhận thấy rằng khi sử dụng agent trên giấy phép Copilot cá nhân, nó hoạt động hoàn hảo, nhưng khi tôi dùng tài khoản công việc, tôi thường gặp lỗi "No choices" (Không có lựa chọn), và lý do là tài khoản công việc của tôi có giới hạn ngữ cảnh thấp hơn. Điều này có nghĩa là tôi có thể gửi ít dữ liệu hơn cho agent, điều này không tốt xét đến quy mô code nhỏ so với các ứng dụng đầy đủ.
Vấn đề về giới hạn ngữ cảnh có thể chịu ảnh hưởng lớn bởi cách bạn xây dựng agent. Trong trường hợp bạn chưa biết, ngăn xếp prompt/ngữ cảnh là mọi thứ bạn phải gửi đến LLM. Bạn thấy đấy, LLM không có bộ nhớ, vì vậy bạn phải gửi toàn bộ lịch sử mỗi lần. Và với việc sử dụng các công cụ, bạn thực sự không gửi một yêu cầu, mà là nhiều yêu cầu. Điều này có thể tạo ra một ngăn xếp khổng lồ. Hình dưới đây minh họa điều này:
Cấu trúc ngữ cảnh trong quá trình xử lý yêu cầu
Như bạn có thể thấy ở trên, không chỉ tất cả các system prompt v.v. được gửi, mà chúng còn được gửi 5 lần (và đây là một ví dụ đơn giản).
Nhưng điều tồi tệ hơn là tin nhắn cuối cùng gửi đến LLM. Ngăn xếp ngữ cảnh vào cuối những lần qua lại này có thể trở nên rất lớn. Như bạn thấy, LLM muốn đọc tệp, viết code, và nó muốn kiểm tra lại/kiểm tra bằng cách đọc thêm một lần nữa. Và đó là cách bạn có thể cạn kiệt ngữ cảnh ngay cả với các dự án nhỏ.
Có một vài cách để khắc phục điều này (và một vài lỗi tôi tìm thấy trong code của mình).
Cách đầu tiên và rõ ràng nhất là đưa nội dung System prompts, Instruction.md và Skill.md xuống mức tối thiểu. Đảm bảo chúng ngắn gọn, không trùng lặp và không quá dài dòng.
Tiếp theo là đảm bảo bạn chỉ gửi dữ liệu đúng, đây là nơi một lỗi của tôi nằm ở chỗ: tôi đang gửi tất cả các tệp skill.md mỗi lần. Tôi đã thử để tiện ích mở rộng chọn đúng tệp bằng từ khóa, nhưng điều này thường dẫn đến việc chúng bị bỏ sót. Cuối cùng, tôi đã chuyển danh sách/mô tả cho LLM và để nó quyết định những tệp nó muốn. Một điều khác cần làm là sử dụng cây tệp (file trees) và giữ chúng chặt chẽ. Cây tệp cho phép LLM biết các tệp nào liên quan và chỉ gửi những tệp đúng. Bạn có thể đặt độ rộng của chúng, nhưng rộng hơn đồng nghĩa với việc gửi nhiều văn bản hơn.
Cách tiếp cận cuối cùng là xử lý lịch sử ngữ cảnh. Như đã nói, bạn gửi lại tất cả các tương tác trước mỗi lần, nhưng nếu bạn có thể giảm bớt nó thì sao? Cách tiếp cận bình thường là nén (compacting), nơi bạn yêu cầu LLM tóm tắt lại lịch sử và sử dụng thay thế. Nó chắc chắn hoạt động, nhưng có thể có nghĩa là ngữ cảnh quan trọng bị mất. Cách tiếp cận tôi đã thử là chia nhỏ quy trình và sau đó loại bỏ thông tin không cần thiết.
Tôi làm điều này bằng cách tạo một tệp nhật ký quyết định được LLM sử dụng để lưu trữ danh sách việc cần làm (todo list) và bất kỳ quyết định chính nào (cũng hữu ích khi quay lại phiên phát triển mới). Sau đó, LLM chia nhỏ dự án thành các nhiệm vụ và hoàn thành từng cái một. Khi hoàn thành một cái, nó cập nhật danh sách việc cần làm và loại bỏ tất cả các lệnh gọi công cụ và lý luận, chỉ giữ lại kết quả.
Như mọi thứ, luôn có sự đánh đổi, bạn không muốn loại bỏ quá nhiều ngữ cảnh, đặc biệt nếu hầu hết người dùng của bạn có giới hạn cao hơn (các mô hình mới liên tục đẩy ranh giới giới hạn token đầu vào/đầu ra).
Một vấn đề khác tôi tìm thấy là mô hình, nó có tác động rất lớn đến hiệu suất. Việc sử dụng Opus 4.6/GPT5.4 sẽ mang lại kết quả tuyệt vời, nhưng việc giảm xuống Auto hoặc GPT4.1 sẽ mang lại kết quả tồi tệ. Tôi không thể làm nhiều ở đây ngoài việc khuyến nghị các mô hình tốt hơn khi thiết lập, và xem xét một số tài liệu về cách lập trình/cấu trúc bản dựng tốt hơn cho các mô hình cũ hơn.
Vấn đề khác tôi gặp phải là cài đặt CLI trùng lặp. Máy tính xách tay của tôi có một phiên bản CLI cũ được cài đặt trực tiếp và một phiên bản đã cập nhật từ tiện ích mở rộng Power Platform. Điều này dẫn đến việc tiện ích mở rộng cung cấp cho LLM sai CLI (phiên bản đã lỗi thời). Đây là một trường hợp cụ thể, nhưng nó cho thấy rủi ro khi phụ thuộc vào các phụ thuộc bên ngoài như CLI và tiện ích mở rộng VS Code. Không nhiều điều bạn có thể làm ở đây, nhưng nó đã thúc đẩy tôi xây dựng nhiều hơn vào giao diện người dùng, và để LLM yêu cầu người dùng sử dụng các nút bấm khi nó gặp vấn đề. Sự thật đơn giản là code mang tính xác định (deterministic), vì vậy bất cứ khi nào có thể, hãy chuyển chức năng sang code và giao diện người dùng truyền thống.
Và đó là tất cả, nếu tôi có thể tạo ra AI Coding Agent của riêng mình, bất kỳ ai cũng có thể.
Nếu bạn muốn thử agent, bạn có thể tải miễn phí tại đây: https://marketplace.visualstudio.com/items?itemName=PowerDevBox.codeappjsplus, và nếu bạn muốn tìm hiểu thêm về CodeAppJS hoặc đóng góp, hãy truy cập codeappjs.com.
Bài viết liên quan

Phần mềm
Ra mắt Rail: Ngôn ngữ lập trình tự hosting tích hợp HTTPS thuần túy
18 tháng 4, 2026

Phần mềm
Tương lai "Headless" cho AI cá nhân: Khi giao diện dòng lệnh lên ngôi
18 tháng 4, 2026

Công nghệ
Cursor đàm phán huy động hơn 2 tỷ USD với định giá 50 tỷ USD khi tăng trưởng doanh nghiệp bùng nổ
17 tháng 4, 2026
