SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-27

Tự viết agent skill từ một lỗi thực tế

Học cách viết SKILL.md từ một lỗi lặp lại: bố cục file, dòng description quyết định lúc skill kích hoạt và cách kiểm thử để agent không sai lần nữa.

Tự viết agent skill từ một lỗi thực tế

Cách tốt nhất để viết agent skill của riêng bạn là rút ra từ một lỗi thực tế. Tìm một tác vụ mà coding agent đã làm sai 2 lần, ghi lại phần sửa bạn đã nhập trong cả 2 lần, rồi lưu phần sửa đó thành file SKILL.md để agent tự tải. Sau đó chỉ còn các bước kỹ thuật: bố cục file và 1 dòng quyết định skill có được kích hoạt hay không.

Thứ tự này rất quan trọng. Skill được viết dựa trên suy đoán sẽ mô tả một vấn đề bạn chưa từng gặp, nhưng vẫn chiếm context trong mọi session. Skill được rút ra từ một lỗi bạn đã quan sát sẽ đi kèm một bài kiểm tra: yêu cầu lại đúng việc đó và xem lần này agent có làm đúng không. Nếu định dạng này còn mới với bạn, trước tiên hãy đọc agent skill là gì và agent tải chúng như thế nào, sau đó quay lại viết skill.

Bắt đầu từ một task mà agent làm sai hai lần

Một lần có thể là ngẫu nhiên. Hai lần là một pattern, và một pattern đáng được ghi thành file.

Đây là một lỗi lặp lại trên các server thực tế. Bạn yêu cầu agent thêm một block reverse proxy vào nginx. Agent sửa /etc/nginx/conf.d/app.conf, rồi chạy sudo systemctl restart nginx. Phần sửa có lỗi typo nên nginx không khởi động được, và site bị down cho đến khi bạn sửa lỗi:

nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12
Job for nginx.service failed because the control process exited with error code.

Bạn sửa lỗi đó trong chat. Hãy test config bằng sudo nginx -t trước khi tác động đến service, rồi áp dụng bằng reload thay vì restart. Một tuần sau, trong một task khác, lỗi tương tự lại xảy ra. Lần thứ hai đó là tín hiệu.

Hãy ghi lại hai thứ khi lỗi vẫn còn trước mắt bạn: request bạn đã nhập và phần correction bạn đã đưa ra, đúng bằng những từ bạn đã dùng. Hai dòng đó trở thành skill. Request cho biết trigger cần match điều gì. Correction là toàn bộ nội dung.

Hướng dẫn authoring của chính Anthropic cũng đặt việc này lên đầu tiên. Hãy chạy agent trên các task đại diện mà không có skill, ghi lại những điểm agent fail, rồi viết các instruction tối thiểu để sửa những lỗi đó. Các lỗi chính là specification. Vì vậy, một skill không thể truy ngược về một lỗi cụ thể thường là skill không ai cần.

Để xem một ví dụ đầy đủ về cùng cách chắt lọc này, bạn có thể đọc Ponytail biến một lỗi lặp lại, trong đó agent rewrite nhiều hơn rất nhiều so với yêu cầu, thành một skill từ đầu đến cuối trước khi tự viết skill của mình.

Cấu trúc của một skill

Một skill là một thư mục chứa một file bắt buộc.

.claude/skills/nginx-config-changes/
├── SKILL.md
├── reference/
│   └── proxy-headers.md
└── scripts/
    └── check-and-reload.sh

SKILL.md mở đầu bằng một khối frontmatter, gồm một số thiết lập được viết bằng YAML (cùng định dạng cấu hình mà các file Docker Compose sử dụng) nằm giữa các marker ---, sau đó là phần hướng dẫn viết bằng markdown. Đây là toàn bộ skill cho lỗi ở trên.

---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
---

## Rules

Run `sudo nginx -t` after every edit under `/etc/nginx`. Do not touch the service until it prints `test is successful`.

Apply the change with `sudo systemctl reload nginx`. Never use `restart`. A reload keeps the running workers serving traffic until the new config parses, so a broken config leaves the site up. A restart stops nginx first, so a broken config takes the site down.

If `nginx -t` fails, fix the file and test again. Never reload a config that failed the test.

For the proxy header defaults this project expects, see [reference/proxy-headers.md](reference/proxy-headers.md).

File này có chưa đến 20 dòng và là một skill hoàn chỉnh. Các phần gồm:

  • name: tối đa 64 ký tự, chỉ được chứa chữ thường, chữ số và dấu gạch ngang; không được chứa các từ claude hoặc anthropic. Trong skill cá nhân hoặc skill dự án, đây chỉ là nhãn hiển thị. Lệnh bạn nhập được lấy từ tên thư mục, nên skill này được gọi bằng /nginx-config-changes.
  • description: mô tả skill thực hiện việc gì và khi nào sử dụng, tối đa 1.024 ký tự. Dòng này thực hiện phần việc chính; phần tiếp theo chỉ nói về nội dung này.
  • Phần body: các hướng dẫn chỉ được nạp khi skill thực sự được kích hoạt.
  • reference/: các file bổ sung mà agent đọc khi cần. Liên kết đến chúng từ SKILL.md và giữ các liên kết ở độ sâu một cấp, vì file được tham chiếu từ một file được tham chiếu khác thường chỉ được đọc một phần.
  • scripts/: các file mà agent thực thi thay vì đọc. Chỉ output của chúng tiêu tốn context, nên một script dài 300 dòng vẫn tốn ít context.

Một skill phát triển thành cấu trúc đầy đủ khi hành vi mà nó sửa quá dai dẳng và cần đến cấu trúc đó, còn skill unlazy dành phần cấu trúc này cho Depth Tree, một tập tin gate và một contract PLAN.md để ngăn agent thông báo đã hoàn tất trong khi toàn bộ nhánh công việc vẫn chưa được xử lý.

Vị trí của thư mục quyết định ai có thể sử dụng skill.

  • .claude/skills/<name>/SKILL.md trong repository: chỉ áp dụng cho dự án này và được chia sẻ với mọi người clone repository.
  • ~/.claude/skills/<name>/SKILL.md: áp dụng cho mọi dự án trên máy của bạn và không áp dụng cho máy của người khác.
  • <plugin>/skills/<name>/SKILL.md: được đóng gói bên trong một plugin và khả dụng ở mọi nơi plugin đó được enable.

Tạo skill bằng mkdir -p .claude/skills/nginx-config-changes rồi ghi file. Claude Code theo dõi các thư mục này, nên việc chỉnh sửa một skill hiện có sẽ có hiệu lực ngay trong session đang chạy. Nếu tạo một thư mục skills cấp cao nhất chưa tồn tại khi session bắt đầu, bạn cần restart, vì lúc session bắt đầu chưa có thư mục đó để theo dõi.

Trường description là dòng có tác động lớn nhất trong file

Khi khởi động, agent nạp namedescription của mọi skill khả dụng vào context. Agent không nạp phần nội dung. Khi request của bạn đến, dòng đó là cơ sở duy nhất để quyết định skill này có liên quan hay không. Vì vậy, một phần nội dung hoàn hảo nằm sau description mơ hồ sẽ không bao giờ được đọc.

Viết description ở ngôi thứ 3. “Kiểm tra và reload nginx an toàn” là phù hợp. “Tôi có thể giúp bạn với nginx” thì không, vì văn bản này được chèn vào system prompt, nơi ngôi thứ nhất khiến câu đó giống như model đang tự nói về mình.

Trong description, cần nêu 2 điều: skill làm gì và điều kiện áp dụng. Đặt use case quan trọng lên đầu, vì Claude Code cắt mục listing ở 1,536 ký tự. Có một field when_to_use tùy chọn để thêm các cụm từ trigger và request mẫu. Nội dung này được nối vào description trong cùng giới hạn ký tự.

Sau đó, dùng những từ bạn thực sự sẽ gõ. description: Helps with nginx không match gì cả, vì không ai gõ “helps with”. Phiên bản trên nêu rõ /etc/nginx, server block, reverse proxyTLS (transport layer security) certificate path. Đây gần như là vocabulary của mọi request cần trigger skill đó.

Đây là cách kiểm tra một description. Đưa riêng dòng đó cho một người chưa từng xem phần nội dung, cùng với request bạn sắp gõ, rồi hỏi họ skill có áp dụng không. Nếu họ không thể xác định, model cũng không thể.

Giữ phần nội dung chính ngắn, vì nó sẽ luôn nằm trong context

Khi một skill được gọi, nội dung đã render của nó được đưa vào conversation dưới dạng một message và giữ nguyên ở đó trong phần còn lại của session. Claude Code không đọc lại file ở các lượt sau. Mỗi dòng bạn viết là chi phí cho toàn bộ session, không chỉ cho một câu trả lời.

Anthropic khuyến nghị giữ SKILL.md dưới 500 dòng và chuyển phần chi tiết vào các file riêng. Cơ chế compaction cho thấy con số này không phải tùy ý. Khi conversation được tóm tắt để giải phóng context, Claude Code gắn lại lần gọi gần đây nhất của mỗi skill, chỉ giữ 5.000 token đầu tiên của mỗi skill và lấp đầy ngân sách tổng hợp 25.000 token, bắt đầu từ skill được gọi gần đây nhất. Một skill dài có thể bị cắt giữa chừng. Nhiều skill dài có thể đẩy hoàn toàn lẫn nhau ra khỏi context.

Vì vậy, chỉ viết những gì model chưa biết. Model biết nginx là gì và reverse proxy hoạt động như thế nào. Model không biết quy tắc nội bộ của bạn về reload trên restart; đó là lý do duy nhất file này tồn tại.

Nếu skill yêu cầu agent chạy một script đi kèm, hãy ghi đường dẫn bằng ${CLAUDE_SKILL_DIR} để đường dẫn được phân giải đúng ở bất kỳ nơi nào skill được cài đặt, đồng thời pre-approve cùng command đó để lần chạy không dừng lại vì prompt cấp quyền.

---
name: nginx-config-changes
description: Tests and reloads nginx safely after a config edit. Use when editing files under /etc/nginx, adding a server block or a reverse proxy, or changing a TLS certificate path.
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/check-and-reload.sh *)
---

Grant này áp dụng cho lượt đã gọi skill và được xóa khi bạn gửi message tiếp theo. Vì vậy, nó không âm thầm trở thành quyền cố định.

Cách chứng minh skill được kích hoạt

Theo dõi việc skill được load cho biết agent đã tìm thấy skill. Điều đó không cho biết câu trả lời đã thay đổi. Hãy kiểm tra cả hai, và kiểm tra trong một session mới, vì session bạn dùng để viết skill đã chứa sẵn mọi nội dung bạn nói trong quá trình viết. Context còn sót lại đó che khuất các khoảng trống trong file.

  1. Bắt đầu một session mới với claude trong project.
  2. Viết request theo cách bạn thường dùng trong một ngày làm việc bình thường, bằng từ ngữ của bạn, không gọi tên skill.
  3. Theo dõi việc invocation. Nếu skill không được kích hoạt, hãy sửa description. Chưa cần sửa body.
  4. Dùng tay invoke skill bằng /nginx-config-changes để làm control. Nếu hành vi đúng khi invoke bằng tay nhưng sai khi invoke bằng request, vấn đề nằm ở trigger chứ không phải instruction.
  5. Chạy cùng request khi skill bị tắt rồi so sánh hai câu trả lời. Trong menu /skills, highlight skill, nhấn Space để chuyển trạng thái sang off, rồi nhấn Enter để lưu. Thao tác này ghi một entry skillOverrides vào .claude/settings.local.json, và nhấn Space lần nữa sẽ chuyển trạng thái về on khi bạn hoàn tất.
  6. Viết một vài request không nên kích hoạt skill, rồi kiểm tra để chắc chắn skill không phản hồi với các request đó.

Để tự động hóa vòng lặp này, hãy cài plugin skill-creator từ marketplace chính thức.

/plugin marketplace add anthropics/claude-plugins-official
/plugin install skill-creator@claude-plugins-official

Nếu output khi cài đặt có nội dung Run /reload-plugins to activate., hãy chạy command đó. Sau đó yêu cầu Claude đánh giá skill theo tên. Plugin lưu các test case trong evals/evals.json bên trong thư mục skill và chạy từng case trong một subagent riêng, nên mỗi lần chạy đều bắt đầu với context sạch. Sau đó plugin ghi lại so sánh with-skill với without-skill. Đây mới là con số phản ánh đúng: mức cải thiện của pass rate được đo dựa trên số token và thời gian mà skill tiêu tốn.

Một skill cũng có thể tự mang theo phần chứng minh thay vì giao việc đó cho một eval run riêng. Đây là cách skill Old Coder tạo ra một evidence report để agent trả lại, và bạn có thể tự chạy lại report đó.

Chế độ lỗi: skill không bao giờ được kích hoạt

Bạn nhập yêu cầu, agent vẫn thực hiện cách cũ và không xuất hiện dòng skill nào. Hãy kiểm tra lần lượt các nguyên nhân sau.

  • Phần mô tả nói skill thực hiện việc gì nhưng không nói khi nào cần dùng, nên không có nội dung nào trong yêu cầu của bạn khớp với mô tả.
  • Phần mô tả không dùng những từ bạn nhập. Nếu bạn nói “nginx”, phần mô tả cũng phải có từ nginx.
  • disable-model-invocation: true được đặt trong frontmatter. Thiết lập này loại phần mô tả khỏi context của model, nên bạn chỉ có thể gọi skill bằng /name.
  • Glob paths trong frontmatter giới hạn việc kích hoạt vào các file khớp mẫu. File bạn đang làm việc không khớp mẫu đó.
  • Skill nằm trong thư mục .claude/skills/ lồng bên dưới thư mục ban đầu. Những skill này chỉ được load sau khi agent đọc hoặc chỉnh sửa một file bên trong thư mục con đó. Trước thời điểm này, skill hoàn toàn chưa khả dụng.

Chế độ lỗi: skill luôn được kích hoạt

Vấn đề ngược lại là mô tả quá rộng, khiến skill được kích hoạt khi xử lý những công việc không liên quan. “Sử dụng khi làm việc trên server” khớp với gần như mọi yêu cầu trong một repository về server. Khi đó, phần nội dung sẽ được tải vào cả những task mà nó không thể hỗ trợ và tiếp tục nằm trong context trong suốt phần còn lại của session.

Hãy thu hẹp mô tả vào điều kiện thực sự quan trọng, đồng thời nêu rõ các file hoặc command mà skill áp dụng. Thêm glob paths khi skill chỉ áp dụng cho một số file nhất định. Với mọi thao tác có side effect, chẳng hạn deploy hoặc commit, hãy đặt disable-model-invocation: true và tự gọi skill bằng /name để agent không tự quyết định rằng đây là thời điểm phù hợp để deploy.

Chế độ lỗi: instruction thuộc về rules file

Một rules file như CLAUDE.md hoặc AGENTS.md được tải khi bắt đầu mỗi session và áp dụng cho mọi task. Nội dung skill chỉ được tải khi skill đó được kích hoạt. Tần suất áp dụng là tiêu chí quyết định. Một thông tin đúng cho mọi task trong repository, chẳng hạn package manager bạn sử dụng, thuộc về rules file. Một quy trình chỉ áp dụng cho một nhóm nhỏ task, chẳng hạn rule cho nginx ở trên, thuộc về skill. Khi đó, quy trình này không tạo thêm chi phí vào những ngày không ai chỉnh sửa nginx.

Lỗi thực sự là đặt instruction đó ở cả hai nơi. Hai bản sao sẽ dần khác nhau. Khi agent thực hiện sai, bạn không thể biết nó đã làm theo bản nào. Hãy chọn một nơi duy nhất cho mỗi instruction. Một rule đã nằm chính xác ở một nơi nhưng vẫn bị bỏ qua là vấn đề khác. Trước khi chuyển rule đó vào skill và hy vọng việc di chuyển sẽ khắc phục lỗi, hãy kiểm tra cơ chế khiến instruction bị bỏ qua. ranh giới giữa skill, MCP server và rules file giúp xử lý các trường hợp phức tạp hơn, bao gồm khi lựa chọn đúng là một MCP (model context protocol) server cung cấp cho agent một tool mới thay vì một instruction mới.

Chia sẻ sau khi đã chứng minh được giá trị

Một skill hoạt động ổn định qua một tuần làm việc thực tế thì đáng được commit. Project skill trong .claude/skills/ được review như code và đi kèm repository, nên teammate clone repository sẽ nhận được bản sửa của bạn mà không cần thêm bước thiết lập nào. Di chuyển một skill giữa các repository mà không copy và paste là một vấn đề riêng, được trình bày trong cách chia sẻ agent skill giữa các repository.

Có một lưu ý về tính portable. Claude Code chấp nhận một danh sách dài các trường frontmatter, nhưng Agent Skills standard chỉ cho phép 6 trường: name, description, license, compatibility, metadataallowed-tools. Nếu upload skill lên claude.ai hoặc đóng gói skill cho Skills API với các trường khác trong frontmatter, thao tác sẽ fail hoàn toàn thay vì bỏ qua trường đó:

Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, name

Chỉ dùng 6 trường này để cùng một file có thể load trong Claude Code và mọi công cụ khác đọc standard. Nơi file được load vẫn quyết định file có thể làm gì, vì Cowork chạy trong sandbox của Anthropic còn Claude Code chạy trên máy riêng hoặc VPS của bạn, nên nginx skill ở trên đáng được mang theo vào checkout của teammate nhưng vô dụng trong sandbox không thể truy cập server. Viết phần instruction sao cho vẫn hoạt động khi chuyển sang model khác là một công việc riêng, được trình bày trong cách viết skill hoạt động với mọi model.

FAQ

Tệp SKILL.md nên dài bao nhiêu?

Giữ tệp dưới 500 dòng và nên dự kiến rằng hầu hết skill hữu ích sẽ ngắn hơn nhiều. Phần nội dung được đưa vào cuộc trò chuyện khi skill được gọi và ở lại đó trong suốt phần còn lại của session. Vì vậy, mỗi dòng là chi phí lặp lại chứ không phải chi phí một lần. Chuyển tài liệu tham khảo dài sang các tệp riêng trong thư mục skill và liên kết đến chúng từ SKILL.md, với độ sâu tối đa 1 cấp, để agent chỉ đọc khi cần. Các script đi kèm được thực thi thay vì được đọc, nên chúng chỉ tốn phần output.

Tại sao skill của tôi không bao giờ được kích hoạt?

Nguyên nhân thường là description, vì đây là phần duy nhất của skill nằm trong context khi model quyết định. Hãy bảo đảm description nêu rõ khi nào cần dùng skill, không chỉ nêu skill làm gì, đồng thời chứa những từ bạn thực sự nhập trong request. Nếu description có vẻ đúng, hãy kiểm tra frontmatter để tìm disable-model-invocation: true, tùy chọn này ẩn hoàn toàn skill khỏi model, và kiểm tra glob paths có giới hạn skill ở các file bạn không thao tác hay không. Skill nằm trong thư mục .claude/skills/ lồng bên dưới thư mục bắt đầu cũng có thể là nguyên nhân: skill chỉ được load sau khi agent đọc hoặc chỉnh sửa một file trong thư mục con đó.

Tôi nên dùng skill hay thêm một dòng vào file rules?

Hãy xem nó áp dụng cho bao nhiêu tác vụ. File rules được load trong mọi session, nên file này chỉ nên chứa các thông tin đúng với mọi tác vụ, chẳng hạn package manager hoặc quy ước đặt tên branch. Skill chỉ được load khi được kích hoạt, nên đây là nơi phù hợp cho một quy trình chỉ áp dụng cho một phần nhỏ tác vụ. Không viết cùng một instruction ở cả hai nơi, vì hai bản sao sẽ dần khác nhau và bạn không còn biết agent đã làm theo bản nào.

Làm sao biết một skill thực sự hữu ích?

Hãy so sánh skill với baseline. Thu thập một vài request thực tế, chạy từng request trong một session mới khi skill được bật, sau đó chạy lại với skill được tắt từ menu /skills và đọc hai câu trả lời cạnh nhau. Session mới rất quan trọng vì cuộc trò chuyện nơi bạn viết skill vẫn chứa các giải thích của bạn, khiến một file chưa đầy đủ trông như đã hoàn chỉnh. Plugin skill-creator thực hiện phép so sánh này cho bạn và báo cáo tỷ lệ pass cạnh chi phí token.

Tôi có thể dùng cùng một SKILL.md với agent khác không?

Có, miễn là bạn chỉ dùng các field được Agent Skills standard định nghĩa: name, description, license, compatibility, metadataallowed-tools. Claude Code chấp nhận nhiều field hơn và cũng hỗ trợ các tính năng trong phần body, chẳng hạn shell command injection mà những tool khác không thực thi. Upload skill có field nằm ngoài standard sẽ fail với lỗi rõ ràng liệt kê các property được phép. Vì vậy, hãy quyết định sớm skill đó chỉ dùng trong Claude Code hay cần được chuyển sang tool khác.