Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 6 — Dựng agent chạy được: tool calling và vòng lặp thực tế

Đã đọc 0/11 mục · còn khoảng 4 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Giờ ta biến bản thiết kế thành agent chạy được. Trọng tâm là tool calling — cơ chế để LLM gọi hàm của bạn — và vòng lặp điều phối. Ví dụ dùng pseudocode kiểu Python/OpenAI-style function calling, nhưng nguyên tắc áp dụng cho mọi framework (LangChain, n8n, hay tự viết).

Bước 1: Khai báo tools cho LLM

LLM chỉ gọi được tool nếu bạn mô tả chúng ở định dạng nó hiểu:

tools = [{
  "type": "function",
  "function": {
    "name": "tra_don_hang",
    "description": "Tra trạng thái và số tiền đơn theo mã. Dùng khi cần thông tin đơn.",
    "parameters": {
      "type": "object",
      "properties": {"ma_don": {"type": "string"}},
      "required": ["ma_don"]
    }
  }
}]

Bước 2: Ánh xạ tên tool sang hàm thật

LLM chỉ trả về tên tool + tham số; bạn phải tự thực thi:

def tra_don_hang(ma_don):
    row = db.query("SELECT status, amount FROM orders WHERE code=?", ma_don)
    return {"status": row.status, "amount": row.amount}

TOOL_MAP = {"tra_don_hang": tra_don_hang}

Bước 3: Vòng lặp điều phối

def run_agent(user_msg, max_steps=8):
    messages = [{"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_msg}]
    for _ in range(max_steps):
        resp = llm.chat(messages, tools=tools)
        if resp.tool_calls:                       # AGENT MUỐN ACT
            for call in resp.tool_calls:
                fn = TOOL_MAP[call.name]
                try:
                    result = fn(**call.args)
                except Exception as e:
                    result = {"error": str(e)}    # đưa lỗi lại cho agent
                messages.append(tool_result(call.id, result))  # SENSE mới
        else:
            return resp.content                    # ĐÃ CÓ CÂU TRẢ LỜI CUỐI
    return "Xin lỗi, tôi cần bàn giao cho nhân viên hỗ trợ."

Đọc kỹ: khi có tool_calls, ta thực thi rồi append kết quả trở lại messages — đó chính là pha Sense của vòng sau. Khi không còn tool_calls, LLM đã tự kết luận xong.

Bước 4: Xử lý lỗi tool đúng cách

Đừng để exception làm sập cả agent. Bắt lỗi và đưa lỗi cho LLM (dòng result = {"error": ...}). Khi đó agent có thể tự thử cách khác hoặc bàn giao người thật, thay vì crash.

Bước 5: Ràng buộc bằng system prompt

Logic không nằm hết trong code; phần lớn ràng buộc nằm ở system prompt (nhắc lại từ bài 5): "tra đơn + tra chính sách TRƯỚC khi hoàn tiền", "không bịa số", "vượt hạn mức thì gọi chuyen_nguoi_that". Code lo khả năng, prompt lo hành vi.

Nếu dùng no-code (n8n / Make / Dify)

Nguyên tắc y hệt, chỉ khác giao diện: bạn tạo node "AI Agent", gắn các "tool node" (HTTP request, DB query), khai báo mô tả tool, đặt giới hạn số vòng lặp. Đừng nghĩ no-code là khác bản chất — vẫn là Sense-Think-Act.

Checklist trước khi bấm chạy

  • [ ] Mỗi tool đã map đúng sang hàm thật chưa?
  • [ ] Có max_steps chưa?
  • [ ] Kết quả tool (kể cả lỗi) có được đưa lại vào messages không?
  • [ ] Có nhánh trả về khi hết bước (fallback người thật) chưa?
  • [ ] System prompt đã có các quy tắc bắt buộc chưa?

Vì sao mô tả tool quan trọng hơn bạn nghĩ

LLM không đọc code hàm của bạn; nó chỉ đọc phần mô tả bạn khai báo. Nếu hai tool có mô tả na ná nhau, agent sẽ chọn nhầm. Hãy viết description trả lời ba câu: tool này làm gì, khi nào nên dùng, và khi nào KHÔNG nên dùng. Ví dụ, thay vì "Tra đơn hàng", hãy viết "Tra trạng thái và số tiền của một đơn theo mã đơn. Dùng khi khách hỏi về giao hàng hoặc trước khi xử lý hoàn tiền. KHÔNG dùng để tìm đơn theo tên khách." Mô tả càng rõ ranh giới, agent càng ít gọi sai tool — đây là cách rẻ nhất để tăng độ tin cậy mà không cần đổi model.

Kiểm thử agent: nghĩ theo 'ca', không theo 'lần chạy'

Một agent chạy đúng ở ca thuận lợi chưa nói lên điều gì. Hãy xây một bộ ca kiểm thử phủ đủ ba nhóm: (1) ca thuận lợi — dữ liệu đầy đủ, đúng định dạng; (2) ca ngoại lệ — thiếu dữ liệu, vượt hạn mức, ngoài scope; (3) ca lỗi kỹ thuật — tool timeout, API trả rác. Với mỗi ca, ghi rõ hành vi mong đợi (gọi tool nào, hay bàn giao người thật). Chạy lại bộ ca này mỗi khi bạn đổi prompt hay thêm tool — vì một thay đổi nhỏ ở prompt có thể làm hỏng hành vi ở ca khác mà bạn không ngờ tới.

Sai lầm thường gặp

  • Quên append kết quả tool vào messages → agent "mù", lặp lại lệnh cũ.
  • Không bắt exception → một API lỗi làm sập toàn bộ agent.
  • Bỏ max_steps → vòng lặp vô tận, cháy token.
  • Nghĩ code là đủ, bỏ bê system prompt → agent có công cụ nhưng hành xử sai quy trình.
  • Test bằng đúng một ca đẹp rồi tưởng đã xong; chưa thử ca lỗi và ca ngoại lệ.
  • Viết mô tả tool mơ hồ, na ná nhau → agent chọn nhầm tool.
Agent đã chạy. Nhưng chạy được ở demo khác xa với chạy an toàn ngoài thật. Bài 7 nói về vận hành, an toàn và giám sát.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi