Trong bài viết này, tôi sẽ chia sẻ những kinh nghiệm thực chiến khi xây dựng hệ thống Agent với khả năng sử dụng tool thông minh. Cách đây 8 tháng, tôi từng gặp một vấn đề nan giải: hệ thống chatbot AI cho sàn thương mại điện tử của một startup Việt Nam đang tiêu tốn $2,340 mỗi tháng chỉ để trả lời câu hỏi về đơn hàng. Sau khi tối ưu chiến lược tool selection và call batching, con số này giảm xuống còn $186 — tiết kiệm 92%. Câu chuyện này sẽ hướng dẫn bạn từng bước để đạt được kết quả tương tự.

Tại Sao Tool Use Quan Trọng Trong Hệ Thống Agent

Khác với LLM thông thường chỉ sinh text, Agent cần tương tác với thế giới thực. Một Agent hiệu quả phải:

Với nền tảng HolyShehe AI, bạn có thể triển khai chiến lược này với chi phí cực kỳ cạnh tranh: DeepSeek V3.2 chỉ $0.42/M tokens so với $8 của GPT-4.1. Điều này có nghĩa bạn có thể thử nghiệm nhiều hơn, tối ưu kỹ hơn mà không lo về chi phí.

Kiến Trúc Tool Registry Thông Minh

Đầu tiên, bạn cần xây dựng một hệ thống đăng ký tool có khả năng metadata-driven selection. Dưới đây là implementation hoàn chỉnh:

"""
Tool Registry System - HolySheep AI Integration
Author: HolySheep AI Technical Blog
"""
import json
import time
from typing import Any, Optional
from dataclasses import dataclass, field
from enum import Enum

============================================================

CẤU HÌNH - Sử dụng HolySheep AI

============================================================

HOLYSHEEP_CONFIG = { "base_url": "https://api.holysheep.ai/v1", "api_key": "YOUR_HOLYSHEEP_API_KEY", # Thay bằng API key thực tế "default_model": "deepseek-v3.2", "pricing_per_mtok": { "gpt-4.1": 8.00, "claude-sonnet-4.5": 15.00, "gemini-2.5-flash": 2.50, "deepseek-v3.2": 0.42 } } class ToolCategory(Enum): """Phân loại tool theo domain và độ phức tạp""" DATA_QUERY = "data_query" FILE_IO = "file_io" API_CALL = "api_call" COMPUTATION = "computation" SEARCH = "search" BUSINESS_LOGIC = "business_logic" @dataclass class ToolMetadata: """Metadata cho mỗi tool - critical cho smart selection""" name: str category: ToolCategory description: str parameters_schema: dict estimated_tokens: int # Ước lượng token cho 1 lần gọi estimated_latency_ms: float # Độ trễ trung bình cost_per_call: float # Chi phí ước tính requires_auth: bool = False rate_limit_rpm: int = 60 dependencies: list[str] = field(default_factory=list) fallback_tool: Optional[str] = None class ToolRegistry: """ Registry thông minh - Core của chiến lược tool selection. Cho phép filtering, ranking và dependency resolution. """ def __init__(self): self._tools: dict[str, ToolMetadata] = {} self._category_index: dict[ToolCategory, list[str]] = {} self._cost_tracker: dict[str, dict] = {} self._init_builtin_tools() def _init_builtin_tools(self): """Khởi tạo các tool mặc định với metadata thực tế""" builtin_tools = [ ToolMetadata( name="get_order_status", category=ToolCategory.DATA_QUERY, description="Lấy thông tin trạng thái đơn hàng theo order_id", parameters_schema={ "type": "object", "properties": { "order_id": {"type": "string", "pattern": "^ORD-\\d{8}$"}, "include_history": {"type": "boolean", "default": False} }, "required": ["order_id"] }, estimated_tokens=120, estimated_latency_ms=45.2, cost_per_call=0.0000504, # 120 tokens × $0.42/M rate_limit_rpm=120 ), ToolMetadata( name="search_product_catalog", category=ToolCategory.SEARCH, description="Tìm kiếm sản phẩm trong catalog với filters", parameters_schema={ "type": "object", "properties": { "query": {"type": "string", "maxLength": 100}, "category": {"type": "string"}, "price_range": {"type": "object"}, "limit": {"type": "integer", "default": 10} }, "required": ["query"] }, estimated_tokens=85, estimated_latency_ms=32.8, cost_per_call=0.0000357, rate_limit_rpm=200, fallback_tool="basic_search" ), ToolMetadata( name="calculate_shipping", category=ToolCategory.COMPUTATION, description="Tính phí vận chuyển dựa trên location và weight", parameters_schema={ "type": "object", "properties": { "fromProvince": {"type": "string"}, "toProvince": {"type": "string"}, "weight_kg": {"type": "number", "minimum": 0.1} }, "required": ["fromProvince", "toProvince", "weight_kg"] }, estimated_tokens=65, estimated_latency_ms=18.5, cost_per_call=0.0000273, rate_limit_rpm=300 ), ToolMetadata( name="apply_promotion", category=ToolCategory.BUSINESS_LOGIC, description="Kiểm tra và áp dụng mã khuyến mãi vào đơn hàng", parameters_schema={ "type": "object", "properties": { "promo_code": {"type": "string"}, "order_total": {"type": "number"} }, "required": ["promo_code", "order_total"] }, estimated_tokens=95, estimated_latency_ms=28.3, cost_per_call=0.0000399, rate_limit_rpm=100, requires_auth=True ), ToolMetadata( name="send_notification", category=ToolCategory.API_CALL, description="Gửi notification qua email/SMS/push", parameters_schema={ "type": "object", "properties": { "user_id": {"type": "string"}, "channel": {"type": "string", "enum": ["email", "sms", "push"]}, "template_id": {"type": "string"}, "data": {"type": "object"} }, "required": ["user_id", "channel", "template_id"] }, estimated_tokens=150, estimated_latency_ms=85.0, cost_per_call=0.000063, rate_limit_rpm=50 ), ] for tool in builtin_tools: self.register(tool) def register(self, tool: ToolMetadata): """Đăng ký tool vào registry""" self._tools[tool.name] = tool # Cập nhật category index if tool.category not in self._category_index: self._category_index[tool.category] = [] self._category_index[tool.category].append(tool.name) # Khởi tạo cost tracker self._cost_tracker[tool.name] = { "total_calls": 0, "total_cost": 0.0, "avg_latency_ms": 0.0 } def find_tools(self, query: str, category: Optional[ToolCategory] = None, max_cost: Optional[float] = None, require_auth: bool = False) -> list[ToolMetadata]: """ Smart tool finding - sử dụng semantic matching. Trả về danh sách tools phù hợp với query và constraints. """ candidates = [] # Filter by category if specified if category: tool_names = self._category_index.get(category, []) candidates = [self._tools[name] for name in tool_names] else: candidates = list(self._tools.values()) # Apply constraints filtered = [] for tool in candidates: if require_auth and not tool.requires_auth: continue if max_cost and tool.cost_per_call > max_cost: continue filtered.append(tool) # Sort by relevance score (simplified: cost × latency) filtered.sort(key=lambda t: t.cost_per_call * t.estimated_latency_ms) return filtered def get_tool(self, name: str) -> Optional[ToolMetadata]: """Lấy tool metadata by name""" return self._tools.get(name) def record_call(self, tool_name: str, latency_ms: float, success: bool): """Ghi nhận metrics của 1 lần gọi""" if tool_name not in self._cost_tracker: return tracker = self._cost_tracker[tool_name] tool = self._tools[tool_name] tracker["total_calls"] += 1 if success: tracker["total_cost"] += tool.cost_per_call # Update exponential moving average cho latency alpha = 0.2 tracker["avg_latency_ms"] = ( alpha * latency_ms + (1 - alpha) * tracker["avg_latency_ms"] ) def get_cost_report(self) -> dict: """Generate báo cáo chi phí chi tiết""" total = sum(t["total_cost"] for t in self._cost_tracker.values()) total_calls = sum(t["total_calls"] for t in self._cost_tracker.values()) return { "total_cost_usd": total, "total_calls": total_calls, "avg_cost_per_call": total / total_calls if total_calls > 0 else 0, "by_tool": self._cost_tracker }

============================================================

SỬ DỤNG VÍ DỤ

============================================================

if __name__ == "__main__": registry = ToolRegistry() # Tìm tất cả tools cho việc truy vấn dữ liệu data_tools = registry.find_tools( query="order status", category=ToolCategory.DATA_QUERY ) print("Data Query Tools:", [t.name for t in data_tools]) # Tìm tools có chi phí thấp cheap_tools = registry.find_tools( query="calculation", max_cost=0.00004 ) print("Low-cost Tools:", [t.name for t in cheap_tools]) # Simulate call và ghi nhận metrics registry.record_call("get_order_status", 42.5, success=True) registry.record_call("calculate_shipping", 19.2, success=True) # In báo cáo chi phí print("\\n=== Cost Report ===") report = registry.get_cost_report() print(f"Tổng chi phí: ${report['total_cost_usd']:.6f}") print(f"Tổng số lần gọi: {report['total_calls']}")

Thuật Toán Tool Selection Tối Ưu

Đây là phần core của bài viết. Tôi sẽ chia sẻ thuật toán đã giúp team của tôi giảm 92% chi phí. Thuật toán này kết hợp 3 yếu tố: cost-benefit analysis, dependency graph, và predictive batching.

"""
Optimized Tool Selection Algorithm
Triển khai thuật toán selection thông minh với cost optimization
"""
import asyncio
from typing import Any, Callable, Optional
from dataclasses import dataclass
import heapq

@dataclass
class ToolCall:
    """Đại diện cho một lệnh gọi tool"""
    tool_name: str
    parameters: dict
    priority: int  # 1 = highest
    estimated_tokens: int
    estimated_latency_ms: float
    dependencies: list[str]  # Tool names phải chạy trước
    
    def __lt__(self, other):
        # Priority queue: priority thấp hơn = cao hơn
        return self.priority < other.priority

class ToolSelector:
    """
    Intelligent Tool Selector với chiến lược tối ưu chi phí.
    
    Chiến lược chính:
    1. Dependency Resolution: topological sort
    2. Cost-Benefit Scoring: weight theo business value
    3. Batch Optimization: group parallelizable calls
    4. Fallback Planning: chuẩn bị fallback khi tool fail
    """
    
    def __init__(self, registry: ToolRegistry):
        self.registry = registry
        self.call_history: list[dict] = []
        self._optimization_cache: dict[str, list[ToolCall]] = {}
    
    def plan_calls(self, 
                   requested_tools: list[dict],
                   context: dict,
                   budget_limit: Optional[float] = None) -> list[ToolCall]:
        """
        Lên kế hoạch execution cho các tool requests.
        
        Args:
            requested_tools: Danh sách tools cần gọi với params
            context: Context info (user tier, urgency, etc.)
            budget_limit: Giới hạn budget cho session này
        
        Returns:
            Danh sách ToolCall đã được optimize và sorted
        """
        plan = []
        total_cost = 0.0
        
        # Bước 1: Tạo initial calls
        for req in requested_tools:
            tool_meta = self.registry.get_tool(req["name"])
            if not tool_meta:
                continue
            
            call = ToolCall(
                tool_name=req["name"],
                parameters=req.get("parameters", {}),
                priority=req.get("priority", 5),
                estimated_tokens=tool_meta.estimated_tokens,
                estimated_latency_ms=tool_meta.estimated_latency_ms,
                dependencies=tool_meta.dependencies
            )
            plan.append(call)
            total_cost += tool_meta.cost_per_call
        
        # Bước 2: Dependency Resolution (Topological Sort)
        plan = self._resolve_dependencies(plan)
        
        # Bước 3: Batch Optimization
        plan = self._optimize_batches(plan)
        
        # Bước 4: Budget Check
        if budget_limit and total_cost > budget_limit:
            plan = self._apply_budget_constraints(plan, budget_limit, context)
        
        # Bước 5: Calculate priority scores
        for call in plan:
            call.priority = self._calculate_priority(call, context)
        
        # Sort by priority
        plan.sort(key=lambda c: c.priority)
        
        return plan
    
    def _resolve_dependencies(self, plan: list[ToolCall]) -> list[ToolCall]:
        """Topological sort để resolve dependencies"""
        # Build dependency graph
        tool_map = {c.tool_name: c for c in plan}
        in_degree = {c.tool_name: len(c.dependencies) for c in plan}
        
        # Queue for BFS topological sort
        queue = [name for name, degree in in_degree.items() if degree == 0]
        sorted_calls = []
        
        while queue:
            current = queue.pop(0)
            sorted_calls.append(tool_map[current])
            
            # Giảm in-degree của các tool phụ thuộc vào current
            for call in plan:
                if current in call.dependencies:
                    in_degree[call.tool_name] -= 1
                    if in_degree[call.tool_name] == 0:
                        queue.append(call.tool_name)
        
        # Handle circular dependencies bằng cách break ties
        if len(sorted_calls) < len(plan):
            remaining = [c for c in plan if c not in sorted_calls]
            sorted_calls.extend(remaining)
        
        return sorted_calls
    
    def _optimize_batches(self, plan: list[ToolCall]) -> list[ToolCall]:
        """
        Batch optimization: nhóm các independent calls lại.
        Mục tiêu: minimize round-trips, maximize parallelism.
        """
        if not plan:
            return []
        
        batches = []
        batch = []
        batch_tokens = 0
        max_batch_tokens = 1000  # Batch size limit
        
        for call in plan:
            # Nếu call quá lớn, flush batch trước
            if call.estimated_tokens > max_batch_tokens:
                if batch:
                    batches.append(batch)
                    batch = []
                    batch_tokens = 0
                batches.append([call])
                continue
            
            # Check nếu thêm call vào batch vượt limit
            if batch_tokens + call.estimated_tokens > max_batch_tokens:
                batches.append(batch)
                batch = [call]
                batch_tokens = call.estimated_tokens
            else:
                batch.append(call)
                batch_tokens += call.estimated_tokens
        
        if batch:
            batches.append(batch)
        
        # Flatten với batch markers
        optimized = []
        for batch in batches:
            if len(batch) > 1:
                # Thêm batch marker
                for call in batch:
                    call.priority = max(1, call.priority - 2)  # Boost priority
            optimized.extend(batch)
        
        return optimized
    
    def _calculate_priority(self, call: ToolCall, context: dict) -> int:
        """
        Tính priority score dựa trên:
        - Base priority
        - User tier (VIP = boost)
        - Urgency level
        - Cost (cheaper tools = lower priority adjustment)
        """
        base = call.priority
        
        # User tier bonus
        user_tier = context.get("user_tier", "standard")
        tier_bonus = {"vip": -3, "premium": -2, "standard": 0, "guest": 2}
        bonus = tier_bonus.get(user_tier, 0)
        
        # Urgency bonus
        urgency = context.get("urgency", "normal")
        urgency_bonus = {"critical": -5, "high": -3, "normal": 0, "low": 2}
        bonus += urgency_bonus.get(urgency, 0)
        
        # Cost adjustment (expensive tools = lower priority = run later if possible)
        tool_meta = self.registry.get_tool(call.tool_name)
        if tool_meta and tool_meta.cost_per_call > 0.0001:
            bonus += 1
        
        return max(1, base + bonus)
    
    def _apply_budget_constraints(self, 
                                   plan: list[ToolCall],
                                   budget: float,
                                   context: dict) -> list[ToolCall]:
        """Loại bỏ hoặc defer các tools không fit budget"""
        # Critical tools không bao giờ bị loại
        critical_tools