Sửa bug API với agent
Dùng agent trong VS Code để tái hiện một bug phân trang, viết regression test thất bại, sửa tối thiểu và rà soát thay đổi trước khi commit.
This content is currently available in Vietnamese only.
Phần lớn công việc phần mềm bắt đầu từ code có sẵn và một báo cáo bug. Bài này tóm tắt tutorial của VS Code: dùng AI agent để điều tra vì sao một API phân trang bỏ sót bản ghi, thêm regression test chứng minh bug, sửa có trọng tâm rồi kiểm chứng kết quả.
API mẫu nằm gọn trong một file và chỉ dùng module có sẵn của Node.js, để bạn tập trung vào quy trình (workflow) debug. Quy trình này áp dụng y như vậy cho dự án lớn hơn.
Chuẩn bị
- Cài VS Code và bật tính năng AI.
- Cài Node.js 22 trở lên.
- Cài Git và cấu hình để commit được.
Dựng API mẫu
-
Tạo thư mục và khởi tạo Git:
bashmkdir pagination-bug cd pagination-bug git init -
Mở thư mục
pagination-bugtrong VS Code (File > Open Folder). -
Tạo file
issues-api.jsvới nội dung sau:javascriptconst assert = require("node:assert/strict"); const http = require("node:http"); const { test } = require("node:test"); const PORT = 3000; const PAGE_SIZE = 10; const issues = Array.from({ length: 35 }, (_, index) => ({ id: index + 1, title: `Issue ${index + 1}`, })); function getIssues(requestUrl) { const url = new URL(requestUrl, `http://localhost:${PORT}`); const pageParameter = url.searchParams.get("page"); const page = pageParameter === null ? 0 : Number(pageParameter); if ( pageParameter !== null && (!Number.isInteger(page) || page < 1) ) { return { status: 400, body: { error: "page must be a positive integer" }, }; } const start = page * PAGE_SIZE; const requestedPage = pageParameter === null ? 1 : page; return { status: 200, body: { page: requestedPage, pageSize: PAGE_SIZE, total: issues.length, issues: issues.slice(start, start + PAGE_SIZE), }, }; } function createServer() { return http.createServer((request, response) => { const requestUrl = request.url ?? "/"; const url = new URL(requestUrl, `http://localhost:${PORT}`); let result; if (request.method === "GET" && url.pathname === "/issues") { result = getIssues(requestUrl); } else { result = { status: 404, body: { error: "not found" }, }; } response.writeHead(result.status, { "Content-Type": "application/json", }); response.end(JSON.stringify(result.body, null, 2)); }); } const command = process.argv[2]; if (command === "serve") { createServer().listen(PORT, () => { console.log(`Issues API listening on http://localhost:${PORT}`); }); } else if (command === "test") { test("default request returns the first page", () => { const result = getIssues("/issues"); assert.equal(result.status, 200); assert.deepEqual( result.body.issues.map((issue) => issue.id), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ); }); test("page numbers must be positive integers", () => { assert.equal(getIssues("/issues?page=0").status, 400); }); } else { console.error("Usage: node issues-api.js <serve|test>"); process.exitCode = 1; } -
Chạy test có sẵn bằng
node issues-api.js test. Cả hai test đều pass, nhưng test pass không chứng minh phần chưa được test là đúng. -
Commit điểm xuất phát để phân biệt thay đổi của agent với code mẫu:
bashgit add issues-api.js git commit -m "Add pagination bug sample"
Tái hiện bug
Báo cáo bug: GET /issues trả issue 1-10, nhưng GET /issues?page=2 trả 21-30 thay vì 11-20. Bỏ page phải cho kết quả giống page=1.
Hãy tự kiểm chứng trước khi nhờ agent sửa. Mở terminal, chạy node issues-api.js serve, rồi ở terminal khác gọi trang 2:
node -e "fetch('http://localhost:3000/issues?page=2').then(r => r.json()).then(d => console.log(d.issues.map(i => i.id)))"
Kết quả trả về các ID 21 tới 30, xác nhận bug (gọi không có page thì ra đúng 1-10). Nhấn Ctrl+C để dừng API. Có triệu chứng tái hiện được và kết quả mong đợi giúp agent điều tra đúng lỗi thay vì đoán "phân trang hỏng" nghĩa là gì.
Nhờ agent điều tra trước
Đừng yêu cầu sửa ngay; để agent điều tra trước để bạn xem nó hiểu đúng chưa. Mở Chat view, chọn Agent và gửi:
Investigate this pagination bug. Do not edit files yet.
GET /issues returns IDs 1-10, but GET /issues?page=2 returns
IDs 21-30. The API uses one-based page numbers, so page 2
should return IDs 11-20. Omitting page should match page=1.
Run the existing tests, trace the request through the relevant
code, explain the cause with file references, and propose a
regression test.
Một chẩn đoán thuyết phục cần giải thích được cả hai phản hồi (response) quan sát được, nối số trang bắt đầu từ 1 của API với offset mảng bắt đầu từ 0, chỉ ra vì sao test hiện có vẫn pass, và không đề xuất thay đổi không liên quan. Nếu chưa khớp với các ID quan sát được, đưa output lệnh cho agent và yêu cầu điều tra tiếp.
Thêm regression test thất bại
Regression test chứng minh bộ test bắt được bug và cho agent một điều kiện thành công cụ thể. Yêu cầu agent chỉ thêm test, chưa sửa code production:
Add regression coverage in the existing test block, but do not
change getIssues or other production code yet.
Verify that:
- /issues?page=1 returns the same issue IDs as /issues
- /issues?page=2 returns IDs 11-20
Run the tests and confirm that the new coverage fails because the
returned IDs are wrong, not because of a test setup error.
Assertion mới phải fail với ID mong đợi và ID thực tế khác nhau; test chỉ kiểm HTTP status thì không tái hiện được bug. Nếu agent lỡ sửa cả phần hiện thực (implement), khôi phục checkpoint trước và gửi lại yêu cầu với phạm vi hẹp hơn.
Sửa và chạy test
Fix the root cause of the pagination bug with the smallest
production-code change. Keep the public API one-based, preserve
the existing response shape and validation, and do not add
dependencies. Run the complete test suite after the change.
Xác nhận cả regression test lẫn test cũ đều pass. Cách sửa đúng dùng số trang bắt đầu từ 1 ở ranh giới API và đổi sang offset bắt đầu từ 0 khi cắt mảng; cách khác tương đương cũng được nếu giữ nguyên hợp đồng API và pass test. Nếu còn test fail, đưa toàn bộ output cho agent và yêu cầu giải thích chỗ lệch trước khi sửa tiếp.
Kiểm tra các trang biên
Chạy lại API và gọi các trang 1, 2, 4, 5:
node -e "(async () => { for (const p of [1, 2, 4, 5]) { const d = await fetch('http://localhost:3000/issues?page=' + p).then(r => r.json()); console.log('page ' + p + ':', d.issues.map(i => i.id)); } })()"
Kết quả mong đợi:
page 1: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
page 2: [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]
page 4: [ 31, 32, 33, 34, 35 ]
page 5: []
Không có ID bị thiếu hay trùng, trang cuối thiếu phần tử vẫn giữ nguyên, trang vượt quá dữ liệu thì rỗng. Nhấn Ctrl+C để dừng API.
Rà soát thay đổi
Mở view Source Control, chọn issues-api.js để xem diff và kiểm tra:
- Regression test thể hiện hợp đồng API đã mô tả, không phụ thuộc chi tiết hiện thực.
- Bạn đã thấy test fail trước khi sửa và pass sau khi sửa.
- Thay đổi production chỉ sửa phép tính offset, không đổi cấu trúc phản hồi, validation hay dữ liệu mẫu.
- Agent không thêm dependency hay refactor không liên quan.
- Toàn bộ test và các lần kiểm tra biên thủ công đều pass.
Nếu diff có thay đổi không liên quan, nhờ agent hoàn tác rồi chạy lại test. Sau đó commit:
git add issues-api.js
git commit -m "Fix issue pagination"
Bằng cách xác lập hành vi mong đợi trước khi sửa code production, bạn có bằng chứng cho chẩn đoán, có regression test bảo vệ hành vi và giữ thay đổi gọn, dễ review.
Tài liệu liên quan
Nguồn
- Tóm tắt từ https://raw.githubusercontent.com/microsoft/vscode-docs/main/docs/agents/guides/fix-a-bug-with-agents.md, giấy phép CC-BY-3.0-US.