Phát triển / Debug

Debug với AI agent: tái hiện lỗi, tìm nguyên nhân, kiểm thử

Một bản sửa đáng tin cần giải thích được vì sao lỗi xảy ra và có cách kiểm tra lại. Với AI agent, hãy giữ vòng lặp ngắn: tái hiện, đặt giả thuyết, kiểm chứng rồi mới sửa.

Trong bài này

1. Ghi trạng thái trước khi thử sửa

Ghi phiên bản mã, môi trường, đầu vào, kết quả mong đợi và lỗi nguyên văn. Xác định lỗi luôn xảy ra hay phụ thuộc thời điểm, tài khoản hoặc dữ liệu. Nếu không tái hiện được, thu thập thêm bằng chứng trước khi thay nhiều thành phần.

systematic-debugging giúp giữ thứ tự này. Cài và đọc runbook trước; sau đó giao cho agent một phạm vi hẹp:

Điều tra lỗi tổng giỏ hàng bỏ qua số lượng sản phẩm.
Trước tiên tạo ca tái hiện nhỏ nhất và ghi expected/actual.
Đưa ra một giả thuyết kèm bằng chứng trước khi sửa.
Không đổi dependency hoặc refactor phần ngoài phạm vi.
Sau bản sửa, chạy lại ca lỗi và kiểm tra các trường hợp liên quan.

2. Tạo ca lỗi tối thiểu

Đây là ví dụ Python minh họa, dùng giá nguyên theo đơn vị xu và số lượng nguyên không âm. Nó chỉ tính tiền hàng, chưa bao gồm thuế, giảm giá hay kiểm tra dữ liệu đầu vào. Lưu đoạn sau vào tệp thử riêng và chạy bằng Python 3 thông thường; assertion phải thất bại.

def cart_total(items):
    return sum(item["price_cents"] for item in items)


items = [{"price_cents": 1250, "quantity": 2}]
assert cart_total(items) == 2500

Actual là 1.250; expected là 2.500. Ca lỗi không cần database, API hay UI nên có thể kiểm tra nhanh. Trong dự án thật, giữ ca tối thiểu đủ thể hiện lỗi và lưu fixture theo quy ước test hiện có.

3. Kiểm tra một giả thuyết tại một thời điểm

Giả thuyết cụ thể: hàm chỉ cộng price_cents, không đọc quantity. Thay số lượng 2 bằng 3 mà kết quả không đổi sẽ củng cố giả thuyết. Đọc luồng dữ liệu để xác nhận giá truyền vào là đơn giá, chưa phải thành tiền của dòng.

Nếu upstream đã nhân số lượng, thêm phép nhân ở đây có thể tạo lỗi mới. Vì vậy, cần đối chiếu hợp đồng dữ liệu hoặc test của nơi gọi. Với lỗi nhiều tầng, theo dấu một đầu vào qua từng ranh giới và tránh ghi token, thông tin đăng nhập hoặc dữ liệu riêng vào log.

4. Sửa đúng nguyên nhân và giữ kiểm tra hồi quy

Với hợp đồng dữ liệu đã nêu, bản sửa nhỏ là nhân đơn giá với số lượng cho từng dòng. Đoạn sau có cả ca ban đầu và kiểm tra giỏ trống, nhiều dòng:

def cart_total(items):
    return sum(
        item["price_cents"] * item["quantity"]
        for item in items
    )


assert cart_total([{"price_cents": 1250, "quantity": 2}]) == 2500
assert cart_total([]) == 0
assert cart_total([
    {"price_cents": 1250, "quantity": 2},
    {"price_cents": 300, "quantity": 3},
]) == 3400

Đưa assertion vào bộ test hiện có của dự án để nó chạy trong CI. Tránh thêm một framework chỉ để kiểm tra phép tính này. Với sửa đổi ảnh hưởng hợp đồng API hoặc nhiều tầng, chạy thêm các test tương ứng; ghi rõ nếu chưa có môi trường thực hiện.

5. Bàn giao cả bằng chứng và giới hạn

Báo cáo nên nêu ca lỗi trước sửa, nguyên nhân, phần mã thay đổi và các kiểm tra đã chạy sau sửa. Nếu chỉ kiểm tra hàm thuần, đừng mô tả rằng toàn bộ checkout hoặc thanh toán đã được xác minh.

Review diff cuối để loại thay đổi thừa và xác nhận không bỏ mất logging hoặc test tạm cần chuyển thành regression test. Một ví dụ thực phức tạp hơn là race condition khi VAS cập nhật manifest JSON; ở đó, kiểm tra phải điều khiển thời điểm giữa các tiến trình.

Đọc thêm