Когда падает один компонент, дежурный получает десятки похожих алертов. Небольшой сервис может принимать их вебхуком, отправлять в Heli API и публиковать в чат одну сводку: что сломалось, где и с чего начать. Ниже — типовая схема для Prometheus Alertmanager; в Grafana ту же роль играет контактная точка типа Webhook.
Настройка Alertmanager
Alertmanager уже группирует алерты: group_by определяет, какие попадут в одно уведомление, а group_wait и group_interval — как часто оно отправляется. В теле вебхука приходят общий status, commonLabels и массив alerts; у каждого алерта есть labels, annotations, startsAt и свой status.
route:
receiver: llm-digest
group_by: ["alertname", "cluster"]
group_wait: 30s
group_interval: 5m
receivers:
- name: llm-digest
webhook_configs:
- url: "http://alert-digest:8080/alerts"
send_resolved: true
max_alerts: 50Сервис сводки
Если Heli или модель недоступны, сервис отправляет исходный список алертов: уведомления не должны теряться из-за сводки. Вместо Slack incoming webhook можно отправлять сообщение в Telegram через Bot API.
import os
import httpx
from fastapi import FastAPI, Request
from openai import AsyncOpenAI
app = FastAPI()
heli = AsyncOpenAI(base_url="https://getheli.ru/v1", api_key=os.environ["HELI_API_KEY"])
@app.post("/alerts")
async def alerts(request: Request):
payload = await request.json()
lines = [
f'{a["status"]} {a["labels"].get("alertname", "")} '
f'{a["labels"].get("instance", "")}: {a["annotations"].get("summary", "")}'
for a in payload.get("alerts", [])[:50]
]
try:
resp = await heli.chat.completions.create(
model="openai/gpt-5.4-mini",
messages=[
{"role": "system", "content": "Ты помощник дежурного. Сожми алерты в сводку: "
"что сломалось, где, возможная общая причина (пометь как гипотезу), "
"с чего начать проверку. Не придумывай фактов. До 5 пунктов."},
{"role": "user", "content": "\n".join(lines)},
],
max_tokens=600,
)
text = resp.choices[0].message.content
except Exception:
text = "Сводка недоступна, исходные алерты:\n" + "\n".join(lines)
async with httpx.AsyncClient() as client:
await client.post(os.environ["SLACK_WEBHOOK_URL"], json={"text": text})
return {"ok": True}Ограничения
- Сводка дополняет алерты, а не заменяет их: критичные уведомления должны по-прежнему приходить дежурному напрямую.
- Возможная причина в сводке — гипотеза модели. Проверяйте её по метрикам и логам.
- Не отправляйте в модель секреты: убедитесь, что в метках и аннотациях нет токенов и паролей.
Модель и расход
Для сводки хватает быстрой модели вроде openai/gpt-5.4-mini или google/gemini-3.5-flash. Частоту вызовов определяет group_interval: модель вызывается на каждое групповое уведомление, а не на каждый алерт. Задайте ключу сервиса бюджет и лимит запросов в минуту во вкладке «Лимиты» — это защитит от лавины вызовов во время крупного инцидента.
Проверка до запуска
Отправьте тестовый алерт через amtool alert add или POST-запросом на /api/v2/alerts Alertmanager и убедитесь, что сводка пришла в чат. Затем возьмите алерты нескольких прошлых инцидентов и проверьте, не теряет ли сводка важные алерты и не объединяет ли несвязанные проблемы.
Первое время отправляйте сводку параллельно с обычными уведомлениями, а не вместо них, и собирайте отзывы дежурных. Если сводки часто ошибаются, уточните промпт или передавайте модели больше полей, например severity и runbook_url из аннотаций.
Попробуйте Heli
Ключ sk-heli- появляется после подтверждения почты. Через Google и Яндекс — сразу в кабинете.