Pipeline ba vai — khi agent ngừng làm bừa
Thêm tool không cứu được agent hay bịa. Playbook tách pipeline thành planner–executor–critic để bạn debug được từng khâu thay vì cầu nguyện.
Bụi WireAgent của bạn có 15 tool mà vẫn hallucinate (bịa thông tin với vẻ mặt tự tin)? Chín phần mười trường hợp, vấn đề không phải thiếu tool — mà là không ai kiểm tra cái agent đó đang làm đúng hay bậy.
Nhiều team Việt Nam mình gặp đều rơi vào cùng một vòng xoáy: nhồi thêm tool, kéo dài system prompt, rồi hy vọng model "tự hiểu". Agent chạy đúng lúc demo, sai lúc production. Bài này là playbook tách agent thành ba vai rõ ràng — planner, executor, critic — để bạn kiểm soát từng bước thay vì đặt cược vào may mắn.
Mục tiêu: một pipeline mà bạn debug được
Thay vì dồn mọi thứ vào một prompt khổng lồ, ta chia agent thành ba vai riêng biệt:
- Planner (vai lập kế hoạch): nhận goal, trả về structured plan dưới dạng JSON — không gọi tool, không thực thi.
- Executor (vai thực thi): nhận plan, gọi tool theo thứ tự, lưu kết quả vào state.
- Critic (vai phản biện / self-critique — tự đánh giá chất lượng output): nhận kết quả của executor, quyết định pass hay retry.
Dịch sang tiếng người: thay vì một nhân viên vừa lên kế hoạch, vừa làm, vừa tự chấm điểm, bạn có ba người — mỗi người chỉ chịu trách nhiệm một việc. Khi sai, bạn biết ngay sai ở khâu nào.
Pattern này khác bài orchestration tổng quan mình từng chia sẻ ở chỗ: nó cho bạn implementation cụ thể trong một buổi chiều, không phải lý thuyết kiến trúc.
Checklist trước khi bắt tay
Đảm bảo bạn có sẵn:
- [ ] 2-3 tool đã hoạt động ổn định — output deterministic, có error handling
- [ ] Function-calling schema cho mỗi tool (bản khai báo JSON để model biết tool nhận gì, trả gì — tradeoff: schema càng strict thì model càng ít sáng tạo khi gọi, nhưng output càng kiểm soát được)
- [ ] Object AgentState lưu goal, memory, và trace các tool call — không có cái này thì không replay được hành trình agent
- [ ] Model hỗ trợ function calling (GPT-4o, Claude 3.5+, Gemini 1.5+)
- [ ] Ít nhất 3 test case: input → expected output → actual output
Giả sử team bạn 3-4 dev, dùng OpenAI API, có sẵn vài tool nội bộ — pipeline này triển khai được trong một buổi.
Ba bước triển khai
Bước 1 — Planner: ép model chỉ được lên kế hoạch
Viết system prompt riêng, yêu cầu trả về JSON với steps[], mỗi step gồm action, tool_name, expected_output. Planner KHÔNG được gọi tool — enforce bằng cách truyền tools=[] khi gọi API.
planner_prompt = """You are a planner. Given a goal, output a JSON plan.
Do NOT execute anything. Do NOT call tools.
Format: {"steps": [{"action": "...", "tool": "...", "expected": "..."}]}"""
# Gọi KHÔNG kèm tool schema → model không có cách gọi tool
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "system", "content": planner_prompt}, ...],
# tools=[] hoặc không truyền param tools
)
Bước 2 — Executor: chạy plan, gọi tool, lưu trace
Executor loop qua từng step, gọi tool tương ứng qua một registry (mapping tên tool → function), lưu toàn bộ vào AgentState.memory.
for step in plan["steps"]:
result = tool_registry[step["tool"]](**step["args"])
state.memory.append({"step": step, "result": result, "ts": now()})
Guardrail ở executor: max 5-7 iterations, timeout per tool call (~30s), và allowlist — executor chỉ được gọi tool có trong plan, không tự phát thêm.
Bước 3 — Critic: gác cổng trước khi trả output
Critic nhận toàn bộ state và trả verdict: pass hoặc retry kèm lý do.
Critic như người kiểm kê trong thư viện — không tìm sách mới, chỉ xác nhận sách đã về đúng kệ chưa. Sai kệ thì trả lại xếp lại, không phải đi mua sách khác.
critic_prompt = """Review execution trace and final output.
If output meets goal AND is grounded in tool results: {"verdict": "pass"}
If not: {"verdict": "retry", "reason": "..."}"""
Set max retry = 2. Vượt quá → fail gracefully, log để team review thủ công. Đừng để agent retry vô hạn — chi phí API sẽ khiến bạn khóc.
Bẫy hay gặp — và cách tránh
Bẫy 1: Planner lén gọi tool. Nếu bạn vẫn truyền tool schema cho planner, model sẽ gọi. Fix duy nhất: cắt hẳn tool schema khỏi API call của planner. Không có tool thì không gọi được — đơn giản vậy thôi.
Bẫy 2: Critic quá dễ dãi. Test critic bằng cách cố tình feed output sai — nếu nó vẫn pass, prompt cần siết. Giả sử team bạn build agent tài chính: cho executor trả số liệu bịa, xem critic có bắt không. Không bắt = critic vô dụng.
Bẫy 3: Không lưu trace. Agent sai nhưng không ai biết sai đâu vì state rỗng. AgentState phải ghi MỌI bước — đây là yêu cầu production, không phải "có thì tốt".
Bẫy 4: "Thêm tool sẽ fix được." Khi orchestration yếu, thêm tool chỉ tăng xác suất agent chọn sai tool. Giống nhét thêm sách vào thư viện không có hệ thống catalog — càng nhiều sách, càng khó tìm đúng cuốn cần.
Mở rộng sau khi pipeline ổn
Khi ba vai đã chạy đúng, bạn có thể:
- Thêm memory layer dài hạn (long-term memory — bộ nhớ xuyên phiên để agent nhớ context cũ)
- Đặt router trước planner: phân loại intent đơn giản vs phức tạp, tránh plan cồng kềnh cho câu hỏi một dòng
- Swap model theo vai: planner dùng model nhẹ (GPT-4o-mini), executor dùng model mạnh khi cần reasoning sâu — tối ưu chi phí đáng kể
Nếu đang dùng LlamaIndex hay LangChain, pattern này vẫn áp dụng được nguyên xi — framework thay đổi cách kết nối, không thay đổi logic tách vai.
Một điều cuối: đừng ship pipeline mà không có observability. Log mỗi run, đo latency từng step, alert khi critic retry vượt ngưỡng. Agent không có monitoring giống deploy service không có healthcheck — sớm muộn cũng cháy âm thầm.
---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng
Nguồn tham khảo
- How to Build an Advanced Agentic AI System with Planning, Tool Calling, Memory, and Self-Critique Using OpenAI API - MarkTechPost
- How to Build a Financial Due Diligence Agent with LiteParse
- How to Build an Autonomous OSINT Agent in Python Using Claude's Tool Use API
- Best AI Agents for Software Development Ranked: A Benchmark-Driven Look at the Current Field - MarkTechPost
- Building a general-purpose accessibility agent—and what we learned in the process - The GitHub Blog