Accueil / Articles

Agents profonds avec SKILL.md : un orchestrateur LangChain qui charge les compétences

Créer un agent profond générique avec LangChain qui parcourt un dossier de compétences, dirige le traitement selon les descriptions SKILL.md, partage la mémoire AGENTS.md, et acquiert de nouvelles capacités sans modification de code.

Éditeur : REACTAPP.TOP8 min de lecture1811 mots

Sources: Building Deep Agents + SKILL.md with Langchain

Que se passerait-il si un agent ne disposait pas d’une liste fixe de capacités et devait découvrir ce qu’il pouvait faire uniquement en explorant son environnement ? C’est l’approche adoptée ici : un agent profond fonctionnel dans LangChain qui charge les fichiers SKILL.md sur demande pour répondre aux questions. Il n’y a ni chaînes de traitement codées à l’avance ni routeur personnalisé. Seul un orchestrateur générique, un dossier contenant les compétences et la bibliothèque deepagents chargée du travail complexe.

Le problème des ensembles d’outils fixes

La plupart des tutoriels LangChain suivent la même méthode : définir des outils, les lier à un modèle, construire un graphe et c’est terminé. Le résultat est un agent superficiel dont la liste de capacités est figée dans son code.

L’alternative est un orchestrateur qui ne sait pas ce qu’il peut faire avant de vérifier. Lors de l’exécution, il parcourt un répertoire skills/, ne lit d’abord que les métadonnées et charge ensuite les instructions complètes lorsque une compétence correspond à la demande. Au lieu d’encoder de manière fixe « cet agent recherche et écrit », on place research/SKILL.md et writer/SKILL.md dans un dossier, et l’agent s’occupe du reste. Demain, vous pouvez ajouter une compétence code-reviewer, et elle sera reconnue sans avoir à modifier une seule ligne de code. C’est le modèle SKILL.md appliqué à LangChain.

Comment les éléments s’assemblent

Quatre idées guident le fonctionnement de agent.py :

  1. La planification vient en premier. L’orchestrateur élabore toujours un plan, transformant l’objectif général de l’utilisateur en étapes techniques concrètes.
  • La délégation reste générique. Au lieu de spécialistes pour des rôles spécifiques, le travail est confié à un sous-agent polyvalent disposant des mêmes outils et du même accès à la bibliothèque de compétences.
  • Les connaissances sont fournies sur demande. Ni l’orchestrateur ni le sous-agent ne connaissent les flux de travail spécialisés au démarrage. Ils les découvrent grâce à SkillsMiddleware, qui révèle progressivement les compétences, et ne chargent la documentation complète qu’en cas de besoin.
  • L’espace de travail est contrôlé. Les outils et les actions basées sur des compétences sont confinés au répertoire ./workspace/ pour assurer leur persistance, tandis que le répertoire racine reste accessible pour la configuration et les compétences.
  • Tout le projet est compact, et trois fichiers suffisent pour effectuer le travail réel.

    Étape 1 : configuration du projet

    Les dépendances se trouvent dans pyproject.toml:

    # pyproject.toml
    [project]
    name = "deep-agents-langchain"
    version = "0.1.0"
    requires-python = ">=3.12"
    dependencies = [
        "deepagents>=0.4.12",
        "langchain-anthropic>=1.4.0",
        "langchain-openai>=1.1.12",
        "python-dotenv>=1.2.2",
        "streamlit>=1.55.0",
        "tavily-python>=0.7.23",
    ]
    

    Le principal est deepagents, la bibliothèque open source de LangChain qui formalise le modèle d’agent profond. Dès sa mise en place, elle vous offre des fonctionnalités de planification via write_todos, des outils pour le système de fichiers, la création de sous-agents grâce à task, une compression du contexte, ainsi que, ce qui est important, le chargement de compétences.

    Étape 2 : définir les outils

    Dans agent.py, le seul outil personnalisé est un enveloppe de recherche Tavily standard :

    import os
    from typing import Literal
    from dotenv import load_dotenv
    from langchain_anthropic import ChatAnthropic
    from langchain_openai import ChatOpenAI
    from tavily import TavilyClient
    from deepagents import create_deep_agent
    from deepagents.backends import FilesystemBackend
    load_dotenv()
    # --- Generic Tools ---
    tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
    def internet_search(
        query: str,
        max_results: int = 5,
        topic: Literal["general", "news", "finance"] = "general",
    ):
        """Search the web for current information."""
        return tavily.search(query, max_results=max_results, topic=topic)
    

    Tout le reste, c’est-à-dire la planification, les opérations d’entrée/sortie de fichiers, les sous-agents et le chargement des compétences, provient de deepagents.

    Étape 3 : l’usine d’agents

    C’est ici que tout se met en place :

    def get_deep_agent():
        model = ChatAnthropic(
            model="claude-3-5-sonnet-20240620",
            temperature=0,
        )
    return create_deep_agent(
            model=model,
            system_prompt="""You are a generic Deep Agent orchestrator.
    1. Use `write_todos` to plan complex requests.
    2. You have access to skills in the `skills/` directory.
       - You ONLY see names and descriptions initially.
       - For specialized tasks, load the matching SKILL.md first.
    3. Use the `task` tool to delegate to subagents.
    4. ALL outputs go to `./workspace/` exclusively.""",
            tools=[internet_search],
            skills=["./skills"],          # <-- This is the magic line
            memory=["./AGENTS.md"],
            backend=FilesystemBackend(root_dir="."),
            name="generic_deep_agent",
        )
    

    Trois paramètres méritent une attention plus approfondie.

    skills=[“./skills”] indique à deepagents de parcourir ce répertoire, d’analyser le frontmatter YAML de chaque fichier SKILL.md qu’il trouve et d’insérer le catalogue des compétences dans l’instruction système. L’agent voit alors quelque chose comme ceci :

    Available Skills:
    - research: "Conducts comprehensive web research on any topic..."
    - writer: "Specialized in writing high-quality content..."
    

    Pour deux compétences, le coût est d’environ 200 tokens. L’agent lit le catalogue et décide quelle compétence charger pour la demande. Il s’agit d’un routage pur basé sur un LLM, sans classificateurs, embeddings ou expressions régulières.

    memory=["./AGENTS.md"] charge les conventions au niveau du projet dans le prompt système. Il sert de contexte partagé pour l’agent principal et chaque sous-agent, une sorte de page « c’est ainsi que nous travaillons ici » pour l’équipe.

    backend=FilesystemBackend(root_dir=".") fournit à l’agent des outils de fichiers (read_file, write_file, edit_file) dont le répertoire racine est le dossier du projet, de sorte que le système de fichiers devient l’espace de travail permanent de l’agent.

    Étape 4 : écrire les compétences

    Une compétence de recherche délibérément simple :

    ---
    name: research
    description: >
      Conducts comprehensive web research on any topic using search APIs
      and web scraping. Use when the user asks for research, information
      gathering, competitive analysis, or needs current data from the web.
    license: MIT
    compatibility: Requires internet access and Tavily API key
    allowed-tools: internet_search Read Write
    ---
    # Web Research Skill
    ## Instructions
    1. Parse the research query to identify key topics.
    2. Use the `internet_search` tool to gather initial results.
    3. If results are insufficient, try alternative search queries.
    4. Synthesize findings into a structured summary.
    5. Save detailed findings to `./workspace/` as a markdown file.
    

    Et une compétence d’écriture :

    ---
    name: writer
    description: >
      Specialized in writing high-quality, creative, and technical content.
      Use when the user needs a blog post, report, technical guide,
      or any form of structured writing.
    license: MIT
    ---
    # Creative Writer Skill
    ## Instructions
    1. Review the input notes or research data provided.
    2. Define an outline (Introduction, Body, Conclusion).
    3. Use a tone appropriate for the target audience.
    4. Ensure all claims are backed by provided data.
    5. Save the final draft to `./workspace/`.
    

    Chaque fichier contient du frontmatter en YAML, qui fonctionne comme la carte d’identité de la compétence, suivi d’un corps en Markdown qui sert de manuel opérationnel. L’agent consulte le frontmatter au niveau 1 et le corps uniquement au niveau 2. Cela suit les spécifications publiées sur agentskills.io.

    Étape 5 : mémoire partagée dans AGENTS.md

    Ce fichier est toujours chargé. Il indique à chaque agent ce qu’il doit faire et comment l’équipe fonctionne :

    # Project Context: Deep Agents Demo
    ## Conventions
    - Skills are stored as directories under `skills/`.
    - Every skill must have a `SKILL.md` file.
    - Subagents should be used for complex, multi-step tasks.
    - All intermediate work goes to `./workspace/`.
    ## Known Entities
    - **Main Agent**: The orchestrator who plans and delegates.
    - **Researcher**: Specialized in web search and data aggregation.
    - **Writer**: Specialized in formatting and synthesizing information.
    

    Comment fonctionne réellement le routage

    Il n’y a ni routeur ni classificateur, car c’est l’LLM lui-même qui s’occupe du routage. Lorsque la bibliothèque crée le prompt système, elle ajoute du texte dans ce style :

    You have access to a library of skills in the `skills/` directory.
    You ONLY see names and descriptions initially.
    For any specialized task, look for matching skills and use
    `read_file` to load the SKILL.md before executing.
    Available skills:
    - research: "Conducts comprehensive web research..."
    - writer: "Specialized in writing high-quality content..."
    

    Le modèle lit le message de l’utilisateur ainsi que les descriptions des compétences, puis choisit entre appeler read_file("skills/research/SKILL.md") ou ne rien faire. Toute cette décision s’effectue au sein du processus de traitement par le transformateur, sans aucune logique externe. En d’autres termes, la description de la compétence agit comme moteur de routage ; il suffit d’une description bien rédigée, contenant des mots déclencheurs et des limites négatives.

    L’interface Streamlit

    app.py encapsule tout cela dans une interface Streamlit qui affiche en temps réel les réflexions de l’agent. La fonction stream("updates") de LangGraph génère un événement pour chaque exécution de nœud, et l’application analyse ces événements pour obtenir des appels d’outils, des indicateurs de chargement des compétences, des mises à jour du plan ainsi que la réponse finale.

    Ajouter une compétence sans aucun changement de code

    Supposons que vous souhaitiez une compétence pour l’évaluation de code. Créez un dossier à côté des autres pour la stocker :

    skills/
    ├── research/
    │   └── SKILL.md
    ├── writer/
    │   └── SKILL.md
    └── code-reviewer/
        └── SKILL.md
    

    Ensuite, écrivez son SKILL.md :

    ---
    name: code-reviewer
    description: >
      Reviews code for bugs, security issues, and best practices.
      Use when the user asks for a code review, security audit,
      or wants feedback on code quality. Do NOT use for writing
      new code or debugging runtime errors.
    license: MIT
    allowed-tools: Read Write
    ---
    # Code Review Skill
    ## Instructions
    1. Read the target file using `read_file`.
    2. Analyze for: bugs, security issues, performance, readability.
    3. Write a structured review to `./workspace/review.md`.
    

    Redémarrez l’application et l’agent saura comment examiner le code. agent.py reste inchangé, tout comme l’invite système. Vous avez simplement ajouté un dossier, rien de plus. La même approche permet d’aboutir à des agents profonds plus sophistiqués.

    Leçons tirées de cette expérience

    • Les descriptions des compétences sont plus importantes que leurs instructions. Si la description est faible, la compétence ne s’active jamais. Ajuster le champ description, avec ses mots déclencheurs et des limites négatives comme "Ne pas utiliser pour...", a pris plus de temps que d’écrire le corps de la compétence, car ce texte constitue en fait la logique de routage.
    • Le système de fichiers est sous-estimé. De nombreux tutoriels sur les agents conservent tout dans l’historique des messages, ce qui convient aux applications simples mais échoue pour les tâches à plusieurs étapes. En enregistrant les résultats intermédiaires dans ./workspace/ et en permettant aux sous-agents de les lire, on assure que toutes les parties fonctionnent correctement ensemble.
  • AGENTS.md permet de coordonner tous les éléments. Sans ce fichier, l’orchestrateur et ses sous-agents fonctionnent chacun de manière indépendante. Avec lui, ils partagent des conventions communes, connaissent la structure du projet et évitent les doubles efforts ; il s’agit d’un petit fichier ayant un impact considérable.
  • Commencez par une version générale puis spécialisez via des fichiers SKILL.md. Il est tentant d’intégrer directement les connaissances sectorielles dans le prompt du système, mais conserver l’orchestrateur généraliste et placer chaque spécialisation dans des fichiers SKILL.md rend le système modulaire et testable. Les compétences peuvent être remplacées sans avoir à modifier l’agent.
  • Ce que la version de production ajouterait

    Cette application est délibérément minimaliste. Une mise en production réelle inclurait probablement une mémoire persistante via LangMem pour le rappel épisodique et sémantique entre sessions, une intégration MCP pour des outils professionnels tels que Slack, Jira et les bases de données, des points de contrôle avec intervention humaine grâce au mécanisme d’interruption de LangGraph, une compression du contexte pour les tâches de recherche longues, ainsi que, bien sûr, davantage de compétences, chacune représentée simplement par un dossier contenant un SKILL.md.

    La direction à suivre semble claire. Concevoir des agents ne consiste pas tant à écrire plus de code qu’à rédiger de meilleurs fichiers SKILL.md. Le framework s’occupe des aspects techniques, les compétences transmettent l’expertise, et le LLM détermine quand utiliser telle ou telle compétence.