{"product_id":"kiểm-soat-chi-phi-ai-agent-token-budget-max-iterations-va-monitoring","title":"Kiểm soát chi phí AI Agent — Token budget, max iterations và monitoring","description":"\n\u003cp\u003eAI agent là công cụ mạnh mẽ, nhưng đi kèm với một rủi ro nghiêm trọng: chi phí không kiểm soát được. Khác với single prompt hay prompt chain có chi phí dự đoán được, agent loop có thể chạy hàng chục vòng, mỗi vòng tích lũy thêm context token, và tổng chi phí có thể gấp 50-100 lần so với dự kiến. Bài viết này hướng dẫn xây dựng hệ thống kiểm soát chi phí hoàn chỉnh cho AI agent trong môi trường production.\u003c\/p\u003e\n\n\u003ch2\u003eVấn đề: Chi phí bùng nổ của Agent\u003c\/h2\u003e\n\u003cp\u003eĐể hiểu tại sao agent có thể gây bùng nổ chi phí, hãy phân tích cơ chế tích lũy token trong agent loop:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003e# Minh hoa van de tich luy token trong agent loop\n# Moi vong, TOAN BO lich su hoi thoai truoc do duoc gui lai\n\n# Vong 1: 1000 input tokens, 500 output tokens\n# Vong 2: 1000 + 500 + 200 = 1700 input, 500 output\n# Vong 3: 1700 + 500 + 200 = 2400 input, 500 output\n# Vong 4: 2400 + 500 + 200 = 3100 input, 500 output\n# ...\n# Vong 10: ~7500 input, 500 output\n# Vong 20: ~14500 input, 500 output\n\n# Tong token sau 20 vong:\n# Input: 1000 + 1700 + 2400 + ... + 14500 = ~155,000 tokens\n# Output: 20 * 500 = 10,000 tokens\n\n# Chi phi voi Claude Sonnet:\n# Input: 155,000 * $3\/1M = $0.465\n# Output: 10,000 * $15\/1M = $0.15\n# Tong: $0.615 cho MOT request cua MOT nguoi dung\n\n# Neu 1000 nguoi dung\/ngay, moi nguoi 5 request:\n# $0.615 * 5000 = $3,075\/ngay = $92,250\/thang\u003c\/code\u003e\u003c\/pre\u003e\n\u003cp\u003eCon số trên cho thấy tại sao kiểm soát chi phí agent không phải \"nice to have\" mà là \"must have\" trước khi deploy ra production.\u003c\/p\u003e\n\n\u003ch2\u003eGiới hạn cơ bản: max_turns và max_tokens\u003c\/h2\u003e\n\u003cp\u003eHai giới hạn đầu tiên và quan trọng nhất cần đặt cho mọi agent:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003edef agent_loop_with_limits(\n    client,\n    user_message,\n    tools,\n    max_turns=10,\n    max_tokens_per_turn=2048,\n    max_total_tokens=50000\n):\n    \"\"\"Agent loop voi gioi han so vong va token.\"\"\"\n    messages = [{\"role\": \"user\", \"content\": user_message}]\n    total_input_tokens = 0\n    total_output_tokens = 0\n\n    for turn in range(max_turns):\n        response = client.messages.create(\n            model=\"claude-sonnet-4-20250514\",\n            max_tokens=max_tokens_per_turn,\n            tools=tools,\n            messages=messages\n        )\n\n        # Cap nhat token count\n        total_input_tokens += response.usage.input_tokens\n        total_output_tokens += response.usage.output_tokens\n        total_tokens = total_input_tokens + total_output_tokens\n\n        # Kiem tra gioi han token tong\n        if total_tokens \u0026gt; max_total_tokens:\n            print(f\"Da dat gioi han token: {total_tokens}\/{max_total_tokens}\")\n            # Yeu cau model tong ket ngay lap tuc\n            messages.append({\"role\": \"assistant\", \"content\": response.content})\n            messages.append({\n                \"role\": \"user\",\n                \"content\": \"Ban da dung het token budget. \"\n                           \"Hay tong ket ket qua hien tai ngay.\"\n            })\n            final = client.messages.create(\n                model=\"claude-sonnet-4-20250514\",\n                max_tokens=1024,\n                messages=messages\n            )\n            return {\n                \"response\": final.content[0].text,\n                \"reason\": \"token_budget_exceeded\",\n                \"total_tokens\": total_tokens,\n                \"turns\": turn + 1\n            }\n\n        # Kiem tra model da hoan thanh chua\n        if response.stop_reason == \"end_turn\":\n            text = \"\"\n            for block in response.content:\n                if block.type == \"text\":\n                    text += block.text\n            return {\n                \"response\": text,\n                \"reason\": \"completed\",\n                \"total_tokens\": total_tokens,\n                \"turns\": turn + 1\n            }\n\n        # Xu ly tool calls\n        messages.append({\"role\": \"assistant\", \"content\": response.content})\n        tool_results = []\n        for block in response.content:\n            if block.type == \"tool_use\":\n                result = execute_tool(block.name, block.input)\n                tool_results.append({\n                    \"type\": \"tool_result\",\n                    \"tool_use_id\": block.id,\n                    \"content\": result\n                })\n        messages.append({\"role\": \"user\", \"content\": tool_results})\n\n    # Da het so vong lap\n    return {\n        \"response\": \"Da dat gioi han so vong lap.\",\n        \"reason\": \"max_turns_exceeded\",\n        \"total_tokens\": total_tokens,\n        \"turns\": max_turns\n    }\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eToken Budget theo loại tác vụ\u003c\/h2\u003e\n\u003cp\u003eKhông phải mọi tác vụ đều cần cùng một ngân sách. Thiết lập budget khác nhau cho từng loại tác vụ:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eTASK_BUDGETS = {\n    \"simple_query\": {\n        \"max_turns\": 3,\n        \"max_tokens_per_turn\": 1024,\n        \"max_total_tokens\": 5000,\n        \"model\": \"claude-haiku-3-5-20241022\",\n        \"estimated_cost_usd\": 0.01\n    },\n    \"data_analysis\": {\n        \"max_turns\": 8,\n        \"max_tokens_per_turn\": 2048,\n        \"max_total_tokens\": 30000,\n        \"model\": \"claude-sonnet-4-20250514\",\n        \"estimated_cost_usd\": 0.15\n    },\n    \"complex_research\": {\n        \"max_turns\": 15,\n        \"max_tokens_per_turn\": 4096,\n        \"max_total_tokens\": 100000,\n        \"model\": \"claude-sonnet-4-20250514\",\n        \"estimated_cost_usd\": 0.50\n    },\n    \"code_generation\": {\n        \"max_turns\": 10,\n        \"max_tokens_per_turn\": 4096,\n        \"max_total_tokens\": 60000,\n        \"model\": \"claude-sonnet-4-20250514\",\n        \"estimated_cost_usd\": 0.25\n    }\n}\n\ndef classify_task(user_message):\n    \"\"\"Phan loai tac vu de chon budget phu hop.\"\"\"\n    # Dung Haiku de phan loai (re va nhanh)\n    response = client.messages.create(\n        model=\"claude-haiku-3-5-20241022\",\n        max_tokens=50,\n        messages=[{\n            \"role\": \"user\",\n            \"content\": f\"Phan loai request sau vao 1 trong 4 loai: \"\n                       f\"simple_query, data_analysis, complex_research, \"\n                       f\"code_generation. Chi tra loi ten loai.\n\n\"\n                       f\"Request: {user_message}\"\n        }]\n    )\n    task_type = response.content[0].text.strip().lower()\n\n    if task_type in TASK_BUDGETS:\n        return task_type\n    return \"simple_query\"  # Mac dinh\n\ndef run_agent_with_budget(client, user_message, tools):\n    \"\"\"Chay agent voi budget tu dong dua tren loai tac vu.\"\"\"\n    task_type = classify_task(user_message)\n    budget = TASK_BUDGETS[task_type]\n\n    print(f\"Task type: {task_type}\")\n    print(f\"Budget: {budget['max_total_tokens']} tokens, \"\n          f\"{budget['max_turns']} turns, \"\n          f\"model: {budget['model']}\")\n\n    return agent_loop_with_limits(\n        client=client,\n        user_message=user_message,\n        tools=tools,\n        max_turns=budget[\"max_turns\"],\n        max_tokens_per_turn=budget[\"max_tokens_per_turn\"],\n        max_total_tokens=budget[\"max_total_tokens\"]\n    )\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eModel Cascade: Bắt đầu rẻ, nâng cấp khi cần\u003c\/h2\u003e\n\u003cp\u003eModel cascade là chiến lược bắt đầu với model rẻ nhất (Haiku) và chỉ nâng lên model đắt hơn (Sonnet, Opus) khi tác vụ thực sự cần. Điều này giảm chi phí trung bình cho mỗi request.\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eclass ModelCascade:\n    \"\"\"Bat dau voi model re, nang cap khi can thiet.\"\"\"\n\n    MODELS = [\n        {\n            \"name\": \"claude-haiku-3-5-20241022\",\n            \"input_price\": 0.80 \/ 1_000_000,\n            \"output_price\": 4.0 \/ 1_000_000,\n            \"max_complexity\": \"low\"\n        },\n        {\n            \"name\": \"claude-sonnet-4-20250514\",\n            \"input_price\": 3.0 \/ 1_000_000,\n            \"output_price\": 15.0 \/ 1_000_000,\n            \"max_complexity\": \"high\"\n        },\n        {\n            \"name\": \"claude-opus-4-20250514\",\n            \"input_price\": 15.0 \/ 1_000_000,\n            \"output_price\": 75.0 \/ 1_000_000,\n            \"max_complexity\": \"very_high\"\n        }\n    ]\n\n    def __init__(self, client):\n        self.client = client\n\n    def call_with_cascade(self, messages, tools=None, **kwargs):\n        \"\"\"Thu model re truoc, nang cap neu ket qua khong du tot.\"\"\"\n\n        # Buoc 1: Thu Haiku truoc\n        haiku_response = self.client.messages.create(\n            model=self.MODELS[0][\"name\"],\n            max_tokens=kwargs.get(\"max_tokens\", 2048),\n            messages=messages,\n            tools=tools\n        )\n\n        # Kiem tra chat luong response\n        if self._is_quality_sufficient(haiku_response, messages):\n            return {\n                \"response\": haiku_response,\n                \"model_used\": self.MODELS[0][\"name\"],\n                \"escalated\": False\n            }\n\n        # Buoc 2: Nang cap len Sonnet\n        print(\"Haiku khong du, nang cap len Sonnet\")\n        sonnet_response = self.client.messages.create(\n            model=self.MODELS[1][\"name\"],\n            max_tokens=kwargs.get(\"max_tokens\", 2048),\n            messages=messages,\n            tools=tools\n        )\n\n        return {\n            \"response\": sonnet_response,\n            \"model_used\": self.MODELS[1][\"name\"],\n            \"escalated\": True\n        }\n\n    def _is_quality_sufficient(self, response, messages):\n        \"\"\"Kiem tra chat luong response co du tot khong.\"\"\"\n        content = response.content[0].text if response.content else \"\"\n\n        # Tieu chi danh gia co ban\n        if len(content) \u0026lt; 50:\n            return False\n        if response.stop_reason == \"max_tokens\":\n            return False\n        if \"toi khong the\" in content.lower():\n            return False\n        if \"xin loi\" in content.lower() and len(content) \u0026lt; 200:\n            return False\n\n        return True\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eCostController Class hoàn chỉnh\u003c\/h2\u003e\n\u003cp\u003eDưới đây là class CostController tích hợp tất cả các kỹ thuật kiểm soát chi phí, sẵn sàng dùng trong production:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport time\nimport logging\nfrom dataclasses import dataclass, field\nfrom typing import Optional\n\nlogger = logging.getLogger(\"cost_controller\")\n\n@dataclass\nclass CostRecord:\n    \"\"\"Ghi nhan chi phi cua mot agent run.\"\"\"\n    run_id: str\n    task_type: str\n    model: str\n    input_tokens: int = 0\n    output_tokens: int = 0\n    cache_read_tokens: int = 0\n    cache_write_tokens: int = 0\n    turns: int = 0\n    cost_usd: float = 0.0\n    start_time: float = field(default_factory=time.time)\n    end_time: Optional[float] = None\n    status: str = \"running\"\n\nclass CostController:\n    \"\"\"Kiem soat chi phi AI agent trong production.\"\"\"\n\n    PRICING = {\n        \"claude-haiku-3-5-20241022\": {\n            \"input\": 0.80 \/ 1_000_000,\n            \"output\": 4.0 \/ 1_000_000,\n            \"cache_read\": 0.08 \/ 1_000_000,\n            \"cache_write\": 1.0 \/ 1_000_000\n        },\n        \"claude-sonnet-4-20250514\": {\n            \"input\": 3.0 \/ 1_000_000,\n            \"output\": 15.0 \/ 1_000_000,\n            \"cache_read\": 0.30 \/ 1_000_000,\n            \"cache_write\": 3.75 \/ 1_000_000\n        },\n        \"claude-opus-4-20250514\": {\n            \"input\": 15.0 \/ 1_000_000,\n            \"output\": 75.0 \/ 1_000_000,\n            \"cache_read\": 1.50 \/ 1_000_000,\n            \"cache_write\": 18.75 \/ 1_000_000\n        }\n    }\n\n    def __init__(\n        self,\n        max_cost_per_run=1.0,\n        max_cost_per_hour=50.0,\n        max_cost_per_day=500.0,\n        alert_threshold_pct=0.8\n    ):\n        self.max_cost_per_run = max_cost_per_run\n        self.max_cost_per_hour = max_cost_per_hour\n        self.max_cost_per_day = max_cost_per_day\n        self.alert_threshold_pct = alert_threshold_pct\n\n        self.active_runs = {}\n        self.completed_runs = []\n        self.hourly_cost = 0.0\n        self.daily_cost = 0.0\n        self.last_hour_reset = time.time()\n        self.last_day_reset = time.time()\n\n    def start_run(self, run_id, task_type, model):\n        \"\"\"Bat dau theo doi mot agent run.\"\"\"\n        self._reset_windows()\n\n        # Kiem tra budget toan cuc\n        if self.hourly_cost \u0026gt;= self.max_cost_per_hour:\n            raise BudgetExceededError(\n                f\"Vuot budget theo gio: \"\n                f\"${self.hourly_cost:.2f}\/${self.max_cost_per_hour:.2f}\"\n            )\n        if self.daily_cost \u0026gt;= self.max_cost_per_day:\n            raise BudgetExceededError(\n                f\"Vuot budget theo ngay: \"\n                f\"${self.daily_cost:.2f}\/${self.max_cost_per_day:.2f}\"\n            )\n\n        record = CostRecord(\n            run_id=run_id,\n            task_type=task_type,\n            model=model\n        )\n        self.active_runs[run_id] = record\n        return record\n\n    def record_usage(self, run_id, usage, model=None):\n        \"\"\"Ghi nhan token usage sau moi API call.\"\"\"\n        record = self.active_runs.get(run_id)\n        if not record:\n            return\n\n        model = model or record.model\n        pricing = self.PRICING.get(model, self.PRICING[\"claude-sonnet-4-20250514\"])\n\n        # Cap nhat token counts\n        record.input_tokens += usage.input_tokens\n        record.output_tokens += usage.output_tokens\n\n        cache_read = getattr(usage, \"cache_read_input_tokens\", 0) or 0\n        cache_write = getattr(usage, \"cache_creation_input_tokens\", 0) or 0\n        record.cache_read_tokens += cache_read\n        record.cache_write_tokens += cache_write\n\n        record.turns += 1\n\n        # Tinh chi phi\n        cost = (\n            usage.input_tokens * pricing[\"input\"] +\n            usage.output_tokens * pricing[\"output\"] +\n            cache_read * pricing[\"cache_read\"] +\n            cache_write * pricing[\"cache_write\"]\n        )\n        record.cost_usd += cost\n        self.hourly_cost += cost\n        self.daily_cost += cost\n\n        # Kiem tra alert threshold\n        if record.cost_usd \u0026gt;= self.max_cost_per_run * self.alert_threshold_pct:\n            logger.warning(\n                f\"Run {run_id}: chi phi dat \"\n                f\"{record.cost_usd \/ self.max_cost_per_run:.0%} budget \"\n                f\"(${record.cost_usd:.4f}\/${self.max_cost_per_run:.2f})\"\n            )\n\n        # Kiem tra vuot budget\n        if record.cost_usd \u0026gt;= self.max_cost_per_run:\n            record.status = \"budget_exceeded\"\n            raise BudgetExceededError(\n                f\"Run {run_id} vuot budget: \"\n                f\"${record.cost_usd:.4f} \u0026gt;= ${self.max_cost_per_run:.2f}\"\n            )\n\n    def end_run(self, run_id, status=\"completed\"):\n        \"\"\"Ket thuc theo doi agent run.\"\"\"\n        record = self.active_runs.pop(run_id, None)\n        if record:\n            record.end_time = time.time()\n            record.status = status\n            self.completed_runs.append(record)\n            logger.info(\n                f\"Run {run_id} hoan thanh: \"\n                f\"${record.cost_usd:.4f}, \"\n                f\"{record.turns} turns, \"\n                f\"{record.input_tokens + record.output_tokens} tokens\"\n            )\n        return record\n\n    def get_dashboard(self):\n        \"\"\"Tra ve thong ke chi phi tong hop.\"\"\"\n        self._reset_windows()\n\n        all_runs = self.completed_runs[-100:]\n        if not all_runs:\n            return {\"message\": \"Chua co du lieu\"}\n\n        total_cost = sum(r.cost_usd for r in all_runs)\n        avg_cost = total_cost \/ len(all_runs)\n        max_cost_run = max(all_runs, key=lambda r: r.cost_usd)\n\n        costs_by_task = {}\n        for run in all_runs:\n            if run.task_type not in costs_by_task:\n                costs_by_task[run.task_type] = {\n                    \"count\": 0, \"total_cost\": 0.0\n                }\n            costs_by_task[run.task_type][\"count\"] += 1\n            costs_by_task[run.task_type][\"total_cost\"] += run.cost_usd\n\n        costs_by_model = {}\n        for run in all_runs:\n            if run.model not in costs_by_model:\n                costs_by_model[run.model] = {\n                    \"count\": 0, \"total_cost\": 0.0\n                }\n            costs_by_model[run.model][\"count\"] += 1\n            costs_by_model[run.model][\"total_cost\"] += run.cost_usd\n\n        return {\n            \"summary\": {\n                \"total_runs\": len(all_runs),\n                \"total_cost_usd\": round(total_cost, 4),\n                \"avg_cost_per_run\": round(avg_cost, 4),\n                \"max_cost_run\": {\n                    \"run_id\": max_cost_run.run_id,\n                    \"cost\": round(max_cost_run.cost_usd, 4)\n                }\n            },\n            \"current_budget\": {\n                \"hourly\": f\"${self.hourly_cost:.2f}\/${self.max_cost_per_hour:.2f}\",\n                \"daily\": f\"${self.daily_cost:.2f}\/${self.max_cost_per_day:.2f}\"\n            },\n            \"by_task_type\": costs_by_task,\n            \"by_model\": costs_by_model\n        }\n\n    def _reset_windows(self):\n        \"\"\"Reset time windows neu can.\"\"\"\n        now = time.time()\n        if now - self.last_hour_reset \u0026gt;= 3600:\n            self.hourly_cost = 0.0\n            self.last_hour_reset = now\n        if now - self.last_day_reset \u0026gt;= 86400:\n            self.daily_cost = 0.0\n            self.last_day_reset = now\n\n\nclass BudgetExceededError(Exception):\n    pass\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eTích hợp CostController vào Agent Loop\u003c\/h2\u003e\n\u003cp\u003eDưới đây là cách tích hợp CostController vào agent loop hoàn chỉnh:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport uuid\n\ndef production_agent(\n    client,\n    user_message,\n    tools,\n    cost_controller,\n    task_type=\"data_analysis\"\n):\n    \"\"\"Agent loop production-ready voi cost control.\"\"\"\n    run_id = str(uuid.uuid4())[:8]\n    budget = TASK_BUDGETS.get(task_type, TASK_BUDGETS[\"simple_query\"])\n\n    # Bat dau tracking\n    cost_controller.start_run(\n        run_id=run_id,\n        task_type=task_type,\n        model=budget[\"model\"]\n    )\n\n    messages = [{\"role\": \"user\", \"content\": user_message}]\n\n    try:\n        for turn in range(budget[\"max_turns\"]):\n            response = client.messages.create(\n                model=budget[\"model\"],\n                max_tokens=budget[\"max_tokens_per_turn\"],\n                tools=tools,\n                messages=messages\n            )\n\n            # Ghi nhan chi phi\n            try:\n                cost_controller.record_usage(run_id, response.usage)\n            except BudgetExceededError:\n                # Yeu cau model tong ket\n                messages.append(\n                    {\"role\": \"assistant\", \"content\": response.content}\n                )\n                messages.append({\n                    \"role\": \"user\",\n                    \"content\": \"Budget da het. Hay tong ket ket qua hien tai.\"\n                })\n                final = client.messages.create(\n                    model=\"claude-haiku-3-5-20241022\",\n                    max_tokens=512,\n                    messages=messages\n                )\n                cost_controller.end_run(run_id, \"budget_exceeded\")\n                return {\n                    \"response\": final.content[0].text,\n                    \"status\": \"budget_exceeded\",\n                    \"run_id\": run_id\n                }\n\n            # Model hoan thanh\n            if response.stop_reason == \"end_turn\":\n                text = \"\"\n                for block in response.content:\n                    if block.type == \"text\":\n                        text += block.text\n                cost_controller.end_run(run_id, \"completed\")\n                return {\n                    \"response\": text,\n                    \"status\": \"completed\",\n                    \"run_id\": run_id\n                }\n\n            # Xu ly tool calls\n            messages.append({\"role\": \"assistant\", \"content\": response.content})\n            tool_results = []\n            for block in response.content:\n                if block.type == \"tool_use\":\n                    result = execute_tool(block.name, block.input)\n                    tool_results.append({\n                        \"type\": \"tool_result\",\n                        \"tool_use_id\": block.id,\n                        \"content\": result\n                    })\n            messages.append({\"role\": \"user\", \"content\": tool_results})\n\n        cost_controller.end_run(run_id, \"max_turns\")\n        return {\n            \"response\": \"Da dat gioi han so vong.\",\n            \"status\": \"max_turns_exceeded\",\n            \"run_id\": run_id\n        }\n\n    except Exception as e:\n        cost_controller.end_run(run_id, f\"error: {str(e)}\")\n        raise\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eAlert Thresholds và Notification\u003c\/h2\u003e\n\u003cp\u003eThiết lập nhiều tầng cảnh báo để phát hiện vấn đề chi phí sớm:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eclass CostAlertManager:\n    \"\"\"Quan ly canh bao chi phi nhieu tang.\"\"\"\n\n    def __init__(self):\n        self.thresholds = [\n            {\"level\": \"info\", \"pct\": 0.5,\n             \"message\": \"Da dung 50% budget\"},\n            {\"level\": \"warning\", \"pct\": 0.8,\n             \"message\": \"Da dung 80% budget - can chu y\"},\n            {\"level\": \"critical\", \"pct\": 0.95,\n             \"message\": \"Da dung 95% budget - sap het\"},\n            {\"level\": \"emergency\", \"pct\": 1.0,\n             \"message\": \"Da vuot budget!\"}\n        ]\n        self.triggered = set()\n\n    def check(self, current_cost, budget, run_id):\n        \"\"\"Kiem tra va gui canh bao neu can.\"\"\"\n        ratio = current_cost \/ budget if budget \u0026gt; 0 else 0\n\n        for threshold in self.thresholds:\n            key = f\"{run_id}_{threshold['level']}\"\n            if ratio \u0026gt;= threshold[\"pct\"] and key not in self.triggered:\n                self.triggered.add(key)\n                self._send_alert(\n                    level=threshold[\"level\"],\n                    message=f\"Run {run_id}: {threshold['message']} \"\n                            f\"(${current_cost:.4f}\/${budget:.2f})\",\n                    ratio=ratio\n                )\n\n    def _send_alert(self, level, message, ratio):\n        \"\"\"Gui canh bao qua cac kenh khac nhau.\"\"\"\n        logger.log(\n            logging.CRITICAL if level in (\"critical\", \"emergency\")\n            else logging.WARNING,\n            message\n        )\n\n        # Tich hop voi Slack\n        # if level in (\"critical\", \"emergency\"):\n        #     slack_webhook.send(message)\n\n        # Tich hop voi PagerDuty\n        # if level == \"emergency\":\n        #     pagerduty.trigger(message)\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eDashboard chi phí đơn giản\u003c\/h2\u003e\n\u003cp\u003eXây dựng dashboard text-based để theo dõi chi phí trong quá trình phát triển và testing:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003edef print_cost_dashboard(cost_controller):\n    \"\"\"In dashboard chi phi ra console.\"\"\"\n    dashboard = cost_controller.get_dashboard()\n    if \"message\" in dashboard:\n        print(dashboard[\"message\"])\n        return\n\n    s = dashboard[\"summary\"]\n    print(\"=\" * 60)\n    print(\"           COST DASHBOARD\")\n    print(\"=\" * 60)\n    print(f\"Tong runs:        {s['total_runs']}\")\n    print(f\"Tong chi phi:     ${s['total_cost_usd']}\")\n    print(f\"Trung binh\/run:   ${s['avg_cost_per_run']}\")\n    print(f\"Run dat nhat:     {s['max_cost_run']['run_id']} \"\n          f\"(${s['max_cost_run']['cost']})\")\n    print()\n\n    b = dashboard[\"current_budget\"]\n    print(f\"Budget gio nay:   {b['hourly']}\")\n    print(f\"Budget hom nay:   {b['daily']}\")\n    print()\n\n    print(\"Chi phi theo task type:\")\n    for task, data in dashboard[\"by_task_type\"].items():\n        avg = data[\"total_cost\"] \/ data[\"count\"] if data[\"count\"] \u0026gt; 0 else 0\n        print(f\"  {task}: {data['count']} runs, \"\n              f\"${data['total_cost']:.4f} total, \"\n              f\"${avg:.4f} avg\")\n    print()\n\n    print(\"Chi phi theo model:\")\n    for model, data in dashboard[\"by_model\"].items():\n        short_name = model.split(\"-\")[1]\n        print(f\"  {short_name}: {data['count']} runs, \"\n              f\"${data['total_cost']:.4f}\")\n    print(\"=\" * 60)\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eChiến lược giảm chi phí thực tế\u003c\/h2\u003e\n\u003cp\u003eNgoài việc đặt giới hạn, có nhiều kỹ thuật giúp giảm chi phí thực sự cho agent:\u003c\/p\u003e\n\n\u003ch3\u003e1. Tóm tắt context thay vì giữ nguyên\u003c\/h3\u003e\n\u003cp\u003eThay vì tích lũy toàn bộ lịch sử hội thoại, tóm tắt các vòng cũ để giảm input token:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003edef summarize_old_turns(client, messages, keep_recent=4):\n    \"\"\"Tom tat cac tin nhan cu de giam token.\"\"\"\n    if len(messages) \u0026lt;= keep_recent * 2:\n        return messages\n\n    old_messages = messages[:-keep_recent * 2]\n    recent_messages = messages[-keep_recent * 2:]\n\n    # Tom tat phan cu\n    summary_response = client.messages.create(\n        model=\"claude-haiku-3-5-20241022\",\n        max_tokens=500,\n        messages=[{\n            \"role\": \"user\",\n            \"content\": \"Tom tat ngan gon noi dung hoi thoai sau, \"\n                       \"giu lai thong tin quan trong:\n\n\"\n                       + \"\n\".join(\n                           f\"{m['role']}: {m['content']}\"\n                           for m in old_messages\n                           if isinstance(m.get(\"content\"), str)\n                       )\n        }]\n    )\n\n    summary = summary_response.content[0].text\n\n    # Thay the lich su cu bang tom tat\n    compressed = [\n        {\"role\": \"user\", \"content\": f\"[Tom tat hoi thoai truoc: {summary}]\"},\n        {\"role\": \"assistant\", \"content\": \"Da hieu. Toi se tiep tuc dua tren \"\n                                         \"noi dung tom tat.\"}\n    ] + recent_messages\n\n    return compressed\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch3\u003e2. Tool result truncation\u003c\/h3\u003e\n\u003cp\u003eGiới hạn kích thước kết quả trả về từ tool để tránh token bloat:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003edef execute_tool_with_limit(tool_name, tool_input, max_chars=2000):\n    \"\"\"Thuc thi tool va gioi han kich thuoc ket qua.\"\"\"\n    result = execute_tool(tool_name, tool_input)\n\n    if len(result) \u0026gt; max_chars:\n        truncated = result[:max_chars]\n        truncated += f\"\n... (da cat bot {len(result) - max_chars} ky tu)\"\n        return truncated\n\n    return result\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch3\u003e3. Early exit khi có đủ thông tin\u003c\/h3\u003e\n\u003cp\u003eThêm cơ chế để model có thể dừng sớm thay vì chạy hết số vòng cho phép. Cách đơn giản nhất là thêm hướng dẫn trong system prompt:\u003c\/p\u003e\n\u003cpre\u003e\u003ccode\u003eCOST_AWARE_SYSTEM_PROMPT = \"\"\"Ban la tro ly AI. Quy tac ve hieu suat:\n1. Chi goi tool khi THAT SU can thiet\n2. Neu da co du thong tin de tra loi, tra loi NGAY, khong goi them tool\n3. Uu tien goi it tool nhat co the\n4. Neu tool tra ve loi, khong retry qua 2 lan\n5. Khi duoc yeu cau tong ket, tra loi ngan gon trong 1 tin nhan\"\"\"\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eChecklist kiểm soát chi phí production\u003c\/h2\u003e\n\u003cp\u003eTrước khi deploy agent ra production, hãy đảm bảo tất cả các mục sau:\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003emax_turns được đặt cho mọi agent loop (khuyến nghị: 5-15 tùy tác vụ)\u003c\/li\u003e\n  \u003cli\u003emax_tokens_per_turn được đặt hợp lý (không dùng giá trị mặc định quá cao)\u003c\/li\u003e\n  \u003cli\u003eToken budget tổng cho mỗi agent run\u003c\/li\u003e\n  \u003cli\u003eBudget theo giờ và theo ngày để ngăn bùng nổ chi phí\u003c\/li\u003e\n  \u003cli\u003eModel cascade: bắt đầu với Haiku, nâng lên khi cần\u003c\/li\u003e\n  \u003cli\u003eContext summarization cho conversation dài\u003c\/li\u003e\n  \u003cli\u003eTool result truncation để giới hạn input token\u003c\/li\u003e\n  \u003cli\u003eAlert thresholds ở nhiều mức (50%, 80%, 95%)\u003c\/li\u003e\n  \u003cli\u003eCost dashboard để theo dõi xu hướng chi phí\u003c\/li\u003e\n  \u003cli\u003eGraceful degradation khi hết budget (tóm tắt thay vì crash)\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eBước tiếp theo\u003c\/h2\u003e\n\u003cp\u003eKiểm soát chi phí là yếu tố sống còn khi triển khai AI agent trong production. Kết hợp CostController với error handling vững chắc và Prompt Caching, bạn sẽ có hệ thống agent vừa mạnh mẽ vừa kinh tế. Khám phá thêm tại \u003ca href=\"\/collections\/nang-cao\"\u003eThư viện Nâng cao Claude\u003c\/a\u003e.\u003c\/p\u003e\n","brand":"Minh Tuấn","offers":[{"title":"Default Title","offer_id":47730149392596,"sku":null,"price":0.0,"currency_code":"VND","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0821\/0264\/9044\/files\/ki_m-soat-chi-phi-ai-agent-token-budget-max-iterations-va-monitoring.jpg?v=1774715292","url":"https:\/\/claude.vn\/products\/ki%e1%bb%83m-soat-chi-phi-ai-agent-token-budget-max-iterations-va-monitoring","provider":"CLAUDE.VN","version":"1.0","type":"link"}