Класичний моніторинг каже, що запит тривав 4 секунди й повернув HTTP 200. Для LLM-застосунку це майже марно. Відповідь могла бути хибною, пошук міг нічого релевантного не знайти, агент міг одинадцять разів викликати той самий інструмент, а запит міг коштувати сорок центів. Спостережуваність LLM — це про те, щоб бачити, що відбувалося всередині: промпти, знайдений контекст, виклики інструментів, токени, затримку кожного кроку й, зрештою, якість. У гайді — що збирати, як структурувати це за допомогою OpenTelemetry і як користуватися цим щодня.
Чому LLM-застосункам потрібна інша спостережуваність
LLM-системи мають властивості, з якими класичний APM погано справляється:
- Недетермінованість. Той самий вхід може давати різні відповіді; для дебагу потрібні фактичні промпт і відповідь.
- Багатокрокові пайплайни. RAG-відповідь включає переписування запиту, ембеддинг, пошук, переранжування й генерацію. Агент може зробити десятки кроків. Збої ховаються посередині.
- Якість не бінарна. Відповідь 200 з вигаданим змістом — це збій, якого не покаже жоден error rate.
- Вартість — на кожен запит. Використання токенів між запитами різниться на порядки і є першокласною метрикою.
- Чутливий вміст. Промпти містять дані користувачів, документи, а іноді й секрети — логувати їх треба обережно.
Що збирати
Для кожного виклику LLM щонайменше:
| Поле | Навіщо |
|---|---|
| Модель і провайдер, параметри (temperature, max tokens) | Відтворення й порівняння |
| Назва й версія шаблону промпту | Зв'язок якості зі змінами промптів; див. промпт-інженерія |
| Вхідні й вихідні токени, кешовані токени | Вартість і ефективність кешування |
| Затримка: час до першого токена, загальна | Досвід користувача |
| Причина завершення (stop, length, tool use, refusal) | Відстеження обрізань і відмов |
| Виклики інструментів з аргументами й результатами | Дебаг агентів |
| Ідентифікатори знайдених документів і оцінки | Дебаг RAG |
| Ідентифікатори користувача/сесії/орендаря (псевдонімізовані) | Групування, вартість на орендаря |
| Відгуки й оцінки evals, додані пізніше | Якість у часі |
Зберігайте повні промпт і відповідь там, де дозволяє політика, з обмеженим строком зберігання й контролем доступу. Без них більшість дебагу — вгадування.
Структуруйте як траси
Траса одного запиту користувача має відображати пайплайн. Для RAG-чату:
trace: POST /api/chat (2.9 s, $0.011)
├─ span: rewrite_query llm claude-… in 420 / out 35 tok 310 ms
├─ span: embed_query embedding 45 ms
├─ span: hybrid_search db top_k=50 80 ms
├─ span: rerank reranker 50 → 8 190 ms
└─ span: generate_answer llm in 6,200 (cached 4,800) / out 310 tok 2.2 s
attributes: prompt=support_answer@v14, finish_reason=stop
Для агента кожна ітерація циклу стає span'ом з рішенням моделі й дочірніми span'ами виконання інструментів. Для мультиагентних систем кожен субагент — дочірня траса span'а оркестратора. Така структура дає змогу відповідати на запитання на кшталт «який крок став повільнішим після релізу минулого тижня?» або «як часто агент двічі поспіль викликає search_orders?».
Семантичні конвенції OpenTelemetry для GenAI
OpenTelemetry має семантичні конвенції для генеративного AI, що стандартизують назви span'ів і атрибути для викликів моделей, агентів та інструментів: атрибути на кшталт gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.response.finish_reasons і назви операцій для чату, ембеддингів та виконання інструментів. Використовуючи їх, ви пропускаєте LLM-телеметрію через той самий Collector і ті самі бекенди, що й решту вашого налаштування OpenTelemetry, а інструменти, які розуміють конвенції, коректно її відображають.
Ручний span у Python:
from opentelemetry import trace
tracer = trace.get_tracer("support-bot")
def generate_answer(messages, prompt_version: str):
with tracer.start_as_current_span("chat claude") as span:
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.request.model", MODEL)
span.set_attribute("app.prompt.version", prompt_version)
resp = client.messages.create(model=MODEL, max_tokens=800, messages=messages)
span.set_attribute("gen_ai.usage.input_tokens", resp.usage.input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", resp.usage.output_tokens)
span.set_attribute("gen_ai.response.finish_reasons", [resp.stop_reason])
return resp
На практиці бібліотеки автоінструментування (наприклад, OpenLLMetry та OpenInference) патчать поширені SDK і фреймворки й генерують ці span'и за вас. Частина конвенцій досі позначена як експериментальна; фіксуйте версії бібліотек і будьте готові, що назви атрибутів змінюватимуться.
Інструменти
| Інструмент | Тип | Примітки |
|---|---|---|
| Langfuse | Open source, self-hosted + хмара | Траси, керування промптами, evals, облік вартості; приймає OpenTelemetry |
| Arize Phoenix | Open source | Трасування через OpenInference, evals, робота з датасетами |
| LangSmith | SaaS (self-host в enterprise) | Глибока інтеграція з LangChain/LangGraph |
| Ваш наявний APM (Grafana, Datadog, Honeycomb…) | Бекенд OTel | Добре для затримки/вартості; слабше для перегляду промптів |
Типове налаштування: генерувати OpenTelemetry один раз, надсилати інфраструктурні метрики й span'и в наявний бекенд, а GenAI-span'и (з вмістом) — у спеціалізований LLM-інструмент для аналізу на рівні промптів. Власний хостинг важливий, коли промпти містять персональні чи конфіденційні дані; див. приватність LLM-застосунків.
Метрики й дашборди
Зробіть по дашборду на кожну LLM-функцію з такими блоками:
- Обсяг: запити, розмови, запуски агентів.
- Затримка: p50/p95 часу до першого токена й загальна; затримка кожного кроку пайплайна.
- Вартість: токени й гроші на запит, користувача, орендаря, функцію; частка влучань у кеш. На цьому ґрунтується оптимізація витрат на LLM.
- Надійність: помилки провайдера, ліміти (429), таймаути, повторні спроби, фолбеки; див. надійність LLM API.
- Поведінка: причини завершення (частка обрізань), частка відмов, частка помилок інструментів, кроки на запуск агента.
- Якість: частка й оцінка відгуків користувачів, онлайн-оцінки evals, частка ескалацій до людини.
Ставте алерти на те, що відчувають користувачі або що коштує грошей: p95 затримки, частка помилок, раптові стрибки вартості на орендаря і запуски агентів, що перевищують ліміт кроків.
Зв'язок спостережуваності з якістю
Траси стають значно ціннішими, коли пов'язані з оцінюванням:
- Онлайн-evals. Запускайте дешеві автоматичні перевірки на вибірці продакшен-трас — обґрунтованість, валідність формату, порушення політик — і прикріплюйте оцінки до трас.
- Відгуки. Прикріплюйте лайки/дизлайки й коментарі до траси, що породила відповідь.
- Датасети з продакшену. Фільтруйте траси з низькими оцінками чи негативними відгуками, переглядайте їх і додавайте показові випадки в еталонний набір.
- Порівняння релізів. Позначайте траси версіями застосунку й промптів; порівнюйте оцінки й вартість до і після кожного релізу.
Цей цикл — продакшен-траси, що живлять офлайн-evals, — серцевина процесу, описаного у статті як оцінювати LLM-застосунки.
Дебаг за трасами: три типові випадки
«Бот відповів упевнено, але неправильно». Відкрийте трасу й спершу перевірте span пошуку. У більшості випадків потрібного документа не було серед знайдених фрагментів або він опинився нижче порогу відсічення. Виправляти треба чанкінг, гібридний пошук чи переранжування, а не промпт; див. ембеддинги та чанкінг.
«Цього тижня відповіді стали повільнішими». Порівняйте затримку кожного span'а до і після релізу. Типовий винуватець — зміна промпту, що перенесла динамічний вміст на початок і зламала кешований префікс: кількість кешованих токенів падає до нуля, вартість входу й час до першого токена стрибають.
«Агент іноді зациклюється». Відфільтруйте траси агента з кількістю кроків вище 95-го перцентиля й прочитайте їх. Повторювані однакові виклики інструментів зазвичай вказують на некорисне повідомлення про помилку або вивід інструмента, з якого модель не розуміє, що задачу виконано; див. проєктування інструментів для агентів.
Приватність і безпека телеметрії
Промпти й відповіді у вашому стеку спостережуваності — це сховище персональних даних. Ставтеся до нього відповідно:
- Редагуйте чи псевдонімізуйте персональні дані перед експортом, де можливо (email, телефони, РНОКПП); допомагають інструменти на кшталт Microsoft Presidio.
- Відокремлюйте вміст від метаданих. Кількість токенів і затримку зберігайте довго; вміст — короткий строк.
- Обмежуйте доступ до вмісту колом людей, яким він потрібен для дебагу.
- Ніколи не логуйте секрети. Вичищайте API-ключі й токени з аргументів інструментів.
- Зважайте на місце зберігання даних при використанні SaaS-інструментів; дані з ЄС можуть потребувати хостингу в ЄС.
План впровадження
- День 1: логуйте модель, токени, затримку, причину завершення й версію промпту для кожного виклику. Навіть структурований рядок логу — великий крок.
- Тиждень 1: додайте трасування OpenTelemetry з конвенціями GenAI по всьому пайплайну; експортуйте в LLM-інструмент спостережуваності.
- Тижні 2–3: дашборди вартості, затримки, помилок і поведінки; алерти на стрибки.
- Місяць 2: збір відгуків, онлайн-evals на вибірці, щотижневий перегляд трас з низькими оцінками.
FAQ
Чи логувати повні промпти в продакшені? Зазвичай так — з редагуванням, коротким строком зберігання й контролем доступу. Без вмісту дебажити проблеми якості майже неможливо.
Чи додає трасування затримку? Мізерну, якщо експорт асинхронний і пакетний, як за замовчуванням в OpenTelemetry.
Як трасувати стрімінгові відповіді? Починайте span на запиті, фіксуйте час до першого токена як подію чи атрибут і завершуйте span, коли стрім закінчився, включно з використанням токенів з останнього фрагмента.
Чи можна використовувати наявні Grafana чи Datadog? Так, для метрик і затримки. Для читання промптів, порівняння версій і розмітки трас продуктивніші спеціалізовані LLM-інструменти.
Джерела
- OpenTelemetry. Semantic conventions for generative AI systems.
- Документація Langfuse.
- Arize Phoenix.
- Traceloop. OpenLLMetry.
- Microsoft. Presidio — data protection and de-identification SDK.
- Hamel Husain. Your AI product needs evals.