Đây là bài trung tâm. Ta lấy một Zap có thật, mổ xẻ, và tái dựng thành agent. Bạn sẽ thấy chính xác chỗ nào giữ nguyên, chỗ nào thay bằng LLM.
Zap gốc: xử lý đơn hàng qua email
Workflow hiện tại của một shop:
[Trigger] Email đơn hàng mới về hộp thư orders@
[Path A] nếu subject chứa 'gấp' -> gắn nhãn URGENT
[Path B] nếu chứa 'huỷ' -> forward cho quản lý
[Path C] còn lại -> parse tay 5 field -> tạo dòng Sheet
[Action] gửi Slack #orders
Vấn đề đội shop gặp: khách viết tự do ("cho mình lấy gấp 2 cái nhé", "thôi không lấy nữa"), Path filter sai liên tục; parse 5 field bằng Formatter vỡ khi khách viết địa chỉ lộn xộn.
Bước 1: Phân loại bước — giữ hay thay?
| Bước Zap | Bản chất | Quyết định |
|---|---|---|
| Trigger email | Sự kiện | Giữ (Zap/n8n trigger) |
| Path theo từ khóa | Quyết định | Thay bằng LLM |
| Parse 5 field | Diễn giải NL | Thay bằng LLM |
| Tạo dòng Sheet | Thực thi | Giữ (tool) |
| Gửi Slack | Thực thi | Giữ (tool) |
Bước 2: Định nghĩa goal và tools
Goal: "Đọc email đơn hàng, xác định ý định (đặt/gấp/huỷ), trích thông tin đơn, và thực thi đúng hành động."
Tools cần: create_order_row, notify_slack, forward_to_manager.
Bước 3: System prompt điều hướng quyết định
Bạn là trợ lý xử lý đơn hàng. Với mỗi email:
1. Phân loại intent: NEW | URGENT | CANCEL.
2. Nếu NEW/URGENT: trích customer, product, qty, address, phone.
Nếu thiếu field bắt buộc (phone HOẶC address) -> KHÔNG tạo đơn,
trả note để nhân viên hỏi lại khách.
3. Gọi tool phù hợp. URGENT thì thêm cờ priority=true.
4. Luôn notify_slack tóm tắt việc đã làm.
Chú ý câu "nếu thiếu field thì KHÔNG tạo đơn": đây là quyết định mà Zapier rất khó làm gọn — agent xử lý tự nhiên.
Bước 4: Vòng lặp thực thi
def run_agent(email_text):
messages = [{"role":"system","content": SYSTEM_PROMPT},
{"role":"user","content": email_text}]
for _ in range(6): # max 6 bước, tránh loop vô tận
r = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=TOOLS)
m = r.choices[0].message
if not m.tool_calls:
return m.content # agent đã xong
for tc in m.tool_calls:
result = dispatch(tc.function.name,
json.loads(tc.function.arguments))
messages.append(m)
messages.append({"role":"tool",
"tool_call_id": tc.id,
"content": json.dumps(result)})
Bước 5: Kiểm thử bằng ca khó
- Email rõ ràng, đủ field → phải tạo đơn + Slack.
- Email "lấy gấp" thiếu số điện thoại → không tạo đơn, trả note hỏi lại.
- Email "thôi huỷ nhé" → forward quản lý, không tạo đơn.
- Email mơ hồ "bạn ơi" → agent hỏi lại, không đoán bừa.
Khung tư duy "Keep / Replace / Wrap"
- Keep: bước deterministic (trigger, ghi DB, gửi tin).
- Replace: bước phán đoán (phân loại, parse NL) → LLM.
- Wrap: bọc bước Keep thành tool để agent gọi được.
Sai lầm thường gặp
- Thay luôn cả bước thực thi bằng LLM: đừng bắt LLM "tự viết vào Sheet" — hãy để nó gọi tool đã kiểm soát.
- Không có nhánh "thiếu dữ liệu": agent sẽ bịa field để lấp chỗ trống.
- Bỏ max_steps trong loop: một lỗi tool khiến agent lặp mãi.
- Không so sánh với Zap cũ: bạn cần bằng chứng agent thực sự tốt hơn trước khi thay thế production.
Tổng kết
Chuyển đổi = phân loại bước, giữ phần thực thi, thay phần phán đoán bằng LLM + tools, đóng vòng lặp có giới hạn. Bài 5 ta làm sâu phần tool-calling để agent hành động chính xác và an toàn hơn.