Nó tự chấm điểm: PASS
Công cụ kiểm tra tích hợp sẵn của Claude Code, /verify, trả về PASS cho một tính năng bị lỗi. Đó là kết quả của một bench gồm 116 phiên Claude Code trên một repository thực tế, nơi mỗi lần "done" được chấm điểm sau đó bằng các acceptance test mà agent chưa từng thấy.
Boris Cherny, người tạo ra Claude Code, gọi việc kiểm tra (verification) là điều quan trọng nhất bạn có thể trang bị cho nó. Công cụ kiểm tra tích hợp sẵn chỉ chạy khi được gọi kể từ Claude Code v2.1.215: bạn gõ /verify, hoặc nó không chạy. Trong bench này, nó trả về PASS ở 24 trên 24 lần chạy, và một trong số đó đã tung ra một tính năng bị lỗi. Bên dưới là những gì thực sự bắt được lỗi, cùng với thiết lập tốn gấp hai lần rưỡi chi phí mà chẳng thay đổi gì.
Bench: 116 lần chạy, test nó chưa từng thấy
Một "done" giả là một phiên làm việc kết thúc bằng cách tuyên bố công việc đã hoàn tất trong khi một acceptance test ẩn, hoặc bộ test suite của chính repository, bị fail. Bench này đo tần suất điều đó xảy ra dưới sáu cách thiết lập kiểm tra.
Sự nghi ngờ đằng sau bài viết này đến từ chính issue tracker của Claude Code: issue #96416, được mở ngày 2026-09-23, mô tả một review liệt kê 19 mối lo ngại, xác minh 5 trong số đó và vẫn kết luận "accept as is".
| Tham số | Giá trị |
|---|---|
| Repository | msiemens/tinydb (cơ sở dữ liệu tài liệu Python), commit 18d73a1 |
| Test suite của repository | 226 test |
| Yêu cầu tính năng | 6, mỗi yêu cầu nêu 5 requirement |
| Acceptance test ẩn | một cho mỗi requirement được nêu, viết trước khi chạy bất kỳ phiên nào, không bao giờ cho agent thấy |
| Model | Opus 5.5, Sonnet 5, Haiku 4.5 |
| Claude Code | 2.1.283, headless (claude -p), giới hạn 60 turn |
| Phiên | 112 lần chạy task + 4 lần chạy /verify liên model = 116 |
| Chi phí | $66.29 quy đổi theo API |
Sáu cách thiết lập chạy từ Claude Code thuần (chỉ có yêu cầu) đến một model thứ hai kiểm tra công việc tại thời điểm dừng:
| Thiết lập | Điều nó thêm vào |
|---|---|
| A plain | không gì cả |
| B /verify | /verify tích hợp sẵn, gõ như một turn thứ hai |
| C verify skill | một project skill viết theo quy trình của Anthropic |
| D Stop hook | một script chặn việc dừng lại khi suite còn đỏ và yêu cầu bằng chứng cho từng requirement |
| E tests first | một quy tắc trong CLAUDE.md: viết một test fail cho mỗi requirement trước khi viết bất kỳ code nào |
| F Opus verifier | một Stop hook chạy /verify bằng Opus trên thay đổi đó |
Những yêu cầu rõ ràng trên một thư viện được test tốt là trường hợp dễ. Opus 5.5 thuần làm đúng cả 12 trên 12 lần chạy, và tự chạy test suite trước khi nói done ở 11 trong số đó.
/verify tích hợp sẵn: PASS, mọi lần, gấp 2.5x
/verify là skill kiểm tra đi kèm sẵn với Claude Code. Nó chạy thay đổi, đọc diff và viết ra một verdict từng bước. Kể từ v2.1.215, nó chỉ chạy khi người dùng tự gọi, nên trong bench này nó được gõ sau mỗi task như một turn thứ hai.
Nó trả về verdict PASS ở 24 trên 24 lần chạy trên cả ba model, bao gồm cả thay đổi bị lỗi của Haiku. Trên Opus 5.5, nó không thay đổi kết quả nào và tốn gấp 2,5 lần chi phí:
| Opus 5.5, mỗi task | Plain | Với /verify |
|---|---|---|
| Chi phí | $0.39 | $0.96 |
| Thời gian thực tế | 75 s | 125 s |
| Kết quả thay đổi | 0 trên 12 |
Công bằng mà nói, /verify đã tìm ra một bug thật: trong một task của Opus, nó đã gắn cờ một vấn đề reuse-after-close vốn đã có sẵn trong thư viện, không phải do thay đổi mà nó đang kiểm tra gây ra. Với công việc vốn đã đúng, đây là một ý kiến thứ hai đắt đỏ.
Skill hay hook: cái nào hay bị bỏ qua
Một skill là một quy trình markdown mà Claude có thể mở ra khi nó đánh giá là phù hợp. Bài blog của Anthropic về verification loop mô tả một công thức sáu bước: chọn ra bước theo dõi thủ công bạn làm thường xuyên nhất, thử /verify tích hợp sẵn trước, viết quy trình đó bằng tiếng Anh đơn giản, biến nó thành một skill, rồi gọi nó trên một task mới và lặp lại. Skill của bench này, verify-change, được xây dựng đúng theo cách đó và yêu cầu Claude chứng minh từng requirement dựa trên code thật trước khi nói done.
Một skill chỉ là một gợi ý, và Claude tự quyết định có mở nó hay không:
| Model | Số phiên mở skill |
|---|---|
| Opus 5.5 | 8 trên 12 |
| Sonnet 5 | 2 trên 6 |
| Haiku 4.5 | 0 trên 6 |
| Tổng | 10 trên 24 |
Trường hợp "done" giả duy nhất của Sonnet đến từ một phiên mà skill không bao giờ được mở: phiên đó kết thúc với hai test mới do chính nó viết bị fail.
Một Stop hook là một script mà Claude Code chạy mỗi khi agent cố gắng kết thúc. Nó có thể từ chối việc dừng lại và gửi agent quay lại làm việc kèm theo lý do. Hook của bench này chạy test suite, chặn dừng lại khi suite còn đỏ, và ở lần dừng đầu tiên yêu cầu một dòng bằng chứng cho mỗi requirement. Nó kích hoạt ở mọi phiên. Trên Opus, nó tốn thêm 20% chi phí, $0.47 so với $0.39 mỗi task (94 s so với 75 s). Trong bench này, nó chưa bao giờ gặp một suite fail vào thời điểm dừng, nên không có gì để bắt: một hook luôn kích hoạt, nhưng nó chỉ kiểm tra những gì bạn bảo nó kiểm tra.
Điểm mù: bỏ sót 11 trên 11
Task bị lỗi yêu cầu các trường unique trên một bảng: hai user không thể dùng chung một email, và bất kỳ update nào khiến hai document có cùng giá trị unique đều phải raise DuplicateKeyError.
Haiku 4.5 đã test việc chuyển một user sang email của một user khác, và trường hợp đó bị từ chối đúng cách. Nó chưa bao giờ test một update khớp với nhiều document và ghi cùng một email mới vào tất cả. Trường hợp đó đi qua mà không báo lỗi trong 11 trên 11 phiên của Haiku, ở mọi thiết lập cùng model: plain, /verify, skill, Stop hook và tests first.
/verify của chính Haiku đã tích vào trường hợp nó đã thử và viết PASS. Test ẩn báo cáo DID NOT RAISE DuplicateKeyError. Sonnet 5, khi được yêu cầu chạy /verify trên cùng thay đổi đó, cũng trả về PASS. Cả Opus và Sonnet đều tự viết đúng tính năng này, nên đây chỉ là một model trên một task, nhưng một bản kiểm do chính model đó viết ra sẽ mang cùng điểm mù.
Bản kiểm từ bên ngoài: Opus nói FAIL
Cùng một /verify trên cùng thay đổi của Haiku, khi được Opus 5.5 chạy, trả về FAIL ở 3 trên 3 lần chạy, mỗi lần đều chỉ đúng trường hợp bị bỏ sót: một update khớp với nhiều document ghi cùng một giá trị vào tất cả mà không báo lỗi. Việc bắt lỗi này đến từ một model khác, không phải từ tác giả và cũng không phải từ bản kiểm của chính tác giả.
Được nối thành một Stop hook (thiết lập F), Opus kiểm tra công việc của Haiku mỗi khi Haiku cố gắng kết thúc. Kết quả:
| T6, mỗi lần chạy | Haiku + Opus checker | Chỉ Opus 5.5 |
|---|---|---|
| Bug được sửa / "done" giả | sửa được ở 3 trên 3 | 0 "done" giả |
| Turn | chạm giới hạn 60 turn ở mọi lần chạy | |
| Chi phí | $1.36 kể cả checker | $0.76 |
Bản kiểm từ bên ngoài có hiệu quả. Trên task này, nó tốn chi phí cao hơn so với việc để model mạnh hơn tự viết tính năng một mình.
Nên áp dụng gì, và cái giá phải trả
Đừng để model đã viết ra thay đổi là bên duy nhất kiểm tra nó.
| Nguyên tắc | Vì sao | Chi phí trong bench này |
|---|---|---|
| Giữ một Stop hook cho bất cứ điều gì một script có thể kiểm tra | nó kích hoạt ở mọi phiên | tốn thêm khoảng 20% trên Opus |
| Để bản kiểm thật sự đến từ bên ngoài tác giả: một model mạnh hơn ở cổng kiểm, hoặc test do chính bạn viết từ yêu cầu | cùng một model đã bỏ sót bug của chính mình 11 trên 11 lần | $1.36 mỗi task cho Haiku + Opus checker |
Với một yêu cầu rõ ràng dùng Opus, bỏ qua việc gõ /verify |
0 kết quả thay đổi | tốn gấp 2,5 lần chi phí, 125 s so với 75 s |
Giới hạn: một thư viện nhỏ, sáu yêu cầu rõ ràng, một đến ba lần chạy mỗi ô, các phiên headless, và các test ẩn chỉ kiểm tra những gì mỗi yêu cầu nêu ra. Với công việc phức tạp hơn, các con số này sẽ thay đổi.
AIDive