Async Agent Thực Sự Là Gì?

Nghe bài viết:

conductor-84y5f0fy-260223000924

Hãy thử tìm kiếm cụm từ “async agents” trên mạng. Bạn sẽ thấy hàng chục bài viết sử dụng cụm từ này, và những bài có định nghĩa thì lại nói về những thứ hoàn toàn khác nhau. Nó xuất hiện trong các bài công bố sản phẩm, thread trên HN, blog về kiến trúc hệ thống — luôn được nhắc đến một cách rất tự nhiên, như thể ai cũng hiểu nó có nghĩa là gì. Vì vậy, tôi muốn tìm hiểu xem rốt cuộc định nghĩa nào mới thực sự đúng.

Định nghĩa phổ biến nhất mà tôi thấy là: async agent đơn giản là một agent chạy trong thời gian dài. Một tác vụ chạy lâu tạo cảm giác “async”. Nếu nó vẫn tiếp tục làm việc trong lúc bạn đi vệ sinh hay rót thêm nước, điều đó có vẻ như bất đồng bộ. Đúng là một tác vụ chạy đủ lâu cho bạn cơ hội làm việc khác. Nhưng vậy thì bao lâu mới được tính? Một agent hoàn thành trong một giây so với một agent mất một giờ — cái nào là synchronous, cái nào là async? Tôi có thể biến một agent thành async chỉ bằng cách thêm một câu lệnh sleep trước khi chạy nó không? Cách định nghĩa này không thực sự thuyết phục.

Một định nghĩa khác tôi thường gặp là: async agent là agent chạy trên cloud. Devin chạy từ xa nên nó async. Claude Code chạy local nên không. Nhưng nếu tôi spin up một EC2, SSH vào, cài Claude Code và chạy ở đó thì tôi vừa biến nó thành async agent à? Công cụ không thay đổi. Chỉ có máy chạy nó thay đổi. Điều đó chắc chắn không phải bản chất vấn đề.

Định nghĩa thứ ba là: async agent là agent hướng sự kiện (event-driven). Những agent tự kích hoạt mà không cần bạn. PR được merge và agent chạy. Cron job kích hoạt và agent nhắn Slack cho bạn. Điều đó có vẻ async vì bạn không trực tiếp gõ lệnh tại thời điểm đó. Nhưng cron job có thể chạy bất kỳ chương trình nào. Trigger có thể là async, nhưng điều đó không làm chương trình nó chạy trở thành async. Đó là vấn đề scheduling, không phải thuộc tính nội tại của agent.

Không định nghĩa nào hoàn toàn sai. Nhưng cũng không định nghĩa nào thực sự là định nghĩa. Chúng chỉ mô tả các đặc tính có liên quan đến thứ mà mọi người đang cố chỉ ra. Vậy hãy quay lại những điều cơ bản.


Agent Là Gì? Async Là Gì?

Như Simon Willison từng nói, một agent đơn giản là một LLM chạy tool trong một vòng lặp. Tôi muốn đi xa hơn một chút: agent cần có tính liên tục của ngữ cảnh (context continuity). Nếu tôi mở hai session Claude Code khác nhau, đó là hai agent khác nhau. Nếu tôi gõ /clear trong một session, tôi vừa “giết” một agent và sinh ra một agent mới. Chính context làm nên “agent đó”.

Còn về bất đồng bộ (asynchrony). Định nghĩa kỹ thuật nói rằng đó là khi các sự kiện xảy ra độc lập với luồng chính của chương trình. Điểm mấu chốt là: một hàm async không tự nhiên là async. Nó async tương đối với caller. Nếu caller không chờ, hàm chạy độc lập. Nếu caller chờ, nó trở thành synchronous. Phần “async” không nằm ở bản thân hàm, mà nằm ở quyết định của caller có block hay không.

Hãy nghĩ lại thời chưa có agent. Bạn gõ; công việc diễn ra. Bạn ngừng gõ; công việc dừng lại. Bạn chỉ có thể tiến triển một tác vụ tại một thời điểm, tất cả đều synchronous.

Khi coding agent xuất hiện, chúng mở ra điều mới: khả năng làm việc bất đồng bộ. Bạn có thể giao việc và không chờ nó hoàn thành. Bạn giao task cho agent, đi ăn trưa, quay lại thấy PR đã xong. Lần đầu tiên, công việc có thể tiến triển trong khi bạn làm việc khác.

Nhưng điều đó không khiến agent trở thành async một cách nội tại. Bạn hoàn toàn có thể hỏi agent một câu hỏi nhanh và chờ câu trả lời. Lúc đó bạn dùng nó theo cách synchronous. Agent không thay đổi. Hành vi của bạn thay đổi.

Vậy “async agent” mà mọi người nhắc đến là gì? Nó nằm trong con mắt người nhìn. Async agent thực sự là… những người bạn chúng ta tạo ra trên hành trình này.

Nhưng nói nghiêm túc: không có agent nào tự thân là async. Tất cả phụ thuộc vào việc bạn có chờ nó hay không.


Sử Dụng Agent Theo Cách Bất Đồng Bộ

Nếu bạn chọn dùng agent theo cách async, bạn mở khóa một thứ rất mạnh: concurrency. Bạn có thể giao nhiều tác vụ cho nhiều agent và để chúng tiến triển song song. Nhưng khi làm vậy, bạn gặp một vấn đề thực tế: tất cả đang làm việc trên cùng một codebase trên máy bạn. Đó không phải cách đội kỹ sư thật sự vận hành. Mỗi người có máy riêng, bản sao code riêng, branch riêng.

Tại sao không cho tất cả cùng chỉnh sửa một codebase theo thời gian thực, như Google Docs? Có vẻ như sẽ loại bỏ merge conflict, branch divergence — mọi thứ Git khiến bạn đau đầu. Nhưng collaborative coding đã được thử (Replit từng làm điều này) và không phổ biến vì một lý do rõ ràng: thiếu isolation. Công việc dang dở của một người có thể phá vỡ code đang chạy của người khác. Mỗi task cần môi trường riêng để build, test và validate độc lập.

Agent cũng vậy. Chúng cần bản sao code riêng để không giẫm chân nhau. Đó là lý do Conductor và Omnara dùng git worktrees, Boris (creator của Claude Code) clone cả thư mục, và các app như Codex Web hay Sculptor dùng VM hoặc container riêng. Mỗi agent có workspace riêng để tiến triển độc lập.

Khi có workspace tách biệt, bạn là manager. Bạn spawn agent, theo dõi agent, điều phối agent. Giao việc cho agent là force multiplier rất lớn. Nó tăng output đáng kể, nhưng cũng tăng lượng context bạn phải quản lý và chuyển đổi giữa chúng. Có một trần giới hạn.

Vậy câu hỏi đặt ra: agent có thể quản lý các agent khác không?


Vậy “Async Agent” Nên Có Nghĩa Gì?

Thành thật mà nói, có lẽ chúng ta không nên dùng thuật ngữ này. Nhưng nếu đã dùng, nó nên có nghĩa gì đó không phải vốn đã đúng với mọi agent.

Trong lập trình, có sự khác biệt giữa async function và async runtime. Async function có thể chạy mà không block caller. Async runtime là thứ quản lý event loop: spawn function, schedule chúng, điều phối kết quả. Function chỉ là “người được quản lý”. Runtime mới là kẻ điều phối.

Agent map vào điều này hoàn hảo. Mọi agent ngày nay đều giống async function. Bạn gọi nó, nó chạy, bạn đi làm việc khác. Nhưng async agent — theo nghĩa có ý nghĩa — là runtime. Đó là agent quản lý event loop của các agent khác.

Bạn giao một task; nó spin up subagent trong background workspace và vẫn tiếp tục tương tác với bạn. Bạn yêu cầu build login page. “OK.” Nó giao việc đó cho agent khác. Bạn yêu cầu billing page. “Được, và tiện thể, agent login hỏi bạn thích GitHub hay Google OAuth?” Bạn không phải mở 10 tab hay quản lý 10 session. Agent đang quản lý team. Bạn nói chuyện với một thực thể duy nhất, và thực thể đó điều phối những thực thể khác.

Bạn không còn là developer. Bạn không còn là manager. Bạn chỉ là người có ý định, và agent lo phần còn lại.

Đã có những thử nghiệm ban đầu theo mô hình này. Claude Agent Teams và Gastown là ví dụ sớm. Bài “Don't Build Multi-Agents” của Cognition giải thích vì sao điều này còn khó: chia sẻ context, chi phí token, suy luận giữa agent chưa ổn định. Nhưng đó là rào cản kỹ thuật, không phải kiến trúc. Khi model rẻ hơn, context window lớn hơn, giao tiếp agent-to-agent tốt hơn, kiến trúc này sẽ không còn thử nghiệm mà sẽ trở thành mặc định.

Trong lập trình, ta phân biệt async runtime với chương trình tuần tự vì runtime quản lý thực thi đồng thời: spawn function, schedule, điều phối kết quả, xử lý event loop, callback, shared state. Chương trình tuần tự thì không.

Sự phân biệt tương tự áp dụng cho agent. Một agent spawn subagent, quản lý thực thi của chúng, chia sẻ context và điều phối kết quả là một kiến trúc khác hoàn toàn so với agent chỉ tự mình hoàn thành task.

Vì vậy, nếu bạn gọi thứ gì đó là “async agent”, hãy dùng nó theo nghĩa đó. Không phải agent chạy lâu. Không phải agent chạy trên cloud. Không phải agent được cron job kích hoạt. Mà là agent quản lý các agent khác một cách đồng thời. Mọi thứ khác chỉ là agent mà bạn tình cờ không chờ nó.


Chú thích

Bài viết về FastAPI là nơi tôi lần đầu thực sự hiểu về async programming. Vẫn là một trong những bài giải thích hay nhất.