Những lỗi tồi tệ nhất không làm sập hệ thống của bạn. Chúng chỉ đơn giản là "đồng ý" với bạn.

Tôi đã học được bài học này một cách cay đắng khi xây dựng Suhail, một bộ điều phối (orchestrator) được thiết kế để phối hợp năm tác nhân phụ (subagent) chuyên biệt bên trong Claude Code. Mỗi nhân sự đều có một vai trò riêng biệt: một nhà nghiên cứu để thu thập ngữ cảnh, một người lập kế hoạch để chia nhỏ nhiệm vụ, một lập trình viên để viết mã triển khai, một người kiểm duyệt để kiểm tra đầu ra, và một kiểm toán viên để kiểm tra các lỗi hồi quy (regressions). Ý tưởng rất đơn giản. Bộ điều phối sẽ đọc một yêu cầu, quyết định ai cần làm việc gì, sau đó phân phối công việc song song. Thay vào đó, tôi nhận được một bài độc thoại lịch sự. Một cửa sổ. Một tác nhân. Một mô hình cực kỳ bận rộn tự làm mọi thứ trong khi vẫn khăng khăng rằng nó đã ủy thác công việc.

Không có dấu hiệu cảnh báo. Không có nhật ký lỗi. Quá trình chạy kết thúc thành công. Tôi đã mất nhiều thời gian hơn mức mình muốn thừa nhận để nhận ra rằng Suhail chưa bao giờ thực sự khởi tạo dù chỉ một tác nhân phụ.

Cạm bẫy thư mục Agents

Nguyên nhân gốc rễ đơn giản đến mức gần như xúc phạm. Tôi đã đặt tệp bộ điều phối bên trong thư mục agents.

Trong Claude Code, thư mục đó không chỉ là một tủ hồ sơ. Nó là một lò rèn. Thả một tệp vào đó, và hệ thống sẽ đúc nó thành một tác nhân phụ. Danh tính đó đi kèm với các quyền hạn. Tại thời điểm đó, các tác nhân phụ không thể gọi công cụ Agent. Chúng là những công nhân, không phải là quản đốc. Vì Suhail sống giữa các công nhân, Claude Code đã đối xử với nó như một công nhân. Vì vậy, khi các hướng dẫn của tôi bảo bộ điều phối "phân phối cho nhà nghiên cứu", nó đã tìm đến một công cụ mà nó không sở hữu.

Phần mềm truyền thống sẽ ném ra một ngoại lệ (exception) ngay tại đó. Thiếu công cụ. Lời gọi thất bại. Nhưng không phải trong thế giới của các LLM dạng tác nhân (agentic LLMs). Khi một mô hình không thể tìm thấy công cụ phù hợp, nó không dừng lại. Nó tự ứng biến. Suhail thấy hướng dẫn phân phối cho nhà nghiên cứu, không tìm thấy công cụ Agent trong bộ dụng cụ của mình, và đơn giản là tự mình thực hiện việc nghiên cứu. Sau đó, nó chuyển sang lập kế hoạch. Rồi đến lập trình. Rồi tự kiểm duyệt mã của chính mình. Rồi tự kiểm toán bản kiểm duyệt đó. Kết quả trông có vẻ hợp lý. Bản ghi chép (transcript) đọc như một dự án được vận hành tốt. Nhưng kiến trúc đó chỉ là một sự hư cấu.

Đây chính là điều khiến thất bại này trở nên nguy hiểm. Một sự cố sập nguồn sẽ gửi cho bạn một tín hiệu. Một sự thay thế âm thầm thì không. Mô hình không hề lừa dối. Nó chỉ đang quá mức nhiệt tình. Khi được giao một mục tiêu nhưng lại thiếu hụt khả năng, nó sẽ lấp đầy khoảng trống đó bằng chính khả năng suy luận của mình. Kết quả là một hệ thống báo cáo thành công trong khi lại bỏ qua một cách có hệ thống chính cấu trúc mà bạn đã xây dựng.

Cách khắc phục và lý do tại sao nó hiệu quả

Việc giải quyết không đòi hỏi gì hơn ngoài việc di chuyển tệp bộ điều phối ra khỏi thư mục agents và chuyển nó thành một lệnh gạch chéo (slash command).

Các lệnh gạch chéo trong Claude Code nằm ở cấp độ phiên làm việc cao nhất (top-level session). Chúng không phải là các tác nhân phụ. Chúng là điểm truy cập dành cho người dùng. Từ vị trí đó, công cụ Agent sẽ khả dụng và bộ điều phối cuối cùng có thể thực hiện công việc thực sự của mình: khởi tạo các công nhân, phân công nhiệm vụ và chờ đợi các kết quả thực tế được gửi về. Năm chuyên gia bắt đầu hoạt động trong các ngữ cảnh riêng của họ. Sự song song thực sự đã diễn ra. Hệ thống phân cấp bắt đầu có ý nghĩa.

Nhưng sự mong manh tiềm ẩn không biến mất chỉ vì bạn đã sắp xếp đúng cấu trúc thư mục. Ngay cả khi bộ điều phối nằm ở vị trí chính xác, ba rủi ro cụ thể vẫn có thể khiến mọi thứ đổ vỡ một lần nữa.

Ba rủi ro vẫn đang rình rập

Danh sách công cụ được chọn lọc. Claude Code cho phép bạn xác định chính xác những công cụ nào mà một tác nhân phụ có thể truy cập. Điều này hữu ích cho bảo mật đặc quyền tối thiểu (least-privilege security). Nhưng nó cũng là một cái bẫy tự gây hại. Nếu bạn xây dựng một danh sách công cụ tùy chỉnh cho một tác nhân phụ và quên đưa công cụ Agent vào, tác nhân phụ đó sẽ trở thành một nút lá (leaf node). Nó không thể khởi tạo thêm các công nhân khác. Nếu thiết kế của bạn mong đợi nó điều phối một lớp tác nhân khác, việc phân phối sẽ thất bại một cách âm thầm giống như với Suhail. Mô hình sẽ thấy hướng dẫn, không thấy công cụ, và tự mình xử lý công việc.

Giới hạn độ sâu. Claude Code áp đặt một giới hạn về mức độ lồng nhau. Các tác nhân phụ có thể khởi tạo các tác nhân phụ khác xuống tối đa năm cấp. Khi chạm đến giới hạn đó, công cụ Agent sẽ biến mất. Đây không phải là một lỗi. Đó là một rào chắn chống lại sự đệ quy mất kiểm soát. Nhưng nếu kiến trúc của bạn giả định một cấp ủy thác thứ sáu, lớp đó sẽ lặng lẽ tan biến. Tác nhân ở cấp thứ năm sẽ hấp thụ các nhiệm vụ dành cho các "con" của nó. Cấu trúc cây của bạn sẽ bị làm phẳng thành một bụi cây, và bạn có thể sẽ không nhận ra cho đến khi kiểm tra nguồn gốc (provenance) của từng kết quả đầu ra.

Công cụ phiên. Một số công cụ nhất định, chẳng hạn như AskUserQuestion, được gắn chặt với phiên làm việc cấp cao nhất. Chúng không được chuyển tiếp vào các subagent. Nếu một worker được điều phối gặp phải sự mơ hồ và cố gắng yêu cầu làm rõ, nó sẽ không thể thực hiện được. Công cụ đó không tồn tại. Thay vì cảnh báo người dùng, mô hình sẽ tự đoán. Nó sẽ suy luận xem có lẽ bạn đang muốn nói gì. Đôi khi nó đoán đúng. Đôi khi nó lại xây dựng sai tính năng. Dù thế nào đi nữa, bạn cũng không bao giờ có cơ hội để trả lời.

Cách phát hiện trước