Series 4 - Bài 4: Agent Communication Patterns
Agents communicate theo ba pattern: Push, Pull, và Event-driven. Mỗi pattern có coupling, reliability và latency khác nhau. Bài này phân tích khi nào dùng cái nào.
Tập này đang được chuẩn bị, quay lại sau nhé.
Agents cần communicate với nhau. Cách chúng communicate quyết định coupling, reliability, và latency của toàn bộ system.
Có ba communication pattern chính, mỗi cái phù hợp với một loại workload khác nhau.
Pattern 1: Push (Direct Call)
Push Pattern:
Orchestrator ─────────▶ Worker
│ call(task) │
│ │ execute
│ result │
◄────────────────────────── │
│ blocking wait │
│ (orchestrator blocks │
│ until worker done) │
Orchestrator gọi worker trực tiếp và đợi kết quả. Đơn giản nhưng synchronous.
Phù hợp khi:
- Tasks sequential, kết quả này là input của task sau
- Task kết thúc nhanh (<30s)
- Cần có kết quả trước khi continue
- Dễ debug và trace
Không phù hợp khi:
- Worker có thể chạy rất lâu (orchestrator bị block)
- Nhiều workers cần chạy parallel (push sequential không tận dụng)
Implementation sketch:
class Orchestrator:
async delegateAndWait(worker, task) {
const result = await worker.execute(task); // blocking
return result;
}
async run(mainTask) {
const analysis = await this.delegateAndWait(
this.backendWorker, analysisTask);
// Chỉ continue sau khi analysis xong
const implementation = await this.delegateAndWait(
this.backendWorker,
{ ...implTask, context: analysis });
}
Pattern 2: Pull (Polling)
Pull Pattern:
Orchestrator Worker
│ │
│── submit(task) ────────────▶│
│ returns task_id │ chạy async
│ │
│── doOtherWork() ──────────▶│
│ (không bị block) │ (vẫn chạy)
│ │
│── poll(task_id) ──────────▶│
◄──────────────────────────┘
status: "pending" | "done" | result
Orchestrator submit task và nhận task_id. Tiếp tục làm việc khác. Poll định kỳ cho đến khi xong.
Phù hợp khi:
- Workers chạy lâu (phut đến giờ)
- Orchestrator có thể làm việc khác trong khi đợi
- Nhiều tasks parallel, orchestrator monitor tất cả
Không phù hợp khi:
- Task nhanh — polling overhead vượt quata lợi
- Cần real-time notification ngay khi xong
Implementation sketch:
class Orchestrator:
async runParallel(tasks) {
// Submit tất cả tasks
const submissions = await Promise.all(
tasks.map(t => this.submit(t))
);
// Poll cho đến khi tất cả xong
const results = [];
while (submissions.some(s => s.status !== 'done')) {
await sleep(2000); // poll mỗi 2 giây
for (const submission of submissions) {
if (submission.status !== 'done') {
submission.status = await this.poll(submission.task_id);
}
}
}
return results;
}
Pattern 3: Event-driven (Message Queue)
Event-driven Pattern:
Orchestrator Queue Workers
│ │ │
│─ publish(task_A) ───▶│ │
│─ publish(task_B) ───▶│ │
│─ publish(task_C) ───▶│ │
│ │── worker1 poll ▶│ Worker 1
│ │── worker2 poll ▶│ Worker 2
│ │── worker3 poll ▶│ Worker 3
│ │ │ execute
│ │◄─ result A ────│
│◄─ subscribe(result) ──│◄─ result B ────│
│ │ │
Orchestrator publish tasks vào queue. Workers tự pull tasks khi available. Results publish lại vào queue.
Phù hợp khi:
- High throughput, nhiều tasks concurrently
- Worker pool có thể scale independently
- Tasks có khác nhau về priority
- System phải survive partial failures
Không phù hợp khi:
- ít tasks, overhead của queue không xứng
- Cần strict ordering
- Simple agent system không cần production scale
So sánh trực tiếp
Push Pull Event-driven
──────────────────────────────────────────────
Complexity Low Medium High
Latency Low Medium Low-Medium
Throughput Low Medium High
Debugging Easy Medium Hard
Fault toler. Low Low High
Scalability Low Medium High
Pattern Selection: Guideline thực tế
Bạn đang build gì?
CLI agent tool, internal use:
→ Push (simple, debụg dễ, phù hợp)
API service với long-running tasks:
→ Pull (async không block)
High-scale enterprise system:
→ Event-driven (khi thực sự cần)
Kết luận
- Ba patterns: Push (sync blocking), Pull (async polling), Event-driven (queue-based).
- Push: đơn giản nhất, phù hợp cho sequential tasks và small systems.
- Pull: cho long-running tasks, orchestrator không bị block, monitor parallel.
- Event-driven: high throughput, scalable, resilient — nhưng complex, debug khó.
- Không có "best" pattern — chọn theo workload characteristics và system requirements.
- Bắt đầu với Push. Move to Pull khi có blocking problem. Event-driven chỉ khi thực sự cần.