BAML vs Instructor : Sorties structurées des LLM
Sorties de LLM type-sûres avec BAML et Instructor
Lors de l’utilisation de grands modèles de langage en production, obtenir des sorties structurées et de type sûr est essentiel. Deux frameworks populaires - BAML et Instructor - adoptent des approches différentes pour résoudre ce problème.
Cette comparaison vous aide à choisir le bon outil pour vos applications Python de LLM.

Comprendre les défis des sorties structurées
Les LLM génèrent naturellement du texte non structuré, mais les applications modernes nécessitent des données prévisibles et analysables. Que vous construisiez des chatbots, des pipelines d’extraction de données ou des agents IA, vous avez besoin d’objets JSON, de types de données validés et de gestion des erreurs - pas de réponses libres. Les deux frameworks, BAML et Instructor, abordent ce défi mais avec des philosophies fondamentalement différentes : BAML utilise une approche contractuelle avec génération de code, tandis qu’Instructor s’appuie sur le système de types Python avec validation en temps réel. Si vous êtes intéressé par un contexte plus large sur les approches de sorties structurées à travers différents fournisseurs de LLM, comprendre ces frameworks devient encore plus précieux.
BAML : Langage spécifique au domaine pour les LLM
BAML (le langage de BoundaryML) introduit un DSL dédié pour définir les interactions avec les LLM. Vous écrivez des fichiers .baml qui déclarent vos invites, types et fonctions, puis BAML génère du code client de type sûr pour plusieurs langages, y compris Python.
Fonctionnalités clés de BAML
Sécurité des types à travers les langages : BAML génère des clients pour Python, TypeScript et Ruby à partir des mêmes définitions .baml, assurant la cohérence dans votre pile technologique.
Contrôle de version pour les invites : Vos invites vivent dans des fichiers .baml, les rendant faciles à suivre, à examiner et à tester indépendamment du code de l’application.
Framework de test intégré : BAML inclut des outils de test pour valider le comportement des invites avant le déploiement, capturant les problèmes tôt dans le développement.
Interface de playground : Le playground BAML vous permet d’itérer sur les invites visuellement avec un retour immédiat, accélérant les cycles de développement.
Exemple d’implémentation BAML
# D'abord, définissez votre schéma dans un fichier .baml :
# persona.baml
class Person {
name string
age int
occupation string
skills string[]
}
function ExtractPerson(text: string) -> Person {
client GPT4
prompt #"
Extract person information from: {{ text }}
Return structured data.
"#
}
Le client Python généré fournit un accès de type sûr :
from baml_client import b
from baml_client.types import Person
# Utilisez le client généré
text = "John Smith, 34, software engineer skilled in Python and Go"
result: Person = b.ExtractPerson(text)
print(f"{result.name} is {result.age} years old")
print(f"Skills: {', '.join(result.skills)}")
L’approche de BAML brille lorsque vous avez plusieurs services consommant les mêmes contrats LLM ou lorsque vous avez besoin de garanties solides sur les formes de données à travers les frontières linguistiques.
Instructor : Framework natif Pydantic pour Python
Instructor adopte une approche centrée sur Python, étendant les modèles Pydantic avec des capacités LLM. Il est naturel pour les développeurs Python utilisant déjà Pydantic pour la validation et les indications de type.
Fonctionnalités clés de Instructor
Zéro boilerplate : Instructor fonctionne directement avec vos modèles Pydantic existants en utilisant des décorateurs simples. Aucun code généré ou étape de construction requise.
Validation riche : Profitez de l’ensemble de l’écosystème de validation de Pydantic - validateurs personnalisés, contraintes de champ, champs calculés et structures imbriquées complexes.
Support multi-fournisseur : Fonctionne de manière transparente avec OpenAI, Anthropic, Google et Ollama via une interface unifiée.
Support du streaming : Prise en charge de premier ordre pour le streaming de réponses avec des mises à jour incrémentielles du modèle Pydantic.
Logique de réessai : Mécanismes de réessai intégrés avec rétroaction exponentielle et récupération d’erreurs basée sur le validateur.
Exemple d’implémentation Instructor
from pydantic import BaseModel, Field
from instructor import from_openai
from openai import OpenAI
# Définissez votre modèle Pydantic
class Person(BaseModel):
name: str = Field(description="Full name of the person")
age: int = Field(ge=0, le=120, description="Age in years")
occupation: str
skills: list[str] = Field(description="List of professional skills")
# Patch the OpenAI client
client = from_openai(OpenAI())
# Extract structured data
text = "John Smith, 34, software engineer skilled in Python and Go"
result = client.chat.completions.create(
model="gpt-4",
response_model=Person,
messages=[
{"role": "user", "content": f"Extract person info: {text}"}
]
)
print(f"{result.name} is {result.age} years old")
print(f"Skills: {', '.join(result.skills)}")
La force d’Instructor réside dans sa simplicité et son intégration avec l’écosystème Python. Si vous utilisez déjà Pydantic, la courbe d’apprentissage est minimale. Pour les développeurs nouveaux à Python ou ayant besoin d’une référence rapide pour les motifs spécifiques à Python, notre fiche de triche Python fournit des rappels de syntaxe utiles aux côtés de ces frameworks.
Comparaison détaillée : BAML vs Instructor
Expérience de développement
BAML nécessite une étape de build supplémentaire et une configuration d’outils. Vous écrivez des fichiers .baml, exécutez le générateur, puis importez le code généré. Cela crée une séparation claire entre l’ingénierie des invites et la logique de l’application, ce qui peut être bénéfique pour les grandes équipes.
Instructor n’a aucune friction de configuration - pip install et vous êtes prêt. Vos invites vivent aux côtés de votre code, facilitant l’itération rapide pour les petits projets ou prototypes.
Sécurité des types et validation
BAML fournit une vérification de type en temps de compilation dans le code généré. Votre IDE sait exactement quels champs sont disponibles avant d’exécuter quoi que ce soit. La cohérence inter-langages est garantie puisque le même fichier .baml génère des clients pour tous les langages pris en charge.
Instructor offre une validation en temps d’exécution via Pydantic. Bien que les indications de type Python fournissent une prise en charge de l’IDE, les erreurs apparaissent pendant l’exécution. C’est standard pour Python mais signifie moins de garantie statique que le code généré de BAML.
Travail avec les LLM locaux
Les deux frameworks prennent en charge les modèles locaux, ce qui est crucial pour la confidentialité, le contrôle des coûts et le développement hors ligne. Lorsque vous utilisez Ollama ou d’autres fournisseurs de LLM locaux, vous conservez les mêmes avantages de sorties structurées sans dépendre des API externes. Pour un approfondissement sur la contrainte des LLM avec des sorties structurées en utilisant Ollama, Qwen3 et Python ou Go, ces frameworks fournissent des abstractions prêtes pour la production sur les API de bas niveau.
BAML se connecte à Ollama en configurant le client dans votre fichier .baml :
# Dans votre fichier .baml :
client OllamaLocal {
provider ollama
options {
model "llama2"
base_url "http://localhost:11434"
}
}
Instructor fonctionne avec Ollama via l’API compatible OpenAI :
from openai import OpenAI
from instructor import from_openai
client = from_openai(OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # clé factice
))
Notez que lors de l’utilisation de modèles locaux, vous devez être conscient des problèmes potentiels de sorties structurées avec Ollama et les modèles GPT-OSS, car tous les modèles ne gèrent pas les sorties structurées avec la même fiabilité.
Gestion des erreurs et réessais
BAML gère les réessais au niveau du framework avec des stratégies configurables. Les erreurs de validation de schéma déclenchent un renvoi automatique avec le contexte d’erreur.
Instructor fournit une logique de réessai décorative avec des crochets pour un comportement personnalisé. Vous pouvez définir des validateurs qui déclenchent des réessais avec des invites modifiées :
from instructor import patch
from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def extract_with_retry(text: str) -> Person:
return client.chat.completions.create(
model="gpt-4",
response_model=Person,
messages=[{"role": "user", "content": text}]
)
Test et observabilité
BAML inclut un framework de test où vous pouvez écrire des cas de test directement dans les fichiers .baml, validant le comportement des invites à travers différentes entrées. Le playground fournit un débogage visuel.
Instructor s’intègre avec les frameworks de test standard Python. Vous pouvez utiliser des fixtures pytest, des bibliothèques de mocking et des aides d’assertion comme n’importe quel code Python.
Considérations de performance
La performance en temps d’exécution est comparable - les deux frameworks effectuent finalement les mêmes appels API LLM. Le surcoût pour la validation et l’analyse est négligeable par rapport à la latence réseau et au temps d’inférence du modèle.
La vitesse de développement diffère considérablement :
- La génération de code de BAML signifie une meilleure autocomplétion et une détection d’erreurs plus précoce, mais nécessite une étape de build
- L’approche de décorateur d’Instructor signifie une itération plus rapide mais une découverte d’erreurs en temps d’exécution
Pour les systèmes de production traitant des millions de requêtes, les deux frameworks gèrent la charge de manière égale. Votre choix dépend plus des préférences de flux de travail de développement que des caractéristiques de performance.
Quand choisir BAML
Sélectionnez BAML lorsque vous avez besoin de :
- Support multi-langages : Accéder aux mêmes contrats LLM depuis des services Python, TypeScript et Ruby
- Développement contractuel : Développement de type API où les interfaces LLM sont conçues avant l’implémentation
- Collaboration d’équipe : Flux de travail séparés d’ingénierie des invites et de développement d’application
- Garanties de typage fortes : Vérifications en temps de compilation à travers toute votre pile
- Développement visuel d’invites : Itération pilotée par le playground sur les invites
Quand choisir Instructor
Choisissez Instructor lorsque vous souhaitez :
- Projets Python uniquement : Pas besoin de cohérence inter-langages
- Prototypage rapide : Configuration minimale pour faire fonctionner les sorties structurées
- Intégration Pydantic : Exploiter les modèles et validateurs Pydantic existants
- Déploiement simple : Pas d’étapes de build ou de code généré à gérer
- Écosystème Python riche : Utiliser des bibliothèques et motifs spécifiques à Python
Combinaison des approches
Certains projets bénéficient de l’utilisation des deux frameworks. Par exemple, vous pourriez utiliser BAML pour les API orientées client qui nécessitent des clients multi-langages, tout en utilisant Instructor pour les services Python internes qui nécessitent une itération rapide.
Vous pouvez également passer d’un framework à l’autre au fur et à mesure que votre projet mûrit - commencer avec Instructor pour une validation rapide, puis passer à BAML lorsque vous avez besoin d’un support linguistique plus large ou de contrats plus stricts.
Cas d’utilisation réels
Pipeline d’extraction de données (BAML)
Un système de traitement de documents utilise BAML pour extraire des données structurées à partir de factures, contrats et reçus. Les définitions .baml servent de contrats entre l’équipe ML et les services backend, avec des clients TypeScript pour le tableau de bord web et des clients Python pour le traitement par lots.
Bot de support client (Instructor)
Un bot de support utilise Instructor pour classer les tickets, extraire les intentions des utilisateurs et générer des réponses. L’équipe itère rapidement sur les invites en utilisant des modèles Pydantic, avec des validateurs garantissant que les numéros de téléphone, adresses e-mail et identifiants de tickets extraits respectent les exigences de format.
Agent IA multimodal (Les deux)
Un système d’agents IA utilise BAML pour les contrats de communication agent-à-agent, garantissant la sécurité des types dans le système distribué, tandis que les agents individuels utilisent Instructor en interne pour le traitement flexible et natif de Python des entrées utilisateur. Des schémas similaires s’appliquent lors de la construction de serveurs MCP en Python, où les sorties structurées permettent une intégration fiable d’outils avec les assistants IA.
Chemins de migration et d’intégration
Si vous utilisez déjà un parsing JSON de base avec les LLMs, les deux frameworks offrent des chemins de migration simples :
De JSON à BAML : Convertissez vos schémas JSON en définitions de types BAML, déplacez les invites dans des fichiers .baml, générez des clients et remplacez le parsing manuel par des types générés.
De JSON à Instructor : Ajoutez des modèles Pydantic correspondant à votre structure JSON, installez instructor, patcher votre client OpenAI et remplacez le parsing JSON par des paramètres response_model.
Les deux migrations peuvent être incrémentielles - vous n’avez pas besoin de convertir l’ensemble de votre codebase d’un seul coup.
Perspectives d’avenir et communauté
Les deux frameworks sont activement développés avec des communautés solides :
BAML (BoundaryML) se concentre sur l’expansion du support des langues, l’amélioration du playground et l’amélioration des capacités de test. Le soutien commercial suggère une stabilité à long terme.
Instructor maintient une forte présence open-source avec des mises à jour fréquentes, une documentation étendue et une adoption croissante. Le projet est bien maintenu par Jason Liu et les contributeurs.
Conclusion
BAML et Instructor représentent deux approches excellentes mais distinctes des sorties structurées des LLMs. La philosophie contract-first et multi-langues de BAML convient aux équipes construisant des systèmes distribués avec des exigences strictes de types. L’approche native de Python et basée sur Pydantic d’Instructor convient au développement rapide et aux stacks centrées sur Python.
Aucun n’est universellement meilleur - votre choix dépend de la taille de votre équipe, des préférences linguistiques, du flux de travail de développement et des exigences de sécurité des types. De nombreuses équipes trouveront que commencer avec Instructor pour le prototypage, puis adopter BAML pour les architectures multi-services de production, offre le meilleur des deux mondes.
Liens utiles
Articles connexes sur ce site
- Contrôler les LLMs avec des sorties structurées : Ollama, Qwen3 & Python ou Go
- Comparaison des sorties structurées parmi les principaux fournisseurs de LLMs - OpenAI, Gemini, Anthropic, Mistral et AWS Bedrock
- Problèmes de sorties structurées d’Ollama GPT-OSS
- Construction de serveurs MCP en Python : WebSearch & Scrape
- Fiche mémo Python
- Fiche mémo Ollama