> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Устранение неполадок

> Документация по устранению неполадок AgentEye.

Это руководство соответствует симптомам, которые вы наиболее вероятно можете столкнуться в production, конкретному диагнозу и исправлению, чтобы вы могли разрешить инциденты из инструментов, которые у вас уже есть, без развертывания дополнительной инфраструктуры наблюдаемости. Оно охватывает сервер, коллектор, приборную панель, помощника ИИ, Python SDK, мониторинг здоровья и сертификатов, резервные копии, аналитику на основе ClickHouse и мультитенантность.

Страницы приборной панели — это область видимости орга в `/<org-slug>/…`, а поток событий — это домашняя страница орга (`/<org-slug>/`). Названия страниц в этом руководстве (например `/sessions`, `/queries`) ссылаются на эти маршруты с областью видимости организации.

***

## Просмотр журналов

AgentEye не поставляется с инфраструктурой логирования или мониторинга. Как сервер, так и приборная панель записывают структурированные журналы в **stdout**, поэтому вы можете читать их напрямую с помощью `kubectl` или `docker`; агрегатор не требуется.

### Kubernetes

Следите за живыми журналами сервера и приборной панели:

```bash theme={null}
kubectl logs -n agenteye -l app=server    -f --timestamps
kubectl logs -n agenteye -l app=dashboard -f --timestamps
```

Полезные варианты:

| Цель                                   | Команда                                                           |
| -------------------------------------- | ----------------------------------------------------------------- |
| Последние 200 строк (без отслеживания) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps`  |
| Журналы из предыдущего краха           | `kubectl logs -n agenteye <pod-name> --previous`                  |
| Отслеживание всех реплик одновременно  | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` |
| Postgres (StatefulSet)                 | `kubectl logs -n agenteye postgres-0 -f`                          |

### Docker Compose

```bash theme={null}
docker logs -f agenteye-server
docker logs -f agenteye-dashboard
```

### Корреляция одного запроса по приборной панели и серверу

Каждый запрос приборной панели помечается `request_id` и распространяется на сервер через заголовок `x-request-id`. Сервер повторяет его в заголовках ответа и в каждой строке журнала, которую он выдает для этого запроса. Чтобы проследить один запрос от конца до конца:

1. Захватите идентификатор из заголовка ответа, например:
   ```bash theme={null}
   curl -i https://dashboard.example.com/api/events | grep -i x-request-id
   # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   ```
2. Найдите этот идентификатор в журналах обоих pod:
   ```bash theme={null}
   REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ"
   kubectl logs -n agenteye -l app=server    --tail=5000 | grep "$REQ"
   ```

Вы увидите строки `proxy passthrough`, `withAuth: authorized` и `upstream response` приборной панели рядом с парой `http request received` / `http request completed` сервера, все они имеют один и тот же `request_id`.

### JSON-журналы и `jq`

Установите `AE_LOG_JSON=1` на приборной панели (он включен по умолчанию при `NODE_ENV=production`), чтобы выдать один JSON-объект на строку. Затем фильтруйте структурно:

```bash theme={null}
kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.level == "warn" or .level == "error")'

kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.route == "POST /api/keys")'
```

Rust-сервер выдает пары `key=value` трассировки, которые хорошо работают с grep без `jq`:

```bash theme={null}
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5'   # 5xx
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id='
```

### Увеличение детализации

| Компонент        | Переменная окружения | Пример                                                     |
| ---------------- | -------------------- | ---------------------------------------------------------- |
| Сервер           | `RUST_LOG`           | `RUST_LOG=debug` или `RUST_LOG=agenteye_server=debug,info` |
| Приборная панель | `AE_LOG_LEVEL`       | `AE_LOG_LEVEL=debug`                                       |

`debug` на сервере добавляет строку `api key authenticated` для каждой аутентификации. `debug` на приборной панели добавляет строки `upstream request`, `session validated` и `proxy passthrough`.

### Хранение журналов

Stdout контейнера эфемерный; kubelet ротирует файлы журналов (по умолчанию \~10 МиБ на контейнер) и хранит небольшое количество на диске. После удаления pod журналы теряются. Если вам нужно более длительное хранение или поиск по pod, направьте ваш кластер на сборщик логов (Loki, CloudWatch, Cloud Logging, Datadog и т. д.), который отслеживает `/var/log/containers/`. AgentEye не требует и не предписывает какой-либо конкретный выбор.

***

## Проблемы с аутентификацией

### `docker pull` не удается с ошибкой "unauthorized"

Убедитесь, что вы аутентифицировали Docker для GHCR с помощью вашего `AGENTEYE_TOKEN`:

```bash theme={null}
echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin
```

Токен должен иметь разрешение `read:packages` на организацию `agenteye-enterprise`. Обратитесь к `support@exosphere.host`, если ваш токен не работает.

### `gh release download` возвращает 404 или 401

* Подтвердите, что `AGENTEYE_TOKEN` экспортирован в вашей оболочке: `echo $AGENTEYE_TOKEN`
* Подтвердите, что вы используете `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (CLI `gh` читает `GITHUB_TOKEN`)
* Токен должен иметь `contents:read` на `agenteye-enterprise/releases`

***

## Проблемы сервера

### Сервер не запускается с ошибкой "invalid port number"

Переменная `POSTGRES_PASSWORD` (или другой учетные данные) содержит специальные символы URL (`/`, `+`, `=`), которые нарушают анализ `DATABASE_URL`. Переформируйте пароль, используя шестнадцатеричное кодирование:

```bash theme={null}
NEW_PASS=$(openssl rand -hex 24)
```

Затем обновите секрет Kubernetes и пароль внутри Postgres (или пересоздайте `.env` для Docker Compose), и перезагрузите сервер. См. полные шаги в [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment) § "PostgreSQL credentials".

### Сервер выходит немедленно при запуске

Проверьте журналы контейнера:

```bash theme={null}
docker logs agenteye-server
```

Распространенные причины:

* `DATABASE_URL` не установлен или неверно сформирован: сервер записывает ошибку и выходит.
* Postgres недостижим: подтвердите, что контейнер Postgres или управляемая БД работают и хост/порт правильны.
* Миграции не удались: проверьте журналы на наличие ошибок SQL.

### `GET /health` возвращает не-200 или истекает

Сервер может все еще запускать миграции при первом запуске. Подождите несколько секунд и повторите попытку:

```bash theme={null}
curl http://localhost:8080/health
```

Если проблема сохраняется, проверьте `docker logs agenteye-server` на наличие ошибок.

### `GET /ready` возвращает 503

`/ready` — это зонд готовности: он возвращает `503`, когда сервер не может достичь **Postgres или ClickHouse**. Тело указывает на неправильную зависимость:

```bash theme={null}
curl -s http://localhost:8080/ready
# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}}
```

Исправьте зависимость, которую оно указывает как `down`: является ли pod ClickHouse/Postgres `Running`? Верны ли `CLICKHOUSE_URL` / `DATABASE_URL` и достижимы? На Kubernetes pod читает `NotReady` до восстановления `/ready`; это ожидаемо и является именно сигналом, по которому оповещения мониторинга здоровья должны срабатывать. Redis никогда не является причиной: он сообщается, но не приводит к отказу готовности.

### Коллектор возвращает 401 Unauthorized

API ключ коллектора не имеет разрешения `events:add`, или ключ был отключен. Создайте новый ключ с правильным разрешением:

```bash theme={null}
curl -s -X POST http://your-server:8080/keys \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"new-collector","permissions":["events:add"]}'
```

### Аутентифицированные запросы вдруг стали медленными (\~200ms вместо \~5ms)

Это симптом того, что Redis находится вниз, пока `REDIS_URL` установлен. Каждый вызов кэша истекает через 100 мс, затем переходит к Postgres; на путях аутентификации и OTP запрос выполняет два таких перехода.

Подтвердите в журналах сервера:

```
auth cache: L2 get failed error=redis call timed out
```

Разрешение:

1. `redis-cli -h <your-redis> ping` чтобы подтвердить, что Redis достижим в сетевом кластере.
2. Если Redis был кратко отключен и теперь вернулся, **перезагрузите pod сервера**. `redis::aio::ConnectionManager` не восстанавливается надежно после падения основного соединения; перезагрузка pod выбирает новое соединение чисто. То же самое относится к приборной панели.
3. Если вы не хотите запускать Redis прямо сейчас, отмените установку `REDIS_URL` в развертывании и перезагрузитесь. Обе службы работают без кэша (корректность сохраняется; задержка возвращается к базовому уровню до Redis).

### Сервер сообщает `OTP request rate-limited` в журналах, но пользователь говорит, что попробовал только один раз

Проверьте, был ли Redis недостижим. Путь резервной копии использует `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, что видит ранее созданные строки OTP. Если пользователь нажимал спам "Отправить" час, окно в 15 минут может все еще содержать ≥5 кодов. Разрешите либо ожидание прохождения окна, либо `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (консоль оператора).

### Я изменил `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` и перезагрузился; ничего не произошло

Эти переменные окружения — это **только семена первой загрузки**. После того как таблица `settings` имеет строку для соответствующего ключа, эта строка является источником истины; переменная окружения читается один раз при первой загрузке, а затем игнорируется при каждой последующей перезагрузке.

Чтобы изменить их после первой загрузки, войдите на приборную панель и отредактируйте их в `/settings`. Изменение применяется за считанные секунды на всех репликах; перезагрузка не требуется.

Если вам необходимо принудительно пересеять из переменной окружения (редко, обычно полезно только в разработке), используйте `DELETE FROM settings WHERE key = '<key>'` и перезагрузите сервер. Bootstrap выберет текущее значение переменной окружения при следующей загрузке. Редактирование через `/settings` — поддерживаемый путь в production.

***

## Проблемы коллектора

### Коллектор запускается, но события не появляются на приборной панели

1. Подтвердите, что коллектор работает: `systemctl status agenteye-collector` (Linux) или проверьте процесс.
2. Подтвердите, что `AGENTEYE_URL` указывает на `http(s)://your-server-host:8080/events` (примечание: путь `/events`).
3. Выполните одноразовый сброс, чтобы увидеть немедленный результат:
   ```bash theme={null}
   agenteye-collector flush
   ```
4. Проверьте, что Python SDK действительно записывает файлы: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/`
5. Если файлы существуют в `${AGENTEYE_HOME:-~/.agenteye}/failed/`, загрузки не удаются. Проверьте журналы коллектора на наличие ошибки, скорее всего 4xx (плохой ключ или URL) или проблема с сетью.

### Файлы накапливаются в `$AGENTEYE_HOME/events/` и не загружаются

* Коллектор может не работать. Запустите его: `agenteye-collector start`; он автоматически сбрасывает существующие события при запуске.
* Проверьте здоровье коллектора: `agenteye-collector health`
* Коллектор может работать, но не может достичь сервера. Проверьте правила брандмауэра между хостами коллектора и сервера.

### Файлы в `$AGENTEYE_HOME/failed/`

Файлы перемещаются в `failed/` после исчерпания всех попыток повторения (по умолчанию: 5 попыток с экспоненциальной отсрочкой). Это означает либо:

* Сервер вернул ошибку 4xx (плохой ключ, неправильный URL или проблема нагрузки)
* Сервер был недостижим для всего окна повторения

Исправьте основную проблему, затем вручную переставьте в очередь:

```bash theme={null}
mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/
agenteye-collector flush
```

### Коллектор сообщает `network error` при каждой загрузке (рукопожатие TLS не удается)

Если `curl -k` для `AGENTEYE_URL` успешен, но двоичный файл коллектора при каждой загрузке не удается с `error sending request for url (...)`, сервер AgentEye представляет сертификат TLS, который не подписан доверенным центром сертификации.

**Путь production** — это имя хоста входящего ACME, настроенное в `deploy/base/certificates/domain.env` (см. [`kubernetes-deployment.md`](/ru/agenteye/kubernetes-deployment) Фаза 3.1 / 4.2). Когда `INGEST_DOMAIN` разрешается на общественный LB Traefik и cert-manager выдал сертификат Let's Encrypt, коллекторы проверяют сертификат сервера по хранилищу системного доверия **без `AGENTEYE_TLS_CA` требуется**; очистите его из конфигурации коллектора, если он был установлен против старого развертывания с самоподписанным сертификатом.

**Симптом: коллектор работал вчера, не удается сегодня после \~90-дневного перерыва.** Это означает, что развертывание по-прежнему использует устаревший издатель `selfsigned` для `ingest-tls`. 90-дневный сертификат ротировался и закрепленный файл центра сертификации устарел. Исправьте окончательно, переключив кластер на издателя ACME (Фаза 3.1 руководства развертывания). Краткосрочная разблокировка: переизвлеките текущий сертификат сервера и обновите `AGENTEYE_TLS_CA`:

```bash theme={null}
kubectl get secret ingest-tls-cert -n agenteye \
  -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt
```

```bash theme={null}
export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt
agenteye-collector flush
```

`AGENTEYE_TLS_CA` добавляет дополнительный якорь доверия; стандартные общественные корни по-прежнему доверены.

### Сертификат `ingest-tls` застрял `Ready: False` после развертывания

```bash theme={null}
kubectl describe certificate ingest-tls -n agenteye
```

Посмотрите на `Events` и указанный `Order` / `Challenge`. Распространенные причины:

* **DNS не разрешается на общественный LB.** Валидатор HTTP-01 не может достичь `INGEST_DOMAIN`. Проверьте с помощью `dig +short INGEST_DOMAIN`; он должен разрешаться на тот же адрес, что и `EXTERNAL-IP` LoadBalancer `traefik-public`. cert-manager автоматически повторяет попытки после распространения DNS; нет необходимости удалять сертификат.
* **Порт 80 заблокирован на load balancer / security group.** HTTP-01 требует, чтобы порт 80 был достижим от общественных валидаторов Let's Encrypt. Если у вас есть вышестоящий WAF или SG, ограничивающий `:80`, откройте его (конфигурация Traefik перенаправляет на HTTPS, но Boulder следует перенаправлению и принимает ответ).
* **`dnsNames` не подставлены.** Если `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` показывает `INGEST_DOMAIN_PLACEHOLDER`, вы пропустили шаг `domain.env`; создайте его из `domain.env.example` и повторно примените.
* **Ограничено Let's Encrypt.** Повторяющиеся неудачные заказы для одного и того же имени хоста триггирует дублирование сертификатов или пределы сбоя валидации. Подождите не менее часа перед повторной попыткой; проверьте статус Order для точного сообщения об ограничении скорости.

### Сертификат `dashboard-tls` застрял `Ready: False` / браузер все еще показывает предупреждение

Тот же поток диагностики, что и для `ingest-tls` выше (`kubectl describe certificate dashboard-tls -n agenteye`); DNS, port-80, placeholder и причины ограничения скорости все применяются, плюс два специфических для приборной панели:

* **`DASHBOARD_DOMAIN` разрешается на неправильный LoadBalancer.** Он должен указывать на LB Traefik *приборной панели*, а не на общественный входящий. `dig +short` имя хоста и сравните с адресом LB приборной панели.
* **Экземпляр приборной панели Traefik не может служить заданием.** Он должен быть установлен с объединенным файлом значений приборной панели, который включает поставщика Ingress с областью видимости для решателя HTTP-01 cert-manager. Без него решатель недостижим и заказ остается `pending` навсегда. Обновите экземпляр с предоставленными значениями; ожидающее задание затем завершается само по себе.
* **LoadBalancer был ограничен IP-адресами.** Исходные диапазоны применяются к порту 80 также, что блокирует валидаторы Let's Encrypt — как при первом выпуске, так и при каждом \~75-дневном обновлении. Переоткройте LB или согласуйте решатель DNS-01 с поддержкой перед его блокировкой.

Пока выпуск не удается, приборная панель продолжает служить своему предыдущему сертификату (или значению по умолчанию входящего при свежей установке) — доступ деградирован предупреждением браузера, никогда полностью недоступен.

### CLI все еще пропускает проверку TLS после того, как приборная панель получила доверенный сертификат

`--insecure` сохраняется в `cli.json` при входе. После того как приборная панель служит общедоступно доверенным сертификатом, снова войдите с `agenteye --base-url https://<your-dashboard-domain> --secure login`; проверка сохраняется обратно включенной и предупреждение запуска исчезает.

***

## Проблемы приборной панели

### Невозможно отключить или отредактировать пользователя `ADMIN_EMAIL`

По дизайну. Пользователь, совпадающий с `ADMIN_EMAIL`, помечается как защищенный при каждом запуске сервера: приборная панель скрывает кнопку Отключить для этой строки, и API отклоняет `DELETE /users/:id` и `PUT /users/:id` для него с `403 Forbidden`. Триггер базы данных также отклоняет прямые операторы `UPDATE`, которые отключили бы защищенную строку.

Чтобы повернуть начальную загрузку администратора, измените `ADMIN_EMAIL` в своей среде и перезагрузите сервер. Новый адрес электронной почты помещается как защищенный. Предыдущий администратор сохраняет защищенный флаг до его очистки в базе данных (обычно в порядке, так как предыдущий адрес электронной почты по-прежнему является действительным администратором, пока вы явно не удалите его).

### Приборная панель не показывает события

1. Подтвердите, что URL сервера и API ключ правильны в переменных окружения приборной панели (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`).
2. API ключ приборной панели должен иметь разрешение `events:read`.
3. Подтвердите, что события действительно были приняты: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"`

### `/errors` пусто, но `/events` показывает красные строки

Более новые версии SDK выдают сбои как события `agent_end` / `tool_result` / `hook_completed` с `outcome: "error"` в нагрузке, а не как специальная строка `event_type: "error"`. Страница `/errors` теперь соответствует обоим: любая строка, которую поток `/events` рисует красным (явный `event_type='error'`, нагрузка `outcome`/`status` в наборе сбоев, `is_error: true` или истинное поле `error`) появляется на `/errors`. Если вы ранее видели, что ошибок нет в этом окне, пока красные строки были видны на `/events`, обновите приборную панель + сервер вместе (расширенный фильтр — это `errored=true` на `GET /events`) и два представления будут согласованы.

### `/models`, `/tools` или `/hooks` медленно или не загружаются на широких диапазонах времени

**Симптом:** в большой таблице событий (миллионы строк) открытие `/models`, `/tools` или `/hooks` — или расширение диапазона времени до `7d`, `30d` или `all` — графики вращаются и затем показывают ошибку загрузки. Сервер логирует ошибку `MEMORY_LIMIT_EXCEEDED` ClickHouse (код 241) или превышение времени ожидания запроса для запроса `latency_aggregate`.

**Причина:** старые сборки вычисляли откат и распределение часов этих страниц с помощью запроса, который читал полную нагрузку исходного события и сопарял события запроса/ответа с внутриполотной сортировкой и объединением. Поэтому пиковая память запроса росла с размером окна, поэтому на занятом тенанте широкий диапазон может превышать потолок памяти ClickHouse для каждого запроса.

**Исправление:** обновитесь до сборки, которая включает это исправление. Откат теперь читает только компактные продвигаемые столбцы и сопаривает события с потоковой агрегацией, поэтому пиковая память больше не масштабируется с нагрузкой исходного события — широкие окна остаются хорошо в пределах потолка памяти и возвращаются за часть времени. Улучшение полностью на стороне запроса: оно применяется ко всем существующим данным при следующей загрузке страницы, без переприема или заполнения.

### Приборная панель не загружается / пустая страница

Проверьте журналы контейнера приборной панели:

```bash theme={null}
docker logs agenteye-dashboard
```

Наиболее распространенной причиной является отсутствие `AGENTEYE_SERVER_URL` или `AGENTEYE_API_KEY`, или указание на недостижимый сервер.

### Аналитика / телеметрия приборной панели

Приборная панель отправляет анонимную телеметрию использования продукта в PostHog по умолчанию, маршрутизируемую через собственный путь приборной панели `/ingest` (обратный прокси на `https://us.i.posthog.com`). Отправка их от первого лица означает, что блокировщики объявлений браузера их не отбрасывают. Это независимо от основной функциональности приборной панели:

* **Контейнер приборной панели** (не браузер) — это то, что достигает PostHog. Если его исходящий доступ к `https://us.i.posthog.com` заблокирован, телеметрия молча не включается; приборная панель работает нормально и никакие ошибки не всплывают пользователям.
* Никогда не включаются данные агента, сеанса или события, только использование UI приборной панели.
* Чтобы полностью отключить телеметрию, установите `AE_ANALYTICS_DISABLED=1` на контейнер приборной панели и перезагрузитесь. См. [Telemetry & privacy](/ru/agenteye/deployment#telemetry--privacy) в руководстве развертывания.

### Телеметрия CLI / телеметрия

CLI `agenteye` отправляет анонимную телеметрию использования в PostHog по умолчанию: какие команды запускаются, успех/статус выхода и продолжительность. Это независимо от функциональности CLI:

* **Машина, запускающая CLI**, напрямую достигает `https://us.i.posthog.com`. Если его исходящий доступ заблокирован, телеметрия молча не включается (отправка ограничена по времени, поэтому команда никогда не задерживается) и CLI работает нормально.
* Никогда не включаются данные агента, сеанса или события: **аргументы команды и значения флагов** (URL приборной панели, токен, адрес электронной почты, идентификаторы сеанса, фильтры запросов) никогда не отправляются.
* Чтобы отключить его, установите `AGENTEYE_ANALYTICS_DISABLED=1` (или кросс-инструментальный `DO_NOT_TRACK=1`) в окружении CLI. См. [Telemetry & privacy](/ru/agenteye/cli#telemetry--privacy) в руководстве CLI.

***

## Проблемы помощника ИИ

См. [enterprise-docs/assistant.md](/ru/agenteye/assistant) для полной установки.

### Пузырь помощника не появляется

Пузырь скрыт, если **не все** из следующих:

* Вошедший пользователь имеет разрешение `agent:use`.
* `AGENTEYE_AGENT_URL` установлен на приборной панели и служба `agent` достижима.
* На служба `agent` настроена конечная точка LLM (`ANTHROPIC_API_KEY`, шлюз через `ANTHROPIC_BASE_URL` или Bedrock/Vertex). Если ничего не установлено, агент сообщает не сконфигурирован и пузырь остается скрытым.

Проверьте здоровье агента с хоста приборной панели: `curl http://agent:9100/health` должно вернуть `{"status":"ok","llm_configured":true,...}`.

### Помощник говорит, что не может прочитать что-то

Инструменты ограничиваются для каждого пользователя. Если пользователь не имеет `evaluations:read` (или `events:read`, `dashboards:read`), соответствующие инструменты не предлагаются и помощник скажет, что не может прочитать эти данные. Предоставьте соответствующее разрешение на чтение.

### assistant not configured (HTTP 503) при отправке

Контейнер `agent` не имеет настроенной конечной точки LLM, или `AGENTEYE_AGENT_TOKEN` приборной панели не совпадает с токеном агента. Установите оба и перезагрузитесь.

### Контейнер `agent` перезагружается / выходит за пределы памяти под нагрузкой

Каждый разговор порождает короткоживущий дочерний процесс. Убедитесь, что контейнер работает с процессом инициализации (изображение использует `tini`; в Compose установите `init: true`) и дайте ему адекватные лимиты памяти. При необходимости уменьшите `AGENTEYE_AGENT_MAX_STEPS`.

***

## Проблемы CLI

### `agenteye` не запускается с `ModuleNotFoundError: No module named 'click'`

Свежая установка CLI `agenteye` версии **0.1.6** может зависать при запуске с:

```
ModuleNotFoundError: No module named 'click'
```

0.1.6 полагалась на `click`, устанавливаемый косвенно посредством `typer`; текущие релизы `typer` больше не
его вытягивают, поэтому чистая среда заканчивается отсутствующим пакетом. **Обновитесь до 0.1.7 или новее**,
который зависит от `click` напрямую:

```bash theme={null}
pipx upgrade agenteye      # если установлен с pipx (или: pipx install --force agenteye)
uv tool upgrade agenteye   # если установлен с uv
pip install --upgrade agenteye
```

См. [enterprise-docs/cli.md](/ru/agenteye/cli) для руководства по установке.

***

## Проблемы Python SDK

### Файлы не появляются в `$AGENTEYE_HOME/events/`

SDK буферизирует события и сбрасывает каждые 500 мс по умолчанию. Если ваш процесс выходит перед сбросом, события могут быть потеряны. Вызовите `agenteye.configure(flush_interval=0.1)` для более быстрого сброса в короткоживущих скриптах или убедитесь, что ваш процесс работает достаточно долго для цикла сброса.

Если `AGENTEYE_HOME` установлен, убедитесь, что SDK пишет в `$AGENTEYE_HOME/events/`, а не в `~/.agenteye/events/` (требуется SDK ≥ 0.0.1b5).

### `ValueError: Reserved field names cannot be used as custom fields`

Названия `timestamp`, `type` и `environment` зарезервированы и не могут использоваться как пользовательские поля. Передача любого из них вызывает:

```
ValueError: Reserved field names cannot be used as custom fields: [...]
```

Переименуйте проблемное пользовательское поле. Обратите внимание, что `session_id` и `agent_id` — это явные параметры вызова события, а не пользовательские поля; передача одного из них снова как пользовательского поля вызывает `TypeError`.

***

## Проблемы мониторинга здоровья

### В Slack не приходят оповещения (Robusta)

Оповещение здоровья Robusta является **opt-in**; оно не отправляет ничего, пока не установлено и не указано на канал Slack. Проверьте выпуск и его раковину:

```bash theme={null}
kubectl get pods -n robusta          # robusta-runner + robusta-forwarder должны быть Running
kubectl logs -n robusta -l app=robusta-runner --tail=50
```

Распространенные причины: Slack `api_key` / `slack_channel` не были установлены (или токен был отозван); `api_key` — это токен облачного релея Robusta (`robusta integrations slack`), но объединенный `disableCloudRouting: true` требует токена бота Slack с собственным размещением (`xoxb-…`), или установите `disableCloudRouting: false`; раковина `scope` исключает пространство имен, в котором работают ваши pod (объединенные значения ограничивают область видимости `agenteye`); или пока не произошел сбой. Принудительно тестовое оповещение путем отключения pod:

```bash theme={null}
kubectl -n agenteye delete pod -l app=clickhouse   # он будет пересоздан
```

См. [enterprise-docs/health-monitoring.md](/ru/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) для установки и конфигурации.

### Сервер продолжает колебаться `NotReady`

Зонд готовности попадает в `/ready`, который не удается, когда Postgres или ClickHouse недостижимы. Если сервер циклирует внутрь и наружу из `NotReady`, зависимость периодически недоступна; проверьте pod ClickHouse и Postgres и `CLICKHOUSE_URL` / `DATABASE_URL` сервера. Подтвердите, что сообщает `/ready`:

```bash theme={null}
kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready'
```

Этот зонд намеренно терпим (щедрый порог отказа), поэтому устойчивое колебание указывает на реальную проблему зависимости, а не на чрезмерно агрессивный зонд. Живучесть остается на `/health`, поэтому колебание готовности **не** перезагрузит pod.

## Проблемы мониторинга сертификатов

### CronJob не отправляет уведомления Slack

Для `cert-renewal-check` CronJob требуется URL вебхука Slack, сохраненный в Secret. Проверьте его наличие:

```bash theme={null}
kubectl get secret cert-renewal-notify-config -n agenteye
```

Если отсутствует, создайте его:

```bash theme={null}
kubectl create secret generic cert-renewal-notify-config \
  --namespace agenteye \
  --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
```

Без секрета CronJob все еще работает и регистрирует результаты в stdout. Проверьте журналы с помощью:

```bash theme={null}
kubectl logs -n agenteye -l job-name --tail=50
```

### Сертификат клиента истек до получения уведомления

CronJob работает каждые 12 часов. Если он не работал, проверьте его статус:

```bash theme={null}
kubectl get cronjob cert-renewal-check -n agenteye
```

Инициируйте ручную проверку:

```bash theme={null}
kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye
kubectl logs -n agenteye -l job-name=manual-cert-check
```

Чтобы немедленно переиздать истекший сертификат:

```bash theme={null}
cd base/certificates/client-certs
./issue-client-cert.sh <cluster-name>
```

Затем примените переформированный `collector-mtls-secret.yaml` в кластер(ы), где работают коллекторы, и перезагрузитесь:

```bash theme={null}
kubectl apply -f collector-mtls-secret.yaml -n <collector-namespace>
```

***

## Проблемы резервного копирования

### `agenteye-backup` не удается с ошибкой "No space left on device"

CronJob `agenteye-backup` выводит Postgres + ClickHouse в `backup-tmp` `emptyDir` временный том (по умолчанию `30Gi`), затем **потоком** архив `tar` прямо в S3 — сжатый архив никогда не записывается обратно на временное хранилище, поэтому временное хранилище должно содержать только *необработанные выгрузки*, а не выгрузки + второй архив на диске. Pod, вытесненный / `No space left on device`, поэтому означает, что **необработанные выгрузки** превышают размер временного хранилища (выгрузка `events` ClickHouse доминирует и растет со временем). Проверьте журналы неудачного задания:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<failed agenteye-backup job>
```

Исправление: в вашей оверлее поднимите `sizeLimit` `emptyDir` `backup-tmp` CronJob выше вашего итога необработанной выгрузки и убедитесь, что узел может действительно его держать (`sizeLimit` — это крышка, не резервирование). Если выгрузки превышают диск одного узла, замените `emptyDir` на PVC (EBS/PD) для `backup-tmp` или сожмите выгрузки у источника.

> Более старые релизы писали `.tar.gz` в *то же* `20Gi` временное хранилище, что и выгрузки, поэтому `dumps + archive` переполнял его и pod был вытеснен **перед** запуском загрузки — что выглядит как сбой S3, но на самом деле это диск. Потоковая передача загрузки избегает этого удвоения.

### `agenteye-backup` не удается установить `curl`

Задание работает на образе `postgres:16` и устанавливает `curl` при запуске для выгрузки ClickHouse по HTTP. В кластере без исходящего доступа к зеркалам пакетов Debian шаг `apt-get` не удается. Либо разрешите исходящий доступ из pod резервного копирования, либо встройте `curl` в зеркальный/пользовательский образ резервного копирования и ссылайтесь на него в вашей оверлее.

### `agenteye-backup` работает, но ничего не попадает в хранилище объектов

База поставляется с реальным `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) и `agenteye-backup` ServiceAccount. Задание **потоком** архив в S3 (`tar cz … | aws s3 cp - s3://…`). Если pod резервного копирования не имеет доступа на запись в ведро, загрузка ошибок — и потому что скрипт работает под `set -euo pipefail`, сбой в любом месте этого конвейера **не удается** во всем задании на шаге `upload` а не молча не включается (ловушка EXIT pod регистрирует `backup FAILED during step: upload`). Это также шаг, который вы достигаете *после* исправления временной эвакуации, поэтому если резервные копии ранее были вытеснены на шаге архивирования, убедитесь, что загрузка теперь приземляется. Найдите ошибку доступа S3 в журналах неудачного задания:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<failed agenteye-backup job> | grep -iE 's3|upload|denied'
```

Исправление: в вашей оверлее установите `BACKUP_BUCKET` на ведро, которым вы владеете, и аннотируйте существующий ServiceAccount `agenteye-backup` с доступом на запись (IRSA / Workload Identity / Pod Identity). См. раздел **Backups** в [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment).

***

## ClickHouse-поддерживаемые оценки / сеансы / запросы

### Боковая панель страницы `/queries` пуста после обновления

Три таблицы (`events`, `evaluations`, `agent_sessions`) ожидаются. Если боковая панель SchemaBrowser пуста после обновления, сервер не применил DDL ClickHouse при запуске. Проверьте журналы сервера на `failed to apply CH DDL statement`:

```bash theme={null}
kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL'
```

Наиболее распространенной причиной является то, что ClickHouse недостижим во время запуска миграций. Сервер отказывается запускаться, если не может достичь CH, поэтому застрявший pod обычно имеет `CrashLoopBackOff`, а не молчаливо сломанную страницу запросов, но частичное применение DDL (одна выписка OK, следующие 5xx) оставляет схему полусырой. Перезагрузите pod сервера после проверки достижимости CH:

```bash theme={null}
kubectl rollout restart deploy/server -n agenteye
```

### Новые оценки не появляются в `/sessions` или `/queries`

После обновления новые оценки пишутся в ClickHouse, не Postgres, и появляются в `/sessions` (ограничены на `evaluations:read`) и в `/queries`. Если они не появляются:

1. Подтвердите, что конвейер оценщика включен (`EVALUATOR_ENDPOINT` установлен на сервере) и выдает терминальные результаты; проверьте наличие строк `evaluation_finalized`.
2. Подтвердите, что CH достижим с сервера: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`.
3. Точечная проверка таблицы CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`.

### Запросы не удаются под нагрузкой с ошибкой "Memory limit exceeded", или ClickHouse `OOMKilled`

**Симптом:** под тяжелой нагрузкой приборной панели/запроса аналитические страницы (поток событий, `/sessions`, представление моделей/задержки, редактор SQL) начинают не удаваться или истекать; сервер кратко колебется `NotReady`; и pod ClickHouse показывает растущее количество перезагрузок. Это почти всегда **память**, а не CPU или диск.

**Подтвердите, что это память** (не проблема пропускной способности, которую исправила бы репликация):

1. Проверьте pod на выходе из памяти:
   ```bash theme={null}
   kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled'
   ```
   `Reason: OOMKilled` / `Exit Code: 137` с растущим количеством перезагрузок является признаком.

2. Спросите ClickHouse, что он отклоняет:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC"
   ```
   Большое количество `MEMORY_LIMIT_EXCEEDED` — это подпись. Сообщение гласит *maximum: N GiB* — это **N это `0.9 × лимит памяти pod`** (значение `max_server_memory_usage_to_ram_ratio` в `deploy/base/clickhouse/configmap.yaml`). Если тяжелые чтения нужны более чем N, они отклоняются.

3. Исключите то, что *не является* проблемой — если CPU, часть количество и диск все низкие, добавление реплик/шардирования будет потраченной стоимостью:
   ```bash theme={null}
   kubectl -n agenteye top pod clickhouse-0
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table"
   ```

**Причина:** лимит памяти pod ClickHouse слишком мал для аналитического рабочего набора. Самые тяжелые чтения вытягивают столбец `payload` с исходным JSON, запускают `JSONExtract*` над ним и используют `FINAL` — каждый может нуждаться в нескольких ГиБ. Если настроенные кэши (`mark_cache_size` + `uncompressed_cache_size`) больше pod, они усугубляют это: кэши заряжаются против того же бюджета и вытесняют память запроса.

**Исправление — масштабируйте память ClickHouse:**

1. Поднимите лимит памяти ClickHouse в вашей оверлее путем патчинга `resources` контейнера `clickhouse` StatefulSet (тот же механизм оверлея, используемый для `resources` других компонентов). Используемый бюджет сервера составляет `0.9 × limit`, поэтому лимит `6Gi` дает \~5.4 ГиБ, `16Gi` дает \~14 ГиБ. Установите `requests.memory` на реальный пол также, чтобы планировщик его зарезервировал. Применение этого **пересоздает CH pod** (одна реплика → \~30–60 сек простоя аналитики); сделайте это в окне низкого трафика.
2. Держите кэши в `deploy/base/clickhouse/configmap.yaml` пропорциональными лимиту — небольшие кэши (несколько сотен МиБ) безопасны на небольшом pod; только поднимите их вместе с соответствующим увеличением лимита памяти. Per-query `max_memory_usage` явно установлен в профиле `users.xml` (см. фиксированный раздел узла ниже) и держится ниже крышки уровня сервера (`0.9 × limit`), поэтому ни один запрос не *разрешено* более RAM, чем контейнер имеет.
3. Если сам узел является потолком, проверьте хост памяти, который ClickHouse может видеть:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'"
   ```
   Если это только немного выше лимита pod, переместите ClickHouse на больший узел (оптимизированный для памяти) — через селектор узла/сродство в вашей оверлее — перед дальнейшим поднятием лимита.

**Когда вы не можете добавить память: запустите запросы в RAM и быстро отклоните — не пролейте на медленный диск.** Если узел зафиксирован и pod не может вырасти, ограничьте то, что может использовать любой один запрос (поэтому один запрос не может занять весь узел) и на **медленном (не-SSD) диске данных** делайте **не** позволяйте большим агрегациям/сортировкам пролегчиться на диск. Пролегчивание на медленный диск медленнее, чем истечение времени чтения клиента сервера, поэтому пролегчивающий запрос возвращает `500` приборной панели в полете, пока ClickHouse продолжает молоть — держание запросов в RAM и быстрое отклонение редкого превышения бюджета (`MEMORY_LIMIT_EXCEEDED`, субсекунда) это то, что восстанавливает загрузку. Обратите внимание на подводный камень ClickHouse для применения этих:

* **Это *профиль* настройки, и ClickHouse читает `<profiles>` только из `users_config` (`users.xml` / `users.d/*.xml`) — никогда из `config.d`.** Блок `<profiles>`, размещенный в `config.d/agenteye.xml`, является **молчаливо игнорируемым** (`max_execution_time`, `max_memory_usage` и т. д. просто не применяются). Объединенная конфигурация поэтому поставляется с ними как ключ `users.xml` в ConfigMap `clickhouse-config`, смонтированный по адресу `/etc/clickhouse-server/users.d/agenteye.xml`.
* Поставляемые по умолчанию: `max_memory_usage` (потолок по запросу — один запрос не может потреблять весь бюджет сервера), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (пролегчивание отключено)** поэтому запросы остаются в RAM вместо того, чтобы ползти на медленный диск, и `max_execution_time` (охрана убежище, согласованная с истечением времени чтения клиента сервера).
* **Проверьте, что они живы** (это также то, как вы обнаруживаете подводный камень config.d):
  ```bash theme={null}
  kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
    "SELECT name, value FROM system.settings
     WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')"
  ```
  Ожидайте ненулевого `max_memory_usage` и `max_bytes_before_external_group_by = 0`. Если `max_memory_usage` читается `0`/default, профиль не применяется — проверьте, что живут в монтировании `users.d`, а не `config.d`.

Компромисс: с отключенным пролегчиванием запрос, чей рабочий набор превышает `max_memory_usage`, — это **отклоняется** (`MEMORY_LIMIT_EXCEEDED`) вместо завершения медленно — на медленном диске то быстрое отклонение предпочтительно, потому что пролегчивающий запрос превышал бы истечение времени клиента и все равно не удалось бы. Если ваш диск данных — это **быстро (SSD)**, вы можете вместо этого поднять пороги `max_bytes_before_external_*` чтобы позволить большим запросам пролегчиться на диск и завершиться.

***

## Мультитенантность (организации)

### Ошибки при обновлении, которое включает организации (смешанные pod старого/нового сервера)

**Симптом:** во время катящегося развертывания рилиза, включающего орг, некоторые запросы не удаются: журналы сервера показывают `there is no unique or exclusion constraint matching the ON CONFLICT specification` на пути `api_keys`, и/или каналы оповещений/Slack/вебхука перестают срабатывать во время развертывания.

**Причина:** обновление заменяет старый уникальный индекс экземпляра на `api_keys(name)` с частичными индексами для каждого орга и перемещает параметры канала оповещения (и `default_user_permissions`) из глобальной таблицы `settings` в `org_settings` для каждого орга. Pod **старого** сервера все еще выдает `ON CONFLICT (name)` (теперь нет соответствующего ограничения) и все еще читает конфигурацию канала из старых строк `settings` (теперь пусто). Старые и новые pod не могут безопасно сосуществовать для этих двух путей.

**Исправление:** не делайте медленный откат для этого конкретного обновления на смешанные версии. Выполните чистое переключение: масштабируйте старый сервер до нуля (или используйте короткое окно обслуживания) и запустите новую версию вместе с ее миграциями, а не запускайте старые и новые реплики рядом. Обычный трафик и прием возобновляются сразу после переключения; это влияет только на окно переходной версии.

### Провизионирование организации не удается на `CREATE USER` / `CREATE ROW POLICY`, или один орг может прочитать данные другого орга

**Симптом:** создание орга возвращает ошибку, упоминающую `CREATE USER`, `CREATE ROW POLICY` или управление доступом отключено; или, что хуже, члены одного орга видят события/оценки другого орга в редакторе SQL или помощнике.

**Причина:** изоляция для каждого орга обеспечивается выделенным пользователем ClickHouse + политикой строк для каждого орга. Это требует **управления доступом** SQL для включения и `users_without_row_policies_can_read_rows=false` на ClickHouse. С отключенным управлением доступом провизионирование не может создать пользователя/политику; со значением политики строк по умолчанию, оставленным в его разрешительном значении, пользователь, имеющий SELECT но отсутствующую политику, читает **все** строки (сбой-открыт).

**Исправление:** используйте объединенную конфигурацию `deploy/base/clickhouse/`, которая устанавливает оба. Если вы запускаете собственную конфигурацию ClickHouse, включите управление доступом SQL для внутреннего пользователя сервера и установите `users_without_row_policies_can_read_rows=false` (см. `deploy/base/clickhouse/configmap.yaml`), затем перезагрузите ClickHouse и пересоздайте орг с CLI `agenteye-orgctl` (см. [enterprise-docs/tenant-management.md](/ru/agenteye/tenant-management)).

### Пользователи организации теряют доступ ClickHouse после изменения `ORG_CH_SECRET`

**Симптом:** редактор SQL и помощник ИИ внезапно возвращают ошибки аутентификации ClickHouse для каждой организации сразу после изменения или несогласованной установки `ORG_CH_SECRET` на репликах.

**Причина:** пароль ClickHouse каждого орга выводится как HMAC `ORG_CH_SECRET`. Ротация его (или запуск реплик с разными значениями) аннулирует сохраненный учетные данные ClickHouse каждого орга; производный пароль больше не совпадает с провизионированным пользователем.

**Исправление:** установите `ORG_CH_SECRET` на одно крепкое значение **перед** провизионированием второго орга и держите его стабильным и идентичным на каждой реплике сервера. Перестройка загрузочного времени сервера пересобирает учетные данные ClickHouse каждого орга с текущего секрета при запуске, поэтому перезагрузка сервера
