Tool Use / Function Calling — cách AI 'gọi function' thay vì chỉ trả text
Tool Use cho AI khả năng gọi function, query DB, fetch API, execute code thay vì chỉ generate text. Foundation cho mọi AI agent 2026. Hiểu pattern Tool Definition + Tool Choice + Multi-tool orchestration + 5 anti-pattern khi build production agent.
Mục lục bài viết(31)

Sơ đồ API Gateway architecture — gateway điều phối multiple service. Pattern tương tự AI Tool Use: AI là "gateway" decide call tool nào (get_weather, send_email, search_db, run_code...) dựa trên user query, orchestrate result thành response. Tool Use là foundation cho agent — không có Tool Use thì AI chỉ "chat" không "do" được. Nguồn: Wikimedia Commons (CC BY-SA 4.0).
Hiểu đơn giản nhất
LLM mặc định chỉ làm 1 việc: generate text dựa trên prompt. Hạn chế:
- Không biết thời gian thật ("hôm nay là...")
- Không tra cứu data live (giá cổ phiếu, đơn hàng status)
- Không send email, không update DB, không run code
Tool Use = cấp cho AI khả năng "gọi function" để break out limitation.
Flow Tool Use
1. User: "Đơn VC2026000001 đang ở trạng thái nào?"
↓
2. AI thấy "đơn hàng" + có tool `get_order_status` → DECIDE call tool
↓
3. AI generate args: { order_number: "VC2026000001" }
↓
4. Framework execute tool → return { status: "shipped", eta: "2026-05-25" }
↓
5. AI nhận result → synthesize: "Đơn VC2026000001 đã ship, dự kiến giao 25/05"
| Khái niệm | Vai trò |
|---|---|
| Tool Definition | Schema mô tả tool: name + description + input schema |
| Tool Choice | Cách AI decide: auto / required / specific tool |
| Tool Call | AI generate args call tool cụ thể |
| Tool Result | Framework execute → return data về AI |
| Multi-tool | AI có thể call multiple tool trong 1 turn |
| Parallel tool | Multiple tool execute song song |
Tool Use là foundation cho mọi AI agent 2026. Không có Tool Use = chỉ chatbot thuần.
Tại sao bạn cần biết
- Mọi AI agent production dùng Tool Use. Cursor Agent, Claude Code, ChatGPT Plugins — đều build trên Tool Use.
- Mở rộng AI từ "chatbot" thành "agent thật". Email + DB + payment + code execution = productivity 10x.
- Foundation cho MCP. MCP là layer cao hơn standardize tool across vendor — học Tool Use trước, MCP sau.
- Critical cho B2B SaaS AI features. "AI auto reply email", "AI generate report", "AI sync data" — đều cần Tool Use.
- Security implication. Tool Use mở attack surface — hiểu mới defend đúng.
Anatomy Tool Definition
const tool = {
name: "get_order_status",
description: `
Get current status of a vietcodex.com order by order number.
Use this when user asks about order delivery, status, or ETA.
Examples of trigger queries:
- "Đơn VC2026000001 đang ở đâu?"
- "Khi nào nhận được hàng?"
- "Status order #123?"
DO NOT use for:
- Refund requests (use 'refund_order' tool)
- Order creation (use 'create_order' tool)
Returns object with status, eta, tracking_url.
`,
input_schema: {
type: "object",
properties: {
order_number: {
type: "string",
description: "Order number, format VC<year><6-digit>, e.g. VC2026000001",
pattern: "^VC\\d{10}$"
}
},
required: ["order_number"]
}
};3 thành phần critical:
1. name — concise + descriptive
✅ "get_order_status"
✅ "send_telegram_notification"
❌ "order" // too vague
❌ "doStuff" // uselesssnake_case, action verb, < 30 char.
2. description — when to use + examples
5 yếu tố:
- Khi nào dùng tool này (primary purpose)
- 3-5 ví dụ trigger query
- Negative example (khi KHÔNG dùng)
- Return format brief
- Side effect warning (nếu tool mutate state)
Description quality quyết định 80% accuracy AI gọi tool đúng.
3. input_schema — strict JSON Schema
Required fields:
type: objectpropertiesvới type + descriptionrequiredarray- Enum cho categorical
- Pattern regex / Min-max cho validation
Strict schema = AI generate args đúng format + security barrier.
Tool Use code pattern (Anthropic)
Setup
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const TOOLS = [
{
name: "get_order_status",
description: "...",
input_schema: { ... }
},
{
name: "send_email",
description: "...",
input_schema: { ... }
},
// ... more tools
];Single tool call
async function chat(userMessage: string) {
// Step 1: AI decide tool
const response = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools: TOOLS,
messages: [{ role: "user", content: userMessage }]
});
// Step 2: Check if AI called tool
if (response.stop_reason === "tool_use") {
const toolUse = response.content.find(c => c.type === "tool_use");
if (!toolUse) throw new Error("Expected tool_use");
// Step 3: Execute tool
const toolResult = await executeToolByName(toolUse.name, toolUse.input);
// Step 4: Send result back to AI
const final = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools: TOOLS,
messages: [
{ role: "user", content: userMessage },
{ role: "assistant", content: response.content },
{
role: "user",
content: [{
type: "tool_result",
tool_use_id: toolUse.id,
content: JSON.stringify(toolResult)
}]
}
]
});
return final.content[0].type === "text" ? final.content[0].text : "";
}
// No tool needed, return AI text
return response.content[0].type === "text" ? response.content[0].text : "";
}Multi-turn tool loop
Production agent thường cần multi-turn (AI call tool A, see result, decide call tool B, ...):
async function agentLoop(userMessage: string, maxTurns = 10) {
const messages: any[] = [{ role: "user", content: userMessage }];
for (let turn = 0; turn < maxTurns; turn++) {
const response = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 4096,
tools: TOOLS,
messages
});
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason === "end_turn") {
// AI finished, return final answer
return extractText(response);
}
if (response.stop_reason === "tool_use") {
// Execute all tool calls in parallel
const toolUses = response.content.filter(c => c.type === "tool_use");
const results = await Promise.all(
toolUses.map(t => executeToolByName(t.name, t.input))
);
messages.push({
role: "user",
content: toolUses.map((t, i) => ({
type: "tool_result",
tool_use_id: t.id,
content: JSON.stringify(results[i])
}))
});
// Continue loop
}
}
throw new Error("Max turns exceeded");
}Tool Choice — control AI decision
3 mode:
tool_choice: "auto" (default)
AI decide có gọi tool hay không.
{ tool_choice: { type: "auto" } }tool_choice: "any"
AI BUỘC call ít nhất 1 tool (không trả text thuần).
{ tool_choice: { type: "any" } }Use case: structured output forcing AI dùng tool format thay vì free text.
tool_choice: "tool" (specific)
AI BUỘC call tool cụ thể.
{ tool_choice: { type: "tool", name: "get_order_status" } }Use case: workflow biết trước phải call tool nào.
Parallel tool calls
Claude 3.5+ + GPT-4 Turbo support parallel:
// User: "Thời tiết Hà Nội và Sài Gòn"
// AI generates 2 tool calls trong 1 response
{
content: [
{ type: "tool_use", id: "1", name: "get_weather", input: { city: "Hanoi" } },
{ type: "tool_use", id: "2", name: "get_weather", input: { city: "HCMC" } }
]
}
// Execute parallel
const results = await Promise.all([
getWeather("Hanoi"),
getWeather("HCMC")
]);
// Result: 1s parallel vs 2s sequentialSaving 50%+ latency cho query có multiple independent tool need.
Common Tool patterns
Pattern 1: Read-only retrieval
const getOrderStatus = {
name: "get_order_status",
description: "Read order status, no side effect",
input_schema: { ... }
};
// Implementation
async function executeGetOrderStatus(input: { order_number: string }) {
return await db.query.orders.findFirst({
where: eq(orders.orderNumber, input.order_number)
});
}Pattern 2: Write/mutation với confirmation
const sendEmail = {
name: "send_email_to_customer",
description: "Send email. CRITICAL: User must confirm before send.",
input_schema: { ... }
};
// Implementation requires human approval
async function executeSendEmail(input: EmailParams) {
// Queue for human approval
await queue.add("pending-email", input);
return { status: "pending_human_approval", queue_id: ... };
}Pattern 3: Code execution sandboxed
const runPython = {
name: "run_python_code",
description: "Execute Python in isolated sandbox. No network, readonly fs.",
input_schema: {
type: "object",
properties: {
code: { type: "string", description: "Python code" }
},
required: ["code"]
}
};
async function executeRunPython(input: { code: string }) {
return await sandbox.execute("python3", input.code, {
timeout: 5000,
network: false,
filesystem: "readonly"
});
}Pattern 4: Multi-step chained
// User: "Tìm 3 customer cao nhất + gửi email upgrade offer"
// AI auto chains:
// 1. query_top_customers({ limit: 3 })
// 2. For each customer:
// a. get_customer_email({ customer_id })
// b. send_email({ to: email, template: "upgrade_offer" })AI orchestrate sequence dựa trên user goal.
5 Anti-patterns
1. Tool description vague
❌ description: "Get data"
✅ description: "Get customer order history. Use when user asks 'my orders', 'past purchases', etc."2. Too many tools (50+)
AI choice degrades với > 20 tools. Solution:
- Group tools theo namespace
- Use tool router (Haiku classifier → switch sub-set)
- MCP server multi-server pattern
3. No input validation
// BAD
async function executeRunSQL({ query }) {
return db.execute(query); // SQL injection paradise
}
// GOOD
async function executeRunSQL({ query }) {
if (!query.match(/^SELECT/i)) throw new Error("Only SELECT allowed");
if (query.includes(";")) throw new Error("Single statement only");
return db.execute(query);
}4. Synchronous expensive tool
// BAD: 30s tool blocking AI response
async function executeProcessVideo({ url }) {
return await processVideo(url); // 30s
}
// GOOD: queue + return job_id
async function executeProcessVideo({ url }) {
const jobId = await queue.add("video", { url });
return { status: "queued", job_id: jobId, check_after: "30s" };
}5. No error handling in tool result
// BAD: tool throw → AI confused
async function execute(input) {
return await fragileAPI(input); // throws on 500
}
// GOOD: graceful error
async function execute(input) {
try {
return { success: true, data: await fragileAPI(input) };
} catch (e) {
return { success: false, error: e.message, retry_after: 60 };
}
}Ví dụ thực tế: vietcodex.com Customer Support Agent (proposed Q3 2026)
const SUPPORT_TOOLS = [
// Read-only knowledge
{ name: "search_wiki", description: "Search wiki.vietcodex.com docs" },
{ name: "get_service_pricing", description: "Get pricing for service" },
{ name: "get_order_status", description: "Get order status by number" },
// Customer-specific (need auth)
{ name: "get_my_orders", description: "Get my orders (auto-scoped to user)" },
{ name: "get_my_subscription", description: "Get my subscription detail" },
// Actions (need confirmation)
{ name: "create_support_ticket", description: "Create ticket" },
{ name: "schedule_call", description: "Book discovery call with team" },
// Escalation
{ name: "escalate_to_human", description: "Transfer to human support" }
];
// Agent loop
async function supportAgent(userMessage: string, userId: string) {
const messages = [
{ role: "user", content: userMessage }
];
for (let turn = 0; turn < 5; turn++) {
const response = await client.messages.create({
model: "claude-sonnet-4-5",
system: SUPPORT_SYSTEM_PROMPT,
tools: SUPPORT_TOOLS,
messages
});
if (response.stop_reason === "end_turn") {
return extractText(response);
}
if (response.stop_reason === "tool_use") {
const toolUses = response.content.filter(c => c.type === "tool_use");
const results = await Promise.all(
toolUses.map(t => executeWithAuth(t, userId))
);
messages.push({ role: "assistant", content: response.content });
messages.push({
role: "user",
content: toolUses.map((t, i) => ({
type: "tool_result",
tool_use_id: t.id,
content: JSON.stringify(results[i])
}))
});
}
}
}Mỗi turn agent có thể: search wiki → get my orders → search pricing → escalate. AI orchestrate based on user need.
Cái gì có thể sai
| Vấn đề | Triệu chứng | Cách fix |
|---|---|---|
| AI không gọi tool dù query match | Description vague | Rewrite description với examples |
| AI gọi sai tool | Multiple tool similar purpose | Add negative example "DO NOT use for X" |
| Tool args malformed | Schema không strict | Add enum + pattern regex |
| Infinite tool loop | Tool result làm AI re-trigger same tool | Set max_turns + dedup tool calls |
| Slow response > 30s | Tool synchronous heavy | Queue async + return job_id |
| Tool injection attack | Args contain malicious SQL/shell | Sanitize args trong tool implementation |
| Cost spike | Multi-turn loop expensive | Cap turn count + cap output tokens |
| Tool result too large | 50KB JSON crash context | Truncate + summarize before pass to AI |
Tóm tắt 1 dòng
Tool Use / Function Calling = cấp cho AI khả năng gọi function (DB query, API call, code execute) thay vì chỉ generate text. Foundation cho mọi agent. Anatomy: name + description + JSON Schema strict. Tool Choice: auto/any/specific. Parallel tool calls save 50% latency. Anthropic native + OpenAI/Gemini tương tự. Anti-pattern: vague description, > 20 tools, no validation, sync expensive, no error handling. Pattern production: read-only retrieval + write với confirmation + sandbox execution + multi-step chained. Foundation cho MCP layer cao hơn.
Đọc tiếp
- MCP (Model Context Protocol) — Tool Use standardized cross-vendor
- Agent Framework Basics — orchestrate Tool Use thành autonomous loop (cùng wave)
- AI Security — Prompt injection + 7 mitigation — Tool Use mở attack surface
- RAG là gì — RAG vs Tool Use complementary