Intégration de Langchain-Chatchat avec Loki pour le diagnostic automatisé des logs

Analyse intelligente des logs via l'intégration Langchain-Chatchat et Loki

Dans les environnements informatiques modernes, les volumes de logs croissent de manière exponentielle, créant un défi pour leur interprétation. Les équipes d'exploitation peinent souvent à extraire des insights actionnables malgré des outils puissants. Parallèlement, l'adoption de bases de connaissances IA locales pour la documentation interne et le support progresse, mais ces systèmes ignorent généralement les données dynamiques des logs.

Lier une application de questions-réponses intelligente à un flux de logs en temps réel est réalisable grâce à l'intégration de Langchain-Chatchat, un framework open source pour les bases de connaissances locales, avec Grafana Loki, un système d'agrégation de logs. Cette synergie va au-delà d'une simple combinaison de fonctionnalités : elle établit un pont entre le savoir statique et l'observation opérationnelle.

Fusion des connaissances et des logs

Langchain-Chatchat excelle dans la mise en œuvre du pipeline RAG (Retrieval-Augmented Generation). Il permet de convertir des documents privés – manuels d'API, guides de dépannage, procédures de déploiement – en vecteurs stockés dans une base de données vectorielle locale. Lors d'une requête, le système retrouve les fragments contextuels les plus pertinents et génère une réponse via un modèle de langage local.

Cependant, ce mécanisme est initialement conçu pour des textes statiques. Pour répondre à des interrogations sur l'état du système comme « Le service de paiement a-t-il récemment affiché des erreurs fréquentes ? » ou « Comment a-t-on historiquement résolu les problèmes de timeout ? », il faut intégrer une source externe. Loki s'avère idéal pour cela.

Contrairement aux architectures ELK traditionnelles qui reposent sur une indexation complète du texte, Loki adopte un modèle léger d'indexation par balises et de stockage brut des logs. Les logs sont classés par balises (ex : job=prometheus, instance=web-01) avec des index inversés uniquement sur ces balises, tandis que le contenu original est compressé et écrit par lots dans un stockage objet. Cette conception offre un débit d'écriture élevé et un coût de stockage réduit, adapté aux environnements conteneurisés.

Loki fournit également un langage de requête puissant, LogQL, similaire au SQL, permettant des opérations de filtrage par balises, de correspondance de contenu et d'extraction par expressions régulières. Par exemple, la requête suivante localise les logs de timeout dans un service de paiement en production :

{namespace="production", app="payment"} |= "timeout" |~ "order creation"

Envelopper cette capacité dans une interface en langage naturel permettrait à des utilisateurs non techniques d'effectuer des diagnostics complexes.

Conception de la couche de traduction

La clé réside dans la création d'une couche de traduction convertissant les questions en langage naturel en requêtes LogQL valides. Cela nécessite une compréhension sémantique et un raisonnement contextuel, au-delà d'une simple substitution de mots-clés.

Le flux de travail se déroule comme suit :

  1. L'utilisateur saisit : « Y a-t-il eu des échecs de connexion à la base de données hier pour payment-service ? »
  2. Langchain-Chatchat encode la requête via un modèle d'embedding, retrouve des documents pertinents dans la base de connaissances locale (ex : normes de configuration du pool de connexions, tableau des codes d'erreur).
  3. Le système identifie les entités clés : nom du service (payment-service), type d'erreur (échec de connexion à la base de données), plage temporelle (hier).
  4. À l'aide de règles prédéfinies ou d'un modèle NLP affiné, ces éléments sémantiques sont mappés en conditions LogQL : {app="payment-service"} |= "connection refused" or |= "failed to connect" | interval: [24h]
  5. Une requête est envoyée à l'API HTTP de Loki : GET /loki/api/v1/query?query={app="payment-service"}%20|=%20"connection%20refused"&direction=backward&limit=100
  6. Les logs bruts récupérés sont analysés pour extraire des informations structurées : horodatages, résumés de piles d'exécution, fréquence d'occurrence.
  7. Un résumé des logs est combiné avec des documents de la base de connaissances locale, et le LLM génère une réponse finale : > « Au cours des dernières 24 heures, 12 échecs de connexion à la base de données ont été détectés pour payment-service, principalement vers 3h du matin. Il est recommandé de vérifier si un basculement principal/secondaire a causé une brève indisponibilité et de confirmer que le nombre maximal de connexions du pool est supérieur à 20. Voir la section 5 du document Optimisation des connexions DB en scénarios à haute concurrence pour plus de détails. »

Ce processus implique plusieurs modules techniques : analyse de texte, reconnaissance d'entités, construction de requêtes, appels d'API, intégration des résultats et génération de langage naturel. Le framwork LangChain offre une flexibilité d'orchestration en chaîne, permettant d'intégrer une logique personnalisée dans le flux RAG standard.

Implémentation avec LangChain et Loki

Voici un exemple de code simplifié intégrant une requête Loki dans LangChain :

import requests
from langchain_core.tools import tool
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate

@tool
def retrieve_logs_from_loki(app_label: str, error_pattern: str, time_window: int = 24) -> str:
    """Récupère les logs récents pour une application donnée."""
    logql_query = f'{{app="{app_label}"}} |= "{error_pattern}"'
    query_params = {
        "query": logql_query,
        "direction": "backward",
        "limit": 100
    }
    custom_headers = {"X-Scope-OrgID": "tenant-x"}  # Support multi-locataire
    api_response = requests.get("http://loki:3100/loki/api/v1/query", params=query_params, headers=custom_headers)

    if api_response.status_code != 200:
        return f"Échec de la requête : {api_response.text}"

    result_data = api_response.json()
    log_streams = result_data.get("data", {}).get("result", [])

    if not log_streams:
        return "Aucun log correspondant trouvé."

    log_entries = []
    for stream in log_streams:
        values = stream.get("values", [])
        for timestamp, log_line in values[:5]:  # Limiter pour éviter la surcharge
            log_entries.append(f"[{timestamp}] {log_line}")

    return "\n".join(log_entries)

# Configuration de l'agent
tools = [retrieve_logs_from_loki]
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "Tu es un assistant d'exploitation intelligent. Utilise les outils pour interroger les logs. Réponds en français."),
    ("placeholder", "{chat_history}"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}")
])

agent = create_tool_calling_agent(llm, tools, prompt_template)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Exemple d'utilisation
result = agent_executor.invoke({
    "input": "payment-service a-t-il rencontré des problèmes de connexion à la base de données récemment ?"
})
print(result["output"])

Notes techniques :

  • Pour l'extraction d'entités, combiner des modèles de règles avec un modèle NER léger (comme spaCy pour le français) améliore la généralisation.
  • Les mots-clés sensibles (ex : mot de passe, jeton) doivent être désactivés ou interdits dans les requêtes.
  • Implémenter un cache de requêtes (ex : Redis) évite une surcharge inutile de Loki.
  • En environnement multi-locataire, la balise X-Scope-OrgID assure l'isolation des données.

Considérations architecturales

1. Latence des requêtes et expérience utilisateur

Les requêtes Loki prennent généralement de quelques centaines de millisecondes à quelques secondes, surtout avec de gros volumes. Pour maintenir une réponse rapide, afficher un indicateur de chargement (ex : « Recherche des logs en cours... ») et prioriser les solutions générales de la base de connaissances comme réponse par défaut.

2. Risque d'explosion des balises

Les performances de Loki dépendent fortement du choix des balises. Autoriser la saisie libre de noms de services ou d'IP peut entraîner des balises à haute cardinalité, causant une inflation des index. Une bonne pratique consiste à maintenir une liste contrôlée de services ou à convertir les requêtes floues en combinaisons de balises fixes.

3. Contrôle des limites de sécurité

L'accès aux logs doit être strictement limité. Exemples :

  • Interdire les requêtes sur les logs contenant des champs sensibles (ex : {level="debug"} |= "password").
  • Attribuer des permissions par rôle : les développeurs n'accèdent qu'aux logs de l'environnement de test.
  • Enregistrer les opérations sensibles dans un journal d'audit pour la traçabilité.

L'intégration avec les mécanismes RBAC et la gestion des locataires de Loki permet une gouvernance fine.

4. Boucle de rétroaction des connaissances

Chaque résolution réussie peut être capitalisée comme une nouvelle connaissance. Par exemple, après avoir identifié une erreur et fourni une solution, le système peut automatiquement archiver un résumé du cas dans la base de connaissances pour une réutilisation future, créant ainsi un cycle vertueux : problème → analyse → résolution → archivage.

Extensions vers des scénarios avancés

Avec l'accès en langage naturel aux logs, des applications sophistiquées deviennent possibles :

  • Hypothèse de cause racine : En combinant les tendances des métriques Prometheus (ex : pic d'utilisation CPU), corréler automatiquement les événements anormaux dans les logs pour déterminer s'ils sont causés par une tâche par lots spécifique.
  • Explication des alertes : Lorsqu'un utilisateur clique sur une notification d'alerte Grafana et demande « Que signifie cette alerte ? », le système peut expliquer la règle et fournir des exemples historiques de traitement.
  • Accueil des nouveaux collaborateurs : En réponse à « Comment redémarrer le service de passerelle ? », fournir non seulement le manuel opérationnel, mais aussi les enregistrements récents de redémarrages et les précautions (ex : « Éviter pendant les heures de pointe le matin »).

Ces capacités incarnent les piliers de l'AIOps (Ops intelligents) : passage de la réaction à l'anticipation, et de l'expérience idnividuelle à l'intelligence collective de l'organisation.

Étiquettes: langchain Chatchat Grafana Loki LogQL rag

Publié le 2 juillet à 16h11