Comment ajouter des skills LangChain à votre agent IA ?

On ajoute des skills LangChain en les séparant du prompt principal, puis en les chargeant seulement quand l’agent en a besoin. Ça évite les prompts énormes, ça baisse les tokens, et ça rend l’agent plus propre. Je vous montre le pattern avec Excel et PowerPoint.

Que sont les skills LangChain ?

Les skills LangChain, je les vois comme des petits dossiers de consignes que l’agent peut ouvrir uniquement quand il en a besoin. Au lieu de mettre toutes les règles dans le prompt système, on découpe les comportements spécialisés en blocs autonomes.

Un agent LangChain combine généralement trois choses : un modèle, des outils et des instructions. Le modèle raisonne, les outils exécutent des actions comme appeler une API ou interroger une base, et les instructions cadrent le comportement. Le problème arrive vite. Dès qu’on ajoute des règles métier, des formats de réponse, des exceptions, des cas clients, le prompt système devient une armoire pleine à craquer. Tout est là, tout le temps, même quand la tâche n’en a pas besoin.

Les skills changent ça. Le modèle ne garde pas tout en mémoire dès le départ. Il voit seulement un index des skills disponibles, avec leur nom et une description courte. Quand il comprend qu’une tâche demande une compétence précise, il charge le détail avec une fonction du style load_skill. C’est simple, mais ça change beaucoup de choses.

Le middleware joue le rôle de chef d’orchestre discret. Comme dans les middlewares web, il intercepte ou enrichit les échanges entre l’agent et le modèle. Il peut injecter les bonnes consignes au bon moment, sans polluer tout le contexte. Un middleware web peut ajouter une authentification ou logger une requête. Ici, il peut ajouter une skill utile avant que le modèle réponde.

Le fichier SKILL.md suit une logique assez propre. Il contient un nom, une description courte, puis des consignes détaillées. Le nom sert à identifier la compétence. La description aide le modèle à savoir quand l’utiliser. Les consignes expliquent vraiment quoi faire, quoi éviter, quel format respecter, quelles règles métier appliquer.

Chez des clients, je vois souvent la même chose : les agents ratent moins quand on isole les règles métier au lieu de les empiler dans un seul prompt géant. Ce n’est pas magique, mais c’est plus lisible, plus testable, et surtout moins confus pour le modèle.

Côté SEO et côté développeur, l’intérêt est très concret. Les prompts sont plus courts, donc on consomme moins de tokens. La maintenance devient plus simple, parce qu’on modifie une skill sans casser tout l’agent. Les consignes se contredisent moins. Et on peut créer des agents très spécialisés sans les rendre rigides ou impossibles à faire évoluer.

Approche Ce que ça donne Limite principale
Prompt géant Toutes les règles sont chargées tout le temps. Plus de tokens, plus de confusion, maintenance pénible.
Tools seuls L’agent peut agir via des fonctions ou des API. Les outils exécutent, mais ne portent pas toujours les bonnes consignes métier.
Skills chargées à la demande L’agent charge seulement les instructions utiles au bon moment. Il faut bien décrire chaque skill pour que le modèle sache quand l’utiliser.

Comment structurer les fichiers de skills ?

Je préfère garder une skill très simple à lire. Un dossier, un fichier SKILL.md, et dedans juste ce qu’il faut pour que le modèle comprenne quand l’utiliser et comment appeler les bons outils. Dans un projet, ça donne une arborescence comme ça.

skills/
  excel_reporter/
    SKILL.md
  pptx_builder/
    SKILL.md

Le haut du fichier contient un front matter YAML. YAML, c’est juste un format clé-valeur lisible par un humain. Ici, je mets name pour identifier la skill, et description pour aider le modèle à décider si cette skill est pertinente. La description doit être courte, parce qu’elle sert d’index, mais assez précise pour éviter les mauvais chargements. Trop vague, et le modèle l’appelle pour tout. Trop longue, et elle devient moins utile.

Ensuite, le corps de la skill décrit le rôle, les règles de sortie, et surtout les paramètres attendus par les outils. C’est là que j’évite les réponses floues du style “je vais créer un fichier”. Non. Je veux que l’agent appelle create_excel ou create_pptx avec les bons champs.

---
name: excel_reporter
description: Create structured Excel reports with clean sheets, numeric values kept as numbers, and a saved .xlsx file.
---
You are a spreadsheet analyst.
Use this skill when the user asks for an Excel report, a workbook, a financial table, a KPI export, or a structured spreadsheet.
Rules:
- Create one workbook with one or more sheets.
- Use short sheet names.
- First row must contain headers.
- Keep numbers as numbers, not text.
- Use dates in ISO format when dates are needed.
- Do not create empty sheets.
- Call create_excel with filename and workbook_json.
- workbook_json must contain sheets, each sheet must contain name and rows.
- After the file is created, tell the user the saved path.
---
name: pptx_builder
description: Build concise PowerPoint presentations with clear slide titles, bullet points, and a saved .pptx file.
---
You are a presentation specialist.
Use this skill when the user asks for a PowerPoint, a pitch deck, slides, or a presentation outline saved as a file.
Rules:
- Create a title slide first.
- Use short titles, ideally under 8 words.
- Use 3 to 5 bullet points per content slide.
- Keep bullet points concise.
- Adapt tone, colors, and structure to the topic when the user gives context.
- Call create_pptx with filename and slides_json.
- slides_json must contain slides, each slide must contain title and bullets.
- After the file is created, tell the user the saved path.

Le point important, c’est la précision opérationnelle. J’ai déjà vu des agents créer des “rapports Excel” avec tous les chiffres en texte. Derrière, impossible de faire une somme propre. Une bonne skill empêche ce genre de détail idiot.

Élément Rôle Erreur à éviter
Name Identifier clairement la skill. Utiliser un nom vague comme report_tool.
Description Aider le modèle à savoir quand charger la skill. Écrire une description trop large ou trop marketing.
Corps de la skill Donner le rôle, les règles, et les paramètres d’outil. Oublier le format exact attendu par create_excel ou create_pptx.

Comment coder l’agent spécialisé ?

Je code cet agent comme un petit système à outils. Le modèle ne connaît pas tout au départ. Il voit juste un index de skills, puis il charge la bonne skill avec load_skill quand il en a besoin. C’est beaucoup plus propre que de coller 50 pages d’instructions dans le prompt système.

J’installe les dépendances nécessaires. LangChain sert à créer l’agent, langchain-core à déclarer les outils, langchain-openai à appeler le modèle OpenAI, langgraph est utilisé derrière par les agents récents, python-pptx crée les PowerPoint, openpyxl crée les Excel, et pyyaml lit les métadonnées des fichiers SKILL.md.

python -m pip install -q langchain langchain-core langchain-openai langgraph python-pptx openpyxl pyyaml

Je demande toujours la clé OpenAI au runtime. Je ne la stocke pas dans le notebook, ni dans le code. Vous pouvez la créer depuis platform.openai.com/api-keys.

from pathlib import Path
import os
import getpass
import json
import yaml
from openpyxl import Workbook
from pptx import Presentation
from pptx.util import Pt
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI

# Demande la clé au runtime pour éviter de la stocker dans le notebook
if not os.environ.get('OPENAI_API_KEY'):
    os.environ['OPENAI_API_KEY'] = getpass.getpass('OpenAI API key: ')

BASE_DIR = Path.cwd()
SKILLS_DIR = BASE_DIR / 'skills'
OUTPUT_DIR = BASE_DIR / 'outputs'
SKILLS_DIR.mkdir(exist_ok=True)
OUTPUT_DIR.mkdir(exist_ok=True)

# Création des dossiers de skills
(SKILLS_DIR / 'excel_reporter').mkdir(parents=True, exist_ok=True)
(SKILLS_DIR / 'pptx_builder').mkdir(parents=True, exist_ok=True)

(SKILLS_DIR / 'excel_reporter' / 'SKILL.md').write_text('''---
name: excel_reporter
description: Create structured Excel reports with clean sheets, numeric values kept as numbers, and a saved .xlsx file.
---
You are a spreadsheet analyst.
Use this skill when the user asks for an Excel report, a workbook, a financial table, a KPI export, or a structured spreadsheet.
Rules:
- Create one workbook with one or more sheets.
- Use short sheet names.
- First row must contain headers.
- Keep numbers as numbers, not text.
- Use dates in ISO format when dates are needed.
- Do not create empty sheets.
- Call create_excel with filename and workbook_json.
- workbook_json must contain sheets, each sheet must contain name and rows.
- After the file is created, tell the user the saved path.
''', encoding='utf-8')

(SKILLS_DIR / 'pptx_builder' / 'SKILL.md').write_text('''---
name: pptx_builder
description: Build concise PowerPoint presentations with clear slide titles, bullet points, and a saved .pptx file.
---
You are a presentation specialist.
Use this skill when the user asks for a PowerPoint, a pitch deck, slides, or a presentation outline saved as a file.
Rules:
- Create a title slide first.
- Use short titles, ideally under 8 words.
- Use 3 to 5 bullet points per content slide.
- Keep bullet points concise.
- Adapt tone, colors, and structure to the topic when the user gives context.
- Call create_pptx with filename and slides_json.
- slides_json must contain slides, each slide must contain title and bullets.
- After the file is created, tell the user the saved path.
''', encoding='utf-8')

def read_skill_file(path: Path) -> dict:
    text = path.read_text(encoding='utf-8')
    if text.startswith('---'):
        parts = text.split('---', 2)
        meta = yaml.safe_load(parts[1])
        body = parts[2].strip()
    else:
        meta = {}
        body = text.strip()
    return {
        'name': meta.get('name', path.parent.name),
        'description': meta.get('description', ''),
        'body': body,
        'path': str(path)
    }

def load_all_skills(skills_dir: Path) -> dict:
    skills = {}
    for skill_file in skills_dir.glob('*/SKILL.md'):
        skill = read_skill_file(skill_file)
        skills[skill['name']] = skill
    return skills

SKILLS = load_all_skills(SKILLS_DIR)

def build_skill_index(skills: dict) -> str:
    lines = []
    for skill in skills.values():
        lines.append(f'- {skill["name"]}: {skill["description"]}')
    return '\n'.join(lines)

@tool
def load_skill(name: str) -> str:
    '''Load the full instructions for a skill by name.'''
    skill = SKILLS.get(name)
    if not skill:
        return f'Skill not found: {name}'
    return skill['body']

@tool
def create_excel(filename: str, workbook_json: str) -> str:
    '''Create an Excel file. workbook_json must contain sheets with name and rows.'''
    if not filename.endswith('.xlsx'):
        filename = filename + '.xlsx'
    safe_path = OUTPUT_DIR / Path(filename).name
    data = json.loads(workbook_json)
    wb = Workbook()
    default_sheet = wb.active
    wb.remove(default_sheet)
    for sheet_data in data.get('sheets', []):
        sheet_name = str(sheet_data.get('name', 'Sheet'))[:31]
        ws = wb.create_sheet(title=sheet_name)
        for row in sheet_data.get('rows', []):
            ws.append(row)
    wb.save(safe_path)
    return f'Excel file created: {safe_path}'

@tool
def create_pptx(filename: str, slides_json: str) -> str:
    '''Create a PowerPoint file. slides_json must contain slides with title and bullets.'''
    if not filename.endswith('.pptx'):
        filename = filename + '.pptx'
    safe_path = OUTPUT_DIR / Path(filename).name
    data = json.loads(slides_json)
    prs = Presentation()
    for index, slide_data in enumerate(data.get('slides', [])):
        layout = prs.slide_layouts[0] if index == 0 else prs.slide_layouts[1]
        slide = prs.slides.add_slide(layout)
        slide.shapes.title.text = slide_data.get('title', 'Slide')
        if index == 0:
            subtitle = slide.placeholders[1]
            subtitle.text = 'Generated by LangChain agent'
        else:
            body = slide.placeholders[1].text_frame
            body.clear()
            for bullet in slide_data.get('bullets', []):
                paragraph = body.add_paragraph()
                paragraph.text = str(bullet)
                paragraph.level = 0
                paragraph.font.size = Pt(20)
    prs.save(safe_path)
    return f'PowerPoint file created: {safe_path}'

SYSTEM_PROMPT = f'''You are a specialized file creation agent.
You have access to these skills, but only their summaries are shown first:
{build_skill_index(SKILLS)}

When a user asks for an Excel file, load excel_reporter before calling create_excel.
When a user asks for a PowerPoint file, load pptx_builder before calling create_pptx.
Use loaded skill instructions exactly.
Always return the final saved file path to the user.
'''

model = ChatOpenAI(model='gpt-4o-mini', temperature=0)
agent = create_agent(
    model=model,
    tools=[load_skill, create_excel, create_pptx],
    system_prompt=SYSTEM_PROMPT
)

response = agent.invoke({
    'messages': [
        {
            'role': 'user',
            'content': 'Crée un fichier Excel avec un tableau de KPI marketing : sessions, leads, taux de conversion et chiffre d affaires pour janvier, février et mars.'
        }
    ]
})

print(response['messages'][-1].content)

response = agent.invoke({
    'messages': [
        {
            'role': 'user',
            'content': 'Crée une présentation PowerPoint de 5 slides pour expliquer les bénéfices des agents IA avec skills à une équipe business.'
        }
    ]
})

print(response['messages'][-1].content)

Le point important, c’est le pattern. Le prompt système expose seulement l’index des skills, donc le nom et la description. Le contenu complet reste dans les fichiers SKILL.md. Il n’entre dans le raisonnement que si l’agent appelle load_skill.

J’aime bien cette approche parce qu’elle évite le prompt géant, difficile à maintenir. Chez un client, on avait une trentaine de “modes opératoires” métier. En les transformant en skills chargeables à la demande, l’agent est devenu plus stable et surtout plus lisible côté debug.

Les outils create_excel et create_pptx sont aussi essentiels. Ce ne sont pas des instructions vagues. Ce sont de vrais outils Python qui sauvegardent des fichiers dans outputs. Ça évite le grand classique du modèle qui dit “voici votre fichier” alors que rien n’existe sur le disque.

Quelles bonnes pratiques garder ?

Une bonne skill LangChain, c’est un outil que l’agent comprend vite et qu’on peut tester sans lancer toute l’usine. J’ai vu trop de projets où une skill fait Excel, PowerPoint, du résumé, de la validation métier et presque le café. Ça marche deux jours, puis ça devient impossible à maintenir.

Je garde une règle simple : une skill = une responsabilité claire. excel_reporter s’occupe des classeurs Excel, des feuilles, des formules, des formats et des exports. pptx_builder s’occupe des slides, des titres, des visuels et de la mise en page. Et rien d’autre. Si l’agent doit choisir, il doit avoir un choix évident.

Les règles qui évitent 80% des problèmes sont assez simples :

  • Gardez le nom de la skill stable, parce que l’agent apprend à s’appuyer dessus dans ses raisonnements.
  • Écrivez une description orientée intention utilisateur, pas une description technique floue. Par exemple : “Créer un fichier Excel avec tableaux et graphiques” est plus utile que “Manipule des données”.
  • Évitez les consignes contradictoires. Une skill ne peut pas “faire court” et “tout détailler” en même temps.
  • Conservez les nombres en nombres dans Excel, pas en texte, sinon les filtres, sommes et graphiques deviennent bancals.
  • Limitez les bullet points dans PowerPoint. Une slide n’est pas un document Word déguisé.
  • Adaptez le thème et la police si le contexte le justifie, surtout pour un rendu client ou comité de direction.
  • Retournez toujours le chemin du fichier créé, sinon l’utilisateur ne sait pas quoi récupérer.

Côté sécurité, je suis assez strict. Je ne sauvegarde jamais la clé OpenAI dans le notebook. Je la passe via une variable d’environnement ou un gestionnaire de secrets. Je n’accepte pas non plus un chemin fichier brut envoyé par l’utilisateur, du genre “../../private”. Les sorties vont dans un dossier contrôlé, par exemple outputs, et la skill construit elle-même le nom du fichier.

Pour tester, je commence simple. Je demande un Excel avec trois lignes de ventes, je vérifie le fichier, les types de données et le chemin retourné. Puis je demande une présentation PowerPoint courte. Puis je teste une demande ambiguë, comme “Prépare-moi un support avec les chiffres”. Là, je regarde si l’agent charge la bonne skill ou s’il hésite. C’est souvent là que les descriptions faibles se voient.

Point à vérifier Pourquoi Signal d’alerte
Nom stable Permet à l’agent d’appeler le bon outil. Le nom change entre deux versions.
Description claire Aide l’agent à choisir selon l’intention utilisateur. La skill est appelée pour des tâches hors sujet.
Sortie contrôlée Réduit les risques fichier et simplifie la récupération. Le chemin vient directement de l’utilisateur.
Fichier vérifiable Permet de tester la skill seule. Le fichier est créé mais inutilisable.
Clé API protégée Évite les fuites de secrets. La clé est écrite dans le notebook.

Et si votre agent arrêtait de tout garder en mémoire ?

Ajouter des skills LangChain, c’est surtout arrêter de mettre toute l’intelligence dans un seul prompt système. Je garde un index léger, je range les consignes spécialisées dans des fichiers SKILL.md, puis je laisse l’agent charger la bonne skill au bon moment. Avec Excel et PowerPoint, on voit bien l’intérêt : les règles restent propres, les outils créent vraiment les fichiers, et l’utilisateur récupère un chemin exploitable. C’est simple, mais ça change beaucoup la maintenance. Vous gagnez un agent plus fiable, moins coûteux en tokens, et plus facile à faire évoluer.

FAQ

  • À quoi servent les skills LangChain ?
    Elles servent à isoler des consignes spécialisées dans des fichiers séparés. L’agent ne charge le détail que quand la tâche le demande. C’est plus propre qu’un énorme prompt système.
  • Quelle différence entre une skill et un tool LangChain ?
    Une skill décrit comment raisonner ou produire un résultat dans un contexte précis. Un tool exécute une action réelle, comme créer un fichier Excel ou sauvegarder une présentation PowerPoint.
  • Pourquoi utiliser un fichier SKILL.md ?
    Parce qu’il garde les instructions lisibles, versionnables et faciles à modifier. On peut ajouter ou corriger une compétence sans réécrire tout le prompt de l’agent.
  • Est-ce que les skills réduisent les coûts en tokens ?
    Oui, dans beaucoup de cas. L’agent voit d’abord seulement le nom et la description des skills. Le contenu complet n’est injecté que si la tâche en a besoin.
  • Peut-on utiliser ce pattern en production ?
    Oui, à condition de tester chaque skill, de sécuriser les chemins de sortie, de ne pas stocker les clés API dans le code, et de connecter les skills à de vrais outils qui produisent des résultats vérifiables.

 

 

A propos de l’auteur

Je suis Franck Scandolera, expert et formateur en Tracking avancé server-side, Analytics Engineering, automatisation No/Low Code avec n8n, intégration de l’IA en entreprise et SEO/GEO. J’accompagne des équipes sur des sujets très concrets : data propre, agents IA utiles, automatisations maintenables, tracking fiable. J’ai travaillé avec Logis Hôtel, Yelloh Village, BazarChic, la Fédération Française de Football, Texdecor et d’autres. Je dirige l’agence webAnalyste et l’organisme Formations Analytics. Si vous voulez industrialiser vos agents IA ou vos automatisations sans usine à gaz, contactez-moi.

Retour en haut