Series 0 - Bài 2: Tại sao Tool Calling ra đời
LLM là reasoning engine mạnh mẽ nhưng bị cô lập hoàn toàn với thế giới thực. Tool Calling ra đời để giải quyết chính xác vấn đề đó — nhưng kèm theo những trade-off không nhỏ.
Một LLM thuần túy là hệ thống bị cô lập hoàn toàn. Nó nhận text, trả text. Không đọc được file. Không gọi được API. Không biết hôm nay là ngày mấy. Không có bất kỳ side effect nào với thế giới bên ngoài.
Đây không phải limitation kỹ thuật có thể fix bằng model tốt hơn. Đây là design property cơ bản của language model. Và Tool Calling ra đời để bridge chính xác gap đó.
LLM bị giới hạn bởi 3 bức tường
Bức tường 1: Knowledge Cutoff
Timeline
─────────────────────────────────────────────▶
│
Training cutoff
│
LLM biết đến đây
│
│ Thế giới tiếp tục
│ thay đổi ở đây
│ ↓
└──────────────────────────▶
LLM được train trên dữ liệu đến một thời điểm nhất định. Mọi thứ xảy ra sau đó — LLM không biết. Giá cổ phiếu hôm nay, tin tức hôm qua, version mới nhất của framework bạn đang dùng — đều nằm ngoài tầm với.
Bức tường 2: Không có side effects
LLM không thể:
- Đọc file trên máy bạn
- Ghi vào database
- Gọi một API bên ngoài
- Gửi email
- Chạy một đoạn code
Nó chỉ có thể nói rằng bạn nên làm những điều đó. Khoảng cách giữa "nói" và "làm" là toàn bộ vấn đề.
Bức tường 3: Không có persistent state
Mỗi LLM call là stateless. Không có gì được lưu lại giữa các request ngoài những gì bạn explicitly đưa vào context. LLM không "nhớ" — nó chỉ "đọc lại".
Tool Calling: Giải pháp và cơ chế
Tool Calling không phải LLM gọi trực tiếp vào hệ thống bên ngoài. Đây là điểm bị hiểu sai nhiều nhất.
Cơ chế thực tế:
┌──────────────────────────────────────────────────┐
│ Your Application │
│ │
│ 1. Gửi messages + tool definitions │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ LLM │ │
│ │ │ │
│ │ "Tôi cần đọc file │ │
│ │ config.json" │ │
│ └──────────┬──────────┘ │
│ │ │
│ 2. LLM trả về tool_use block │
│ { │
│ type: "tool_use", │
│ name: "read_file", │
│ input: { path: "config.json" } │
│ } │
│ │ │
│ 3. BẠN thực thi read_file() │
│ │ │
│ 4. Trả tool_result về LLM │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ LLM │ │
│ │ Nhận file content, │ │
│ │ tiếp tục reasoning │ │
│ └─────────────────────┘ │
└──────────────────────────────────────────────────┘
LLM không execute gì cả. Nó chỉ đề xuất một tool call bằng cách trả về structured data. Bạn là người quyết định có thực thi không, thực thi như thế nào, và trả kết quả gì lại.
Đây là design rất quan trọng — toàn bộ control vẫn nằm ở phía developer.
Tool Calling giải quyết 3 bức tường thế nào
Giải quyết Knowledge Cutoff
Tool: web_search(query)
Tool: get_current_time()
Tool: fetch_stock_price(symbol)
LLM có thể request thông tin real-time thông qua tools. Knowledge không còn bị đóng băng tại training cutoff.
Giải quyết Side Effects
Tool: write_file(path, content)
Tool: call_api(url, payload)
Tool: send_email(to, subject, body)
Tool: run_command(cmd)
LLM có thể trigger actions thực sự trong thế giới bên ngoài — thông qua trung gian là application code của bạn.
Giải quyết Persistent State
Tool: read_from_db(query)
Tool: write_to_db(data)
Tool: get_user_preferences(user_id)
LLM có thể đọc và ghi state thực sự, không chỉ dựa vào context window.
Trade-off của Tool Calling
Tool Calling không phải free lunch.
Latency tăng: Mỗi tool call là một round trip. LLM call → tool execute → LLM call lại. Task phức tạp có thể cần 5-10 vòng, nghĩa là latency nhân 5-10 lần so với single call.
Attack surface mở rộng: Mỗi tool bạn expose cho LLM là một potential attack vector. Nếu LLM bị prompt injection, attacker có thể trigger tools với input độc hại. Tool run_command với input không được sanitize là security nightmare.
Cost tăng: Nhiều LLM call hơn, thêm token cho tool definitions và tool results. Một conversation có 10 tool calls có thể tốn gấp 3-5 lần so với single call.
Unpredictability: LLM có thể gọi tool theo thứ tự bạn không mong đợi, hoặc gọi tool không cần thiết. Testing và debugging phức tạp hơn nhiều.
Trade-off Summary
Thêm tools ──────────────────────────────────▶
│ │ │
Capability Latency Risk
tăng tăng tăng
Tool Calling không phải magic, là interface design
Cách tốt nhất để hiểu Tool Calling là xem nó như một API design problem. Bạn đang thiết kế API cho một developer đặc biệt — developer đó là LLM, không phải human.
LLM đọc tool definition như human đọc API docs. Nếu description mơ hồ, LLM sẽ dùng sai. Nếu parameter names không rõ ràng, LLM sẽ truyền sai giá trị. Nếu error message không informative, LLM không biết cách recover.
Tool design là một kỹ năng riêng — không phải chỉ là viết function và expose nó.
Kết luận
- LLM thuần túy bị cô lập bởi 3 giới hạn: knowledge cutoff, không có side effects, không có persistent state.
- Tool Calling bridge 3 giới hạn đó bằng cách cho LLM đề xuất actions, còn application code thực thi.
- LLM không gọi tool trực tiếp — nó trả về structured data, bạn quyết định có execute không.
- Tool Calling đi kèm trade-off thực: latency, cost, attack surface, và unpredictability.
- Thiết kế tool tốt là interface design cho LLM — không phải chỉ là expose function.