Danh sách bài viết

Bài 42: Function Calling là gì? Vì sao LLM cần gọi function

Bài này mở đầu Module 7 — Function Calling & Tool Use. Function Calling là cơ chế LLM tự quyết định khi nào nên gọi function nào với arguments gì; app execute function thực sự rồi trả result về cho LLM tổng hợp câu trả lời. Đây là nền tảng để LLM thoát khỏi giới hạn knowledge cutoff (không có real-time data), không action được (gửi email, query DB), và hay hallucinate khi cần phép tính chính xác. Bài đi qua định nghĩa, ba nhóm tool (retrieval, action, computation), workflow 5 bước, code OpenAI và Anthropic, tool_choice, MCP, và lộ trình 5 bài của Module 7.

25/05/2026
14 phút đọc
1 lượt xem
1

Mục tiêu bài học

Sau bài này, bạn cần nắm được:

  • Function Calling = LLM tự quyết định khi nào nên gọi function và truyền argument nào; app (không phải LLM) thực sự execute function rồi gửi result trở lại LLM.
  • Ba lý do LLM cần function: không có real-time data, không thực hiện được action ngoài text, không tính toán chính xác.
  • Ba nhóm tool: information retrieval, action, computation.
  • Workflow 5 bước: user query → LLM phát tool call → app execute → gửi tool result → LLM synthesize answer.
  • Khác biệt giữa OpenAI tools/tool_calls/role: "tool" và Anthropic tools/tool_use/tool_result.
  • Vai trò tool_choice để ép model gọi tool cụ thể, hoặc cấm gọi tool.
  • Tool Use là foundation cho agent (LLM + tools + loop) và là tiền đề cho Model Context Protocol (MCP).

Bài này là conceptual overview. Các bài sau Module 7 sẽ đào sâu schema, workflow một turn, parallel/sequential và error handling.

2

Mở đầu Module 7 — Function Calling & Tool Use

Trong sáu module đã đi qua, LLM nhận text — sinh text. Module 6 thêm RAG để LLM nhìn được tài liệu mới qua retrieval thụ động: hệ thống truy xuất chunk dựa trên embedding similarity rồi nhét vào prompt. LLM không tự chọn lấy gì.

Module 7 mở ra cơ chế ngược: LLM chủ động phát ra yêu cầu gọi function khi thấy cần. App ngoài LLM execute function (HTTP, DB, file, code, calculator…), kết quả trở thành input vòng tiếp theo. LLM không còn bị giới hạn ở text trong và ra; nó có khả năng "đặt câu hỏi" về thế giới qua function và xử lý câu trả lời.

Đây là nền cho mọi agent hiện nay: tool calling + loop = agent. Cùng với MCP đang chuẩn hoá phía tool, Function Calling trở thành lớp giao tiếp chuẩn giữa LLM và môi trường.

3

Function Calling là gì

Định nghĩa thực dụng:

Function Calling là cơ chế mà LLM, dựa trên prompt và tool schema được khai báo, tự quyết định khi nào nên trả về một "tool call" (tên function + arguments JSON) thay vì câu trả lời text. App nhận tool call, execute function tương ứng, rồi gửi kết quả trở lại LLM dưới dạng message để LLM tổng hợp câu trả lời cuối.

Vài hiểu nhầm cần loại:

  • LLM không tự execute function. Model chỉ phát ra chuỗi JSON mô tả call. Server, runtime của app mới thực sự chạy function.
  • "Function" ở đây là khái niệm trừu tượng. Có thể là HTTP API, DB query, Python function local, lệnh shell, file IO, hay thậm chí query một LLM khác.
  • LLM không quyết định 100%. App vẫn có quyền chặn, validate, đổi argument, hoặc từ chối gọi tool.

Đầu ra của model lúc tool call thường có hai phần: (1) optional text giải thích, (2) cấu trúc tool_calls (OpenAI) hoặc tool_use block (Anthropic) chứa tên function và argument JSON.

4

Vì sao LLM cần function

LLM weights là snapshot. Knowledge cutoff khoá lại tại một thời điểm. Ba giới hạn dẫn tới nhu cầu gọi function:

  • Không có real-time data. Giá cổ phiếu hôm nay, thời tiết hiện tại, số liệu bán hàng tuần này — model không biết. Function fetch external API là cách duy nhất chính xác.
  • Không action được. Model không tự gửi email, không insert record vào DB, không transfer money, không tạo branch git. Mọi side-effect đều phải qua function trong app.
  • Hallucinate khi cần chính xác. Phép tính số học lớn, regex phức tạp, lookup id, conversion currency — LLM hay đoán. Tool calculator hoặc python_exec ép kết quả deterministic.

Cách hình dung đơn giản: weights của LLM giống một bộ não bị khoá trong phòng kín, không nhìn, không sờ vào gì. Function là kênh để não tương tác với môi trường — đọc dữ liệu, kích hoạt hành động.

5

Ba nhóm tool

Tool có thể chia thành 3 nhóm theo mục đích:

  • Information retrieval: lấy dữ liệu, đọc. Ví dụ: get_weather, search_web, query_db, get_user_profile, read_file. Read-only, idempotent, thường an toàn cho parallel.
  • Action: gây side-effect lên thế giới. Ví dụ: send_email, create_order, book_flight, delete_record, charge_card. Cần xác thực, log, đôi khi cần confirm trước khi thực thi.
  • Computation: tính toán deterministic, không cần state ngoài. Ví dụ: calculator, convert_currency, run_python, parse_date, compute_taxes. Tránh hallucinate số học.

Một tool có thể nằm ở giao điểm — ví dụ summarize_document(doc_id) vừa retrieval (đọc doc) vừa computation (chạy summarize). Phân nhóm chủ yếu để thiết kế: read-only thì parallel-safe, action thì cần guard rail và logging chặt.

6

Workflow 5 bước

Một vòng function calling chuẩn gồm 5 bước:

  1. User query: "Thời tiết Hà Nội bây giờ thế nào?"
  2. LLM phát tool call: model thấy có tool get_weather(city) phù hợp, trả về tool_calls=[{name: "get_weather", arguments: {"city": "Hanoi"}}].
  3. App execute: lấy tên tool, parse argument, gọi function thật. Ví dụ HTTP GET tới OpenWeather API. Nhận về {"temp_c": 28, "desc": "cloudy"}.
  4. App gửi tool result lại: append message role: "tool" (OpenAI) hoặc block tool_result (Anthropic) chứa kết quả JSON. Gọi LLM lần thứ hai.
  5. LLM synthesize: với tool result trong history, model viết câu trả lời tự nhiên: "Hà Nội đang khoảng 28 độ, mây nhiều."

Nếu trong bước 2 model không thấy cần tool, nó trả thẳng text — workflow rút lại còn 1 bước. Nếu cần nhiều tool, bước 2-4 lặp lại (sequential) hoặc model phát nhiều tool call cùng lúc (parallel — Bài 45).

7

Năm component cốt lõi

Một hệ tool calling đầy đủ gồm:

  • Tool definition (schema): khai báo cho LLM biết tool tồn tại — tên, mô tả, parameter type. Bài 43 sẽ đào sâu phần này (JSON Schema).
  • Tool call: object LLM phát ra khi muốn dùng tool, gồm name, arguments (JSON), và id (correlate với result).
  • Execution: code app nhận tool call, dispatch tới function thật, xử lý timeout, error, retry.
  • Tool result: payload trả lại cho LLM, thường là JSON. Phải gắn đúng id để LLM khớp request-response.
  • Final response: text trả về cho user sau khi LLM xử lý xong tool result.

Mỗi component có pitfall riêng. Schema sai → model gọi sai parameter. Execute không validate → app crash trên input lạ. Result quá dài → tốn token và confuse model. Bài 46 sẽ tập trung vào error handling toàn bộ chuỗi.

8

Lịch sử ngắn 2023 - 2026

  • 3/2023 — OpenAI Plugins: ChatGPT plugin cho phép gọi external API qua manifest (ai-plugin.json). Sản phẩm consumer, không phải API. Đóng cửa năm 2024 nhường chỗ cho GPTs và tool calling.
  • 6/2023 — OpenAI Function Calling: ra mắt cùng gpt-3.5-turbo-0613gpt-4-0613. Field functions + function_call trong API. Đây là API tool calling lần đầu chuẩn hoá ở mức enterprise.
  • 11/2023 — OpenAI đổi tên: functionstools, function_calltool_calls, hỗ trợ parallel tool calls. Mô hình mới gpt-4-turbo mặc định parallel ON.
  • 4/2024 — Anthropic Tool Use: Claude 3 ra public tool use với tools + tool_use/tool_result content block.
  • 11/2024 — Anthropic công bố MCP (Model Context Protocol): chuẩn open-source cho LLM client kết nối tool server.
  • 2024 - 2026: Llama 3.1, Qwen 2.5, Mistral, Gemini, DeepSeek đều hỗ trợ tool calling theo schema gần OpenAI. Tool use thành chuẩn de facto cho mọi LLM API hiện đại.
9

Function Calling vs RAG

Cùng giải bài toán "LLM thiếu dữ liệu", hai cách tiếp cận khác hẳn nhau:

  • RAG (passive retrieve): app chạy retrieval trước mọi prompt — embedding query, tìm chunk gần nhất, nhét vào context. LLM không quyết định lấy gì, chỉ đọc và trả lời. Phù hợp Q&A trên corpus tĩnh.
  • Function Calling (active call): LLM quyết định lúc nào cần data, gọi gì, với argument gì. App execute và trả result. Phù hợp khi nguồn dữ liệu nhiều, dynamic, hoặc cần action.

Hai pattern không loại trừ. Một agent thực tế thường có cả hai: tool search_kb(query) bên trong chính là retrieval (Bài 41 đã xây). Cấu hình "RAG as a tool" phổ biến trong các framework agent. RAG trả lời câu hỏi dạng "what", Function Calling lo "do" — cộng lại là LLM useful trong production.

10

Use case thực tế

  • Weather, stock, news: fetch real-time API.
  • Calculator, unit converter: ép số học chính xác.
  • SQL query: tool run_sql(query) trên DB nội bộ, model tự sinh query.
  • External API: Stripe (payment), Gmail (gửi email), Slack (post message), GitHub (tạo PR), Jira (open ticket).
  • File operations: read_file, write_file, list_dir — nền tảng của coding assistant như Cursor, Claude Code.
  • Web search: search_web qua Google, Bing, Tavily, Brave Search.
  • Code execution: run_python(code) trong sandbox — pattern data analysis của ChatGPT Advanced Data Analysis.
  • Calendar: list_events, create_event, find_free_slot.
  • RAG tool: search_docs(query, top_k) bao bọc vector search Bài 36.
11

OpenAI Function Calling — code

API OpenAI dùng field tools để khai báo, tool_calls để nhận, role: "tool" để gửi result:

from openai import OpenAI
import json

client = OpenAI()

weather_tool = {
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Lấy thời tiết hiện tại của một thành phố",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string",
                         "description": "Tên thành phố, ví dụ Hanoi"}
            },
            "required": ["city"],
        },
    },
}

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user",
               "content": "Thời tiết Hà Nội thế nào?"}],
    tools=[weather_tool],
)

msg = resp.choices[0].message
# msg.tool_calls[0].function.name == "get_weather"
# json.loads(msg.tool_calls[0].function.arguments) == {"city": "Hanoi"}

Field quan trọng:

  • type: "function" — cho phép mở rộng các loại tool khác sau này (file_search, code_interpreter).
  • parameters theo chuẩn JSON Schema. Bài 43 sẽ trình bày kỹ.
  • tool_calls là array — mặc định parallel ON cho gpt-4o (Bài 45).
  • argumentschuỗi JSON, phải json.loads.
12

Anthropic Tool Use — code

Anthropic dùng tools ở top-level, mỗi tool có input_schema. Response chứa content là list các block, trong đó tool call là block type: "tool_use":

import anthropic

client = anthropic.Anthropic()

tools = [{
    "name": "get_weather",
    "description": "Lấy thời tiết hiện tại của một thành phố",
    "input_schema": {
        "type": "object",
        "properties": {
            "city": {"type": "string"}
        },
        "required": ["city"],
    },
}]

resp = client.messages.create(
    model="claude-opus-4",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user",
               "content": "Thời tiết Hà Nội thế nào?"}],
)

# resp.content = [
#   TextBlock("Để tôi kiểm tra..."),
#   ToolUseBlock(id="toolu_01...", name="get_weather",
#                input={"city": "Hanoi"})
# ]
# resp.stop_reason == "tool_use"

Khác biệt chính với OpenAI:

  • input_schema thay vì parameters; input là dict đã parse, không phải chuỗi JSON.
  • Tool call nằm trong content chung với text, không có field riêng tool_calls.
  • stop_reason: "tool_use" là tín hiệu rõ ràng model đang chờ tool result.
13

Multi-tool — LLM chọn tool nào

App khai báo nhiều tool, LLM tự chọn cái phù hợp dựa trên tên và description:

tools = [weather_tool, calculator_tool, search_web_tool]

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user",
               "content": "Tính 234 * 567 giúp tôi."}],
    tools=tools,
)
# msg.tool_calls[0].function.name == "calculator"
# (LLM chọn calculator, không gọi weather hay search)

Quy tắc thiết kế khi có nhiều tool:

  • Tên tool phải gợi semantic: get_weather, calculator rõ ràng hơn tool1, helper.
  • Description không trùng lặp: hai tool description gần nhau → LLM nhầm.
  • Đừng khai báo quá nhiều: 50 tool trong một call làm model decide kém. Group bằng namespace (db.query, db.insert) hoặc tách multiple agent.
14

tool_choice — auto, none, specific, required

App có thể can thiệp vào quyết định gọi tool qua tool_choice:

  • "auto" (default OpenAI): model tự quyết. Có thể gọi tool hoặc không.
  • "none": cấm gọi tool, model chỉ trả text — dùng khi muốn final synthesis.
  • {"type": "function", "function": {"name": "get_weather"}}: ép gọi đúng tool này.
  • "required" (OpenAI) / {"type": "any"} (Anthropic): bắt buộc phải gọi một tool, model không được trả text.
# Ép model phải gọi get_weather
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
    tool_choice={"type": "function",
                 "function": {"name": "get_weather"}},
)

Pattern thực dụng: ép tool ở turn 1 khi biết chắc cần (form filling, structured extraction), rồi để auto ở turn sau cho LLM tự synthesize.

15

Foundation cho agent

Một câu phổ biến trong cộng đồng AI hiện nay:

Agent = LLM + tools + loop.

Cụ thể: LLM phát tool call → app execute → trả result → LLM xem result → phát tool call tiếp theo (hoặc dừng) → … Vòng lặp tiếp tục đến khi LLM không gọi tool nữa hoặc đạt max_steps. Đây chính là agent loop. Bài 44 sẽ trình bày chi tiết workflow một turn, Bài 45 đào sâu parallel/sequential, các bài về agent ở module sau sẽ dựng skeleton này thành planner, memory, multi-agent.

Hiểu Function Calling là điều kiện cần để hiểu agent. Mọi framework agent (LangGraph, CrewAI, AutoGen, LlamaIndex) đều build trên cùng một skeleton này, chỉ thêm trace, memory, planner.

16

Model Context Protocol (MCP)

MCP do Anthropic công bố 11/2024 là chuẩn open-source cho LLM client kết nối tới tool server qua giao thức chung. Vấn đề trước MCP:

  • Mỗi app gắn tool theo cách riêng — code lock-in.
  • Tool server không chia sẻ được giữa client (Claude Desktop, IDE, Slack bot…).
  • Auth, transport, schema mỗi nơi một kiểu.

MCP định nghĩa:

  • Server: process expose tool (resources, prompts, tools) qua stdio hoặc HTTP+SSE/Streamable HTTP.
  • Client: LLM host (Claude Desktop, Cursor, Claude Code) discover và gọi tool qua MCP.
  • Tool schema MCP tương thích trực tiếp với tools của Anthropic/OpenAI — cùng JSON Schema.

Đến 2026, MCP là chuẩn de facto: GitHub, Stripe, Slack, Notion, Google Drive đều có MCP server chính thức. Tool Use không thay đổi về bản chất — MCP chỉ là transport chuẩn cho việc host tool và discover chúng.

17

Best practice — viết tool description

  • Function description rõ mục đích và side-effect. "Sends an email to recipient. This action is irreversible." tốt hơn "Send email".
  • Parameter description cụ thể: "city: tên thành phố theo IATA hoặc tên tiếng Anh, ví dụ 'Hanoi', 'New York'".
  • Strong typing: dùng enum, format, minimum/maximum để giới hạn input. Schema chặt → model gọi đúng hơn.
  • Idempotent khi có thể: design tool sao cho gọi 2 lần cùng input ra cùng output, không gây side-effect lặp.
  • Một việc một tool: tránh tool đa năng. do_stuff(action, target) khó hơn cho LLM so với create_order, cancel_order, update_order.
  • Tên ngắn, snake_case: gpt-4o và claude đều handle tốt naming convention này.
  • Test với model nhỏ: nếu gpt-4o-mini gọi đúng, model lớn hơn càng dễ.
18

Pitfall thường gặp

  • Description mơ hồ: "Get data" — model không biết khi nào gọi. Sửa: nói rõ trả gì, dùng cho mục đích nào.
  • Result trả về quá dài: nhét nguyên 50KB JSON vào tool result → tốn token, model confuse. Sửa: filter, project field, paginate.
  • Quên gắn tool result vào history: gọi tool rồi không append role: "tool" trước khi gọi LLM lần 2 — OpenAI trả 400 error.
  • Hallucinate parameter: model bịa tên thành phố hoặc id không tồn tại. Sửa: validate input ở app, nếu sai trả error message rõ ràng để model retry.
  • JSON parse fail: arguments đôi khi không đúng schema. Dùng strict: True (OpenAI structured output cho tool) hoặc parse defensive.
  • Infinite loop: model gọi tool liên tục, không thoát. Phải có max_steps chặn.
  • Forget tool_call_id: result phải gắn id tương ứng với call gốc; sai id → model không match được.
19

Tools vs Agents

Hai khái niệm liên quan nhưng không bằng nhau:

  • Tool use đơn giản: 1 turn (hoặc một vòng request-response). User hỏi, LLM gọi 1-2 tool, trả lời. Không cần planner, không cần memory dài.
  • Agent: multi-turn loop. LLM lặp gọi tool nhiều lần, có planner, có memory, đôi khi có sub-agent. Phù hợp task phức tạp như "research topic X" hoặc "code feature Y".

Mọi agent đều dùng tool calling, nhưng không phải mọi tool calling đều thành agent. Chat assistant với "get_weather" là tool use 1 turn — không phải agent. Claude Code, Cursor, ChatGPT Operator là agent đầy đủ. Module này tập trung mechanism tool calling; concept agent sẽ ở các module sau.

20

Open-source model với tool use

Tool calling không còn là đặc quyền của model closed-source:

  • Llama 3.1+ (Meta, 7/2024): 8B/70B/405B đều support tool use với chat template chuẩn.
  • Qwen 2.5 (Alibaba, 9/2024): từ 7B trở lên, đặc biệt Qwen 2.5-Coder mạnh về structured output.
  • Mistral, Codestral, DeepSeek: tất cả expose API gần OpenAI schema khi serve qua vLLM, SGLang.
  • Gemma 2, Phi-3.5: tool use yếu hơn, cần prompt engineering hoặc fine-tune thêm.

Khi serve qua vLLM, Ollama, LM Studio, app chỉ cần POST tới endpoint giống OpenAI và parse tool_calls. Compatibility OpenAI schema là tiêu chuẩn chung của ecosystem 2024-2026.

21

Cost — schema + result là input token

Tool calling tốn token theo cách nhiều người không lường trước:

  • Tool schema: mỗi tool definition (tên + description + JSON Schema) được serialize thành chuỗi và tính vào input token mọi turn. 10 tool, mỗi tool 200 token = 2k token mỗi call.
  • Tool result: payload JSON trả về cũng là input cho turn LLM tiếp theo. Result dài 5KB ≈ 1.5k token.
  • Tool call output: LLM phát ra tool_calls tính vào output token, nhưng thường nhỏ (~50-200 token).

Một vòng tool calling 3 tool có thể tốn:

  • Schema: ~600 token × 2 lần gọi LLM = 1200.
  • Tool result: 3 × 300 = 900 token (chỉ tính ở lần gọi LLM thứ hai).
  • Output: 100 token.
  • Tổng ~2200 token cho một câu trả lời tưởng đơn giản.

Tối ưu: chỉ khai báo tool cần thiết cho mỗi turn (tool routing), nén tool result, dùng prompt caching cho schema không đổi.

22

Lộ trình Module 7

Module 7 gồm 5 bài, đi từ concept đến code chi tiết:

  • Bài 42 (bài này): Function Calling là gì, vì sao cần, ba nhóm tool, workflow 5 bước, OpenAI và Anthropic overview, MCP.
  • Bài 43: Tool schema — JSON Schema chi tiết, parameters, input_schema, type, enum, required, nested object.
  • Bài 44: Function calling workflow — code một turn end-to-end, parse tool call, execute, gửi tool result, LLM synthesize.
  • Bài 45: Parallel vs sequential tool calls — pattern multi-tool, asyncio.gather, ThreadPoolExecutor, agent loop, ReAct.
  • Bài 46: Tool error handling — schema invalid, parameter sai, downstream lỗi, retry, fallback.

Sau Module 7, bạn đã đủ kiến thức build agent thực sự ở các module kế tiếp.

23

Code Python — full flow

Một vòng đầy đủ OpenAI từ user query đến final answer:

from openai import OpenAI
import json

client = OpenAI()

def get_weather(city: str):
    # mock — trong thực tế gọi OpenWeather API
    return {"city": city, "temp_c": 28, "desc": "cloudy"}

weather_tool = {
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Lấy thời tiết hiện tại của một thành phố",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}

messages = [{"role": "user",
             "content": "Thời tiết Hà Nội thế nào?"}]

# Turn 1 — LLM phát tool call
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=[weather_tool],
)
msg = resp.choices[0].message
messages.append(msg)

# App execute tool
for tc in msg.tool_calls or []:
    args = json.loads(tc.function.arguments)
    result = get_weather(**args)
    messages.append({
        "role": "tool",
        "tool_call_id": tc.id,
        "content": json.dumps(result),
    })

# Turn 2 — LLM synthesize
resp2 = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=[weather_tool],
)
print(resp2.choices[0].message.content)
# "Hà Nội đang khoảng 28°C, trời nhiều mây."

Tương đương với Anthropic:

import anthropic, json

client = anthropic.Anthropic()
tools = [{
    "name": "get_weather",
    "description": "Lấy thời tiết hiện tại của một thành phố",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

messages = [{"role": "user", "content": "Thời tiết Hà Nội thế nào?"}]

resp = client.messages.create(
    model="claude-opus-4", max_tokens=1024,
    tools=tools, messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})

tool_results = []
for block in resp.content:
    if block.type == "tool_use":
        result = get_weather(**block.input)
        tool_results.append({
            "type": "tool_result",
            "tool_use_id": block.id,
            "content": json.dumps(result),
        })

messages.append({"role": "user", "content": tool_results})

resp2 = client.messages.create(
    model="claude-opus-4", max_tokens=1024,
    tools=tools, messages=messages,
)
print(resp2.content[0].text)

Hai SDK, cùng một mental model: schema → tool call → execute → tool result → final response. Các bài sau Module 7 sẽ generalize pattern này ra nhiều tool, nhiều turn, error handling.

24

Bài tập

  1. Define tool get_weather(city) mock (return dict cố định). Khai báo schema. Hỏi gpt-4o-mini "Thời tiết Hà Nội?". In msg.tool_calls, parse arguments, execute, gửi role: "tool" message, in final answer.
  2. Lặp lại bài 1 với Anthropic Claude. So sánh structure content array, cách gửi tool_result.
  3. Khai báo 3 tool: get_weather, calculator, search_web (cái sau mock return list). Test với 3 prompt khác nhau, mỗi prompt LLM nên chọn 1 tool khác. Print tên tool model chọn.
  4. Dùng tool_choice={"type": "function", "function": {"name": "calculator"}} để ép model gọi calculator với prompt "Hôm nay thứ mấy?". Quan sát model gọi tool gì với argument vô lý ra sao, suy nghĩ về vấn đề "ép tool sai context".
  5. (Tuỳ chọn) Thử tool get_weather với gpt-4o-mini, claude-haiku, và một model open-source (Llama 3.1 8B qua Ollama). So sánh tỉ lệ gọi đúng tool và đúng argument trên 20 prompt.