Перейти до вмісту
cd /blog

Спостережуваність агентів: хуки, Alloy та Grafana

[Спостережуваність][Grafana][OpenTelemetry][Архітектура]

> Ми під'єднали Claude Code та Codex до єдиного стеку Grafana за допомогою OpenTelemetry та Alloy, а потім використали трейси й логи, щоб знаходити та виправляти проблеми в поведінці агентів у джерелі.

Агентні системи ламаються дивними способами.

Іноді проблема в моделі. Іноді проблема в інструменті. Іноді ваш сервер MCP у порядку, але агент обрав не того спеціаліста, або витратив половину сесії на роботу з shell, якої ви не очікували, або мовчки спалив кошти в циклі, що зовні виглядав продуктивним.

Якщо ви не бачите різниці, ви насправді не керуєте агентною системою. Ви вгадуєте.

Тож ми побудували стек спостережуваності для нашого власного робочого процесу: Claude Code, Codex, події хуків Claude, події сповіщень Codex, нативний OpenTelemetry, Grafana Alloy та Grafana Cloud на іншому кінці.

Цікава частина не в тому, що «ми зробили дашборд». Цікаво те, що нам довелося розділити телеметрію на два різні потоки, бо жоден окремий канал не давав повної картини.

Проблема: телеметрія агентів фрагментована

Сучасні агенти для кодування вже надсилають певну телеметрію. Це допомагає, але цього недостатньо.

Нативний OTEL добре відповідає на запитання на кшталт:

  • Скільки запитів ми зробили?
  • Скільки коштувала сесія?
  • Де спани та трейси?
  • Чи стрибнула затримка?

Він набагато гірше відповідає на запитання на кшталт:

  • На який сервер MCP спирався агент?
  • Ця помилка сталася в Bash, у вбудованому файловому інструменті чи у виклику MCP?
  • Який навик насправді активувався?
  • Який тип субагента було відправлено?
  • Сесія робила корисну роботу чи просто буксувала?

Цей другий клас запитань живе ближче до хуків, ніж до трейсів.

Але вірним є і зворотне: деякі з найважливіших запитань про продуктивність живуть ближче до трейсів, ніж до хуків.

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

Архітектура, до якої ми прийшли

Ми запускаємо два шляхи телеметрії паралельно.

Claude Code
  native OTEL -> Alloy -> Grafana Cloud
  hooks        -> send_event.py -> Grafana Cloud Loki

Codex
  native OTEL -> Alloy -> Grafana Cloud
  notify hook -> codex_notify.py -> shared Loki schema

Цей поділ навмисний.

Він також асиметричний. Claude Code дає нам набагато багатшу поверхню хуків життєвого циклу. Codex дає нам нативний OTEL плюс поверхню сповіщень, тож ми нормалізуємо тонші події завершення ходу в ту саму схему логів, замість того щоб вдавати, ніби обидва середовища виконання надають однакові засоби керування.

Нативний OTEL дає нам базовий потік: логи та трейси від самого середовища виконання, плюс метрики там, де середовище виконання їх справді надсилає.

Події хуків і сповіщень дають нам семантичний шар: такі речі, як PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, SubagentStop, SkillActivated, та класифіковані метадані, які нас справді цікавлять під час діагностики поведінки агента. Claude Code надає тут багатший потік подій. Codex надає тонший, але все ще корисний нормалізований потік.

Навіщо взагалі потрібні хуки

Наш конвеєр хуків збагачує події, перш ніж вони потрапляють у Loki.

Замість того щоб просто сказати «інструмент виконався», ми класифікуємо подію за полями на кшталт:

  • tool_type: builtin, mcp, skill, agent, bash
  • mcp_server: який бекенд MCP обробив виклик
  • bash_cli: родина shell-команди
  • subagent_type: який тип спеціаліста було відправлено
  • agent_tool: чи джерелом був Claude Code, чи Codex

Це означає, що ми можемо ставити операційно важливі запитання:

{service_name="claude-code-hooks"} | agent_tool="codex-cli"
{service_name="claude-code-hooks"} | tool_type="mcp"
{service_name="claude-code-hooks"} | json | bash_cli="git"

Це не поля заради галочки. Це різниця між «агент здавався повільним» і «агент витратив останні десять хвилин на насичені shell-операціями git з високим рівнем відмов інструментів».

Одна деталь реалізації, яка виглядає дивнішою, ніж є насправді: спільний потік Loki все ще використовує service_name="claude-code-hooks" як мітку, навіть коли подія прийшла з Codex. Реальний поділ між середовищами виконання відбувається за agent_tool.

Чому Alloy стоїть посередині

Grafana Alloy у цій конфігурації не просто пересилач. Це межа політики.

Ми спрямовуємо нативний потік OTEL від Claude Code та Codex на локальний проксі Alloy на localhost:4318, а потім дозволяємо Alloy очистити payload, перш ніж пересилати його до Grafana Cloud.

Це важливо, бо сира телеметрія агентів переповнена полями з високою кардинальністю, які корисні для аналізу, але жахливі як індексовані мітки:

  • session_id
  • prompt_id
  • кількість токенів
  • тривалості
  • блоби параметрів інструментів

Якщо індексувати все, отримаєте вибух міток і поганий день.

Тож Alloy робить для нас три речі:

  1. Тримає індексованим дуже невеликий набір міток з низькою кардинальністю.
  2. Переносить шумні, але корисні поля в структуровані метадані.
  3. Повністю відкидає чистий шум.

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

Чому потік хуків обходить Alloy

Потік хуків уже сформований для Loki.

До того моменту, коли send_event.py надсилає подію, ми вже вирішили, які поля заслуговують на обробку як мітки, а які належать до структурованого тіла JSON. Цей потік іде прямо до OTLP-шлюзу Grafana Cloud, замість того щоб проходити ще один прохід через Alloy.

Тож у системи чіткий розподіл обов’язків:

  • Alloy приборкує сирий нативний потік OTEL.
  • Збагачення хуків робить семантичні події придатними для запитів.

Це тримає архітектуру простішою, ніж спроба протягнути все через один шлях.

Що насправді показує дашборд

Знімок екрана нижче — з одного з дашбордів спостережуваності, що стоїть за нашим агентним робочим процесом. Це не бенчмарк, а числа — лише зріз у певний момент часу. Суть у формі даних: стрічка активності, виклики інструментів, відмови, промпти та розбивки за агентом, вбудованими інструментами, використанням MCP, shell-командами та навичками.

Корисно те, що цей дашборд живе на тому самому стеку Grafana, що й решта телеметрії агентів. Ми можемо фільтрувати за вихідним агентом та родиною інструментів і дивитися крізь середовища виконання, не вигадуючи окрему історію спостережуваності для кожної системи.

Дашборд Grafana зі стрічкою активності, кількістю викликів інструментів, відмовами, промптами та розбивками за агентами, вбудованими інструментами, використанням MCP, CLI-командами та навичками для агентного робочого процесу.
Один із живих дашбордів, що стоїть за нашим агентним робочим процесом. Цей знімок екрана — лише один зріз спільного стеку Grafana, який також отримує телеметрію від інших наших агентних середовищ виконання та систем. Натисніть на зображення, щоб переглянути версію в повній роздільній здатності.

Чому трейси важливіші, ніж здається на перший погляд

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

Ця відмінність важлива в агентних системах, бо слово «повільно» надто тупе, щоб бути корисним.

Трейс може сказати нам, звідки взявся біль:

  • затримка моделі
  • час виконання інструмента
  • повторні спроби
  • одна особливо дорога взаємодія з MCP
  • довгий хвіст дрібних операцій, які поодинці виглядали безпечними

На практиці ми використовуємо потік хуків і трейси Tempo разом.

  • Логи хуків відповідають: що за річ сталася?
  • Трейси відповідають: куди пішов час?

Саме ця комбінація перетворює спостережуваність з дашборда на пояснення.

Де в цьому місце Codex

Codex — частина того самого стеку, але він не ідентичний Claude Code.

Для Codex ми під’єднуємо дві частини:

  • Нативний OTEL від Codex в Alloy
  • Вебхук сповіщень у codex_notify.py, який відображає завершення ходів у ту саму схему Loki, яку ми використовуємо для подій хуків

Це дає нам уніфікований фільтр на кшталт agent_tool="codex-cli" у межах того самого потоку логів.

Чесне застереження: payload сповіщень Codex наразі тонший за payload хуків Claude Code, бо це не той самий тип поверхні інтеграції. У нашій сьогоднішній конфігурації завершення ходів Codex можна нормалізувати в спільну схему, але детальне вилучення по кожному інструменту все ще краще виходить у нативному потоці OTEL, ніж у мосту сповіщень.

Це не привід уникати цього допису. Це якраз і є суть допису. Реальні системи спостережуваності збираються з недосконалих сигналів.

Grafana через MCP змінює правила гри

Більший зсув у тому, що Grafana — це не лише місце, куди люди заходять у браузері.

У цьому репозиторії ми також надаємо доступ до Grafana через MCP. Це означає, що агент може напряму запитувати Loki, Prometheus і Tempo, замість того щоб чекати, поки людина спершу вручну огляне дашборди.

Це перетворює спостережуваність на активний вхід у робочий процес.

Агент може запитати:

  • Які родини інструментів найчастіше відмовляли за останню годину?
  • Який сервер MCP домінував у сесії?
  • Чи нещодавні зміни зменшили кількість відмов інструментів, чи просто перемістили роботу в більш насичені shell-операціями шляхи з тими самими помилками?
  • Які трейси показують найвищу затримку чи повторні спроби?

Як тільки у вас це є, ви дуже близькі до циклу самовдосконалення.

Від дашборда до циклу зворотного зв’язку

Це та частина, яку ми вважаємо найцікавішою.

Щойно стек спостережуваності стає доступним для запитів з рівня агента, телеметрія перестає бути пасивною поверхнею звітності й стає керуючим сигналом.

Цикл виглядає так:

  1. Активність агента породжує трейси, метрики та збагачені логи хуків.
  2. Grafana зберігає докази в Loki, Tempo та Prometheus там, де існують метрики.
  3. Агенти запитують ці докази через Grafana MCP.
  4. Система виявляє поганий мікс інструментів, крихкі навички, слабку маршрутизацію чи насичені shell-операціями робочі процеси, що постійно призводять до помилок, яких можна уникнути.
  5. Агенти чи оператори коригують промпти, конфігурації агентів, описи навичок, правила маршрутизації чи доступ до інструментів.
  6. Наступна сесія породжує нову форму телеметрії, і цикл повторюється.

Саме так ви переходите від «цікавого дашборда» до «вимірюваної системи вдосконалення».

Мета не в тому, щоб максимізувати одну категорію інструментів. Мета в тому, щоб знайти правильний мікс CLI, вбудованих інструментів, викликів MCP та навичок для роботи, яка справді виконується.

На що це дозволяє нам відповісти

Щойно обидва середовища виконання потрапляють в один стек Grafana, ми можемо набагато швидше відповідати на операційні запитання:

  • Чи зосереджені відмови в одній родині інструментів?
  • Чи насичені shell-операціями робочі процеси створюють помилки, яких можна було б уникнути, там, де мав би існувати інструмент вищого рівня?
  • Які сервери MCP несуть основне навантаження?
  • Чи платимо ми за активність агента, яка не дає значущого прогресу?
  • Чи нездорова сесія через модель, інструменти чи шар оркестрації?

Це особливо корисно в багатоагентних робочих процесах, де фраза «агент був зайнятий» майже нічого не повідомляє.

Якщо якийсь спеціаліст постійно отримує завдання і показує високий рівень відмов, це проблема маршрутизації чи формулювання промпту.

Якщо один сервер MCP домінує в усіх викликах, це може бути хорошою архітектурою — або ознакою того, що все інше мертвий вантаж.

Якщо відмови інструментів різко зростають, а вартість залишається високою, у вас операційна проблема, а не проблема якості.

Якщо робота з shell постійно й передбачувано провалюється так, як цього можна було б уникнути, там, де мав би існувати інструмент вищого рівня, це продуктовий сигнал.

Якщо один навик активується постійно, але не покращує результати, це сигнал про промпт чи маршрутизацію.

Справжній урок

Глибший урок тут у тому, що спостережуваність агентів потребує і телеметрії середовища виконання, і телеметрії робочого процесу.

Телеметрія середовища виконання повідомляє, що зробила система.

Телеметрія робочого процесу повідомляє, що, на думку агента, він робив.

Нам потрібно і те, і те.

Якщо зберігати лише трейси й лічильники, ви втрачаєте семантичний шар. Якщо зберігати лише події хуків, ви втрачаєте затримку, спани та ширшу картину середовища виконання.

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

Саме ця комбінація робить систему достатньо пояснюваною, щоб нею керувати, і достатньо налаштовуваною, щоб її вдосконалювати.

Що досі недосконале

Шершавостей ще вистачає.

  • Не кожна подія хука містить дані про тривалість і токени, які ми хотіли б мати.
  • Деякі з найкращих поглядів на час досі беруться з трейсів Tempo, а не з логів хуків.
  • Codex сьогодні семантично бідніший за Claude Code у збагаченому потоці подій.
  • Знімок екрана дашборда — це поверхня живих операцій, а не відшліфований маркетинговий артефакт.

Остання теза навмисна. Ми радше покажемо реальну панель приладів, ніж вдаватимемо, що агентні системи магічно самопояснювальні.

Чому це важливо для Maguyva

Maguyva про те, щоб дати агентам кращий інтелект коду. Але щойно агенти справді виконують корисну роботу, одразу з’являється нова вимога: потрібно бачити, як вони поводяться.

Якість пошуку, якість маршрутизації, вибір інструментів та ефективність контексту — все це стає спостережуваними проблемами.

Саме тому ми вважаємо, що про це варто писати. Майбутній агентний стек — це не лише промпти й інструменти. Це промпти, інструменти та шар інструментування, який повідомляє, чи працює все загалом.

Якщо ви будуєте серйозні агентні робочі процеси, спостережуваність — не опціональна інфраструктура. Вона частина продукту.

Читайте також

Ще з журналу розробки Maguyva

Чому ми оновили пошук коду до voyage-4-large_

Ми перевели наші ембеддинги коду на voyage-4-large — наразі верхівку публічного рейтингу RTEB для пошуку коду. Чесна версія: компроміс, на який ми йдемо, що ми насправді індексуємо, і чому ми платимо за преміум-ембеддинги.

[Ембедінги][Пошук][Архітектура]

Рекурсивне самовдосконалення мов: шліфування інтелекту коду для ~280 мов_

Ми підтримуємо інтелект коду для ~280 мов. Жодна людина не здатна вручну перевірити це. Тож ми побудували цикл рекурсивного самовдосконалення мов — вибіркова перевірка, LLM як суддя, виправлення одного пункту, повторна валідація — і запускаємо його з флотом ізольованих агентів, доки вилучення не стане справді правильним, а не просто «зеленим».

[Архітектура][Мови][Агенти]

Мультимодальний пошук зі злиттям: обираємо правильний ретрівер для кожного запиту_

Запит на кшталт «де визначено parseConfig» потребує іншого пошуку, ніж «як працює автентифікація». Maguyva класифікує намір, відповідно зважує чотири режими пошуку і зливає результати за допомогою зваженого Reciprocal Rank Fusion.

[Пошук][Архітектура]