Passer au contenu principal
Ce guide couvre le déploiement du serveur et du tableau de bord AgentEye en production.

Vue d’ensemble de l’architecture

  • Serveur : service HTTP Rust qui reçoit les lots d’événements, les écrit dans ClickHouse et maintient l’état relationnel dans PostgreSQL.
  • Tableau de bord : application web Next.js qui lit et écrit exclusivement via l’API du serveur.
  • agenteye-collector : déployé sur les machines des agents, pas sur l’hôte du serveur.
  • Postgres 15+ : OBLIGATOIRE. (Relevé de la version 14 lors de la mise à jour multi-tenant ; le schéma org-membership utilise une clé étrangère ON DELETE SET NULL avec liste de colonnes, fonctionnalité propre à Postgres 15+. Mettez à niveau Postgres avant de déployer cette version.) Stocke l’état OLTP : api_keys, users, sessions, evaluation_jobs (queue), dashboards, saved_queries, otp_codes, ainsi que les tables multi-tenant orgs, org_memberships, org_settings.
  • ClickHouse 24+ : OBLIGATOIRE. Le store analytique pour chaque événement ingéré. Moteur : ReplacingMergeTree, partitionné par mois, ordonné par (session_id, ts, dedup_key). Le serveur se connecte via CLICKHOUSE_URL ; le répertoire deploy/base/clickhouse/ fourni embarque une configuration mono-nœud optimisée pour les performances. Exigence multi-tenant : la configuration fournie active la gestion des accès SQL + users_without_row_policies_can_read_rows=false afin que le serveur puisse créer un utilisateur ClickHouse en lecture seule et une politique de lignes par organisation (la frontière d’isolation appliquée par le moteur pour l’éditeur SQL et l’agent IA). Si vous fournissez votre propre configuration ClickHouse, reportez ces paramètres (voir deploy/base/clickhouse/configmap.yaml).
  • Redis 7+ : cache partagé et backend de limitation de débit optionnels. Le serveur et le tableau de bord se connectent tous deux via REDIS_URL. En l’absence de Redis, les deux dégradent gracieusement vers des chemins Postgres uniquement. Voir Redis (cache optionnel) ci-dessous.

Serveur

Récupérer l’image

Les builds actuels sont publiés sous beta-latest ; latest est réservé aux versions stables. En production, épinglez un tag :v<version> spécifique ; voir Tags d’images disponibles.

Variables d’environnement

VariableRequiseDéfautDescription
DATABASE_URLOuiaucunDSN Postgres. Format de chaîne de connexion libpq standard avec le schéma postgres://. Supporte ?sslmode=require et d’autres paramètres libpq. Le mot de passe ne doit pas contenir /, + ou = ; utilisez openssl rand -hex pour générer des mots de passe sûrs pour les URL.
ADMIN_KEYNonaucunClé API d’administration de démarrage. Mise à jour avec toutes les permissions à chaque démarrage. Faites pivoter en changeant la valeur et en redémarrant.
LISTEN_ADDRNon0.0.0.0:8080Adresse TCP à écouter
MAX_BODY_BYTESNon134217728 (128 Mo)Taille maximale du corps de la requête
ADMIN_EMAILNonaucunEmail de l’utilisateur administrateur de démarrage. Mis à jour avec toutes les permissions à chaque démarrage et marqué comme protégé : ne peut pas être désactivé ni voir ses permissions modifiées via le tableau de bord/l’API. Pour faire pivoter l’administrateur de démarrage, changez ADMIN_EMAIL et redémarrez ; le nouvel email est mis à jour comme protégé, et l’ancien conserve sa protection jusqu’à ce qu’elle soit manuellement supprimée en base de données.
ALLOWED_EMAILSNonaucun (tout bloqué)Liste d’emails autorisés séparés par des virgules pour la création d’utilisateurs et la connexion. Supporte les adresses exactes (user@example.com) et les jokers de domaine (*@example.com). Si non défini, aucun utilisateur ne peut être créé ni se connecter. Initialisation au premier démarrage uniquement : alimente la liste blanche de l’organisation par défaut au premier démarrage ; ensuite, la page /<org>/settings de chaque organisation fait foi et toute modification de cette variable d’environnement n’a aucun effet.
SMTP_HOSTNonaucunNom d’hôte du serveur SMTP pour l’envoi des emails OTP. Si non défini, les codes OTP sont enregistrés sur stdout.
SMTP_PORTNon587Port du serveur SMTP
SMTP_USERNAMENonaucunNom d’utilisateur pour l’authentification SMTP
SMTP_PASSWORDNonaucunMot de passe pour l’authentification SMTP
SMTP_FROMNonaucunAdresse email expéditeur pour les emails OTP
SMTP_TLSNonSTARTTLSSTARTTLS est utilisé sauf si vous le désactivez explicitement : false ou 0 envoie en texte clair (sans TLS) ; toute autre valeur — y compris l’absence de définition — active STARTTLS.
DASHBOARD_URLNonvaleur par défaut intégréeOrigine du tableau de bord utilisée pour construire à la fois le lien magique de l’email OTP et les liens magiques d’incidents dans les notifications d’alerte. Si non défini, il revient à une valeur par défaut intégrée (et, pour les OTP uniquement, à l’origine de la requête dérivée du tableau de bord en premier). Définissez-le pour les configurations à domaines séparés afin que les liens email et Slack/incident pointent vers votre tableau de bord. Voir URL du lien magique email ci-dessous ; la plupart des opérateurs n’ont pas besoin de le définir.
SESSION_TTL_SECSNon86400 (24 h)Durée de session du tableau de bord en secondes. Initialisation au premier démarrage uniquement : modifiable par organisation via /<org>/settings après le premier déploiement.
OTP_TTL_SECSNon600 (10 min)Durée de validité du code OTP en secondes. Initialisation au premier démarrage uniquement : modifiable par organisation via /<org>/settings après le premier déploiement.
REDIS_URLNonaucunBackend de cache partagé et de limitation de débit optionnel, ex. redis://redis:6379/0. Lorsqu’il est défini, le serveur met en cache les lookups de clés API authentifiées, l’agrégat /models du tableau de bord, la liste des sessions, et la facette de liste des environnements ; il déplace également la limitation de débit des requêtes OTP de Postgres COUNT vers Redis INCR. Si non défini ou inaccessible, le serveur fonctionne sans cache (la limite OTP revient à Postgres, tous les autres appels au cache passent à la source de vérité). Voir Redis (cache optionnel) ci-dessous.
CLICKHOUSE_URLOuiaucunURL de base de l’instance ClickHouse, ex. http://clickhouse:8123. Le serveur applique son schéma d’événements à cette base de données à chaque démarrage et refuse de démarrer s’il ne peut pas atteindre ClickHouse. Voir ClickHouse (store analytique requis) ci-dessous.
CLICKHOUSE_DATABASENonagenteyeNom de la base de données (schéma) ClickHouse. Le serveur la crée au démarrage si elle n’existe pas.
ORG_CH_SECRETNon (mono-tenant) / Oui (multi-org)valeur dev par défautClé HMAC à partir de laquelle le mot de passe ClickHouse par tenant de chaque organisation est dérivé. L’éditeur SQL et le run_query de l’agent IA s’exécutent en tant qu’utilisateur ClickHouse en lecture seule propre à l’organisation, dont la politique de lignes applique l’isolation des tenants dans le moteur. Les déploiements mono-tenant démarrent correctement avec la valeur dev intégrée ; avant de provisionner une seconde organisation, vous DEVEZ définir une valeur forte et stable, car la CLI agenteye-orgctl org create refuse de s’exécuter avec la valeur dev intégrée. La faire pivoter orpheline l’utilisateur ClickHouse de chaque organisation jusqu’au prochain démarrage qui les re-provisionne automatiquement. Gardez-la secrète et inchangée entre les réplicas. Le provisionnement des organisations est réservé aux opérateurs ; voir Organisations (multi-tenancy) ci-dessous.
DEFAULT_ORG_NAMENonDefaultNom d’affichage initialisé pour l’organisation par défaut intégrée. Initialisation au premier démarrage uniquement, et uniquement tant que l’organisation conserve son identité générique fraîchement migrée, appliquée au démarrage, puis ignorée. Une fois que vous renommez l’organisation (agenteye-orgctl org rename), le renommage fait autorité et cette variable d’environnement n’a plus aucun effet.
DEFAULT_ORG_SLUGNondefaultSlug d’URL pour l’organisation par défaut intégrée, le chemin du tableau de bord où elle réside (/<slug>/…). Mêmes sémantiques de premier démarrage uniquement / état initial que DEFAULT_ORG_NAME. Doit comporter 1 à 40 caractères alphanumériques minuscules avec des tirets internes simples et ne pas être un mot réservé ; une valeur invalide est ignorée (l’organisation conserve default). Permet à une installation mono-tenant de se présenter par ex. comme /acme au lieu de /default sans aucune étape CLI post-déploiement.
RUST_LOGNoninfoVerbosité des logs (debug, warn, error, agenteye_server=trace)
EVALUATOR_ENDPOINTNonaucunURL de base de votre service d’évaluation (ex. http://evaluator:9000). Si non défini, l’intégralité du pipeline d’évaluation est sans effet ; aucune ligne de queue n’est écrite, aucun worker ne s’exécute. Voir Suite d’évaluation.
EVALUATOR_TOKENNonaucunEnvoyé en tant que Authorization: Bearer <token> à l’évaluateur. Doit être égal à la valeur avec laquelle le service d’évaluation est configuré. Optionnel uniquement si votre évaluateur est configuré sans token.
EVALUATOR_WORKERSNon2Concurrence : nombre de tâches worker par instance de serveur qui dispatche les évaluations. Sûr à exécuter sur plusieurs serveurs à mise à l’échelle horizontale.
EVALUATOR_CLAIM_BATCHNon4Nombre maximum d’évaluations qu’un seul worker revendique par tick. Les lots sont dispatchés de façon concurrente, donc la concurrence totale sur votre endpoint d’évaluation est EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH.
EVALUATOR_POLL_IDLE_SECSNon2Durée de sommeil d’un worker entre les tentatives de dispatch lorsqu’aucune évaluation n’est en attente.
EVALUATOR_POLLING_INTERVAL_SECSNon10Cadence de repli finale (en secondes) pour les sondages GET /evaluate/{id} lorsque l’évaluateur ne retourne pas de next_poll_secs par réponse et n’annonce pas de default_poll_interval_secs via GET /config.
EVALUATOR_REQUEST_TIMEOUT_MSNon30000Timeout par requête HTTP vers l’évaluateur (en millisecondes).
EVALUATOR_MAX_ATTEMPTSNon5Après autant de tentatives échouées, une évaluation est enregistrée comme error terminal (ou timeout si les échecs étaient des timeouts de requête).
EVALUATOR_CONFIG_REFRESH_SECSNon300 (5 min)Fréquence à laquelle le serveur re-récupère GET /config depuis l’évaluateur.
EVALUATOR_MAX_POLL_DURATION_SECSNon3600 (1 h)Temps d’horloge murale maximum pendant lequel une session peut rester dans la queue de sondage avant qu’AgentEye la termine en timeout. Protège contre un évaluateur qui retourne indéfiniment pending.
ALERT_WORKERSNon1Concurrence : nombre de tâches worker par instance de serveur qui évaluent les règles d’alerte. Voir Alertes.
ALERT_CLAIM_BATCHNon16Nombre maximum d’alertes qu’un seul worker revendique par tick.
ALERT_POLL_IDLE_SECSNon5Durée de sommeil d’un worker d’alertes lorsque la queue est vide.
ALERT_REQUEST_TIMEOUT_MSNon15000Timeout d’évaluation par déclenchement (requêtes ClickHouse + HTTP de canal sortant).
ALERT_MAX_ATTEMPTSNon5Nombre d’échecs transitoires consécutifs avant qu’une alerte soit replanifiée à sa cadence normale plutôt qu’avec un backoff exponentiel.
AUDIT_WORKERSNon1Concurrence : nombre de tâches worker par instance de serveur qui exécutent des audits. Voir Audits.
AUDIT_CLAIM_BATCHNon1Nombre maximum d’audits dus qu’un seul worker revendique par tick. Une investigation agentique est une longue boucle, d’où le défaut à 1.
AUDIT_POLL_IDLE_SECSNon30Durée de sommeil d’un worker d’audits lorsqu’aucun audit n’est dû.
AUDIT_REQUEST_TIMEOUT_MSNon30000Timeout par requête de politique vers ClickHouse (en millisecondes).
AUDIT_LLM_TIMEOUT_MSNon1440000Timeout pour l’appel d’investigation agentique au service d’assistant IA. Une boucle d’agent complète s’exécute pendant plusieurs minutes ; gardez-le AU-DESSUS du propre AGENTEYE_AUDIT_TIMEOUT_MS de l’agent pour que l’agent retourne ses conclusions partielles avant que le serveur abandonne.
AUDIT_MAX_ATTEMPTSNon5Nombre d’échecs transitoires consécutifs avant qu’un audit soit replanifié à sa cadence normale plutôt qu’avec un backoff exponentiel.
AGENTEYE_AGENT_URL / AGENTEYE_AGENT_TOKENNonL’investigation agentique de l’audit appelle le service agent d’assistant IA, réutilisant la même connexion que l’assistant — définissez donc ces deux variables sur le serveur également (les manifestes/compose fournis le font). Les deux définis ⇒ les audits exécutent l’investigation IA ; l’un ou l’autre non défini ⇒ les audits s’exécutent en mode politique uniquement (la passe de politique SQL déterministe s’exécute quand même), quel que soit le flag llm_enabled par audit. L’agent doit également avoir un LLM configuré — voir assistant.md.
Service d’assistant IA — paramètres d’audit et de sandbox. L’investigation agentique et son sandbox Python dans le pod sont configurés sur le service agent (pas le serveur), tous avec le préfixe AGENTEYE_AUDIT_* et tous optionnels :
VariableDéfautSignification
AGENTEYE_AUDIT_MAX_STEPS200Nombre maximum de tours d’agent par investigation.
AGENTEYE_AUDIT_TIMEOUT_MS1200000Temps d’horloge murale pour une investigation (20 min). Doit rester en dessous du AUDIT_LLM_TIMEOUT_MS du serveur.
AGENTEYE_AUDIT_MAX_CONCURRENCY1Investigations concurrentes par pod agent (séparé du budget de l’assistant de chat).
AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS / _MEM_MB / _CPU_SECS / _OUTPUT_MAX_BYTES / _SCRIPT_MAX_BYTES20000 / 768 / 10 / 64000 / 64000Limites par script pour le sandbox bubblewrap.
Exigence de plateforme pour le sandbox. Le sandbox de code d’audit exécute le Python du modèle dans une cage bubblewrap, ce qui nécessite des espaces de noms utilisateurs non privilégiés. Le pod agent doit autoriser les flags clone() — définissez seccompProfile: Unconfined (k8s) ou security_opt: [seccomp:unconfined] (compose) sur l’agent. Lorsque le noyau du nœud désactive les espaces de noms utilisateurs non privilégiés (ex. certaines images GKE COS), le preflight du sandbox échoue et l’auditeur se dégrade automatiquement en mode SQL uniquement — pas d’erreur, juste un sandbox_available: false sur le /health de l’agent.

Démarrer

Définissez DATABASE_URL dans votre environnement, puis transmettez-le au conteneur :
Le serveur exécute automatiquement les migrations de base de données au démarrage ; aucune étape de migration séparée n’est nécessaire.

Vérification de l’état

Aucune authentification requise. Utilisez /health pour les sondes de liveness et /ready pour les sondes de readiness / d’équilibreur de charge. /ready vérifie les dépendances essentielles sans lesquelles le serveur ne peut pas fonctionner (Postgres + ClickHouse), donc un serveur en cours d’exécution mais incapable d’atteindre sa base de données est retiré de la rotation et apparaît comme NotReady ; Redis est rapporté mais ne fait jamais échouer la readiness. Sur les manifestes Kubernetes fournis, la sonde de readiness pointe déjà sur /ready et la liveness reste sur /health. Voir enterprise-docs/health-monitoring.md pour l’image complète, y compris les alertes Slack optionnelles pour les défaillances de pods Kubernetes.

URL du lien magique email

Les emails de connexion OTP contiennent un bouton ouvrir le tableau de bord en un clic. En cliquant dessus, l’utilisateur atterrit sur /login?token=<code>&email=<address> ; le tableau de bord échange cette paire contre une session et redirige vers l’application, sans ressaisie manuelle du code. Le serveur résout l’origine du tableau de bord utilisée pour construire le lien en trois niveaux :
  1. En-tête X-AgentEye-Dashboard-Url : défini automatiquement par le proxy /api/auth/otp/request du tableau de bord depuis sa propre origine publique. Dans un déploiement à même origine (serveur et tableau de bord partagent un hôte derrière un seul ingress qui transmet les en-têtes proxy), aucune configuration n’est requise.
  2. Variable d’environnement DASHBOARD_URL : définissez-la si votre tableau de bord est accessible sur une origine différente de celle que voit l’endpoint de requête OTP du serveur (séparation api.example.com / app.example.com), ou si votre ingress ne propage pas l’hôte public dans le pod tableau de bord (de sorte que request.nextUrl.origin résoudrait sinon vers une adresse générique comme 0.0.0.0:3000). Exemple : DASHBOARD_URL=https://app.example.com.
  3. Par défaut : https://app.befailproof.ai, utilisé uniquement si aucun des cas ci-dessus n’est présent.
La valeur de l’en-tête est validée : seules les origines https://* et de loopback (http://localhost*, http://127.0.0.1*) sont acceptées, et les adresses de liaison génériques (0.0.0.0, [::]) sont rejetées même avec le schéma https://. Tout le reste passe au niveau 2. Définissez-le sur un cluster en cours d’exécution en une seule commande ; pas de fichier, pas de reconstruction kustomize :
Cela déclenche un rollout ; les nouveaux pods récupèrent la valeur à la première requête. Notez que la substitution ne vit que sur le Deployment ; un kustomize build | kubectl apply ultérieur contre l’overlay l’effacera sauf si vous ajoutez la même variable d’environnement au patch server-env.yaml de votre overlay.

Tableau de bord

Récupérer l’image

Variables d’environnement

VariableRequiseDéfautDescription
AGENTEYE_SERVER_URLOuiaucunURL de base du serveur, ex. http://localhost:8080
AGENTEYE_API_KEYOuiaucunClé API que le tableau de bord utilise pour s’authentifier auprès du serveur. Nécessite toutes les permissions (clé admin recommandée).
AE_LOG_LEVELNoninfoVerbosité des logs côté serveur : debug, info, warn, error. Définissez sur debug pour voir les lignes de requête/réponse en amont et les traces de validation de session lors du diagnostic de problèmes.
AE_LOG_JSONNonauto1 force la sortie JSON par ligne ; 0 force la sortie lisible par l’humain. Si non défini, JSON est activé automatiquement si NODE_ENV=production. JSON est recommandé en production pour que les logs soient analysés proprement avec jq ou un agrégateur de logs.
AE_ANALYTICS_DISABLEDNonaucunDéfinissez sur 1/true pour désactiver la télémétrie anonyme d’utilisation du produit du tableau de bord. Voir Télémétrie et confidentialité ci-dessous.
REDIS_URLNonaucunBackend de cache partagé optionnel, ex. redis://redis:6379/0. Lorsqu’il est défini, le tableau de bord met en cache les résultats de validateSession() entre les réplicas et partage le cache de récupération Next.js pour les routes proxy d’agrégat de latence et de liste d’environnements. Les limites de débit des requêtes et vérifications OTP côté edge utilisent également Redis lorsqu’il est présent (échouant ouvertes si Redis est inaccessible ; la limite côté serveur est le garde-fou de sécurité). Voir Redis (cache optionnel) ci-dessous.
AGENTEYE_AGENT_URLNonaucunURL de base du service agent d’assistant IA optionnel, ex. http://agent:9100. Laissez-le non défini pour masquer entièrement l’assistant : aucune bulle d’assistant n’apparaît dans le tableau de bord. Voir enterprise-docs/assistant.md.
AGENTEYE_AGENT_TOKENNonaucunSecret partagé que le tableau de bord présente au service agent. Doit correspondre à l’AGENTEYE_AGENT_TOKEN configuré sur l’agent. Voir enterprise-docs/assistant.md.

Démarrer

Télémétrie et confidentialité

Le tableau de bord envoie des analyses d’utilisation anonymes du produit au service d’analyse d’Exosphere (PostHog) : les pages du tableau de bord consultées et quelques actions de l’interface utilisateur comme la création d’une clé API ou la réévaluation d’une session. Ce signal d’utilisation informe la priorisation des fonctionnalités.
  • Aucune donnée d’agent, de session ou d’événement ne quitte jamais votre infrastructure. Seule l’utilisation de l’interface du tableau de bord est rapportée. Les URL des pages sont dépouillées de leurs identifiants avant l’envoi, et les opérateurs ne sont identifiés que par un identifiant interne opaque, jamais par email.
  • La télémétrie est activée par défaut. Pour la désactiver complètement, définissez AE_ANALYTICS_DISABLED=1 sur le conteneur du tableau de bord et redémarrez.
  • Les analyses sont envoyées vers le propre chemin /ingest du tableau de bord, que le tableau de bord relaie en proxy inverse vers PostHog (https://us.i.posthog.com). Garder les requêtes en first-party signifie que les bloqueurs de publicité des navigateurs ne les suppriment pas. Le conteneur du tableau de bord a besoin d’un accès sortant vers PostHog ; s’il est bloqué, la télémétrie ne fait silencieusement rien et le tableau de bord n’est pas affecté.

Assistant IA (optionnel)

Un assistant IA intégré au tableau de bord permet à votre équipe de poser des questions sur les données de leurs agents en langage naturel (résumer des sessions, rédiger du SQL pour l’éditeur /queries, et transformer des requêtes sauvegardées en tuiles de tableau de bord) sans quitter le tableau de bord. Il fonctionne comme un conteneur agent interne séparé (basé sur le Claude Agents SDK) que seul le tableau de bord peut atteindre, et reste désactivé jusqu’à ce que vous configuriez un endpoint LLM. Pour l’activer, définissez sur le service agent une connexion LLM (Portkey via PORTKEY_API_KEY + un slug de catalogue de modèles AGENTEYE_AGENT_MODEL=@<slug>/<model>, Anthropic direct via ANTHROPIC_API_KEY, une autre passerelle via ANTHROPIC_BASE_URL, ou Bedrock/Vertex), une clé de données dédiée, et un AGENTEYE_AGENT_TOKEN partagé correspondant au tableau de bord. Les utilisateurs du tableau de bord ont également besoin de la permission agent:use. Pour la clé de données de l’assistant, vous n’avez rien à créer manuellement : choisissez un secret aléatoire, définissez-le comme AGENTEYE_API_KEY sur l’agent et comme AGENT_API_KEY sur le server, et le serveur l’initialise au démarrage avec un ensemble de permissions fixes. Son accès aux données est en lecture seule (events:read, evaluations:read, dashboards:read, queries:read), et il détient en outre des portées d’authoring soumises à approbation (dashboards:write, queries:write, queries:run) pour qu’il puisse rédiger et valider des requêtes sauvegardées et construire des tuiles de tableau de bord au nom de l’utilisateur ; tout le SQL s’exécute quand même via le rôle ClickHouse en lecture seule de l’organisation, ce qui élargit ce que l’assistant peut créer, pas les données auxquelles il peut accéder. Les portées sont fixes dans le code et ne peuvent pas être élargies par configuration. Cette clé est protégée ; elle ne peut pas être désactivée ou régénérée via l’API, uniquement pivotée en changeant la valeur et en redémarrant. Ne réutilisez jamais la clé admin/tableau de bord pour cela. La configuration complète, la référence complète des variables d’environnement, les options de télémétrie et le modèle de sécurité sont dans enterprise-docs/assistant.md.

ClickHouse (store analytique requis)

ClickHouse maintient la réactivité de vos tableaux de bord à des volumes d’événements élevés et permet à l’éditeur SQL /queries de joindre événements, évaluations et sessions dans un seul store. Il est le store canonique requis pour chaque événement ingéré, chaque résultat d’évaluation terminal, et les agrégats par session dérivés. PostgreSQL contient les tables d’état relationnel/mutable (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries) ; la surface analytique vit dans ClickHouse pour que les rollups du tableau de bord et vos propres requêtes SQL puissent l’analyser et la joindre nativement, sans allers-retours entre bases de données. Le serveur refuse de démarrer sans CLICKHOUSE_URL.

Schéma

Trois objets ClickHouse sont créés au démarrage du serveur, tous idempotents (CREATE IF NOT EXISTS) :
  • agenteye.events : ReplacingMergeTree(ingested_at), partitionné par toYYYYMM(ts), ordonné par (session_id, ts, dedup_key). Les insertions dupliquées (nouvelles tentatives du collecteur) se réduisent à une seule ligne lors de la fusion ; le serveur calcule un dedup_key SHA-256 déterministe pour chaque événement afin que les nouvelles tentatives soient sûres.
  • agenteye.evaluations : ReplacingMergeTree(ingested_at), partitionné par toYYYYMM(finished_at), ordonné par (session_id, finished_at, dedup_key). Écrit une fois par résultat d’évaluation terminal par le pipeline d’évaluation. Même modèle de clé de déduplication que events.
  • agenteye.agent_sessions : une VUE sur agenteye.events, pas une table physique. Chaque colonne est dérivée (started_at = min(ts), last_event_at = max(ts), ended_at = max(if event_type='agent_end', ts, NULL), event_count = count(), etc.). Pas d’upsert par événement ni de backfill séparé ; la vue reflète automatiquement ce qui est dans events.
Pour la compatibilité ascendante avec les requêtes sauvegardées qui référencent analytics.evaluations / analytics.sessions, le serveur crée également une base de données ClickHouse analytics avec des vues sur les tables agenteye.* ; analytics.events, analytics.evaluations, analytics.agent_sessions, analytics.sessions se résolvent tous correctement.

Configuration

Le docker-compose fourni et deploy/base/clickhouse/ embarquent un service ClickHouse optimisé pour la charge de travail d’AgentEye :
  • 2 Gio demandés / 4 Gio limite de mémoire dans l’overlay de base fourni (dimensionné pour tenir dans de petits nœuds POC/staging) ; les clients en production devraient augmenter — le plancher recommandé est 2c / 4Gi demandé, 6c / 8Gi limite. max_server_memory_usage_to_ram_ratio=0.9
  • Cache de marques de 5 Gio + cache non compressé de 8 Gio
  • background_pool_size=16, background_merges_mutations_concurrency_ratio=2
  • MergeTree : parts_to_throw_insert=3000, parts_to_delay_insert=1500, non_replicated_deduplication_window=1000
  • local_io_method=auto (io_uring sur les noyaux supportés)
  • fsync_metadata=0 : acceptable grâce à l’ingest au-moins-une-fois + déduplication ReplacingMergeTree
  • query_log activé avec TTL de 30 jours ; query_thread_log supprimé (coûteux à fort QPS)
  • max_execution_time=30 pour les requêtes côté utilisateur
  • PVC de 100 Gio au template StatefulSet (les overlays clients DEVRAIENT le remplacer par une classe de stockage SSD rapide pour la production)

Sauvegardes

Votre jeu de données complet est capturé chaque nuit dans une seule archive restaurable, de sorte qu’une perte de cluster ou de stockage est récupérable. ClickHouse est sauvegardé automatiquement par le CronJob quotidien agenteye-backup, qui dump à la fois PostgreSQL et ClickHouse en une seule passe. ClickHouse est lu via son API HTTP : agenteye.events et agenteye.evaluations sont dumpés au format natif ClickHouse (les vues et politiques de lignes sont recréées par le serveur au démarrage, donc les données des tables constituent le tableau complet) et regroupés avec le dump Postgres dans une seule archive compressée téléchargée vers votre stockage objet. Le bucket de destination et les identifiants cloud sont configurés par overlay. Voir la section Sauvegardes de enterprise-docs/kubernetes-deployment.md pour la configuration de téléchargement et les étapes de restauration.

Redis (cache optionnel)

Redis est un backend de cache partagé et de limitation de débit optionnel utilisé par le serveur et le tableau de bord. Avec Redis déployé et REDIS_URL défini sur les deux services :
  • Le serveur met en cache les lookups de clés API authentifiées, les listes /events/environments + /evaluations/environments, le rollup /events/latency_aggregate (la requête la plus lourde que le tableau de bord interroge), la liste /sessions, et bascule la limitation de débit des requêtes OTP d’un COUNT(*) Postgres vers un INCR + EXPIRE Redis.
  • Le tableau de bord met en cache les résultats de validateSession() pour que les 10 à 20 appels API authentifiés qu’un chargement de page typique émet partagent tous une seule vérification de session en amont. Il limite également le débit des requêtes OTP et des vérifications OTP au niveau edge du tableau de bord.
Les deux services se dégradent gracieusement si Redis est inaccessible. Chaque appel au cache retourne Err dans un timeout borné et l’appelant revient à la source de vérité (Postgres sur le serveur, le serveur Rust en amont sur le tableau de bord). La limitation de débit OTP revient au chemin COUNT(*) Postgres sur le serveur (la propriété de sécurité est préservée) ; la limite OTP edge du tableau de bord échoue ouverte tandis que la limite côté serveur tient toujours. L’indisponibilité de Redis dégrade la latence, pas la correction.

Configuration

Le bundle docker-compose inclut déjà un service Redis et câble REDIS_URL=redis://redis:6379/0 dans le serveur et le tableau de bord. Pour utiliser un Redis externe, définissez REDIS_URL vers votre endpoint et retirez le service redis du fichier compose.

Mémoire et persistance

L’image Redis fournie s’exécute avec --appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru. La persistance AOF signifie que le cache survit aux redémarrages des conteneurs ; everysec est le bon équilibre durabilité/performances car perdre la dernière seconde d’écritures cache est sans conséquence. L’éviction LRU plafonne la croissance mémoire.

Quand NE PAS déployer Redis

  • Développement/QA sur instance unique. Les caches en mémoire du serveur seul offrent la plupart des bénéfices par réplica ; Redis ajoute le partage inter-réplicas dont les configurations mono-instance n’ont pas besoin.
  • Installations isolées (air-gapped) où le coût opérationnel de faire tourner un service supplémentaire dépasse le gain en latence.

Docker Compose (recommandé)

Un docker-compose.yml est disponible dans le dépôt agenteye-enterprise/releases. Il démarre Postgres, le serveur et le tableau de bord avec une seule commande.
Remplacer les valeurs par défaut via .env :
Arrêter (conserve le volume de données) :
Arrêter et effacer toutes les données :

Paramètres opérationnels

Un petit ensemble de réglages opérationnels qui étaient autrefois fixés par des variables d’environnement sont maintenant modifiables par organisation depuis la page /<org>/settings du tableau de bord ; chaque organisation configure les siens. Les modifications prennent effet en quelques secondes, sans redémarrage ni redéploiement.
ParamètreVariable d’environnement de démarrageCe qu’il contrôle
Connexions autoriséesALLOWED_EMAILSEmails (ou jokers *@domain.com) autorisés à recevoir un OTP et à être ajoutés comme utilisateurs
Permissions utilisateur par défautDEFAULT_USER_PERMISSIONSTokens de permission séparés par des virgules présélectionnés lorsqu’un administrateur ouvre + nouvel utilisateur. Chaque token doit être l’une des chaînes listées sous Permissions des clés API. Par défaut, le préréglage standard : accès en lecture seule plus les actions quotidiennes d’astreinte (déclencher des réévaluations, exécuter des requêtes, acquitter des incidents, utiliser l’assistant).
Durée de vie de la sessionSESSION_TTL_SECSDurée pendant laquelle une connexion au tableau de bord reste valide avant une nouvelle authentification. Le tableau de bord re-vérifie la session en amont toutes les 5 secondes, donc une mise à jour des permissions sur /<org>/users prend effet à la prochaine requête de l’utilisateur concerné, sans reconnexion.
Durée de vie du code à usage uniqueOTP_TTL_SECSDurée pendant laquelle un OTP / lien magique reste utilisable
Canaux de notification d’alerteALERTS_ENABLED_CHANNELSListe séparée par des virgules des types de canaux que le dispatcher d’alertes est autorisé à utiliser : email, slack, webhook. La configuration par alerte est toujours créée sur /<org>/alerts/<id>, mais le dispatcher filtre chaque livraison sortante à travers cet ensemble ; un canal désactivé ici court-circuite avec une ligne d’audit skipped_disabled. Le canal dashboard (l’insertion d’audit locale) est toujours autorisé. Par défaut, les trois sont activés.

Fonctionnement du démarrage

Les paramètres sont stockés par organisation dans org_settings. Au premier démarrage, le serveur alimente les lignes manquantes de l’organisation par défaut à partir de la variable d’environnement correspondante (ou d’une valeur par défaut raisonnable si la variable d’environnement n’est pas définie). Après cela, la valeur stockée est la source de vérité et la variable d’environnement est ignorée ; modifier la variable d’environnement lors d’un redémarrage ultérieur n’affectera pas la valeur d’une organisation active, et les organisations supplémentaires démarrent avec des valeurs par défaut et configurent les leurs. Cela signifie :
  • Pour un nouveau déploiement, définissez les variables d’environnement comme indiqué ci-dessus et l’organisation par défaut les lira au premier démarrage.
  • Pour modifier une valeur ultérieurement, connectez-vous au tableau de bord et modifiez-la sous /<org>/settings. La modification s’applique en quelques secondes sur tous les réplicas du serveur ; aucun redémarrage n’est nécessaire.
  • Une ligne de log au démarrage enregistre ce qui a été initialisé vs. ce qui était déjà présent, pour vous permettre de confirmer que le démarrage a pris effet :

Sémantiques de connexion entre organisations

Une session et un OTP sont globaux à l’utilisateur, pas à une seule organisation, donc deux règles conccilient les paramètres par organisation au moment de la connexion :
  • Durée de vie de la session / OTP : la durée de vie la plus stricte (la plus courte) parmi les organisations auxquelles l’utilisateur appartient l’emporte.
  • Connexions autorisées : la porte fait un OU de la liste blanche de chaque organisation avec l’appartenance à l’organisation : un utilisateur peut demander un OTP si la liste blanche de n’importe quelle organisation admet son email ou s’il est déjà membre de n’importe quelle organisation.

Permissions

L’accès à une page /<org>/settings est conditionné par deux permissions :
  • settings:read : voir la page et les valeurs actuelles.
  • settings:write : sauvegarder les modifications.
L’utilisateur administrateur de démarrage (initialisé à partir de ADMIN_EMAIL) obtient les deux automatiquement avec toutes les autres permissions. Accordez-les à d’autres utilisateurs depuis /<org>/users selon les besoins.

Organisations (multi-tenancy)

Un seul déploiement peut servir plusieurs organisations (tenants) isolées ; chaque ligne de données appartient exactement à une organisation et l’isolation est appliquée dans le moteur de base de données. Une installation mono-tenant n’a rien à faire ici ; toutes les données vivent dans une organisation default intégrée. (Vous pouvez donner à cette organisation un nom plus convivial et un slug d’URL, pour qu’elle vive par ex. à /acme au lieu de /default, en définissant DEFAULT_ORG_NAME / DEFAULT_ORG_SLUG avant le premier démarrage, ou en la renommant à tout moment avec agenteye-orgctl org rename.) Le provisionnement des tenants est réservé aux opérateurs. Les organisations et leurs membres sont créés et gérés avec la CLI agenteye-orgctl, qui est embarquée dans l’image du serveur (aux côtés de agenteye-server) et s’exécute dans le pod serveur existant ; il n’y a pas de pod/Job séparé, pas d’API HTTP, et pas de bouton dans le tableau de bord. Elle réutilise DATABASE_URL, CLICKHOUSE_URL et ORG_CH_SECRET du serveur.
Verbes disponibles : org create | list | rename | delete | purge et member add | list | update | remove, avec les ensembles de permissions intégrés admin, standard et read-only. Les membres ajoutés reçoivent un OTP lors de leur première connexion au tableau de bord. Avant de créer une deuxième organisation : définissez un ORG_CH_SECRET fort et stable (la commande org create refuse de s’exécuter avec la valeur dev intégrée par défaut) et assurez-vous que Postgres est en version 15+. Inchangé : les clés API par organisation sont toujours créées dans le tableau de bord/l’API par les membres de l’organisation ; seul le cycle de vie des organisations et des membres a été déplacé vers la CLI. Référence complète des commandes et exemple détaillé : enterprise-docs/tenant-management.md.

Remplissage de la fenêtre de contexte

Chaque événement model_response affiche une pastille de remplissage de contexte — les tokens d’entrée plus les tokens de sortie en pourcentage de la fenêtre de contexte de ce modèle. Les plages sont healthy (0–24 %), watch (25–49 %), compacting (50–74 %), et reset context (75–100 %). AgentEye résout automatiquement les identifiants de modèles courants, donc aucune configuration initiale n’est requise. Chaque modèle qu’une organisation envoie apparaît sous Paramètres → fenêtres de contexte de modèle. Les utilisateurs avec settings:write peuvent remplacer sa fenêtre ou ajouter un modèle privé/proxy (0–1 000 000 tokens) ; 0 signifie « inconnu » et supprime la pastille. Les modifications s’appliquent aux événements nouvellement ingérés. Les utilisateurs avec settings:read peuvent consulter la liste. Les nouveaux événements reçoivent le remplissage à partir du moment où vous effectuez la mise à niveau. Pour également renseigner les événements historiques (et la liste par modèle) pour un déploiement existant, exécutez le backfill ponctuel — il est embarqué dans l’image du serveur (comme agenteye-orgctl) et s’exécute dans le pod serveur existant :
Il est idempotent (sûr à ré-exécuter) et réutilise DATABASE_URL / CLICKHOUSE_URL / REDIS_URL depuis le pod. Ré-exécutez-le après avoir modifié les fenêtres de modèles si vous souhaitez que les événements existants soient recalculés.

Considérations pour la production

  • Postgres : Utilisez un service Postgres géré ou une instance dédiée avec des sauvegardes régulières. Le DATABASE_URL supporte tous les paramètres libpq standard, y compris sslmode=require pour les connexions chiffrées.
  • TLS : Placez le serveur et le tableau de bord derrière un proxy inverse (nginx, Caddy, Traefik) qui termine TLS.
  • Pare-feu : Le port du serveur (par défaut 8080) ne doit être accessible que depuis les machines collectrices et l’hôte du tableau de bord, pas depuis l’internet public.
  • Clé admin : Définissez ADMIN_KEY avec un secret aléatoire fort. Après l’initialisation, créez des clés dédiées à portée limitée pour les collecteurs et le tableau de bord plutôt que d’utiliser la clé admin partout.
  • Tags d’images : Épinglez à la version dans vos manifestes de release (par exemple, server:v0.0.1-beta.48) en production plutôt qu’un tag flottant pour éviter les mises à niveau non intentionnelles. Les builds beta actuels sont publiés sous beta-latest ; latest est réservé aux versions stables.
  • Surveillance de l’état : Sur Kubernetes, la sonde de readiness utilise /ready (accessibilité Postgres + ClickHouse) tandis que la liveness reste sur /health. Pour des alertes Slack à l’échelle de la flotte sur la disponibilité d’AgentEye lui-même, activez l’add-on Robusta opt-in ; voir enterprise-docs/health-monitoring.md.

Tags d’images disponibles

TagDescription
latestDernière version stable
beta-latestDernière version pré-release (bêta)
v<version>Version épinglée, ex. v0.0.1-beta.48 (recommandé pour la production)