Tôi bắt đầu tin vào multi-agent không phải sau một demo đẹp, mà sau một buổi sửa blog có hơn trăm file markdown, trong đó mỗi file nhìn đơn giản nhưng có state riêng: pubDate, seriesOrder, ngôn ngữ, giọng viết, tracker audit. Một agent làm một file thì ổn. Bốn agent cùng làm, mọi thứ bắt đầu có mùi: hai người cùng chọn một seriesOrder, một người update tracker quá sớm, một người format lại đoạn mà người khác vừa sửa.
Vấn đề không nằm ở chuyện agent “thông minh” hay không. Vấn đề là mình giao việc như giao cho một developer junior cực nhanh, cực chăm, nhưng không có cảm giác ownership tự nhiên nếu mình không ghi rõ boundary. Multi-agent chỉ nhanh hơn khi task được cắt theo đường gãy sạch. Nếu cắt sai, phần “nhanh” biến thành merge conflict, diff review dài hơn cả tự làm.
Đừng chia theo số lượng, chia theo ownership
Sai lầm đầu tiên là nhìn backlog rồi chia đều: “bạn làm bài 1-5, bạn làm bài 6-10”. Cách đó chỉ ổn khi mỗi item độc lập hoàn toàn. Trong codebase thật, dependency thường nằm ở file phụ, config, schema, migration, test helper, hoặc một registry nhỏ mà ai cũng muốn sửa.
Tôi thích chia theo ownership cụ thể hơn:
- Agent A sở hữu
src/content/blog/post-a.mdvà chỉ file đó. - Agent B sở hữu
src/content/blog/post-b.mdvà chỉ file đó. - Lead giữ file tổng hợp như tracker, changelog, release note, route registry.
- Nếu một agent bắt buộc sửa shared file, nó phải báo trước thay vì tự tiện sửa.
Với code cũng tương tự. Đừng giao “làm dashboard”. Hãy giao “sửa component filter trong FilterPanel.tsx, không đụng API hook”, hoặc “thêm validation trong service layer, không đổi response shape”. File ownership không phải bureaucracy. Nó là cách giữ dirty worktree đọc được.
Một prompt giao việc tốt thường có ba phần:
Scope: chỉ sửa src/features/orders/OrderFilters.tsx và test tương ứng.
Boundary: không đổi API endpoint, không sửa shared table component.
Verification: chạy npm test -- OrderFilters và git diff --check trên file đã sửa.
Điểm quan trọng là nói rõ cái gì không được làm. Agent có xu hướng “helpful”: thấy một helper hơi xấu sẽ refactor, thấy import order lệch sẽ sửa, thấy test gần đó fail sẽ “dọn luôn”. Trong một worktree có nhiều người cùng làm, helpful quá là phá.
Song song hóa phần đọc trước khi song song hóa phần sửa
Tôi ít khi cho nhiều agent sửa ngay từ đầu. Cách an toàn hơn là cho chúng đọc các phần khác nhau rồi trả về plan ngắn. Một agent đọc frontend route, một agent đọc API contract, một agent đọc test hiện có. Sau đó lead mới quyết định ai được sửa file nào.
Lý do thực dụng: phần đọc ít gây conflict, nhưng giúp phát hiện boundary sớm. Nếu cả ba agent cùng kết luận “task này đụng shared hook”, tôi sẽ không chia ba nữa. Tôi đổi thành một agent implement, một agent review diff, một agent viết test hoặc kiểm tra regression.
Mẫu chia việc tôi dùng nhiều:
- Research agent: tìm files, endpoints, behavior hiện tại.
- Implement agent: sửa đúng scope đã được chốt.
- Review agent: đọc diff như reviewer khó tính.
- Verify agent: chạy test, build, lint, hoặc manual checklist.
Đây không phải mô hình cao siêu. Nó giống cách team nhỏ làm việc: một người code, một người review, một người giữ release checklist. Khác biệt là AI làm các bước đó nhanh, nên lỗi do giao việc mơ hồ cũng lộ nhanh hơn.
Giữ rollback point trước khi mở rộng blast radius
Trước khi spawn nhiều agent, tôi muốn biết rollback point đang ở đâu. Tối thiểu:
git status --short --branch
git diff --stat
Nếu worktree đã bẩn, phải phân loại: phần nào của user, phần nào của agent trước, phần nào liên quan task hiện tại. Không có bước này thì rất dễ “dọn sạch” nhầm diff người khác. Với repo có nhiều worker, nguyên tắc của tôi là: không revert file mình không sở hữu, không format file ngoài scope, không chạy command tự động rewrite cả repo.
Rollback point không nhất thiết phải là commit. Có khi chỉ là ghi lại danh sách file mình được phép sửa. Nhưng với task rủi ro cao, tôi thích tạo commit nhỏ trước khi chia việc, hoặc ít nhất stash riêng phần không liên quan nếu user cho phép. Không có rollback point, multi-agent giống chạy nhiều script sửa code cùng lúc rồi hy vọng git cứu được.
File shared là bottleneck, không phải chỗ để ai cũng đụng
Trong blog repo, file shared là tracker JSON. Trong frontend app, nó có thể là router, i18n dictionary, generated type, schema barrel, hoặc package.json. Trong backend, nó có thể là migration folder, OpenAPI spec, queue contract.
Nếu nhiều agent phải sửa cùng shared file, tôi thường gom lại thành một bước cuối do lead làm. Các agent chỉ trả về patch intent: “cần thêm route X”, “cần mark post Y edited”, “cần thêm enum Z”. Lead đọc toàn bộ diff rồi cập nhật shared file một lần.
Điều này chậm hơn vài phút nhưng tiết kiệm rất nhiều review. Một shared file bị bốn agent sửa sẽ có conflict cơ học. Tệ hơn, nó có conflict semantic: không conflict text nhưng sai thứ tự, thiếu item, duplicate key, hoặc override field mới.
Task slicing tốt có output kiểm chứng được
Một task giao cho agent nên có output nhỏ và check được. “Cải thiện test strategy” quá rộng. “Thêm test cho case token hết hạn trong refreshSession mà không mock endpoint mới” tốt hơn. Khi output rõ, review cũng rõ:
- File nào thay đổi?
- Behavior nào đổi?
- Contract nào giữ nguyên?
- Test nào chứng minh?
- Nếu rollback, revert file nào?
Tôi tránh giao task kiểu “làm cho sạch hơn” trong multi-agent session. Refactor có thể làm sau, một mình, khi không có người khác đang chạm cùng khu vực. Trong session song song, sạch nghĩa là diff nhỏ, reason rõ, không bất ngờ.
Khi nào không nên dùng nhiều agent
Có những task tôi không chia:
- Migration dữ liệu có side effect thật.
- Sửa auth hoặc permission boundary.
- Refactor xuyên nhiều module mà chưa có test tốt.
- Incident production đang cần một timeline duy nhất.
- Task chưa hiểu rõ input/output.
Multi-agent không thay thế judgment. Nó khuếch đại judgment. Nếu mình chưa biết hệ thống đang hỏng ở đâu, thêm agent có thể tạo thêm giả thuyết, nhưng chưa nên để chúng sửa. Tôi thường dùng nhiều agent ở phase đọc log, so sánh diff, liệt kê regression surface. Đến lúc chạm code nguy hiểm, quay về một implementer và một reviewer.
Prompt thực dụng cho worker
Một prompt tôi dùng nhiều có dạng:
Bạn là worker trong repo này. Nhiều worker khác đang sửa file khác song song.
File ownership của bạn: <list file>.
Không sửa file ngoài list. Không commit, push, deploy.
Mục tiêu: <behavior cụ thể>.
Boundary: <điều không được đổi>.
Sau khi xong chạy: <command verify>.
Báo lại file đã sửa và test result.
Đọc qua thì hơi khô, nhưng nó giảm 80% lỗi operational. Đặc biệt là câu “nhiều worker khác đang sửa file khác song song”. Agent cần biết nó không ở một mình trong codebase. Nếu không nói, nó sẽ hành xử như owner toàn repo.
Review lead vẫn là chốt chặn
Sau khi các worker xong, đừng merge bằng niềm tin. Lead phải đọc:
git status --short
git diff --stat
git diff -- <files>
Tôi nhìn trước tiên vào file list. Nếu có file ngoài scope, dừng. Sau đó nhìn diff shape: có rename lạ không, có format churn không, có generated file không, có log/debug không. Cuối cùng mới đọc logic.
Một dấu hiệu task slicing tốt là review lead nhàm chán: mỗi diff đúng file, đúng behavior, test command rõ. Một dấu hiệu task slicing tệ là review lead phải đọc lại toàn bộ repo để hiểu vì sao agent sửa chỗ đó.
Chia việc cho nhiều agent không phải để biến một task mơ hồ thành nhiều task mơ hồ. Nó chỉ đáng dùng khi bạn có thể vẽ ranh giới đủ rõ để mỗi agent ship một mảnh nhỏ, còn lead giữ contract chung. Tốc độ đến từ boundary, không đến từ số lượng agent.