Mở đầu: Track B bắt đầu — khi 1 agent không còn đủ

Track C (Bài 7–9) xây một Agent hoàn chỉnh: có tool, có memory, biết tự suy luận từng bước. Nhưng nhiều bài toán thực tế cần chia nhỏ theo VAI TRÒ — một agent lên kế hoạch, một agent viết code, một agent phản biện — thay vì nhồi tất cả trách nhiệm vào 1 agent duy nhất. Bài này mở Track B: điều phối nhiều agent cùng lúc.

Từ bài này, series dùng file dùng chung mới aisys-orchestrator.js — tách biệt khỏi aisys-agent-kernel.js của Track C, vì đây là một lớp trách nhiệm khác: điều phối GIỮA các agent, không phải logic BÊN TRONG 1 agent.


📚 Điều kiện tiên quyết
Nên đã đọc Bài 9 để hiểu 1 agent đơn hoạt động ra sao trước khi ghép nhiều agent lại. Bài này không yêu cầu dùng lại code Track C — các "agent vai trò" ở đây là bản rút gọn (rule-based) để tập trung vào KIẾN TRÚC điều phối.

1. Vì Sao Một Agent Không Đủ Cho Task Phức Tạp

Khi giao 1 agent duy nhất một nhiệm vụ nhiều bước (lên kế hoạch, viết code, tự kiểm tra lại), nó phải "đóng nhiều vai" trong cùng 1 lượt suy luận — dễ bỏ sót bước (ví dụ quên tự phản biện code của chính mình, vì không có góc nhìn "bên ngoài"). Chia theo vai trò (Planner/Executor/Critic) giúp mỗi agent tập trung đúng 1 trách nhiệm, và quan trọng hơn: Critic đóng vai trò kiểm tra ĐỘC LẬP, không bị "thiên vị" bởi chính lý luận đã dùng để viết ra code đó.

2. Message Passing Giữa Agent

Các agent không gọi hàm trực tiếp lẫn nhau — chúng giao tiếp qua message: một cấu trúc dữ liệu có người gửi, người nhận, và nội dung. Đây là nền tảng để sau này (Bài 11) nhiều agent có thể ghi vào một trạng thái chung (blackboard) mà không phụ thuộc cứng vào lời gọi hàm của nhau:

message-bus.js
class MessageBus {
  constructor() { this.log = []; }
  send(from, to, content) {
    const msg = { id: this.log.length, from, to, content };
    this.log.push(msg); // toàn bộ lịch sử giao tiếp được ghi lại — dễ audit
    return msg;
  }
  history() { return this.log; }
}
💡 Mẹo: Log message = "hộp đen" gỡ lỗi hệ multi-agent
Vì các agent không gọi hàm trực tiếp, cách DUY NHẤT để hiểu "tại sao hệ thống ra kết quả này" là đọc lại lịch sử message. Luôn giữ nguyên vẹn history() (không xoá, không ghi đè) — đây chính là "hộp đen" giúp bạn tái hiện lại toàn bộ quá trình phối hợp khi cần điều tra sự cố, giống hệt log của MessageBus hiển thị ở demo mục 5.

3. Điều Phối Tập Trung vs Phi Tập Trung

Có 2 cách tổ chức luồng giao tiếp: tập trung — mọi message đi qua 1 "orchestrator" trung gian quyết định ai nói với ai tiếp theo; và phi tập trung — các agent gửi thẳng cho nhau, tự thoả thuận thứ tự:

routing-modes.js
function relay(bus, from, to, content, mode) {
  if (mode === "centralized") {
    bus.send(from, "Orchestrator", content); // agent -> orchestrator
    bus.send("Orchestrator", to, content);   // orchestrator -> agent đích
  } else {
    bus.send(from, to, content); // gửi thẳng, 1 message duy nhất
  }
}
Tiêu chí Tập trung (Centralized) Phi tập trung (Decentralized)
Ai quyết định thứ tự 1 orchestrator trung tâm Từng agent tự quyết định gửi cho ai
Dễ giám sát/audit Dễ — mọi thứ đi qua 1 điểm Khó hơn — phải gộp log từ nhiều nguồn
Chi phí giao tiếp Cao hơn (gấp đôi số message, xem demo mục 5) Thấp hơn
Điểm lỗi duy nhất (SPOF) Có — orchestrator sập là toàn hệ dừng Không có 1 điểm lỗi trung tâm

Ví dụ kiến trúc thật: AutoGen (Microsoft) nghiêng về mô hình "group chat" phi tập trung hơn, trong khi CrewAI có chế độ "hierarchical" gần với điều phối tập trung — cả hai sẽ được so sánh sâu hơn ở Bài 12.

4. Cạm Bẫy: Over-Engineering Multi-Agent

🕳️ Cạm bẫy: Thêm agent không tương xứng lợi ích
Multi-agent KHÔNG phải lựa chọn mặc định tốt hơn 1 agent đơn. Mỗi agent thêm vào đồng nghĩa với thêm message qua lại, thêm độ trễ (mỗi vòng phải chờ agent trước xong), và thêm chi phí (mỗi agent có thể là 1 lệnh gọi model riêng). Với một tác vụ mà 1 agent đơn đã đủ năng lực xử lý trong 1 bước, việc chia thành 3 agent chỉ tạo ra 5+ message trao đổi để hoàn thành việc lẽ ra xong ngay — đúng như con số demo mục 5 cho thấy. Chỉ dùng multi-agent khi có LÝ DO KIẾN TRÚC rõ ràng (cần góc nhìn độc lập để phản biện, cần chuyên môn hoá vai trò, cần song song hoá công việc) — không phải vì "nhiều agent nghe có vẻ AI hơn".
estimate-coordination-overhead.js
function estimateOverhead(agentCount, avgLatencyMsPerAgent, routingMode) {
  const messagesPerRound = routingMode === "centralized" ? agentCount * 2 : agentCount;
  const totalLatencyMs = messagesPerRound * avgLatencyMsPerAgent;
  return { messagesPerRound, totalLatencyMs };
}

// 1 agent đơn xử lý xong trong 1 bước ~ avgLatencyMs.
// 3 agent phi tập trung: 3x message, ~3x độ trễ.
// 3 agent tập trung: 6x message, ~6x độ trễ — GẤP ĐÔI so với phi tập trung,
// cho CÙNG một công việc — cái giá cụ thể của "dễ giám sát hơn" ở mục 3.

5. Thực hành tương tác: Planner–Coder–Critic

Chạy 1 vòng phối hợp 3 agent viết hàm cộng 2 số kèm validate — Coder cố tình "quên" validate ở lần đầu để bạn thấy rõ vòng phản hồi (feedback loop) khi Critic từ chối. Đổi chế độ điều phối để so sánh số lượng message:

🧩 Planner–Coder–Critic
🗺️ Planner
💻 Coder
🔍 Critic
aisys-multiagent-lab.js (trích)
import { MessageBus, definePlanner, defineCoder, defineCritic, runMultiAgentRound } from "./aisys-orchestrator.js";

const bus = new MessageBus();
const steps = runMultiAgentRound(bus, { planner, coder, critic }, task, routingMode);
// centralized luôn tốn ĐÚNG GẤP ĐÔI số message so với decentralized

Bài 11 sẽ thêm Blackboard — một không gian trạng thái CHUNG mà mọi agent cùng đọc/ghi, thay vì chỉ gửi message điểm-tới-điểm như bài này.

Tải file code thực hành minh họa bài học

File JavaScript aisys-orchestrator.jsMessageBus và 3 agent vai trò Planner/Coder/Critic dùng trong bài, cùng aisys-multiagent-lab.js wiring demo:

Tải về aisys-orchestrator.js

📖 Tài liệu tham khảo

Bài viết liên quan trong series

Bài 9: ReAct Loop, Callback & Streaming Bài 11: Blackboard Pattern & Shared State Quay lại Lộ trình Kỹ Thuật Hệ Thống AI

Bình luận