Метрики використання інструментів

Метрики показують як часто агенти викликають tools.
На цій сторінці
  1. Ідея за 30 секунд
  2. Основна проблема
  3. Як це працює
  4. Типові production-метрики по tools
  5. Як читати tool-layer
  6. Коли використовувати
  7. Приклад реалізації
  8. Investigation
  9. Типові помилки
  10. Є загальна кількість викликів, але немає розбиття по tool
  11. Не відстежуються повторні виклики
  12. Немає p95 latency по інструментах
  13. Висококардинальні labels
  14. Немає алертів по tool-layer
  15. Самоперевірка
  16. FAQ
  17. Пов'язані сторінки

Ідея за 30 секунд

Tool usage metrics показують не «чи працює агент», а як саме він використовує інструменти і де ламається tool-layer.

Вони допомагають зрозуміти, які інструменти викликаються найчастіше, де росте latency, і де починаються повторні або помилкові виклики.

Без цих метрик складно вчасно помітити перевантаження tool-layer і зростання витрат.

Основна проблема

Загальні метрики run не показують, що саме відбувається на рівні інструментів.

Два run можуть мати схожу загальну latency, але в одному випадку проблема у повільному search, а в іншому — у повторних викликах fetch. Без метрик по tools це важко побачити до інциденту.

Далі розберемо, як читати ці сигнали і знаходити проблеми.

У production це зазвичай виглядає так:

  • один tool непомітно стає «гарячою точкою»;
  • retries ростуть, але причина неочевидна;
  • частина run витрачає забагато кроків саме на інструменти;
  • команда бачить проблему тільки коли зростає error rate або бюджет.

Саме тому tool-layer варто моніторити окремо, а не лише через загальні run-метрики.

Як це працює

Метрики використання інструментів (tool usage metrics) будуються навколо подій tool_call і tool_result.

Tool metrics поділяються на:

  • infra metrics (tool_latency_p95, tool_error_rate);
  • behavior metrics (repeated_tool_calls, tool_calls_per_run, unique_tools_per_run).

Ці метрики відповідають на питання «як поводиться tool-layer у часі». Логи й трейсинг потрібні, щоб пояснити конкретний проблемний run.

Retries зазвичай виникають не на рівні коду, а на рівні runtime: агент отримує помилку tool як observation і пробує ще раз. Retries — це не просто повторні виклики, а сигнал того, що агент намагається адаптуватись до помилки інструмента.

Типові production-метрики по tools

МетрикаЩо показуєНавіщо потрібна
tool_calls_totalзагальна кількість викликів toolsконтроль навантаження на tool-layer
tool_calls_per_runскільки tool calls припадає на один runвиявлення зайвих або циклічних викликів
unique_tools_per_runскільки різних tools використовує runоцінка складності workflow
tool_error_rateчастка помилкових tool callsраннє виявлення нестабільних інструментів
tool_latency_p50 / p95типова й «довга» затримка по toolsлокалізація повільних залежностей
repeated_tool_callsвиклики, що повторюють попередній виклик того самого tool з тими самими argsвиявлення спаму інструментами
tool_cost_per_runприблизна вартість tools у межах одного runконтроль бюджету і пошук дорогих інструментів

Щоб метрики були практичними, їх зазвичай сегментують за tool, release і, за потреби, model.

Важливо: не додавай у labels висококардинальні поля (run_id, request_id, args_hash), інакше сховище метрик швидко перевантажиться.

Як читати tool-layer

Що викликається → як агент поводиться → що відбувається у часі. Це три рівні, які завжди потрібно дивитися разом.

Важливо дивитися на тренди у часі і різницю між релізами, а не на одиничні значення.

Далі дивимось на комбінації сигналів:

  • tool_error_rate ↑ + repeated_tool_calls ↑ → tool нестабільний, агент ретраїть
  • tool_latency_p95 ↑ + tool_cost_per_run ↑ → деградація дорогого інструмента
  • tool_calls_per_run ↑ + unique_tools_per_run ↑ → надмірна складність workflow

Коли використовувати

Повний набір tool-метрик не завжди потрібен.

Для простого агента з 1-2 інструментами інколи вистачає tool_calls_total і tool_error_rate.

Але детальні метрики використання tools стають критичними, коли:

  • агент активно використовує зовнішні API або БД;
  • у системі часто виникають retries;
  • важливо контролювати витрати на інструменти;
  • треба виявляти tool spam до того, як він вплине на користувачів.

Приклад реалізації

Нижче — спрощений приклад інструментації метрик використання tools у стилі Prometheus. Приклад показує базовий контроль: кількість викликів, latency, error classes, повтори й навантаження на run.

PYTHON
import hashlib
import json
import time
from prometheus_client import Counter, Histogram

TOOL_CALL_TOTAL = Counter(
    "agent_tool_call_total",
    "Total tool calls",
    ["tool", "status", "release"],
)

TOOL_ERROR_TOTAL = Counter(
    "agent_tool_error_total",
    "Total tool errors by class",
    ["tool", "error_class", "release"],
)

TOOL_LATENCY_MS = Histogram(
    "agent_tool_latency_ms",
    "Tool latency in milliseconds",
    ["tool", "release"],
    buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)

TOOL_CALLS_PER_RUN = Histogram(
    "agent_tool_calls_per_run",
    "Number of tool calls per run",
    ["release"],
    buckets=(0, 1, 2, 4, 8, 12, 16, 24, 32),
)

UNIQUE_TOOLS_PER_RUN = Histogram(
    "agent_unique_tools_per_run",
    "Number of unique tools used in run",
    ["release"],
    buckets=(0, 1, 2, 3, 4, 6, 8, 12),
)

REPEATED_TOOL_CALL_TOTAL = Counter(
    "agent_repeated_tool_call_total",
    "Repeated tool calls with same tool+args signature",
    ["tool", "release"],
)

TOOL_COST_USD_TOTAL = Counter(
    "agent_tool_cost_usd_total",
    "Estimated total tool cost in USD",
    ["tool", "release"],
)

STEP_ERROR_TOTAL = Counter(
    "agent_step_error_total",
    "Total non-tool step errors by type and class",
    ["step_type", "error_class", "release"],
)


def stable_hash(value):
    # default=str дає базову сумісність;
    # у критичних системах краще явна серіалізація (наприклад ISO 8601)
    payload = json.dumps(value, sort_keys=True, ensure_ascii=False, default=str).encode("utf-8")
    return hashlib.sha256(payload).hexdigest()


def run_agent(agent, task, release="2026-03-21"):
    tool_calls = 0
    unique_tools = set()
    seen_signatures = set()

    try:
        for step in agent.iter(task):
            step_type = step.type
            result = None

            if step_type != "tool_call":
                try:
                    result = step.execute()
                except Exception as error:
                    STEP_ERROR_TOTAL.labels(
                        step_type=step_type,
                        error_class=type(error).__name__,
                        release=release,
                    ).inc()
                    raise

                if result and result.is_final:
                    break
                continue

            tool_name = getattr(step, "tool_name", "unknown")
            args = getattr(step, "args", {})

            tool_calls += 1
            unique_tools.add(tool_name)

            signature = (tool_name, stable_hash(args))
            if signature in seen_signatures:
                REPEATED_TOOL_CALL_TOTAL.labels(tool=tool_name, release=release).inc()
            else:
                seen_signatures.add(signature)

            started_at = time.time()
            try:
                result = step.execute()
                TOOL_CALL_TOTAL.labels(tool=tool_name, status="ok", release=release).inc()
                cost_usd = getattr(result, "cost_usd", None)
                if cost_usd:
                    TOOL_COST_USD_TOTAL.labels(tool=tool_name, release=release).inc(cost_usd)
            except Exception as error:
                TOOL_CALL_TOTAL.labels(tool=tool_name, status="error", release=release).inc()
                TOOL_ERROR_TOTAL.labels(
                    tool=tool_name,
                    error_class=type(error).__name__,
                    release=release,
                ).inc()
                # Цей приклад робить raise.
                # У реальних агентах помилку часто передають у LLM як observation для retry.
                raise
            finally:
                TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
                    (time.time() - started_at) * 1000
                )

            if result and result.is_final:
                break
    finally:
        TOOL_CALLS_PER_RUN.labels(release=release).observe(tool_calls)
        UNIQUE_TOOLS_PER_RUN.labels(release=release).observe(len(unique_tools))

# tool_cost_per_run зазвичай рахується на рівні дашборду:
# sum(agent_tool_cost_usd_total) / run_count

Ось як ці метрики виглядають разом у реальному дашборді:

Toolcalls/minerror_ratep95 latencyСтатус
search_docs3206.8%1.9scritical: alert
fetch_url1801.4%680mswarning: p95 росте
db_lookup950.3%120msok

Для error_class краще використовувати нормалізований словник значень, щоб уникати зайвої кардинальності.

Investigation

Коли алерт спрацьовує:

  1. знайти tool з аномалією через метрики;
  2. подивитись конкретні runs у трейсингу;
  3. перевірити аргументи й відповіді в логах;
  4. знайти root cause (tool, логіка агента або зовнішній API).

Типові помилки

Навіть коли tool metrics уже додані, вони часто не працюють як треба через типові помилки нижче.

Є загальна кількість викликів, але немає розбиття по tool

tool_calls_total без розбиття за конкретним інструментом майже не допомагає в інциденті. У такій ситуації складно швидко знайти джерело збою інструмента.

Не відстежуються повторні виклики

Без метрики repeated_tool_calls важко побачити, що агент викликає той самий tool з тими самими аргументами. Це часто маскує ранню фазу спаму інструментами.

Немає p95 latency по інструментах

Система може виглядати стабільною, поки частина користувачів уже чекає 5+ секунд. Для tool-layer мінімум — p50 і p95.

Висококардинальні labels

Додавання run_id, request_id або args_hash у labels швидко перевантажує бекенд метрик. Краще тримати ці дані в логах, а не в labels.

Немає алертів по tool-layer

Без алертів метрики залишаються пасивною телеметрією. Через це легко пропустити перші сигнали вибуху бюджету через надмірні виклики зовнішніх API.

Самоперевірка

Нижче — короткий checklist базових tool usage metrics перед релізом.

Прогрес: 0/9

⚠ Бракує базової observability

Систему буде складно дебажити в production. Почніть з run_id, structured logs і tracing tool calls.

FAQ

Q: Чим tool usage metrics відрізняються від загальних метрик агента?
A: Загальні метрики показують стан системи в цілому. Tool usage metrics показують, що відбувається саме на рівні інструментів.

Q: Який мінімум tool-метрик потрібен на старті?
A: Почни з tool_calls_total, tool_error_rate, tool_latency_p95 і tool_calls_per_run.

Q: Чи треба додавати args_hash у labels?
A: Ні. Це майже завжди створює високу кардинальність. Для таких даних краще використати структуровані логи.

Q: Як відрізнити разовий збій від системної проблеми tool-layer?
A: Перевір, чи проблема стабільно повторюється для конкретного tool у кількох run і релізах. Якщо повторюються ті самі сигнали (error_class, latency, repeated_tool_calls) — це системна проблема, а не разовий збій.

Пов'язані сторінки

Далі за темою:

⏱️ 7 хв читанняОновлено 22 березня 2026 р.Складність: ★★★
Інтегровано: продакшен-контрольOnceOnly
Додай guardrails до агентів з tool-calling
Зашип цей патерн з governance:
  • Бюджетами (кроки / ліміти витрат)
  • Дозволами на інструменти (allowlist / blocklist)
  • Kill switch та аварійна зупинка
  • Ідемпотентність і dedupe
  • Audit logs та трасування
Інтегрована згадка: OnceOnly — контрольний шар для продакшен агент-систем.

Автор

Микола — інженер, який будує інфраструктуру для продакшн AI-агентів.

Фокус: патерни агентів, режими відмов, контроль рантайму та надійність систем.

🔗 GitHub: https://github.com/mykolademyanov


Редакційна примітка

Ця документація підготовлена з допомогою AI, із людською редакторською відповідальністю за точність, ясність і продакшн-релевантність.

Контент базується на реальних відмовах, постмортемах та операційних інцидентах у розгорнутих AI-агентних системах.