Anthropic ra mắt claude plugin eval trong Claude Code v2.1.269 vào ngày 11/9, và nó lặng lẽ trả lời một câu hỏi mà mọi team xây dựng plugin nội bộ cho Claude Code đã né tránh suốt nhiều tháng: skill này có thực sự làm được gì, hay chỉ trông có vẻ bận rộn trong transcript?

Tôi đã xây dựng và review đủ nhiều skill nội bộ để thuộc lòng kiểu thất bại này. Ai đó viết một SKILL.md với description hay ho, test thủ công ba bốn lần, thấy Claude gọi đúng tool, rồi ship. Ba tuần sau, một đồng nghiệp báo skill “có vẻ không còn hoạt động nữa.” Không ai chắc chắn được liệu nó có từng hoạt động ổn định hay không, vì chưa bao giờ có một con số gắn với chữ “ổn định” cả — chỉ là vài lần chạy thử ngẫu nhiên và cảm giác mơ hồ rằng nó từng chạy tốt lần cuối ai đó kiểm tra.

Ý tưởng cốt lõi: chấm điểm dựa trên baseline, không dựa trên cảm tính

Lệnh quan trọng nhất là claude plugin eval init, nó hỏi về plugin của bạn, đề xuất các prompt và grader, rồi viết ra một bộ suite dưới thư mục evals/ trong plugin. Mỗi case là một prompt mà người dùng thật có thể gõ, cộng với một hoặc nhiều grader kiểm tra xem kết quả có đúng thực sự hay không — regex trên output, có tool cụ thể được gọi hay không (tool_used), thứ tự các tool được gọi (tool_order), file có được tạo ra hay không (file_exists), hoặc một rubric chấm bởi model khác (llm hoặc baseline) cho các trường hợp đúng-sai mơ hồ hơn.

Phần thực sự thay đổi cách bạn nghĩ về chất lượng plugin là baseline không-dùng-plugin. Mặc định, mỗi case chạy ba lần có plugin và ba lần không có plugin. Bạn nhận được hai điểm số — WITHW/OUT — và chênh lệch giữa chúng, Δ, chính là những gì plugin của bạn thực sự đóng góp:

CASE        WITH  W/OUT Δ      RUNS COST    NOTES
first-case  1.00  0.33  +0.67  6    $0.41

Đây là chi tiết đáng để dừng lại suy nghĩ. Một plugin có thể đạt điểm 1.0 trên mọi case và vẫn hoàn toàn vô dụng, nếu Claude vốn dĩ đã cho ra kết quả đúng tương tự ngay cả khi không có plugin. Tôi từng thấy đúng tình huống này với một skill “viết changelog từ diff” mà tôi review cho một khách hàng: skill đạt điểm tuyệt đối, nhưng baseline không-dùng-plugin cũng đạt điểm tuyệt đối, vì Claude vốn đã đủ giỏi để làm việc đó một mình. Skill không sai. Nó chỉ thừa. Nếu không có baseline, sự khác biệt này hoàn toàn vô hình — bạn chỉ thấy dấu tích xanh rồi bỏ qua.

Gắn vào CI

Phần tôi thực sự quan tâm với vai trò lead là hợp đồng exit-code, vì đó là thứ biến công cụ này từ một tiện ích dev cục bộ thành một release gate thực sự:

claude plugin eval . \
  --trust-plugin \
  --json results.json \
  --threshold 0.8 \
  --model claude-sonnet-5 \
  --judge-model claude-haiku-4-5 \
  --no-publish \
  --max-cost-usd 20
  • --threshold 0.8 sẽ làm fail build (exit code 1) nếu điểm with-plugin của bất kỳ case nào tụt xuống dưới 0.8. Mặc định là 1.0 — yêu cầu điểm tuyệt đối — điều này phi thực tế với hầu hết plugin thực tế và đáng để bạn chủ động ghi đè thay vì để mặc định rồi ngạc nhiên.
  • --max-cost-usd 20 đặt trần chi phí cứng cho ước tính giá niêm yết của lần chạy. Khi tiêu hết, không có run mới nào bắt đầu, các run đang chạy dở sẽ hoàn tất, và lệnh thoát với mã 2 kèm partial: true trong kết quả — một mã thoát khác với thất bại thật sự, điều này quan trọng nếu script CI của bạn rẽ nhánh dựa trên đó.
  • --trust-plugin bỏ qua prompt xác nhận tin cậy tương tác, thứ mà nếu không có sẽ từ chối chạy hoàn toàn trong shell CI không tương tác.
  • Việc pin cả --model--judge-model quan trọng hơn vẻ ngoài của nó. Nếu không pin, một lần nâng cấp model âm thầm từ phía Anthropic có thể làm lệch điểm số của bạn và bị hiểu nhầm thành plugin bị regression — đúng kiểu báo động giả làm xói mòn niềm tin vào CI gate chỉ trong vòng một tháng sau khi bật lên.

Một điểm thực tế đáng lưu ý: grader tool_used: Skill tự động bị loại khỏi điểm số so sánh baseline, vì “skill đã được gọi” không bao giờ đúng trong nhánh không-dùng-plugin — nếu tính vào sẽ thổi phồng Δ một cách giả tạo. Chúng vẫn xuất hiện như chỉ báo pass/fail, đây là quyết định đúng, nhưng có nghĩa là bạn không thể đơn giản lấy trung bình tỷ lệ pass của mọi grader để làm ngưỡng gate mà không hiểu grader nào được chấm ở nhánh nào. Hãy đọc aggregate-result.json, không chỉ bảng tóm tắt, trước khi gắn một gate tự động vào đó.

Nơi nó thực sự mang lại giá trị

Phát hiện cụ thể mà tôi kỳ vọng hầu hết các team sẽ gặp trong tuần đầu tiên: một case có Δ gần bằng không và grader tool_used: Skill fail. Sự kết hợp đó nghĩa là Claude không chọn skill của bạn một cách ổn định khi gặp cách diễn đạt tự nhiên — đây là vấn đề về description, không phải vấn đề logic. Đó là một nhận định cụ thể, có thể sửa được và có thể kiểm chứng, khác hẳn với báo cáo lỗi kiểu “skill có vẻ chập chờn.”

Lưu ý thành thật: công cụ này không thay thế integration testing và không bắt được mọi loại regression. Nó vốn dĩ không xác định — mỗi case mặc định chạy ba lần chính vì một lần chạy của agent gần như không nói lên điều gì — và grader llm có thể tự mâu thuẫn giữa các lần chạy với rubric tinh tế, đặc biệt với judge model nhỏ. Hướng dẫn chính thức của Anthropic là chấm output dài, có cấu trúc bằng regex trên nội dung file thay vì dùng grader llm trên cả một khối văn bản, và chỉ dùng judge model cho các rubric PASS/FAIL ngắn gọn, cụ thể. Đó là lời khuyên hay, và bạn chỉ thấy nó hữu ích sau khi từng bị một judge grader chập chờn “cắn” một lần.

Nếu bạn duy trì hơn hai ba plugin Claude Code nội bộ, đây là thứ đáng áp dụng ngay tuần này, không phải quý sau. Chi phí là có thật — mỗi lần chạy eval và mỗi lệnh gọi judge đều tính vào gói hoặc hóa đơn API — nhưng trần --max-cost-usd giữ nó trong tầm kiểm soát, còn lựa chọn thay thế là thứ hầu hết các team đang có hôm nay: những plugin hoạt động dựa trên danh tiếng hoặc bị âm thầm bỏ rơi khi cuối cùng có ai đó yêu cầu bằng chứng.

Xuất nội dung

Bình luận