Khám phá Learn Stream About Jokes
COHORT 2 Foundation — Claude Code — 3 buổi Zoom · 21 · 24 · 28/07, 20:00 Đăng ký →
Bài viết

10 design pattern cũ đang sống lại trong thế giới AI agent

23 Gang-of-Four design pattern tưởng là chuyện của một thời OOP. Nhưng khi nối agent, subagent, MCP, hook và tool-call thành workflow, mình vẫn đang dùng đúng những hình đó — object thành agent, method thành tool, application flow thành orchestration. Đây là những pattern map sạch nhất, và mấy cái map lỏng lẻo mình không cố kéo qua.

10 design pattern cũ đang sống lại trong thế giới AI agent

10 design pattern cũ đang sống lại trong thế giới AI agent

Mình từng nghĩ 23 Gang-of-Four design pattern là chuyện của một thời OOP: class, object, inheritance, mấy ví dụ cửa gỗ với tổng thống. Nhưng khi bắt đầu nối agent, subagent, MCP, hook và tool-call thành workflow, mình nhận ra mình vẫn đang dùng đúng những “hình” đó, chỉ là vật liệu đã đổi. Design pattern không biến mất; object được thay bằng agent, method được thay bằng tool, còn application flow trở thành orchestration.

Điều thú vị là mình không cần nhớ đủ 23 cái để thấy chúng hữu ích. Một số pattern map rất sạch sang agent system, tới mức nhìn ra tên của nó giúp mình thiết kế workflow gọn hơn ngay lập tức. Một số khác chỉ giống bề ngoài, cố kéo qua sẽ thành content cho đủ số hơn là một cách nghĩ có ích.

Nên đây không phải bài “23 design patterns phiên bản AI”. Mình chỉ chọn những pattern mà mình thiệt sự thấy xuất hiện khi build với agent.

Hóa ra một skill thường chỉ là Facade

Trong sách, Facade là một interface đơn giản nằm trước một subsystem phức tạp. Người dùng bấm nút nguồn, còn phía sau máy tính tự chạy một đống bước mà họ không cần biết.

Một skill hay slash-command tốt cũng làm đúng việc đó. Mình gọi /tony-play, nhưng phía sau nó có thể đọc session state, kiểm tra red flag, xác định hôm nay đang ở Plan, Do, Check hay Act, rồi dispatch sang workflow phù hợp. Người dùng không cần nhớ mười file nằm ở đâu, gọi tool nào trước, hay output bước này phải đưa vào bước nào tiếp theo.

Đó là lúc mình nhận ra skill không chỉ là một prompt được lưu lại. Nó là Facade của cả một subsystem gồm prompt, script, tool, rule và state. Nếu một slash-command vẫn bắt người dùng hiểu toàn bộ plumbing phía sau mới dùng được, Facade đó chưa làm xong việc của nó.

Facade: không dùng thì bạn tự nhớ và chạy từng bước; dùng thì một slash-command /tony-play, skill lo phần còn lại

Adapter thì xuất hiện ngay bên cạnh. Một API bên ngoài có authentication, endpoint và response schema riêng; agent không tự nhiên biết nói chuyện với nó. MCP server bọc API đó lại thành những tool có tên, input và output mà agent hiểu được. Card reader ngày xưa nối thẻ nhớ với computer; MCP hôm nay nối một dịch vụ lạ với tool-calling interface.

Adapter: không dùng thì agent không nói được với API lạ; dùng thì MCP server bọc API thành tool agent gọi được

Còn Proxy là lớp đứng trước tool để thêm quyền kiểm soát. Ví dụ fork-gate hook không tự làm công việc của subagent, nó chỉ đứng trước Task tool, đọc input rồi hỏi lại khi thấy subagent_type == "fork". Tool thật vẫn ở phía sau, nhưng mọi request phải đi qua một cái cổng có permission, logging hoặc policy. Khi cần audit, rate limit, secret protection hay human approval, mình đang nghĩ bằng Proxy dù không gọi tên nó.

Proxy: không dùng thì fork chạy thẳng không ai chặn; dùng thì fork-gate hook chen một cổng kiểm tra trước Task tool

Orchestration thật ra là bài toán chọn, giao và chuyển việc

Strategy là pattern dễ thấy nhất khi dùng nhiều model hoặc nhiều cách giải. Cùng một task “nghiên cứu rồi viết”, nhưng mình có thể chọn Claude cho phần đọc context dài, Codex cho phần sửa code, hoặc một fresh agent đọc contract thay vì fork toàn bộ context. Mục tiêu không đổi; strategy thực thi được thay dựa trên loại việc, chi phí và lượng context cần mang theo.

Điểm quan trọng là lựa chọn đó phải nằm ở một chỗ rõ ràng. Nếu mọi prompt tự quyết định model theo cảm tính, mình không có Strategy, mình chỉ có nhiều nhánh behavior rải rác. Một decision matrix kiểu “task cần inherited nuance thì fork, task đã có contract thì fresh agent” biến lựa chọn thành policy có thể kiểm tra và sửa.

Strategy: không dùng thì mỗi prompt tự chọn model theo cảm tính; dùng thì một policy chọn Claude/Codex/fresh agent theo loại việc

Command xuất hiện khi orchestrator đóng gói một hành động thành task card hoặc tool-call rồi giao cho worker. Orchestrator không cần biết worker sẽ dùng shell, MCP hay đọc file nào; nó chỉ cần một contract đủ rõ:

Task: audit authentication flow
Done when: findings có path:line và test tái hiện được

Task này có thể được queue, retry, log, giao lại cho agent khác hoặc chờ dependency hoàn tất. Đó chính là giá trị của Command: tách người yêu cầu hành động khỏi nơi thực thi hành động. Prompt mơ hồ kiểu “xem giúp repo này” chưa phải Command tốt, vì nó chưa đóng gói được intent và completion criteria.

Command: không dùng thì orchestrator gọi worker trực tiếp khó queue/retry; dùng thì đóng gói thành task card queue/retry/reassign được

Chain of Responsibility lại phù hợp với routing. Một request đi qua các handler cho tới khi có handler nhận: câu hỏi về billing sang support agent, lỗi code sang debugging agent, thay đổi permission sang security review. Trong thực tế mình hay viết nó thành dispatch rule hoặc decision tree hơn là một chuỗi class, nhưng shape vẫn giống nhau.

Pattern này hữu ích khi không có một orchestrator khổng lồ phải hiểu mọi domain. Mỗi handler chỉ cần biết “việc này có thuộc phần mình không?”. Tuy nhiên phải có điểm dừng; nếu agent nào cũng được quyền đẩy tiếp mà không ai chịu trách nhiệm cuối cùng, Chain of Responsibility rất dễ biến thành vòng chuyền việc đẹp mắt nhưng không có output.

Chain of Responsibility: không dùng thì một orchestrator ôm mọi domain; dùng thì request chuyền qua từng agent tới khi có agent nhận

Một agent và một team đôi khi nên nhìn giống nhau

Composite giúp orchestrator đối xử với một worker và một nhóm worker qua cùng một interface. Nó giao task, chờ kết quả, nhận status và đọc output. Bên dưới có thể là một agent duy nhất, hoặc một fan-out gồm ba agent nghiên cứu độc lập rồi một agent synthesis.

Điều này không có nghĩa single agent và team có cùng chi phí hay cùng failure mode. Chúng chỉ có chung “hình dáng” ở boundary. Nhờ vậy orchestrator không cần viết lại toàn bộ flow mỗi khi mình đổi từ một worker sang một team.

Composite: không dùng thì viết hai flow riêng cho một agent và một team; dùng thì cả hai gọi cùng một interface

Mediator giải quyết phần còn lại: subagent không tự nhắn lung tung cho nhau, mà giao tiếp qua orchestrator. Worker A trả findings, orchestrator quyết định phần nào chuyển cho worker B, rồi tự reconcile kết quả. Cách này giảm coupling và giữ một nơi chịu trách nhiệm cho quyết định cuối cùng.

Mình thấy Mediator đặc biệt quan trọng khi chạy song song. Cho các agent nói chuyện trực tiếp nghe có vẻ autonomous hơn, nhưng rất nhanh sẽ khó biết ai đã quyết định gì, context nào là canonical, và conflict được giải ở đâu. Orchestrator không nhất thiết phải làm hết việc; nó phải giữ được đường đi của thông tin.

Mediator: không dùng thì subagent nhắn chéo nhau không ai chốt; dùng thì mọi giao tiếp đi qua orchestrator ở giữa

Hook và pipeline cũng là những pattern cũ

Observer là hook hoặc event listener. Khi state đổi, một subscriber được báo: tool sắp chạy thì PreToolUse hook kiểm tra permission, task hoàn tất thì gửi notification, file thay đổi thì trigger validation. Producer không cần biết subscriber sẽ log, chặn, báo Slack hay cập nhật dashboard.

Observer: không dùng thì nhét phản ứng cứng vào chỗ phát; dùng thì phát một event, hook/notification/validation tự nhận

Nhưng mình phải phân biệt notification với orchestration. Observer rất hợp cho side effect và phản ứng độc lập; nó không lý tưởng cho một chuỗi bước bắt buộc phải chạy đúng thứ tự. Nếu bước build chỉ được chạy sau khi PRD đã approved, dependency đó nên nằm trong workflow rõ ràng, không nên hy vọng một event nào đó sẽ tự nối mọi thứ lại.

Chỗ đó hợp với Template Method hơn. Mình có thể cố định skeleton:

discovery → PRD → task cards → build → verify

Mỗi project điền implementation khác nhau cho từng bước, nhưng không được bỏ qua contract hoặc verification. Trong agent pipeline, “subclass” không còn nhất thiết là class; nó có thể là một skill, prompt template hay agent chuyên môn được cắm vào một stage.

Template Method: không dùng thì mỗi project tự dựng pipeline dễ bỏ bước; dùng thì khung chung cố định chỉ thay implementation từng bước

Template Method giúp workflow có kỷ luật, nhưng skeleton càng dài thì càng dễ giả định sai. Có project không cần fan-out, có project cần security review trước build. Mình giữ phần xương đủ chặt để bảo vệ chất lượng, còn những bước phụ nên được cấu hình thay vì đóng đinh.

Không phải pattern nào cũng cần kéo sang agent

Nói thiệt, mình không thấy lợi ích khi cố map đủ 23 pattern. Flyweight có thể được ví với shared context hoặc cache, nhưng economics của token và context window không giống memory sharing trong object system. Prototype có thể giống clone một agent config, nhưng phần quan trọng của agent thường nằm trong runtime context, tool access và state chứ không chỉ trong bản sao ban đầu.

Memento nghe giống checkpoint và resume, nhưng muốn gọi đúng pattern thì phải thật sự capture rồi restore được state, không phải chỉ lưu một transcript. Visitor còn lỏng hơn nữa; mình chưa thấy analogy nào làm workflow agent sáng rõ hơn thay vì chỉ đổi tên khái niệm. Ngay cả Singleton được ví thành “một canonical config” hay “một collection duy nhất” cũng chủ yếu là lời nhắc về single source of truth, chưa chắc là Singleton theo nghĩa kỹ thuật.

Với mình, giá trị của GoF không nằm ở việc gắn đủ nhãn. Nó cho mình một bộ từ vựng để nhận ra coupling đang nằm ở đâu: interface có đang che complexity không, policy có tách khỏi execution không, worker có phụ thuộc trực tiếp vào nhau không, và state change đang được truyền đi bằng cách nào. Khi tên pattern làm câu hỏi thiết kế rõ hơn thì giữ; khi nó chỉ làm diagram trông thông minh hơn thì bỏ.

Câu hỏi thường gặp

Có cần học đủ 23 GoF pattern trước khi build agent system không?

Không. Mình sẽ bắt đầu với Facade, Strategy, Command, Adapter và Proxy vì chúng xuất hiện rất thường xuyên ở boundary giữa user, orchestrator và tool. Khi workflow có nhiều worker hoặc event hơn, lúc đó Composite, Mediator, Chain of Responsibility và Observer mới thật sự đáng học kỹ.

Một skill luôn luôn là Facade à?

Không hẳn. Một skill chỉ chứa prompt viết bài chưa chắc đang che một subsystem phức tạp; nó có thể đơn giản là reusable instruction. Mình gọi nó là Facade khi nó cung cấp một entry point ổn định cho nhiều bước, nhiều tool hoặc nhiều rule phía sau.

MCP server là Adapter hay Facade?

Có thể là cả hai, tùy boundary mình đang nhìn. Nó là Adapter khi chuyển một API không tương thích thành tool interface mà agent gọi được. Nếu nó còn gom nhiều endpoint và workflow thành vài operation đơn giản, nó đồng thời đang làm công việc của Facade.

Dùng pattern có làm agent workflow bớt lỗi không?

Không tự động. Pattern chỉ giúp mình đặt đúng boundary và nói rõ trách nhiệm; prompt tệ, contract thiếu, permission rộng hoặc verification yếu vẫn làm hệ thống hỏng như thường. Nhưng khi failure xảy ra, một workflow có cấu trúc rõ sẽ dễ biết lỗi nằm ở routing, execution, state hay interface hơn.

Bạn thì sao: trong workflow agent bạn đang build, có pattern nào bạn đã dùng mỗi ngày nhưng tới giờ mới nhận ra nó có tên?

#design-patterns #ai-agents #orchestration #mcp #claude-code #architecture

Bài viết liên quan

Bản đồ đầy đủ: 23 design pattern cho người vibe code

idea

Bài trước là 6 pattern bạn gặp nhiều nhất. Đây là bản đồ đủ 23 — mỗi cái một ý chính và một ví dụ app, để lần sau gặp đúng vấn đề bạn biết nó có tên và gọi tên được cho AI. Bạn không cần dùng hết, chỉ cần nhận ra.

6 design pattern giúp bạn bảo AI viết app đỡ rối

idea

Bạn vibe code một app, nó chạy được, nhưng thêm feature là code rối thêm — và bạn không biết bảo AI sửa theo hướng nào. Biết tên 6 pattern thường gặp là đủ để chỉ đường cho AI: tách theo Strategy, bọc bằng Adapter, phát event theo Observer. Đây là bản cho người vibe code, không phải cho người build agent.

0:00

Chia sẻ ảnh

Bắt đầu gõ để tìm kiếm...