Workstation техническое описание: как выявить узкие места LLM и многоагентных систем с помощью OpenTelemetry, Prometheus/Grafana/Thanos и платформы LLM, такие как Лангфузе / ЛМНР — включая схемы охвата, распределение затрат, выборку и жесткие ограничения использования. Компаньон: бизнес-блог · сервировка: LLM с турбонаддувом · лаборатория: Корпоративная лаборатория искусственного интеллекта.
- Проблема: Стоимость агента и задержка скрываются в прыжках (LLM → инструменты → RAG → повторы), а не в одном показателе «модель медленная».
- Стандарт: Инструмент с OpenTelemetry; одна схема атрибутов для токенов, модели, арендатора, маршрута, Assessment_cost_usd.
- Путь к метрикам: Прометей (+ Танос) за золотые сигналы; Grafana для плат SLO и FinOps.
- Путь LLM: Langfuse/LMNR для трассировок, оценок, наборов данных, версий подсказок.
- Контроль: Ограничить токены, вызовы инструментов и раунды отладки; Модели маршрутов по ступенчатой сложности.
- Победить: Прежде чем покупать больше GPU или повышать квоты на API, измерьте стоимость каждой успешной задачи.
1. Что означает «узкое место» для агентов LLM
Узкие места во время обучения (данные, FLOP) отличаются от времени обслуживания и время агента узкие места. У производственных агентов преобладающими видами отходов являются:
- Быстрое раздувание — слишком большие системные подсказки, неиспользуемый контекст, отсутствие попаданий в префикс/кеш.
- Модельное излишество — граничные модели, используемые для шагов классификации/маршрутизации, которые может выполнить небольшая модель.
- Неограниченные циклы — повторные попытки инструмента и циклы самоотладки без жесткого бюджета (см. компромиссы Self-Debugging в LLM с турбонаддувом).
- Внешние ожидания — векторные базы данных, SaaS API и шлюзы «человек в цикле», ошибочно приписываемые «задержке LLM».
- Обслуживание фрагментации — Потеря кэша KV на GPU (территория PagedAttention/vLLM) после того, как вы уже подтвердили, что граф агентов является нормальным.
Без распределенных трассировок вы не сможете их разделить. Таким образом, наблюдаемость — это не удобная панель мониторинга, а плоскость управления FinOps и SRE в продуктах искусственного интеллекта.
2. Эталонная архитектура
User / Orchestrator
→ Agent runtime (tools, RAG, LLM calls)
→ OpenTelemetry SDK (spans + metrics)
→ OTEL Collector (filter, sample, redact)
├─→ Prometheus / Thanos (rates, costs, SLOs)
├─→ Grafana (boards, alerts)
└─→ Langfuse / LMNR (traces, scores, datasets)
FinOps / policy layer reads the same metrics to enforce caps and model routing.
3. Схема диапазона OpenTelemetry для вызовов LLM
Примите одно соглашение для всех платформ (LangChain, специальные агенты Go/Python, Bedrock SDK). Отдавайте предпочтение семантическим соглашениям там, где они существуют, и расширяйте их с помощью стабильных атрибутов Workstation:
| Атрибут | Пример | Почему |
|---|---|---|
gen_ai.system | openai / антропный / коренная порода / vllm | Объединения поставщиков |
gen_ai.request.model | Клод-сонет-4 / Лама-3.1-8b | Стоимость и качество в зависимости от модели |
gen_ai.usage.input_tokens | 1820 | Быстрый драйвер затрат |
gen_ai.usage.output_tokens | 410 | Фактор затрат на завершение |
wsw.estimated_cost_usd | 0.0124 | FinOps без присоединения к прайс-листам позже |
wsw.tenant_id | акме-прод | Возвратный платеж |
wsw.route | поддержка.triage | Атрибуция характеристик продукта |
wsw.agent_step | план/инструмент/критика | Найдите дорогие ступени |
wsw.retry_n | 2 | Обнаружение петель |
wsw.prompt_version | сортировка@v17 | Регрессионная связь |
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
tracer = trace.get_tracer("workstation.agents")
PRICE_IN = 0.003 / 1000 # example $/token — load from config
PRICE_OUT = 0.015 / 1000
def complete_llm(model: str, prompt: str, tenant: str, route: str):
with tracer.start_as_current_span("gen_ai.chat") as span:
span.set_attribute("gen_ai.system", "openai")
span.set_attribute("gen_ai.request.model", model)
span.set_attribute("wsw.tenant_id", tenant)
span.set_attribute("wsw.route", route)
try:
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
)
usage = resp.usage
cost = usage.prompt_tokens * PRICE_IN + usage.completion_tokens * PRICE_OUT
span.set_attribute("gen_ai.usage.input_tokens", usage.prompt_tokens)
span.set_attribute("gen_ai.usage.output_tokens", usage.completion_tokens)
span.set_attribute("wsw.estimated_cost_usd", round(cost, 6))
return resp.choices[0].message.content
except Exception as e:
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise
Упражняться: вычислить estimated_cost_usd на пролете. Не ждите ночной работы, чтобы объединить количество токенов с прайс-листами — дежурным владельцам продуктов и владельцам продуктов нужны живые FinOps.
3б. Иерархия и багаж многоагентных диапазонов
Для графиков агентов требуется стабильная родительско-дочерняя модель, чтобы стоимость корректно складывалась:
session (root)
└─ agent.run {wsw.route, wsw.tenant_id}
├─ rag.retrieve {wsw.agent_step=retrieve}
├─ gen_ai.chat {wsw.agent_step=plan, model=…}
├─ tool.execute {tool=…, wsw.retry_n}
├─ gen_ai.chat {wsw.agent_step=synthesize}
└─ eval.score {score.name, score.value}
- Один корень для каждой задачи пользователя — не для каждого вызова LLM. Стоимость сеанса = сумма дочерних
wsw.estimated_cost_usd. - Багаж - распространять
wsw.tenant_idиwsw.routeмежду асинхронными рабочими процессами/очередями, поэтому диапазоны инструментов наследуют метки возвратных платежей без повторного подключения каждого сайта вызова. - Ссылки — когда субагент запускает новую трассировку (например, отдельный потребитель очереди), используйте ссылки на родительский сеанс, чтобы Langfuse/Grafana все еще мог сшить график.
- Всегда высокая стоимость выборки — для счастливого пути подойдет выборка головы в размере 5–20 %; принудительная выборка, когда затраты на сеанс превышают пороговое значение или статус = ОШИБКА.
4. Метрики, которые имеют значение (Прометей)
Экспортируйте гистограммы и счетчики (через метрики OTEL или клиент Prometheus). Минимальный жизнеспособный набор:
llm_requests_total{model,route,status}llm_tokens_total{model,direction}где направление ∈ {вход,выход}llm_estimated_cost_usd_total{model,tenant,route}llm_ttft_seconds/llm_e2e_secondsгистограммыagent_tool_calls_total{tool,status}agent_retries_total{route}agent_task_success_total{route}— знаменатель цены за успех
Производные запросы FinOps (эскизы PromQL):
# Cost per successful task (last 1h), by route sum(rate(llm_estimated_cost_usd_total[1h])) by (route) / sum(rate(agent_task_success_total[1h])) by (route) # Retry tax sum(rate(agent_retries_total[1h])) by (route) / sum(rate(llm_requests_total[1h])) by (route)
Танос (или Mimir/Cortex) имеет значение, когда финансы запрашивают ежеквартальные расходы на модель. Один только местный «Прометей» вполне подойдет для дежурства; это не архив FinOps.
5. Доски и оповещения Grafana
Отправьте три аудитории из одного источника данных:
- По вызову: частота ошибок, p95 e2e, сбои зависимостей (векторная БД/инструменты).
- Платформа: токенов/с, утилита GPU (при локальном размещении), глубина очереди, TTFT.
- Финансовые операции/продукт: $/успех по арендаторам и маршрутам, самые дорогие предложения, сочетание моделей.
Оповещение об ожоге, а не о тщеславии:
- Цена за успех > бюджет SLO на 30 млн.
- Частота повторных попыток > 15 % для маршрута
- Нарушение p95 e2e с ростом входных токенов (быстрая регрессия)
6. Платформы, основанные на LLM: Langfuse, LMNR и их коллеги.
Метрики расскажут вам что стоимость выросла; Платформы LLM расскажут вам какую подскажите версию и какой диапазон инструментов сделал это. Лангфузе и ЛМНР являются примерами этого класса с открытым исходным кодом:
- Иерархические трассировки (сеанс → агент → LLM/диапазоны инструментов)
- Оценки человека и LLM в качестве судьи
- Наборы данных для автономной оценки при изменении подсказок
- Дополнительная телеметрия использования для улучшения продукта (соблюдайте политику конфиденциальности)
Схема интеграции: сохранить OTEL в качестве системы учета SRE; двойной экспорт или мост в Langfuse для быстрого проектирования. Не изобретайте второй, несовместимый словарь атрибутов.
Эксперименты с фреймворками, такие как среды выполнения агентов с приоритетом функций (исторически продаваемые вокруг агентов структурированной потоковой передачи), могут уменьшить шаблонность, но рассматривать нишевые фреймворки как необязательные — стандарты наблюдаемости их переживут.
7. Конвейер оценки: ручной или автоматический
| Метод | Выполнение | Режим отказа |
|---|---|---|
| Руководство | Превью/рубрики в пользовательском интерфейсе Langfuse; отзывы о золотых комплектах. | Не масштабируется; все еще требуется для калибровки. |
| Автоматический | LLM-как судья, модульные проверки, валидаторы схемы, возврат данных. | Судья дрейфует; игры, если оптимизировать только для судьи. |
Прикрепите оценки в виде событий диапазона или оценок Лангфьюза, обозначенных wsw.prompt_version. Запускайте продвижение подсказок так же, как и версии приложений — Ring Promoter для кода; оценочные ворота для подсказок.
8. Процесс экономии средств (подробно)
- Базовая неделя: никаких изменений в поведении; только инструментарий. Захват $/успеха, токенов/успеха, частоты повторов.
- Атрибуция: ранжируйте маршруты по расходам × объёму. Выберите тройку лучших.
- Маршрутизация модели: разделить классификацию/извлечение на небольшие/локальные модели; держать границу для синтеза. Повторно измерьте показатели качества.
- Срочная операция: удалить неиспользуемые схемы инструментов; сократить несколько выстрелов; включите кэш префиксов там, где это безопасно.
- Колпачки петель: максимальное количество вызовов инструментов, максимальное количество циклов самоотладки, экспоненциальная отсрочка с автоматическими выключателями.
- Выборка: сохранять 100% показатели; выборочные трассировки (например, 5–20%) плюс постоянная выборка на наличие ошибок и дорогостоящих сеансов.
- Редакция: удалить PII из атрибутов диапазона перед экспортом; храните полные подсказки только в одобренных магазинах с TTL.
- Частота просмотра: еженедельная доска FinOps; ежемесячная калибровка судей против людей.
8б. Управление использованием агентов с помощью действующих бюджетов
Сами по себе информационные панели не остановят беглых агентов. Обеспечивайте соблюдение бюджетов во время выполнения, выдавайте решение как событие диапазона и предупреждайте, когда сеансы часто достигают потолка:
# Pseudocode: hard budget around an agent session
class Budget:
def __init__(self, max_usd=0.50, max_tool_calls=8, max_llm_calls=12):
self.max_usd, self.max_tool_calls, self.max_llm_calls = max_usd, max_tool_calls, max_llm_calls
self.spent = 0.0
self.tools = self.llms = 0
def charge(self, usd: float, kind: str):
self.spent += usd
if kind == "tool":
self.tools += 1
else:
self.llms += 1
if self.spent > self.max_usd or self.tools > self.max_tool_calls or self.llms > self.max_llm_calls:
raise RuntimeError("agent budget exhausted")
- Ограничения за сеанс — Доллар США, вызовы LLM, вызовы инструментов (выше).
- Ежедневные квоты на одного арендатора — Redis/счетчик с ключом
wsw.tenant_id; вернуть контролируемый ухудшенный путь при исчерпании. - Политика модели для каждого маршрута — модели разрешенных списков для
support.triageпротивlegal.draft; отклонить или понизить передачу при промахе политики и записатьwsw.policy_action=downshift. - Идемпотентные клавиши инструментов — аргументы хеш-инструмента, поэтому повторные попытки не приводят к двойному выставлению счетов внешним API.
- Формула стоимости —
cost = in_tokens × p_in + out_tokens × p_out + tool_fees; обновитьp_in/p_outиз версионного прайс-листа, поэтому исторические данные Таноса остаются сопоставимыми.
Метрика, на которую следует обратить внимание после попадания заглавных букв: agent_budget_exhausted_total{route,reason}. Скачок означает либо злоупотребление, либо сломанный инструментальный цикл, либо бюджет, который слишком ограничен для реальных рабочих нагрузок.
9. Эскиз конфигурации коллектора
# otel-collector-config.yaml (illustrative)
receivers:
otlp:
protocols:
http:
grpc:
processors:
memory_limiter: {}
batch: {}
attributes/redact:
actions:
- key: gen_ai.prompt
action: delete
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
otlp/langfuse:
endpoint: "${LANGFUSE_OTLP_ENDPOINT}"
headers:
Authorization: "Bearer ${LANGFUSE_KEY}"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, attributes/redact, batch]
exporters: [otlp/langfuse]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheus]
10. Плюсы, минусы и когда не стоит заморачиваться
Плюсы: Возврат платежей, более быстрая сортировка инцидентов, измеримая рентабельность инвестиций при оперативных изменениях/моделях, удобные для соблюдения нормативных требований контрольные журналы, общий язык между командами машинного обучения и платформой.
Минусы: задолженность по инструментам; стоимость хранения, если вы сохраняете каждое приглашение навсегда; риск отправки PII не в ту серверную часть; еще одна консоль для изучения инженерами.
Пропустите (пока), если: у вас есть одно автономное пакетное задание с фиксированными ежедневными расходами и без интерактивных агентов. Все еще регистрируйте токены; пропустите полный стек нескольких серверов, пока не появится параллелизм.
11. Контрольный список миграции
- ☐ OTEL SDK в среде выполнения агента; коллектор в кластере
- ☐ Атрибуты диапазона включают модель, токены, стоимость, арендатора, маршрут.
- ☐ Метрики Prometheus + плата Grafana FinOps
- ☐ Langfuse (или LMNR) подключен как минимум для одного критического пути.
- ☐ Жесткие ограничения на токены/инструменты/повторные попытки
- ☐ Политика редактирования проверена службой безопасности.
- ☐ Еженедельный обзор соотношения «долл./успех» для наиболее популярных маршрутов.
- ☐ Документ ADR, связывающий наблюдаемость → обслуживание (vLLM) → продвижение (Ring Promoter)
12. Сопутствующий материал Workstation
- Компаньон по бизнес-блогу
- LLM с турбонаддувом — исправлено обслуживание после того, как вы заметили узкое место
- Ring Promoter — продвигать агентские услуги с помощью медицинских ворот
- Muse Glimmer / местные агенты
- Свяжитесь с Workstation для участия в Enterprise AI Lab
Ссылки
Опубликовано Workstation.