Tool Search — Các chiến lược tìm kiếm tool thay thế
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Công cụ AI sẽ thay đổi cách bạn làm việc: Embedding-based search rất mạnh nhưng có overhead: Cần setup và maintain embedding model Cold start time khi build. Điểm mấu chốt là biết cách đặt prompt đúng để nhận kết quả có thể sử dụng ngay.
- 2 Thành thật mà nói: Ý tưởng đơn giản: thay vì dùng ML để search, để Claude tự search bằng cách: List tất cả tool names trong system prompt. Phương pháp này hiệu quả trong hầu hết trường hợp, nhưng bạn cần điều chỉnh cho phù hợp ngữ cảnh riêng.
- 3 Không thể bỏ qua: import anthropic import json from typing import Dict, List, Optional client = anthropic.Anthropic Full tool catalog —. Đây là kiến thức nền tảng mà mọi người làm việc với AI đều cần hiểu rõ.
- 4 Khai thác tối đa công cụ AI: def rundeferredloadingagentuserrequest: str: """ Agent voi deferloading pattern: 1. Bí quyết nằm ở cách bạn cấu trúc yêu cầu — prompt càng rõ ràng, output càng sát nhu cầu thực tế.
- 5 Thành thật mà nói: Chiến lược Embedding Search describetool All tools upfront ML infrastructure Cần SentenceTransformer Không cần Không. Phương pháp này hiệu quả trong hầu hết trường hợp, nhưng bạn cần điều chỉnh cho phù hợp ngữ cảnh riêng.
Bài trước giới thiệu cách dùng embeddings để tìm tools. Nhưng không phải lúc nào cũng cần setup SentenceTransformer. Anthropic giới thiệu một pattern khác — đơn giản hơn, không cần ML infrastructure, và có một tính năng đặc biệt quan trọng: bảo toàn prompt cache khi danh sách tools thay đổi.
Vấn đề với embedding approach
Embedding-based search rất mạnh nhưng có overhead:
- Cần setup và maintain embedding model
- Cold start time khi build index
- Infrastructure phức tạp hơn cho team nhỏ
Và quan trọng hơn: khi bạn add tools mới vào active_tools list trong agent loop, Anthropic's prompt cache sẽ bị invalidate — tăng cost và latency.
Pattern thay thế: describe_tool meta-tool
Ý tưởng đơn giản: thay vì dùng ML để search, để Claude tự search bằng cách:
- List tất cả tool names trong system prompt (chỉ names, không có schemas)
-
Cung cấp
describe_tool— meta-tool cho phép Claude "đọc" full definition của một tool - Claude dựa vào names + descriptions ngắn để tự quyết định cần tool nào, rồi gọi
describe_toolđể lấy schema đầy đủ
Key innovation: defer_loading=True
Đây là điểm khác biệt quan trọng nhất. Với defer_loading=True:
- Tool definition không được inject vào cached prompt prefix
- Khi Claude discover và load một tool mới, phần cache prefix không bị invalidate
- Chi phí và latency của prompt caching được bảo toàn
Điều này quan trọng trong production vì tool catalogs thay đổi liên tục — team devops add tool mới, marketing add campaign tools — nếu mỗi lần add tool là mất cache, cost sẽ tăng vọt.
Setup: Tool registry với lazy loading
import anthropic
import json
from typing import Dict, List, Optional
client = anthropic.Anthropic()
# Full tool catalog — chỉ load khi được request
FULL_TOOL_CATALOG: Dict[str, Dict] = {
# CRM tools
"get_customer_profile": {
"name": "get_customer_profile",
"description": "Lay thong tin day du cua mot khach hang bao gom: contact info, purchase history, support tickets, preferences va segment.",
"input_schema": {
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"description": "Customer ID bat dau bang C-"
},
"include_history": {
"type": "boolean",
"description": "Co lay purchase history khong",
"default": True
}
},
"required": ["customer_id"]
}
},
"update_customer_segment": {
"name": "update_customer_segment",
"description": "Cap nhat customer segment (VIP, Regular, At-Risk, Churned) dua tren RFM score hoac manual assignment.",
"input_schema": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"segment": {
"type": "string",
"enum": ["VIP", "Regular", "At-Risk", "Churned", "New"]
},
"reason": {
"type": "string",
"description": "Ly do thay doi segment"
}
},
"required": ["customer_id", "segment"]
}
},
# Inventory tools
"get_stock_level": {
"name": "get_stock_level",
"description": "Kiem tra so luong ton kho hien tai cua san pham theo SKU. Tra ve: available, reserved, in-transit quantities.",
"input_schema": {
"type": "object",
"properties": {
"sku": {"type": "string", "description": "Product SKU"},
"warehouse_id": {
"type": "string",
"description": "Warehouse cu the (optional, neu bo trong lay tat ca kho)"
}
},
"required": ["sku"]
}
},
"trigger_reorder": {
"name": "trigger_reorder",
"description": "Tao purchase order khi stock xuong duoi reorder point. Tu dong chon supplier theo gia tot nhat.",
"input_schema": {
"type": "object",
"properties": {
"sku": {"type": "string"},
"quantity": {
"type": "integer",
"description": "So luong can dat them"
},
"urgent": {
"type": "boolean",
"description": "Express order (them phi)",
"default": False
}
},
"required": ["sku", "quantity"]
}
},
# Analytics tools
"get_sales_report": {
"name": "get_sales_report",
"description": "Tao bao cao doanh so theo period: ngay/tuan/thang/quy/nam. Bao gom: revenue, units sold, top products, top customers.",
"input_schema": {
"type": "object",
"properties": {
"period": {
"type": "string",
"enum": ["daily", "weekly", "monthly", "quarterly", "yearly"]
},
"start_date": {"type": "string", "description": "YYYY-MM-DD"},
"end_date": {"type": "string", "description": "YYYY-MM-DD"},
"breakdown_by": {
"type": "string",
"enum": ["product", "category", "region", "channel"],
"description": "Phan nhom theo chieu nao"
}
},
"required": ["period", "start_date", "end_date"]
}
},
# Finance tools
"process_refund": {
"name": "process_refund",
"description": "Xu ly yeu cau hoan tien cho don hang. Kiem tra dieu kien hoan hang, khoi tao refund transaction.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"amount": {
"type": "number",
"description": "So tien hoan (VND). De trong neu hoan toan bo."
},
"reason": {
"type": "string",
"enum": ["defective", "wrong_item", "not_delivered", "customer_changed_mind", "other"]
},
"notes": {"type": "string", "description": "Ghi chu them"}
},
"required": ["order_id", "reason"]
}
},
# HR tools
"get_employee_info": {
"name": "get_employee_info",
"description": "Lay thong tin nhan vien: department, position, start date, manager, performance rating, current salary band.",
"input_schema": {
"type": "object",
"properties": {
"employee_id": {"type": "string"},
"include_salary": {
"type": "boolean",
"description": "Co bao gom thong tin luong (can HR manager permission)",
"default": False
}
},
"required": ["employee_id"]
}
},
# DevOps tools
"get_service_health": {
"name": "get_service_health",
"description": "Kiem tra suc khoe cua cac microservices: uptime, response time P50/P95/P99, error rate, CPU/memory usage.",
"input_schema": {
"type": "object",
"properties": {
"service_name": {"type": "string"},
"time_window": {
"type": "string",
"enum": ["5m", "15m", "1h", "6h", "24h"],
"description": "Khoang thoi gian lay metrics",
"default": "1h"
}
},
"required": ["service_name"]
}
},
}
# Short descriptions cho tool listing (chi 1 dong)
TOOL_SHORT_DESCRIPTIONS = {
"get_customer_profile": "Lay thong tin day du cua khach hang",
"update_customer_segment": "Cap nhat segment cua khach hang (VIP/Regular/At-Risk)",
"get_stock_level": "Kiem tra ton kho hien tai cua san pham",
"trigger_reorder": "Tao purchase order khi het hang",
"get_sales_report": "Bao cao doanh so theo ngay/tuan/thang",
"process_refund": "Xu ly hoan tien don hang",
"get_employee_info": "Lay thong tin nhan vien",
"get_service_health": "Kiem tra trang thai microservices",
}
Define describe_tool meta-tool
DESCRIBE_TOOL_META = {
"name": "describe_tool",
"description": """Lay full schema va documentation cua mot tool cu the.
Goi truoc khi su dung bat ky tool nao de biet chinh xac parameters can thiet.
Tool nay se tra ve: description day du, input schema, examples.""",
"input_schema": {
"type": "object",
"properties": {
"tool_name": {
"type": "string",
"description": "Ten chinh xac cua tool can xem (tu danh sach trong system prompt)"
}
},
"required": ["tool_name"]
}
}
# tool_reference: cho phep tham chieu tool ma khong load definition
# Dung trong system prompt de list available tools
def build_tool_reference_list() -> str:
"""
Tao danh sach tools cho system prompt.
Chi list names + short descriptions, khong co full schemas.
"""
lines = ["AVAILABLE TOOLS (dung describe_tool de xem schema day du):"]
lines.append("")
by_category = {
"CRM": ["get_customer_profile", "update_customer_segment"],
"Inventory": ["get_stock_level", "trigger_reorder"],
"Analytics": ["get_sales_report"],
"Finance": ["process_refund"],
"HR": ["get_employee_info"],
"DevOps": ["get_service_health"],
}
for category, tool_names in by_category.items():
lines.append(f"[{category}]")
for name in tool_names:
desc = TOOL_SHORT_DESCRIPTIONS.get(name, "")
lines.append(f" - {name}: {desc}")
lines.append("")
return "
".join(lines)
Agent loop với defer_loading pattern
def run_deferred_loading_agent(user_request: str):
"""
Agent voi defer_loading pattern:
1. System prompt co tool list (names + short descs)
2. Cung cap describe_tool meta-tool
3. Claude goi describe_tool de load definition
4. Cache prefix duoc bao ton vi tools duoc defer
"""
tool_reference_list = build_tool_reference_list()
system_prompt = f"""Ban la enterprise assistant co quyen truy cap nhieu tools.
{tool_reference_list}
HUONG DAN:
1. Doc yeu cau cua user
2. Xac dinh tools can dung tu danh sach tren
3. Goi describe_tool de xem schema chinh xac
4. Su dung tools da load de hoan thanh nhiem vu
5. Bao cao ket qua ro rang cho user"""
# Ban dau chi co describe_tool
# Tools khac se duoc add vao khi Claude request
active_tools_dict = {"describe_tool": DESCRIBE_TOOL_META}
messages = [{"role": "user", "content": user_request}]
print(f"
User: {user_request}")
print(f"Initial context: system prompt + 1 meta-tool (tools deferred)
")
tool_calls_count = 0
describe_calls = 0
real_tool_calls = 0
while True:
# Chuyen dict sang list cho API
active_tools_list = list(active_tools_dict.values())
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=4096,
system=system_prompt,
tools=active_tools_list,
messages=messages
)
if response.stop_reason == "end_turn":
for block in response.content:
if hasattr(block, 'text'):
print(f"
Claude: {block.text}")
break
elif response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
tool_results = []
tool_calls_count += 1
for block in response.content:
if block.type == "tool_use":
if block.name == "describe_tool":
tool_name = block.input["tool_name"]
describe_calls += 1
if tool_name in FULL_TOOL_CATALOG:
# Load full definition
full_def = FULL_TOOL_CATALOG[tool_name]
# KEY: Add to active tools voi defer_loading=True concept
# Trong thuc te, day la luc Claude nhan duoc schema
# va co the goi tool trong turn tiep theo
active_tools_dict[tool_name] = full_def
print(f"[Discover] '{tool_name}' loaded into context")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps({
"tool_name": tool_name,
"schema": full_def,
"available": True,
"message": f"Tool '{tool_name}' da san sang su dung."
}, ensure_ascii=False)
})
else:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps({
"available": False,
"message": f"Tool '{tool_name}' khong ton tai. Hay chon tu danh sach trong system prompt."
})
})
elif block.name in FULL_TOOL_CATALOG:
# Execute discovered tool
real_tool_calls += 1
print(f"[Execute] {block.name}({json.dumps(block.input, ensure_ascii=False)[:60]}...)")
# Simulate execution
mock_result = simulate_tool_execution(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(mock_result, ensure_ascii=False)
})
else:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps({"error": f"Unknown tool: {block.name}"})
})
messages.append({"role": "user", "content": tool_results})
else:
break
print(f"
[Stats] describe_tool calls: {describe_calls} | real tool calls: {real_tool_calls}")
print(f"[Cache] Prompt prefix cache preserved (tools were deferred, not in cached prefix)")
def simulate_tool_execution(tool_name: str, inputs: Dict) -> Dict:
"""Simulate tool execution voi mock data."""
simulations = {
"get_customer_profile": lambda i: {
"customer_id": i.get("customer_id"),
"name": "Nguyen Thi Bich",
"email": "bich.nguyen@email.com",
"segment": "VIP",
"total_orders": 47,
"total_spent_vnd": 15750000,
"last_order": "2024-12-10"
},
"get_stock_level": lambda i: {
"sku": i.get("sku"),
"available": 234,
"reserved": 12,
"in_transit": 50,
"reorder_point": 100
},
"get_sales_report": lambda i: {
"period": i.get("period"),
"total_revenue_vnd": 1250000000,
"total_orders": 3847,
"top_products": ["SP-001", "SP-015", "SP-023"],
"growth_vs_previous": "+12.4%"
},
"process_refund": lambda i: {
"order_id": i.get("order_id"),
"refund_id": "REF-789456",
"amount_vnd": 450000,
"status": "approved",
"estimated_processing": "3-5 business days"
},
"get_service_health": lambda i: {
"service": i.get("service_name"),
"uptime": "99.97%",
"p50_ms": 45,
"p99_ms": 312,
"error_rate": "0.03%",
"status": "healthy"
},
}
simulator = simulations.get(tool_name)
if simulator:
return {"success": True, "data": simulator(inputs)}
return {"success": True, "data": {"message": f"[Mock result for {tool_name}]"}}
Demo: So sánh hai requests
# Request 1: CRM query
run_deferred_loading_agent(
"Lay thong tin khach hang C-5521, ho thuoc segment nao va da chi bao nhieu tien?"
)
# Request 2: Inventory + Analytics
run_deferred_loading_agent(
"Kiem tra stock cua SP-001 va cho toi biet doanh so thang 12/2024"
)
Output Request 1:
User: Lay thong tin khach hang C-5521...
[Discover] 'get_customer_profile' loaded into context
[Execute] get_customer_profile({"customer_id": "C-5521"}...)
Claude: Khach hang C-5521 (Nguyen Thi Bich) thuoc segment VIP.
Ho da dat tong cong 47 don hang voi tong gia tri 15,750,000 VND.
Don hang gan nhat la ngay 10/12/2024.
[Stats] describe_tool calls: 1 | real tool calls: 1
[Cache] Prompt prefix cache preserved
So sánh ba chiến lược tool search
| Chiến lược | Embedding Search | describe_tool | All tools upfront |
|---|---|---|---|
| ML infrastructure | Cần (SentenceTransformer) | Không cần | Không cần |
| Context usage | Thấp (3-5 tools) | Thấp (1-3 tools) | Rất cao (tất cả tools) |
| Cache preservation | Trung bình | Tốt (defer_loading) | Tốt (cố định) |
| Discovery latency | 1 search call | 1-2 describe calls | 0 (sẵn có) |
| Scale đến 1000+ tools | Tốt | Tốt | Không thể |
| Phù hợp nhất | Catalog lớn, unknown tools | Catalog có structure, cache quan trọng | Ít tools (<20) |
Khi nào dùng describe_tool pattern?
Ideal khi:
- Cost optimization quan trọng — prompt cache bị invalidate thường xuyên làm tăng chi phí
- Tool catalog có naming convention rõ ràng — Claude có thể đoán tool cần dùng từ tên
- Tools được thêm/sửa thường xuyên — cần bảo toàn cache khi catalog thay đổi
- Team không muốn maintain ML infrastructure cho embedding search
Kết hợp hai patterns:
Trong production lớn, thường kết hợp cả hai:
- Dùng embedding search khi user query mơ hồ — tìm semantic matches
- Dùng describe_tool cho fine-grained discovery khi đã biết category
- Cả hai đều bảo vệ context window khỏi bị ngốn bởi tool definitions
Tổng kết
describe_tool với defer_loading là pattern elegant cho tool discovery:
- Zero ML infrastructure — không cần embedding model hay vector database
- Cache preservation — defer_loading giữ tools khỏi cached prompt prefix, tránh invalidation
- Tool names làm ngôn ngữ chung — đặt tên tool tốt giúp Claude tìm đúng ngay lần đầu
- Graceful degradation — nếu tool không tồn tại, model biết ngay và suggest alternative
Cả hai patterns — embedding search và describe_tool — đều là tools trong arsenal của bạn. Chọn theo infrastructure, team size, và requirements về cache optimization của project.
Bước tiếp theo: Quay lại Tool Use series để xem full picture về cách build production-grade Claude agents với memory, compaction, PTC, và dynamic tool loading.
Bai viet co huu ich khong?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.






