
Tool Use với Claude API: hướng dẫn định nghĩa tool, xử lý vòng lặp tool_use → tool_result để agent tự gọi hàm
Người học biết cách bật tool use trên Claude API: viết JSON schema cho tool, đọc khối tool_use trong response, trả tool_result đúng định dạng và chạy
Claude trả lời rất khá khi chỉ cần văn bản, nhưng khi bạn cần nó query database, gọi API thời tiết, hoặc check lịch — model raw không làm được. Tool use giải quyết đúng vấn đề đó: bạn khai báo schema, Claude tự quyết định khi nào gọi tool và truyền argument gì. Bài này đi qua cấu trúc JSON schema chuẩn, vòng lặp `tool_use` → `tool_result`, code Python chạy được với 2 tool liên tiếp, và 5 lỗi mình hay gặp khi build agent thực tế.
Tool use là gì và khi nào cần dùng
Tool use là khả năng của Claude tự động nhận diện khi nào cần tương tác với các công cụ bên ngoài để hoàn thành yêu cầu của bạn. Thay vì chỉ trả lời dựa trên kiến thức nội tại, Claude sẽ quyết định gọi một function cụ thể để lấy thêm dữ liệu hoặc thực hiện một hành động nào đó. Điều này giúp Claude mở rộng đáng kể phạm vi xử lý tác vụ, vượt ra ngoài giới hạn của một mô hình ngôn ngữ thuần túy.
Có hai loại tool chính: client tools và server tools. Client tools là những công cụ bạn tự định nghĩa và chạy trong ứng dụng của mình. Claude sẽ trả về thông tin cần thiết để bạn gọi function đó. Ngược lại, server tools là các công cụ được Anthropic cung cấp sẵn và chạy trên hạ tầng của họ, ví dụ như web_search để tìm kiếm thông tin trên internet hoặc code_execution để chạy code. Việc phân biệt này giúp bạn linh hoạt hơn trong việc tích hợp Claude vào hệ thống hiện có.
Tool use đặc biệt hữu ích trong nhiều trường hợp thực tế. Bạn có thể dùng nó để query database nội bộ, gọi các REST API để lấy thông tin sản phẩm, đọc file từ hệ thống, hoặc thậm chí là trigger một workflow phức tạp nào đó. Ví dụ, Claude có thể tích hợp vào các nền tảng sáng tạo như Ableton, Blender, Photoshop và Splice để hỗ trợ các dự án âm nhạc, thiết kế và viết kịch bản [F5]. Điều này biến Claude thành một agent có khả năng tương tác và thực thi hành động trong thế giới thực.
Điểm khác biệt chính giữa tool use và function calling thông thường là cách Claude phản hồi. Khi cần dùng tool, Claude sẽ trả về một stop_reason là 'tool_use' cùng với thông tin về tool cần gọi và các tham số. Sau đó, bạn có trách nhiệm thực thi tool đó và gửi kết quả (tool_result) trở lại cho Claude để nó tiếp tục cuộc hội thoại. Quá trình này thường diễn ra trong một vòng lặp cho đến khi Claude hoàn thành nhiệm vụ.
Các mô hình Claude mới nhất đều hỗ trợ tool use native. Cụ thể, Claude Opus 4.8, phiên bản tiên tiến nhất của Anthropic phát hành ngày 28 tháng 5 năm 2026 [F1], có khả năng xử lý các tác vụ mã hóa phức tạp với "dynamic workflows" dưới dạng bản xem trước nghiên cứu [F4]. Ngoài ra, Claude Sonnet 4.5 cũng hỗ trợ tính năng này, giúp bạn xây dựng các ứng dụng mạnh mẽ hơn.

Định nghĩa tool: cấu trúc JSON schema chuẩn
Mỗi tool gửi cho Claude API là 1 JSON object với 3 field bắt buộc: `name`, `description`, và `input_schema`. `name` là định danh duy nhất Claude dùng để tham chiếu khi gọi tool. `description` mô tả tool làm gì và khi nào nên dùng. `input_schema` định nghĩa kiểu dữ liệu tham số theo chuẩn JSON Schema. Thiếu 1 trong 3 field này, request sẽ fail validation trước khi tới model.
{
"name": "get_weather",
"description": "Lấy thời tiết hiện tại tại 1 địa điểm. Dùng khi user hỏi nhiệt độ, độ ẩm, hoặc tình trạng trời ngay lúc này. Không dùng cho dự báo nhiều ngày — task đó hãy dùng get_forecast.",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "Tên thành phố hoặc địa điểm, ví dụ 'Hà Nội' hoặc 'San Francisco, CA'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Đơn vị nhiệt độ. Default celsius nếu không chỉ định."
}
},
"required": ["location"]
}
}Description là phần quan trọng nhất nhưng dễ bị viết qua loa. Theo kinh nghiệm của mình, chất lượng description ảnh hưởng phần lớn tới việc Claude chọn đúng tool hay không. Bạn nên nói rõ 4 thứ: tool dùng cho task gì, input cần gì, output trả về kiểu nào, và quan trọng nhất là khi nào KHÔNG nên dùng. Nếu schema có 2 tool gần nhau như `search_users` và `get_user`, description phải vạch ranh giới rõ — nếu không model sẽ chọn nhầm và bạn debug rất mệt.
Về naming, convention phổ biến trong SDK Anthropic là snake_case theo pattern verb-noun. Vài ví dụ chuẩn: `get_weather`, `search_orders`, `create_invoice`, `delete_session`. Tránh camelCase hay PascalCase để đồng nhất với docs. Verb đứng trước giúp Claude phân loại nhanh trong schema lớn:
`get_*`, `list_*`, `search_*` cho read-only
`create_*`, `update_*`, `delete_*` cho mutation
`run_*`, `execute_*` cho task chạy lâu hoặc side-effect mạnh
Lỗi hay gặp nhất khi mới làm tool use là description ngắn kiểu `"Get user info"`. Với description này, nếu schema có thêm `get_user_orders` hoặc `get_user_profile`, model sẽ lúng túng không biết chọn cái nào. Cách fix đơn giản: viết description 2-3 câu, nói rõ scope và phân biệt với tool tương tự. Một lỗi khác là quên field `required` trong `input_schema` — Claude sẽ gọi tool mà thiếu tham số cần thiết, code phía bạn crash khi đọc `input.location`.
Vòng lặp tool_use → tool_result step-by-step
Để Claude có thể tự động gọi hàm và xử lý thông tin, chúng ta cần triển khai một vòng lặp giữa `tool_use` và `tool_result`. Đây là cốt lõi của Tool Use, cho phép Claude thực hiện các tác vụ phức tạp mà không cần sự can thiệp liên tục từ bạn.
Về cơ bản, vòng lặp này hoạt động như một cuộc hội thoại hai chiều: Claude yêu cầu thực hiện một công cụ, bạn thực thi nó và trả lại kết quả cho Claude, sau đó Claude tiếp tục xử lý hoặc yêu cầu công cụ khác.
Các bước trong vòng lặp
Ví dụ pseudocode
messages = [...] # Lịch sử hội thoại ban đầu
tools = [...] # Định nghĩa các tool
while True:
response = claude_api_call(messages, tools)
if response.stop_reason == 'tool_use':
tool_use = response.content[-1] # Lấy khối tool_use cuối cùng
tool_name = tool_use.name
tool_input = tool_use.input
# Thực thi tool tương ứng
tool_output = execute_tool_function(tool_name, tool_input)
# Thêm phản hồi của Claude và kết quả tool vào lịch sử
messages.append({
"role": "assistant",
"content": response.content
})
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(tool_output)
}
]
})
else:
# Claude đã kết thúc hoặc trả lời trực tiếp
messages.append({
"role": "assistant",
"content": response.content
})
break
final_answer = messages[-1].contentCode mẫu Python: agent gọi 2 tool liên tiếp
Để minh họa cách Claude API xử lý tool use đa bước, mình sẽ xây dựng một ví dụ đơn giản. Agent sẽ có hai tool: một để lấy thời gian hiện tại và một để lấy thông tin thời tiết. Claude sẽ tự động gọi các tool này dựa trên yêu cầu của bạn, sau đó tổng hợp kết quả để trả lời.
Đầu tiên, bạn cần cài đặt Anthropic SDK cho Python. Sau đó, định nghĩa các tool mà Claude có thể sử dụng. Ở đây, chúng ta có `get_current_time` và `get_current_weather`.
import anthropic
import json
from datetime import datetime
# Khởi tạo client Anthropic
client = anthropic.Anthropic()
# Định nghĩa các tool
tools = [
{
"name": "get_current_time",
"description": "Lấy thời gian hiện tại theo định dạng HH:MM:SS.",
"input_schema": {
"type": "object",
"properties": {}
}
},
{
"name": "get_current_weather",
"description": "Lấy thông tin thời tiết hiện tại cho một thành phố cụ thể.",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "Tên thành phố (ví dụ: 'Hanoi', 'London')."
}
},
"required": ["location"]
}
}
]
# Hàm thực thi tool
def process_tool_call(tool_name, tool_input):
if tool_name == "get_current_time":
return {"time": datetime.now().strftime("%H:%M:%S")}
elif tool_name == "get_current_weather":
location = tool_input.get("location", "Unknown")
# Đây là dữ liệu giả lập, trong thực tế sẽ gọi API thời tiết
return {"location": location, "temperature": "25°C", "conditions": "Nắng đẹp"}
return {"error": "Tool không tồn tại"}
# Vòng lặp chính để xử lý tool use
def run_conversation(user_message, max_iterations=5):
messages = [
{"role": "user", "content": user_message}
]
for _ in range(max_iterations):
response = client.messages.create(
model="claude-3-opus-20240229", # Hoặc model bạn đang dùng
max_tokens=4000,
messages=messages,
tools=tools
)
if response.stop_reason == "tool_use":
tool_use = response.content[0]
tool_name = tool_use.name
tool_input = tool_use.input
print(f"Claude gọi tool: {tool_name} với input {tool_input}")
tool_result = process_tool_call(tool_name, tool_input)
print(f"Kết quả tool: {tool_result}")
messages.append(response.content[0])
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": json.dumps(tool_result)
}
]
})
else:
return response.content[0].text
return "Đã đạt số lần lặp tối đa cho tool use."
# Ví dụ sử dụng
user_query = "Thời gian hiện tại là bao nhiêu và thời tiết ở Hà Nội thế nào?"
final_answer = run_conversation(user_query)
print(f"\nCâu trả lời cuối cùng của Claude: {final_answer}")Trong đoạn code trên, hàm `run_conversation` sẽ liên tục gửi `messages` và `tools` đến Claude. Nếu Claude quyết định gọi một tool (`response.stop_reason == "tool_use"`), chúng ta sẽ thực thi tool đó thông qua `process_tool_call` và gửi kết quả trở lại Claude dưới dạng `tool_result`.
Bạn sẽ thấy Claude gọi `get_current_time` trước, sau đó là `get_current_weather` với `location` là 'Hà Nội'. Sau khi nhận đủ kết quả từ cả hai tool, Claude sẽ tổng hợp lại thành một câu trả lời hoàn chỉnh.
Để tránh vòng lặp vô hạn, mình đã thêm tham số `max_iterations` với giá trị mặc định là 5. Điều này giới hạn số lần Claude có thể gọi tool liên tiếp. Ngoài ra, việc đặt `max_tokens` hợp lý cũng quan trọng để kiểm soát chi phí và hiệu suất, đặc biệt khi sử dụng các model như Claude Opus 4.8 có chi phí 5 đô la cho mỗi triệu token đầu vào và 25 đô la cho mỗi triệu token đầu ra [F2].

Lỗi hay gặp và cách debug
Khi làm việc với Tool Use của Claude API, bạn có thể gặp một số lỗi phổ biến. Việc hiểu rõ nguyên nhân sẽ giúp mình debug nhanh chóng và hiệu quả hơn.
Một lỗi thường gặp là `tool_use_id` không khớp. Bạn cần đảm bảo rằng `tool_use_id` trong message `tool_result` phải chính xác là ID mà Claude đã trả về trong block `tool_use` của nó. Nếu không khớp, API sẽ báo lỗi.
Lỗi `schema validation fail` xảy ra khi Claude trả về input không đúng với kiểu dữ liệu bạn đã định nghĩa trong schema của tool. Để khắc phục, mình nên viết `description` cho tool và các parameter thật rõ ràng, cụ thể để Claude hiểu đúng yêu cầu. Claude Opus 4.8 có khả năng "trung thực" được cải thiện, giúp nó ít đưa ra các tuyên bố không có căn cứ hơn [F3], nhưng việc mô tả rõ ràng vẫn rất quan trọng.
Quên append `assistant` message trước `tool_result` cũng là một lỗi phổ biến. Nếu bạn gửi `tool_result` mà không có message `assistant` tương ứng ngay trước đó, API sẽ trả về lỗi 400. Luôn nhớ duy trì đúng thứ tự message trong lịch sử hội thoại.
Khi `tool_result` trả về quá nhiều dữ liệu, token có thể tăng nhanh và dẫn đến chi phí cao. Nếu kết quả quá dài, mình có thể cắt bớt hoặc tóm tắt thông tin quan trọng trước khi gửi lại cho Claude. Chi phí cho Claude Opus 4.8 là 5 đô la cho mỗi triệu token đầu vào và 25 đô la cho mỗi triệu token đầu ra [F2].
Để ép Claude gọi tool khi debug, bạn có thể thiết lập `tool_choice: 'any'` trong lời gọi API. Điều này sẽ buộc Claude phải chọn một trong các tool đã định nghĩa. Cuối cùng, khi gặp lỗi khó hiểu, mình nên log toàn bộ raw response từ API thay vì chỉ dựa vào abstraction của SDK. Điều này giúp mình thấy được chính xác những gì API trả về và dễ dàng xác định nguyên nhân hơn.
Mẹo nâng cao: parallel tools và server tools
Claude Opus 4.8, phiên bản mới nhất của Anthropic ra mắt ngày 28 tháng 5 năm 2026, mang đến nhiều cải tiến đáng kể [F1]. Một trong số đó là khả năng hỗ trợ "dynamic workflows" dưới dạng bản xem trước nghiên cứu [F4]. Tính năng này cho phép Claude xử lý các tác vụ mã hóa phức tạp bằng cách triển khai hàng trăm tác nhân phụ song song [F4].
Với tool use, Claude có thể trả về nhiều block `tool_use` trong một phản hồi duy nhất. Điều này có nghĩa là nó yêu cầu gọi nhiều công cụ cùng lúc. Để xử lý hiệu quả, bạn nên thực thi các lời gọi công cụ này đồng thời, ví dụ dùng `asyncio.gather` trong Python. Sau đó, bạn gửi tất cả các `tool_result` trở lại Claude trong một lần.
Anthropic cũng cung cấp các "server tools" sẵn có mà bạn không cần tự implement, như `web_search`, `code_execution` và `web_fetch`. Các công cụ này giúp bạn nhanh chóng mở rộng khả năng của Claude mà không tốn công phát triển từ đầu.
Khi quyết định sử dụng client-side tools (tự định nghĩa) hay server-side tools (có sẵn), bạn cần cân nhắc các yếu tố như độ trễ (latency), khả năng kiểm soát (control) và chi phí (cost). Mỗi lựa chọn đều có ưu và nhược điểm riêng, phù hợp với từng trường hợp sử dụng cụ thể.
Để tìm hiểu sâu hơn về tool use và các kỹ thuật nâng cao, bạn có thể tham khảo chuỗi 6 bài học về tool use trên trang của Anthropic.
Tool use là nền tảng để biến Claude từ chatbot thành agent thật sự gọi được hàm trong codebase của bạn. Khi đã quen vòng lặp `tool_use` → `tool_result`, bước tiếp theo là gắn MCP server để chuẩn hoá tool layer — bạn có thể xem bài MCP starter pack trên blog để nối tiếp.