# Vì Sao AI Không Nên Tự Chấm Test Case Của Chính Nó

> Chào các bạn 👋 Khi nhờ AI sinh test case, hầu hết chúng ta làm theo bản năng: nhét luôn checklist chất lượng vào cùng một prompt, kiểu "viết test case rồi tự kiểm tra theo 12 tiêu chí sau". Một lần chạy, tiết kiệm token, AI vừa viết vừa soát. Với đa số mọi người, cấu trúc đó có thể đã là đủ. Tuy nhiên, thí nghiệm dưới đây sẽ đưa ra một góc nhìn khác để các bạn lựa chọn khi áp dụng  "Cấp độ độc lập trong kiểm thử" vào workflow của các AI agent

- **URL canonical**: https://itlearn.vn/blog/ai-tu-cham-test-case
- **Published**: 2026-09-10T22:18:00+07:00
- **Modified**: 2026-09-12T20:54:14+07:00
- **Author**: Anh Tuấn
- **Category**: AI for Tester (https://itlearn.vn/blog/cat/ai-for-tester)
- **Reading time**: 43 phút
- **Source site**: IT LEARN — Học viện Software Testing tiếng Việt

---

## Thí nghiệm AI sinh test case gồm những gì

### Spec thử nghiệm: một tính năng voucher có gài bẫy

Mình soạn một bản đặc tả tính năng **quản lý mã giảm giá (voucher)** trên Admin Portal, mã VCH-201, viết đúng kiểu spec ngoài đời: bảng phân quyền 3 role, bảng validation 10 field, sơ đồ vòng đời 5 trạng thái, luồng áp mã ở Checkout với thứ tự kiểm tra 6 bước, công thức tính tiền giảm, 5 acceptance criteria. Và một đoạn comment trao đổi của PO, Dev lead, QA ở cuối, y như một ticket Jira thật. Bạn có thể tham khảo specs này[ tại đây](https://drive.google.com/drive/folders/13-Cb2TYg2wjCARLml86h1O5OH0R528hx?usp=sharing) 

Điểm mấu chốt: spec **cố tình được gài 12 cái bẫy**, đúng những kiểu lỗi spec mà bạn gặp hằng ngày:

Loại bẫy

Ví dụ trong spec VCH-201

Mâu thuẫn nội bộ

Bảng ghi `end_date` tối đa **90 ngày**, message lỗi chuẩn lại ghi "không quá **180 ngày**"

Thông tin chỉ nằm trong comment

PO comment: `code` không được bắt đầu bằng chữ số. Bảng validation không có dòng này

Sơ đồ thiếu nhánh

Diagram không có mũi tên `PAUSED → ACTIVE`, nhưng comment PO nói "được, sẽ update sau"

Spec im lặng

Voucher đang `PAUSED` mà quá `end_date` thì thành gì? Không ai nói

Diễn đạt nước đôi

`max_discount` cột "Bắt buộc" ghi "Chỉ khi PERCENT", cột quy tắc lại ghi "bỏ trống = không giới hạn"

Hệ quả tính toán không ai nghĩ tới

Đơn 15.000đ, giảm 5%, làm tròn xuống nghìn → giảm **0đ**. Cho qua hay chặn?

Cửa sổ thời gian

Job chuyển `EXPIRED` chạy 15 phút/lần → có 15 phút voucher đã hết hạn nhưng DB vẫn ghi `ACTIVE`

Một tester giỏi không chỉ viết test case cho những gì spec ghi. Họ **phát hiện những gì spec quên ghi**. 12 cái bẫy này là thước đo cho đúng năng lực đó. Danh sách bẫy được viết trước, cất riêng, và không agent nào được nhìn thấy.

### Hai cách dùng AI được đem so

Mình dựng hai luồng AI sinh test case bằng Claude Code với subagent, cùng model, cùng spec, cùng format output. Khác biệt duy nhất nằm ở chỗ **checklist nằm ở đâu**.

 

Cách 1: gộp chung (tự kiểm)

Cách 2: tách kiểm độc lập

Ai viết test case

1 agent

1 agent

Agent viết có thấy checklist 12 tiêu chí?

**Có**, nằm ngay trong context lúc viết

**Không**, hoàn toàn mù checklist

Ai chấm

Chính agent đó tự đọc lại và tự chấm

Một agent **verifier riêng**, chỉ đọc, không được sửa

Vòng sửa

Tự sửa trong cùng lượt, tối đa 2 vòng

Verifier trả báo cáo FAIL kèm bằng chứng → agent viết sửa, tối đa 2 vòng revise

Số test case ra

98

119

Thời gian chạy

~13 phút

~37 phút

Bộ checklist 12 tiêu chí là loại nhị phân, PASS hoặc FAIL, mỗi FAIL phải kèm bằng chứng là ID test case cụ thể. Nó gồm những thứ rất quen với người [viết test case](/blog/cach-viet-test-case) chuẩn: ID duy nhất, truy vết được về requirement, có case negative, đủ giá trị biên, test data cụ thể, kết quả kỳ vọng quan sát được, mỗi step một hành động, dùng đúng thuật ngữ spec, khai báo assumption, không trùng lặp, có priority.

## Môi trường thực hiện so sánh

Minh ghi rõ môi trường ở đây, và quan trọng hơn là ghi rõ **những gì được giữ giống hệt nhau** giữa hai setup, để khi kết quả lệch, ta biết chắc nó lệch vì đâu. Cấu trúc thư mục đã được để trong folder google drive trên đầu bài nha.

### Nền tảng

Thành phần

Cấu hình

Công cụ điều phối

Claude Code, mỗi agent là một subagent định nghĩa bằng file markdown trong thư mục `.claude/agents/`

Model của agent sinh và agent verifier

**Claude Fable 5.1**, khai báo `model: inherit` nên cả hai cách kế thừa đúng một model từ phiên làm việc

Model của judge (bên chấm cuối)

Claude Opus, cấu hình riêng, **khác model sinh**, để bên chấm không "cùng gu" với bên viết

Cách kích hoạt

Mỗi cách là một slash command: một lệnh cho cách 1, một lệnh cho cách 2, một lệnh chấm judge. Người điều phối chỉ gõ lệnh, không tự viết hay tự chấm test case

Spec

Một file markdown duy nhất, cả hai cách đọc cùng file, cùng phiên bản

Answer key (12 bẫy + 31 yêu cầu gốc)

Viết xong trước khi chạy, để ngoài context của mọi agent sinh và verifier, chỉ judge được đọc

Chọn Fable 5.1 cho cả hai bên là có chủ ý. Nếu để cách 2 chạy model mạnh hơn, mọi khoảng cách đo được đều có thể đổ cho model, và thí nghiệm mất ý nghĩa. Còn judge chạy trên một model khác là để tránh một dạng thiên vị tinh vi: model thường "thích" văn phong của chính nó, và nếu judge cùng model với bên sinh, nó có thể chấm nhẹ tay hơn cho những đoạn nghe quen tai.

### Những gì giống nhau giữa hai setup

Đây là danh sách tôi kiểm lại từng dòng trước khi chạy. Bất kỳ dòng nào khác nhau đều là một biến số lẫn vào kết quả.

Yếu tố

Cách 1

Cách 2

Giống?

Model sinh test case

Fable 5.1

Fable 5.1

Có

Spec đầu vào

`VCH-201-voucher.md`

`VCH-201-voucher.md`

Có

Vai được gán trong system prompt

"Senior QA engineer sinh test case từ spec"

"Senior QA engineer sinh test case từ spec"

Có

Skill định dạng output

`tc-format`: cùng header, cùng mục Assumptions, cùng bảng Requirement index, cùng khối test case (ID, Requirement, Type, Priority, Preconditions, Test data, Steps, Expected result)

Cùng skill `tc-format`

Có

Quy tắc trích yêu cầu

"Đọc hết spec, trích mọi requirement vào Requirement index, gồm validation, message, chuyển trạng thái, phân quyền"

Cùng câu chữ

Có

Xử lý chỗ spec mơ hồ

"Không hỏi lại, ghi mọi điểm mơ hồ thành assumption"

Cùng câu chữ

Có

Bộ công cụ agent được dùng

Read, Write, Glob, Grep

Read, Write, Glob, Grep

Có

Nội dung checklist 12 tiêu chí

Cùng file `tc-checklist`, cùng câu chữ từng mục

Cùng file, verifier dùng

Có

Giới hạn số vòng sửa

Tối đa 2 vòng tự sửa

Tối đa 2 vòng revise sau verifier

Có

Nơi ghi output

`docs/refinements/VCH-201/test-cases-A.md`

`docs/refinements/VCH-201/test-cases-B.md`

Có (chỉ khác hậu tố)

Ngôn ngữ output

Theo ngôn ngữ spec (tiếng Việt, thuật ngữ giữ tiếng Anh)

Cùng quy tắc

Có

Ai được nhìn answer key

Chặn với AI agent

Chặn với AI agent

Có

### Điểm biệt

Yếu tố

Cách 1

Cách 2

Skill nạp vào agent sinh

`tc-format` **+ `tc-checklist`**

Chỉ `tc-format`

Chỉ dẫn lúc viết

"Dùng 12 tiêu chí làm kim chỉ nam khi viết"

"Phủ positive, negative, boundary cho từng requirement bằng phán đoán nghề nghiệp của bạn"

Ai chấm

Cùng agent, cùng context, ngay sau khi viết xong

Agent verifier riêng, context mới hoàn toàn, nạp `tc-checklist`

Verifier có được sửa file không

(không có verifier)

**Không**. Chỉ đọc, chỉ ghi báo cáo, chỉ mô tả cần sửa gì ở đâu, không được viết lại test case

Verifier đọc gì trước

(không có)

Đọc spec trước, tự lập danh sách requirement riêng, rồi mới mở file test case để đối chiếu

Thứ báo cáo tự chấm nằm ở đâu

Nối vào cuối chính file test case, mục `## Self-check`

File báo cáo riêng, mỗi vòng một file

Nghĩa là toàn bộ chênh lệch đo được phía sau chỉ có thể đến từ hai chỗ: **checklist có nằm trong context lúc viết hay không**, và **người chấm có phải là người viết hay không**. Hai biến này đi cùng nhau trong thí nghiệm hiện tạ. Đây cũng là mục tiêu chính của thí nghiệm lần này,

Với các thứ 2, mình cũng sẽ có 1 orchestrator nhỏ để đảm bảo được điều phối giữa 2 agent (generator và verifier) . Orchestrator sẽ  chuyển báo cáo từ verifier sang agent Generator và đếm số lượt phản hồi. Tuyệt đối không cho phép đưa thêm thông tin vào cho bất kỳ agent nào.

## Cách thực hiện đánh giá

Mình dùng 3 phương án để đảm bảo tính độc lập trong quá trình đánh giá. Việc đánh giá cũng được sử dụng AI với model khác để đảm bảo tính độc lập:

- **Answer key viết trước, chỉ cung cấp cho agent đánh giá.** 12 bẫy và 31 yêu cầu gốc được soạn xong trước khi chạy bất kỳ agent nào, và không đưa vào context của agent nào cả. Điểm cuối cùng không lấy từ bản tự chấm của cách 1, cũng không lấy từ báo cáo verifier của cách 2, mà từ một agent chấm (judge) thứ ba.

- **Chấm mù.** Judge chỉ nhận hai file tên "X" và "Y", không biết đâu là cách 1, đâu là cách 2. Nó được dặn không để độ dài file hay độ "bóng bẩy" ảnh hưởng điểm, và mọi điểm PASS đều phải có bằng chứng.

- **Chạy 2 lần, đảo vị trí.** Vòng 1: X là cách 1, Y là cách 2. Vòng 2: đổi ngược lại. Nếu judge có thói quen thiên vị file đứng trước (position bias), đảo vị trí sẽ lộ ra ngay. Kết luận chỉ có hiệu lực khi cả hai vòng cùng chọn một bên.

Bạn để ý nhé: đây chính là **tính độc lập ở tầng chấm điểm**. Mình không tin cả bản tự chấm lẫn bản verifier, nên mới cần một judge không dính dáng gì đến quá trình sinh.

## Kết quả

### Bảng tổng kết

Tiêu chí đo

Cách 1: gộp chung

Cách 2: tách kiểm độc lập

Bên hơn

Phủ 31 yêu cầu gốc

31/31

31/31

Hòa

Có case negative cho 20 yêu cầu nhận input

20/20

20/20

Hòa

Phủ giá trị biên cho 13 ràng buộc

12/13

**13/13**

Cách 2

Precision (không có test case thừa)

1.00

1.00

Hòa

**Phát hiện bẫy gài trong spec**

**6/12**

**10/12**

**Cách 2**

**Đạt checklist chất lượng**

**8–9/12**

**11/12**

**Cách 2**

Tổng số test case

98

119

(không tính điểm)

**Cả hai vòng chấm đều chọn cách 2.** Không có tiêu chí nào hai vòng mâu thuẫn nhau.

## Bốn cái bẫy chỉ cấu trúc agent độ lập phát hiện được

Cả hai cách đều bắt được 6 bẫy "dễ thấy" như nhau: mâu thuẫn 90/180 ngày, quy tắc `code` trong comment, nhánh `PAUSED → ACTIVE` thiếu trong diagram, hai chỗ nước đôi của `max_discount`, và chuyện phân biệt hoa/thường khi gọi API. Cách 2 bắt thêm 4 điểm sau:

Bẫy

Vấn đề spec không nói

Cách 2 xử lý thế nào

Voucher `PAUSED` quá `end_date`

Diagram chỉ có `ACTIVE → EXPIRED`. Voucher đang tạm dừng mà hết hạn thì job có đụng không?

Khai báo assumption "job chỉ tác động voucher `ACTIVE`" + test case kiểm tra voucher `DRAFT`/`PAUSED` quá hạn vẫn giữ nguyên trạng thái, ghi rõ cần PO xác nhận

Cửa sổ 15 phút của job

`end_date` là 23:59, khách áp mã lúc 00:05 hôm sau, job chưa chạy nên DB vẫn `ACTIVE`. Checkout từ chối hay cho qua?

Test case riêng cho đúng khe 00:05 đó, kỳ vọng "Mã không còn hiệu lực" vì Checkout kiểm tra khoảng ngày theo thời gian thực, không phụ thuộc job

PERCENT làm tròn về 0

Đơn 15.000đ, giảm 5% = 750đ, làm tròn xuống 1.000 → 0đ

Test case biên với đơn 15.000đ + assumption "mã vẫn được áp dụng, giảm 0đ"

Xóa voucher ngoài `DRAFT`

Bảng phân quyền chỉ nói Admin xóa "chỉ khi Draft", không nói xóa trạng thái khác thì lỗi gì

Test case gọi thẳng API xóa voucher `ACTIVE`, kỳ vọng HTTP 409, ghi rõ 409 là assumption cần dev xác nhận

Điểm chung của cả bốn điểm này là gì: **tất cả đều không nằm cụ thể trong specs.** Chúng chỉ hiện ra khi đối chiếu chéo bảng với sơ đồ, sơ đồ với comment, công thức với dữ liệu thực tế. Đây chính là phần "nghề" của tester, thứ mà các [kỹ thuật thiết kế test](/blog/ky-thuat-thiet-ke-test) như phân tích giá trị biên hay bảng chuyển trạng thái được sinh ra để hệ thống hóa.

Cả hai cách đều bỏ lỡ 2 bẫy giống nhau: đơn đã `PAID` rồi hoàn tiền thì có trả lại lượt dùng không, và admin sửa `end_date` khi voucher đang `ACTIVE` có được rút về quá khứ không. Không cấu hình nào đạt 12/12.

## Điểm nổi bật: Agent có checklist lại trượt đúng mục checklist

Dưới đây là các điểm mà cấu hình 1 (Agent có checklist trước khi tạo test case) đã để lọt

Mục

Nội dung tiêu chí

Cách 1 tự chấm

Judge chấm mù

C04

Đủ giá trị biên cho mọi ràng buộc

PASS

**FAIL** (thiếu biên "tổng đơn bằng đúng `discount_value`")

C06

Kết quả kỳ vọng phải quan sát được, không cần diễn giải

PASS

**FAIL**

C10

Hành vi ngoài spec phải khai báo ở mục Assumptions

PASS

**FAIL** (5 hành vi dùng ngầm)

C12

Priority gán nhất quán, P1 dành cho luồng lõi

PASS

FAIL ở 1/2 vòng

Cách 1 kết thúc với bản tự chấm ghi **PASS 12/12**.

Cụ thể nó để lọt gì:

- **7 test case kết thúc bằng "hiện viền đỏ kèm message lỗi"** mà không ghi message là gì. Tester chạy test không biết lấy chuỗi nào để đối chiếu. Trong khi spec có sẵn 5 message chuẩn.

- **2 test case ghi kỳ vọng "HTTP 400 hoặc 409".** Đây bản chất là 2 **giả định** cần phải đưa vào danh sách giả định để đảm bảo được làm rõ với các bên liên quan.

- **1 test case ghi field "bị ẩn hoặc disable".** Lỗi nước đôi, dẫn tới test case không chính xác, cần đưa vào danh sách giả định.

- **5 hành vi không có trong spec bị dùng ngầm:** hộp thoại xác nhận xóa, màn hình audit log, trường "số lượt đã dùng", mã lỗi API khi kích hoạt voucher hết hạn, nhãn nút ở Checkout. Test case được tạo có các yêu tố này mặc dù nó không được thể hiện rõ ràng trong specs.

Cách 2 không hề nhìn thấy checklist lúc viết. Bản nháp đầu tiên của nó tệ hơn hẳn: verifier đánh FAIL 5/12, với 25 test case dùng placeholder kiểu "các field bắt buộc hợp lệ" và hàng loạt kỳ vọng nước đôi. Nhưng sau hai vòng bị một agent khác soi từng ID, nó đạt 11/12 theo judge.

Có một chi tiết nhỏ mà mình thấy nói lên tất cả. Ở vòng sửa thứ hai, agent viết của cách 2 ghi vào revision log rằng đã tách các step gộp ở 10 test case. Verifier đọc lại file và ghi thẳng: *"Revision log khẳng định đã tách; thực tế chưa."* Agent generator tiếp tục nói **dối **và chỉ bị phát hiện nếu xử dụng agent khác để kiểm chứng lại !!!

## Công bằng: cách 1 thắng ở đâu

Cách 1 thắng đúng **một tiêu chí**: tính đơn nhất của step (C08). Nó tách mỗi thao tác thành một step riêng; test case đầu tiên có 11 step nhập 11 field rồi mới submit. Cách 2 đến vòng cuối vẫn còn gộp "vào Checkout và nhập mã" hay "mở chi tiết và quan sát" ở một số test case, sai chuẩn viết test case.

Nhưng cả hai vòng judge đều xếp đây là **lỗi trình bày, sửa cơ học được**. Tách step không đòi hỏi hiểu thêm gì về nghiệp vụ. Còn khoảng cách 4 bẫy của cách 1 là **thiếu hiểu biết về spec**, điểm này sẽ khó phát hiện hơn và đòi hỏi mức độ hiểu specs sâu hơn mới thấy được lỗi.

## Nguyên nhân giả định

Mình trình bày đây là giả thuyết, không phải kết luận đã chứng minh.

- **Thiên kiến tác giả.** Khi cùng một context vừa viết vừa chấm, AI đang chấm bản nháp nó vừa tạo ra. Nó đã "tin" là mình hiểu đúng spec, nên đọc lại chỉ thấy cái mình định viết, không thấy cái mình bỏ sót. Đúng hệt con người: dev tự test code của mình thường test cái mình đã nghĩ tới.

- **Checklist thành cái trần, không phải cái sàn.** Khi 12 tiêu chí nằm sẵn trước mắt lúc viết, AI có xu hướng viết vừa đủ để tick hết ô rồi dừng. Agent không thấy checklist thì không có mốc nào để dừng, nên đào sâu spec hơn. Đây có thể là lý do nó bắt được 4 bẫy kia. Giả thuyết này ngược với trực giác của hầu hết chúng ta, và là cái tôi muốn thử tiếp nhất.

- **Vòng phản hồi thật.** Cách 2 có tối đa 2 lần verifier trả lỗi về, mỗi lần kèm ID test case và trích dẫn cụ thể. Mỗi vòng là một lần *bị buộc* nhìn lại bằng con mắt khác. Cách 1 tự trả lỗi cho chính mình, và ở vòng 1 nó chỉ tìm thấy đúng một lỗi.

## Liên hệ nguyên tắc ISTQB: tính độc lập trong kiểm thử

[ISTQB](/blog/istqb-la-gi) CTFL v4.0 dành hẳn một mục cho **independence of testing**. Ý chính: người kiểm thử càng độc lập với người tạo ra sản phẩm thì càng dễ phát hiện lỗi, vì không mang theo thiên kiến và giả định của chính tác giả. Syllabus phân thành các mức, và tôi thấy chúng ánh xạ rất khớp sang thế giới AI agent:

Mức độc lập theo ISTQB

Với con người

Với AI agent

Không độc lập

Dev tự test code của mình

Một agent vừa sinh vừa tự chấm trong cùng context (cách 1)

Độc lập một phần

Đồng nghiệp cùng team test chéo

Agent chấm riêng nhưng dùng chung context hoặc chung lịch sử chat

Độc lập cao

Team test riêng trong công ty

Agent verifier riêng, context sạch, chỉ được đọc, không được sửa (cách 2)

Độc lập rất cao

Bên thứ ba bên ngoài

Judge chấm mù, đảo vị trí, có answer key viết trước

ISTQB cũng nói thẳng mặt trái của độc lập: người kiểm thử tách biệt có thể thiếu ngữ cảnh, và giao tiếp giữa hai bên tốn kém hơn. Thí nghiệm này cho thấy đúng như vậy: cách 2 tốn gần gấp ba thời gian (và hiển nhiên là cũng tốn token hơn), và verifier ở vòng 3 vẫn còn than về vài step gộp mà judge cuối cùng coi là chuyện nhỏ.

Nguyên tắc không đổi khi thay người bằng AI. Một agent tự kiểm sản phẩm của mình dính đúng cái bẫy mà một dev tự test code của mình gặp phải. Chỉ khác là AI làm việc đó trong 13 phút thay vì 2 ngày, nên **lỗi tự xác nhận cũng đến nhanh hơn và trông tự tin hơn**: một bản báo cáo PASS 12/12 sạch sẽ, có bảng, có bằng chứng.

## Sáu việc bạn làm được ngay

Kể cả khi bạn chỉ dùng ChatGPT hay Claude một mình để AI sinh test case, không dựng multi-agent:

- **Tách đôi hội thoại.** Sinh test case ở một chat. Mở **chat mới hoàn toàn**, dán test case và spec vào, kèm checklist, yêu cầu chấm PASS/FAIL từng tiêu chí với bằng chứng là ID test case. Chat mới không có ký ức "mình vừa viết ra nó". Đó là tính độc lập, bản đơn giản nhất.

- **Đừng đưa checklist vào lúc sinh.** Để AI viết tự do theo spec, rồi mới lấy checklist ra soi. Nếu bạn đã có bộ [prompt mẫu sinh test case](/blog/dung-ai-viet-test-case-prompt), thử bỏ phần "tự kiểm tra" ra khỏi prompt đó và chuyển nó sang bước hai.

- **Bắt khai báo assumption.** Yêu cầu output có mục *Assumptions* liệt kê mọi chỗ spec không nói rõ, và mỗi test case dựa vào assumption nào phải ghi "(xem A-số)". Đây là nơi lộ ra AI có thật sự đọc kỹ spec hay chỉ chép lại. File của cách 2 kết thúc với 29 assumption; file của cách 1 có 14.

- **Cấm kết quả kỳ vọng nước đôi.** Quy tắc cứng: không có chữ "hoặc", không có "hiện message lỗi" chung chung. Phải ghi nguyên văn message hoặc mã HTTP cụ thể. Nếu spec chưa chốt, chọn một giá trị, ghi vào assumption, và đánh dấu cần PO xác nhận.

- **Chấm bằng bẫy, đừng chấm bằng cảm giác.** Muốn biết prompt hay quy trình nào tốt hơn: lấy một spec thật, tự gài vài mâu thuẫn bạn đã biết, rồi đếm xem AI bắt được mấy cái. Đừng đếm số test case. Trong thí nghiệm này bên nhiều test case hơn cũng là bên tốt hơn, nhưng đó là hệ quả của việc đọc kỹ, không phải nguyên nhân.

- **Con người vẫn chốt cuối.** Cấu hình tốt nhất vẫn bỏ lỡ 2/12 bẫy, và cả hai bên đều không nghĩ tới chuyện hoàn tiền. Câu hỏi [AI có thay thế tester không](/blog/ai-co-thay-the-tester-khong) có thêm một bằng chứng nữa: chưa, ít nhất là chưa ở bước đọc spec.

## Ba hướng xử lý và ưu nhược của từng hướng

Từ kết quả trên, có ba cách bố trí quy trình AI sinh test case mà tôi cân nhắc. Hai cách đầu chính là hai biến thể vừa đo. Cách thứ ba là hướng tôi đề xuất, chưa đo, và tôi sẽ nói rõ vì sao mình tin nó đáng thử.

### Hướng 1: gộp chung, agent tự kiểm

 

 

**Ưu**

Rẻ nhất: một lượt chạy, ~13 phút, ít token nhất. Dễ dựng: một prompt, không cần điều phối. Mỗi step một hành động rất chuẩn vì checklist nhắc ngay lúc viết. Đủ dùng cho spec đơn giản, ít mâu thuẫn

**Nhược**

Báo cáo tự chấm **không tin được**: tự tuyên PASS 12/12 nhưng chấm mù ra 8 đến 9. Bỏ lỡ nửa số bẫy spec. Lỗi lọt là lỗi đắt: thiếu hiểu biết về nghiệp vụ, không sửa cơ học được. Không có ai để "cãi" lại, nên sai từ đầu là sai đến cuối

**Dùng khi**

Spec ngắn, sạch, đã được PO chốt kỹ; cần nháp nhanh để thảo luận; hoặc ngân sách token thật sự eo hẹp và sẽ có người review tay ngay sau đó

### Hướng 2: tách hẳn, agent viết mù checklist, verifier độc lập

 

 

**Ưu**

Bắt bẫy spec tốt nhất trong thí nghiệm (10/12). Khai báo assumption đầy đủ nhất (29 mục), tức là lộ ra đúng chỗ cần hỏi PO. Báo cáo verifier có bằng chứng theo ID nên người review tay đọc rất nhanh. Bắt được cả chuyện agent viết báo cáo sai "đã sửa"

**Nhược**

Đắt gấp gần ba về thời gian, ba lượt verifier cộng hai lượt sửa. Bản nháp đầu tệ (FAIL 5/12) nên vòng 1 gần như luôn phải sửa, tức là lãng phí một vòng cho những lỗi hình thức mà chỉ cần nhắc trước là tránh được. Đến vòng cuối vẫn còn lỗi trình bày (step gộp). Cần dựng điều phối, nhiều file, khó hơn cho người mới

**Dùng khi**

Spec có nhiều bảng, sơ đồ, comment chồng lên nhau; tính năng có tiền hoặc phân quyền; chi phí phát hiện muộn cao hơn nhiều so với vài chục phút máy chạy

### Hướng 3: lai, checklist rút gọn lúc viết, verifier độc lập giữ checklist đầy đủ

 

 

**Ưu** (kỳ vọng)

Giữ được phần độc lập tạo ra khoảng cách 4 bẫy, đồng thời bớt được vòng sửa đầu tiên vì bản nháp đã đúng hình thức. Chi phí nằm giữa hai hướng trên

**Nhược**

**Chưa đo.** Có rủi ro chính là giả thuyết "checklist thành cái trần": đưa 5 mục vào lúc viết có thể đủ để agent lại viết vừa đủ tick ô rồi dừng. Phải chạy lại với cùng spec và cùng cách chấm mới biết

**Dùng khi**

Muốn đưa vào quy trình thật sau khi đã có hai baseline trên để so

Bảng gọn để bạn chọn nhanh:

Tiêu chí

Hướng 1

Hướng 2

Hướng 3

Thời gian, token

Thấp

Cao (~3×)

Trung bình (dự kiến)

Phát hiện bẫy spec

6/12

10/12

Chưa đo, kỳ vọng gần hướng 2

Chất lượng hình thức bản nháp đầu

Tốt

Kém

Tốt (dự kiến)

Độ tin của báo cáo chấm

Thấp

Cao

Cao

Độ phức tạp dựng

1 prompt

3 agent + điều phối

3 agent + điều phối

Loại lỗi còn lọt

Lỗi hiểu spec (đắt)

Lỗi trình bày (rẻ)

Chưa biết

### Cách tôi lập luận khi chọn hướng lai để áp dụng

Tôi không chọn hướng 3 vì nó "ở giữa nên chắc an toàn". Tôi đi từng bước như sau, và ghi ra để bạn phản biện.

**Bước 1: tách hai biến số đang đi chung.** Trong thí nghiệm, cách 2 khác cách 1 ở hai chỗ cùng lúc: agent viết không thấy checklist, và người chấm là người khác. Kết quả cho thấy cặp này thắng, nhưng chưa nói được cái nào đóng góp bao nhiêu. Hướng 3 chính là cách tách: giữ nguyên "người chấm là người khác", chỉ thay đổi "agent viết thấy bao nhiêu checklist". Nếu hướng 3 vẫn bắt được 9 đến 10 bẫy thì độc lập là yếu tố chính. Nếu tụt về 6 đến 7 thì giả thuyết "checklist thành cái trần" là thật, và ta phải giữ agent viết mù hoàn toàn.

**Bước 2: phân loại 12 tiêu chí theo thời điểm nó có ích.** Tôi đọc lại từng mục và hỏi: mục này giúp agent viết *tốt hơn* ngay từ đầu, hay chỉ giúp *phát hiện* lỗi sau khi đã viết?

Nhóm

Tiêu chí

Vì sao xếp vào nhóm này

Định hướng lúc viết

Truy vết về requirement, có negative, đủ biên, test data cụ thể, kỳ vọng quan sát được

Đây là **kỹ thuật thiết kế test**. Biết trước thì viết đúng luôn, không biết thì phải sửa hàng chục test case ở vòng sau. Bản nháp đầu của cách 2 trượt đúng những mục này với 25 test case dùng placeholder

Chỉ có ích khi soi lại

Khai báo assumption, dùng đúng thuật ngữ spec, không trùng lặp, priority nhất quán, ID duy nhất, có precondition, mỗi step một hành động

Đây là **kỷ luật rà soát**. Đưa vào lúc viết thì agent tick ô cho có, như cách 1 đã tự cho PASS ở mục assumption dù dùng ngầm 5 hành vi ngoài spec. Chúng cần một con mắt khác

Năm mục nhóm đầu là checklist rút gọn cho agent viết. Bảy mục còn lại chỉ verifier thấy.

**Bước 3: ưu tiên loại lỗi rẻ hơn.** Nếu buộc phải chọn, tôi thà nhận lỗi trình bày còn hơn lỗi hiểu spec. Lỗi trình bày sửa bằng một vòng revise cơ học, thậm chí bằng script. Lỗi hiểu spec phải có người đọc lại từ đầu. Hướng 3 đẩy lỗi về phía rẻ: hình thức được lo từ lúc viết, hiểu spec được verifier độc lập soi.

**Bước 4: giữ những rào chắn đã chứng minh có tác dụng.** Ba thứ tôi không đổi khi chuyển sang hướng 3: verifier chỉ đọc không sửa, verifier tự lập danh sách requirement trước khi mở file test case, và điểm cuối cùng lấy từ judge chấm mù chứ không lấy từ báo cáo verifier. Chính rào chắn thứ hai đã bắt được vụ agent viết báo cáo "đã tách step" trong khi chưa tách.

**Bước 5: định trước ngưỡng thất bại.** Tôi viết sẵn điều kiện để bỏ hướng 3 trước khi chạy, để không tự thuyết phục mình sau khi thấy số: nếu hướng 3 bắt bẫy ít hơn hướng 2 từ 2 bẫy trở lên trên cùng spec, hoặc nếu số vòng verifier không giảm, thì hướng 3 không đáng và quay về hướng 2.

### Khi áp dụng vào quy trình thật

Nếu bạn muốn đưa hướng này vào team, đây là thứ tự tôi khuyên, mỗi bước có một sản phẩm kiểm được:

- **Chốt checklist trước.** Mỗi mục phải PASS hoặc FAIL, FAIL phải kèm ID. Mục nào bạn thấy mình hay đánh "tạm được" thì viết lại cho đến khi không còn "tạm được". Checklist mơ hồ sẽ làm verifier báo sai, và lúc đó lỗi nằm ở checklist chứ không nằm ở kiến trúc.

- **Chạy hướng 1 và hướng 2 trên 3 đến 5 spec thật** của chính team, có gài bẫy bạn đã biết. Đây là baseline. Không có baseline thì mọi tranh luận sau này đều là cảm giác.

- **Đo độ tin của verifier bằng chấm tay** ít nhất 3 spec: đếm số finding verifier nêu ra mà bạn đồng ý trên tổng số finding. Dưới 80% thì quay lại bước 1.

- **Chạy hướng 3** với checklist rút gọn 5 mục cho agent viết, so với baseline bằng cùng judge, cùng đảo vị trí.

- **Giới hạn vòng sửa ở 2** và chấp nhận trạng thái "FAIL còn lỗi hình thức" đưa cho người review, thay vì chạy thêm vòng. Vòng thứ ba trong thí nghiệm chỉ sửa được 2 mục nhỏ mà tốn thêm mười mấy phút.

- **Người review tay đọc mục Assumptions trước**, rồi mới đọc test case. Đó là nơi tập trung mọi câu cần hỏi PO, và là phần AI không thể tự chốt.

Nếu bạn muốn học cách dựng những quy trình như thế này một cách bài bản, từ viết prompt sinh test case, dựng agent kiểm độc lập, đến thiết kế phép đo bằng bẫy, đó chính là nội dung [khóa học AI cho tester](/ai-tester.html) của IT LEARN. Còn nếu chỉ muốn thử ngay tối nay: mở hai cửa sổ chat, và đừng để cửa sổ thứ hai biết cửa sổ thứ nhất đã viết gì.

## Kết luận trong một câu

**Cho AI tự chấm test case của chính nó bằng checklist chất lượng lại kém hơn việc để AI viết "mù checklist" rồi giao một AI khác kiểm độc lập.** Trong thí nghiệm của tôi, cách tự kiểm bỏ lỡ 6/12 mâu thuẫn được gài sẵn trong spec và trượt đúng những mục checklist mà nó được giao để tự bắt. Cách kiểm độc lập bắt được 10/12 bẫy và đạt 11/12 mục checklist.

Nói cách khác: nguyên tắc **tính độc lập trong kiểm thử** mà ISTQB dạy từ chương đầu tiên vẫn đúng nguyên khi "tác giả" là một AI agent. Đổi con người thành AI, nguyên tắc kiểm thử không đổi. Chỉ có tốc độ mắc lỗi là nhanh hơn.

## Câu hỏi thường gặp

### AI có thay thế được tester trong việc viết test case không?

Chưa. Trong thí nghiệm này, cấu hình tốt nhất vẫn bỏ lỡ 2/12 mâu thuẫn spec, và cả hai cách đều không phát hiện được vấn đề hoàn tiền có trả lại lượt dùng hay không. AI viết nháp rất nhanh và khá đầy đủ, nhưng người đọc spec lần cuối và chốt assumption với PO vẫn phải là tester.

### Tôi chỉ dùng ChatGPT, không dựng được multi-agent thì làm sao?

Mở một cuộc hội thoại mới hoàn toàn để chấm. Dán spec, test case và checklist vào, yêu cầu chấm PASS/FAIL từng mục với bằng chứng là ID test case. Chat mới không mang theo thiên kiến "mình vừa viết ra cái này", nên đóng vai người kiểm độc lập tốt hơn hẳn việc hỏi lại trong cùng chat.

### Vậy có nên bỏ hẳn checklist chất lượng đi không?

Không. Checklist vẫn rất cần, chỉ là dùng ở bước kiểm chứ không phải bước sinh. Đưa checklist vào lúc viết dễ khiến AI viết vừa đủ để tick hết ô rồi dừng. Cách 2 trong thí nghiệm không thấy checklist lúc viết nhưng vẫn đạt 11/12 sau khi verifier dùng chính checklist đó soi.

### Làm sao biết bộ test case AI sinh ra có tốt không?

Đừng đếm số lượng test case AI sinh ra. Lấy một spec bạn đã biết rõ các điểm mơ hồ, tự gài thêm vài mâu thuẫn, rồi đếm xem AI phát hiện được bao nhiêu điểm trong số đó. Đồng thời soi mục Assumptions: file nào khai báo được nhiều chỗ spec im lặng thì file đó đã đọc spec kỹ hơn.

### Quy trình hai agent có tốn kém hơn không?

Có, khá nhiều. Trong thí nghiệm này cách tách kiểm độc lập tốn gần gấp ba thời gian so với cách gộp chung, vì thêm hai lượt verifier và hai lượt sửa. Đổi lại là 4 mâu thuẫn spec được phát hiện trước khi code, rẻ hơn nhiều so với phát hiện lúc đã lên production.

