СИСТЕМА КОМПЬЮТЕРНОГО ДОСТУПА

Оптимизация затрат на агентов: практическое руководство по сокращению расходов на API


Оптимизация затрат на агентов: практическое руководство по сокращению расходов на API

Ваш агент отлично справляется с задачами. Он обрабатывает 200 запросов в день, пользователи довольны. Затем вы смотрите счёт за API: $3 400 в этом месяце. Разбирая цифры, вы понимаете, что агент в среднем делает 12 обращений к API на каждый запрос, причём каждое из них содержит системный промпт объёмом 4 000 токенов. Это 9,6 миллиона входных токенов в день только на системные промпты. При цене $3 за миллион токенов получается $864 в месяц только на повторяющийся контент.

Именно стоимость — главная причина, по которой продакшн-развёртывания агентов урезают или полностью закрывают. Оптимизация — это не преждевременная мера, это вопрос выживания. Хорошая новость: в большинстве развёртываний агентов можно сократить затраты на 50–80% с помощью простых изменений, не требующих полной перестройки системы.

В этом руководстве вы узнаете о семи стратегиях снижения затрат, упорядоченных по ROI (возврату инвестиций). Начните сверху и двигайтесь вниз, пока не достигнете целевого бюджета. Каждый раздел содержит конкретные цифры, чтобы вы могли оценить экономию ещё до написания кода.


1. Учёт токенов: знайте, куда уходят деньги

Невозможно оптимизировать то, что не измеряешь. Прежде чем что-либо менять, составьте полную картину того, куда уходит каждый доллар в рабочем процессе вашего агента.

Разбивка входных токенов

Каждый вызов API к Claude включает несколько категорий токенов на входе:

  • Системный промпт — инструкции, персона, ограничения. Часто 1 000–5 000 токенов, повторяются при каждом вызове.
  • Определения инструментов — JSON-схемы для каждого инструмента, доступного агенту. 10 инструментов могут легко занять 2 000–3 000 токенов.
  • История разговора — все предыдущие сообщения в диалоге. Растёт с каждым шагом.
  • Результаты инструментов — выходные данные предыдущих вызовов инструментов, добавляемые обратно в контекст. Могут быть огромными (полные веб-страницы, результаты из базы данных).

Разбивка выходных токенов

Выходные токены обходятся в 3–5 раз дороже входных, что делает их критически важной целью для оптимизации:

  • Рассуждения агента — внутренняя цепочка мыслей (особенно при расширенном мышлении).
  • Генерация вызовов инструментов — JSON для вызовов инструментов.
  • Финальный ответ — ответ, который видит пользователь.

Расчёт стоимости одной задачи

Общая стоимость одной задачи агента:

Общая стоимость = Σ (input_tokens × input_price + output_tokens × output_price)
для каждого вызова API в задаче

Пример разбивки стоимости

Вот реалистичная разбивка для задачи исследовательского агента из 10 шагов с использованием Claude Sonnet ($3/M входных, $15/M выходных):

ШагКомпонентВходные токеныВыходные токеныСтоимость входаСтоимость выходаИтого
1Первоначальное планирование4 200800$0.0126$0.0120$0.025
2Вызов веб-поиска4 800200$0.0144$0.0030$0.017
3Обработка результатов поиска8 500600$0.0255$0.0090$0.035
4Детальное чтение (стр. 1)12 000500$0.0360$0.0075$0.044
5Детальное чтение (стр. 2)15 200500$0.0456$0.0075$0.053
6Дополнительный поиск16 800200$0.0504$0.0030$0.053
7Обработка результатов20 100600$0.0603$0.0090$0.069
8Синтез22 5001 200$0.0675$0.0180$0.086
9Проверка24 000400$0.0720$0.0060$0.078
10Финальный ответ25 5001 500$0.0765$0.0225$0.099
Итого153 6006 500$0.461$0.098$0.558

Обратите внимание: входные токены доминируют в расходах, и они растут с каждым шагом по мере накопления истории разговора. Шаги 8–10 составляют 47% от общей стоимости, хотя занимают лишь 30% от всех шагов.

Код для отслеживания затрат

Реализуйте обёртку для отслеживания с первого дня:

import anthropic
import time
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class CostRecord:
step: int
model: str
input_tokens: int
output_tokens: int
cache_read_tokens: int = 0
cache_creation_tokens: int = 0
input_cost: float = 0.0
output_cost: float = 0.0
total_cost: float = 0.0
duration_ms: float = 0.0
# Pricing per million tokens (as of early 2026)
MODEL_PRICING = {
"claude-haiku": {"input": 0.25, "output": 1.25, "cache_read": 0.025, "cache_write": 0.30},
"claude-sonnet": {"input": 3.00, "output": 15.00, "cache_read": 0.30, "cache_write": 3.75},
"claude-opus": {"input": 15.00, "output": 75.00, "cache_read": 1.50, "cache_write": 18.75},
}
@dataclass
class TaskCostTracker:
task_id: str
budget_limit: Optional[float] = None
records: list = field(default_factory=list)
total_cost: float = 0.0
def record_call(self, step: int, model: str, usage) -> CostRecord:
pricing = MODEL_PRICING.get(model, MODEL_PRICING["claude-sonnet"])
input_cost = (usage.input_tokens / 1_000_000) * pricing["input"]
output_cost = (usage.output_tokens / 1_000_000) * pricing["output"]
cache_read_cost = (getattr(usage, 'cache_read_input_tokens', 0) / 1_000_000) * pricing["cache_read"]
cache_write_cost = (getattr(usage, 'cache_creation_input_tokens', 0) / 1_000_000) * pricing["cache_write"]
total = input_cost + output_cost + cache_read_cost + cache_write_cost
record = CostRecord(
step=step,
model=model,
input_tokens=usage.input_tokens,
output_tokens=usage.output_tokens,
cache_read_tokens=getattr(usage, 'cache_read_input_tokens', 0),
cache_creation_tokens=getattr(usage, 'cache_creation_input_tokens', 0),
input_cost=input_cost + cache_read_cost + cache_write_cost,
output_cost=output_cost,
total_cost=total,
)
self.records.append(record)
self.total_cost += total
print(f" Step {step} [{model}]: {usage.input_tokens} in / {usage.output_tokens} out = ${total:.4f} (cumulative: ${self.total_cost:.4f})")
if self.budget_limit and self.total_cost > self.budget_limit:
raise BudgetExceededError(
f"Task {self.task_id} exceeded budget: ${self.total_cost:.4f} > ${self.budget_limit:.4f}"
)
return record
def summary(self) -> dict:
return {
"task_id": self.task_id,
"total_steps": len(self.records),
"total_input_tokens": sum(r.input_tokens for r in self.records),
"total_output_tokens": sum(r.output_tokens for r in self.records),
"total_cost": self.total_cost,
"cost_by_model": self._cost_by_model(),
}
def _cost_by_model(self) -> dict:
by_model = {}
for r in self.records:
if r.model not in by_model:
by_model[r.model] = {"calls": 0, "cost": 0.0}
by_model[r.model]["calls"] += 1
by_model[r.model]["cost"] += r.total_cost
return by_model
class BudgetExceededError(Exception):
pass

Начните отслеживать уже сегодня, даже до начала оптимизации. Вам нужны базовые показатели, чтобы измерить прогресс.


2. Выбор модели под задачу

Это самый мощный рычаг снижения затрат из доступных вам. Не каждый шаг агента требует самой мощной модели.

Уровни моделей и цены

Используя семейство Claude в качестве ориентира:

| Модель | Входные (за 1M токенов) | Вы


Связанные статьи