BAML vs. Instructor: Saídas Estruturadas de LLMs
Saída de LLM com segurança de tipos usando BAML e Instructor
Ao trabalhar com Grandes Modelos de Linguagem (LLMs) em produção, obter saídas estruturadas e com segurança de tipos é crítico. Dois frameworks populares — BAML e Instructor — adotam abordagens diferentes para resolver este problema.
Esta comparação ajuda a escolher a ferramenta certa para suas aplicações Python com LLMs.

Compreendendo os Desafios de Saída Estruturada
Os LLMs geram naturalmente texto não estruturado, mas as aplicações modernas precisam de dados previsíveis e analisáveis. Seja você construindo chatbots, pipelines de extração de dados ou agentes de IA, você precisa de objetos JSON, tipos de dados validados e tratamento de erros — não de respostas em formato livre.
Tanto o BAML quanto o Instructor abordam este desafio, mas com filosofias fundamentalmente diferentes: o BAML utiliza uma abordagem baseada em contratos com geração de código, enquanto o Instructor aproveita o sistema de tipos do Python com validação em tempo de execução. Se você está interessado em um contexto mais amplo sobre abordagens de saída estruturada entre diferentes provedores de LLM, entender esses frameworks torna-se ainda mais valioso.
BAML: Linguagem de Domínio Específico para LLMs
O BAML (linguagem da BoundaryML) introduz uma DSL dedicada para definir interações com LLMs. Você escreve arquivos .baml que declaram seus prompts, tipos e funções, e o BAML gera código de cliente com segurança de tipos para várias linguagens, incluindo Python.
Principais Características do BAML
Segurança de Tipos em Múltiplas Linguagens: O BAML gera clientes para Python, TypeScript e Ruby a partir das mesmas definições .baml, garantindo consistência em toda a sua stack.
Controle de Versão para Prompts: Seus prompts residem em arquivos .baml, facilitando o rastreamento, revisão e teste independentemente do código da aplicação.
Framework de Testes Integrado: O BAML inclui ferramentas de teste para validar o comportamento dos prompts antes da implantação, capturando problemas cedo no desenvolvimento.
Interface Playground: O playground do BAML permite iterar sobre prompts visualmente com feedback imediato, acelerando os ciclos de desenvolvimento.
Exemplo de Implementação BAML
# Primeiro, defina seu schema em um arquivo .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.
"#
}
O cliente Python gerado fornece acesso com segurança de tipos:
from baml_client import b
from baml_client.types import Person
# Use o cliente gerado
text = "John Smith, 34, software engineer skilled in Python and Go"
result: Person = b.ExtractPerson(text)
print(f"{result.name} tem {result.age} anos de idade")
print(f"Habilidades: {', '.join(result.skills)}")
A abordagem do BAML brilha quando você tem múltiplos serviços consumindo os mesmos contratos de LLM ou quando precisa de garantias fortes sobre a forma dos dados através de fronteiras de linguagem.
Instructor: Framework Nativo do Python Baseado em Pydantic
O Instructor adota uma abordagem focada em Python, estendendo modelos Pydantic com capacidades de LLM. Parece natural para desenvolvedores Python que já utilizam Pydantic para validação e dicas de tipo.
Principais Características do Instructor
Zero Boilerplate: O Instructor trabalha diretamente com seus modelos Pydantic existentes usando decoradores simples. Não requer geração de código ou etapas de build.
Validação Rica: Aproveite todo o ecossistema de validação do Pydantic — validadores personalizados, restrições de campos, campos computados e estruturas aninhadas complexas.
Suporte a Múltiplos Provedores: Funciona perfeitamente com OpenAI, Anthropic, Google e Ollama através de uma interface unificada.
Suporte a Streaming: Suporte de primeira classe para respostas em streaming com atualizações incrementais de modelos Pydantic.
Lógica de Retentativa: Mecanismos de retentativa integrados com backoff exponencial e recuperação de erros baseada em validadores.
Exemplo de Implementação Instructor
from pydantic import BaseModel, Field
from instructor import from_openai
from openai import OpenAI
# Defina seu modelo Pydantic
class Person(BaseModel):
name: str = Field(description="Nome completo da pessoa")
age: int = Field(ge=0, le=120, description="Idade em anos")
occupation: str
skills: list[str] = Field(description="Lista de habilidades profissionais")
# Aplique o patch no cliente OpenAI
client = from_openai(OpenAI())
# Extraia dados estruturados
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} tem {result.age} anos de idade")
print(f"Habilidades: {', '.join(result.skills)}")
A força do Instructor reside em sua simplicidade e integração com o ecossistema do Python. Se você já estiver usando Pydantic, a curva de aprendizado é mínima. Para desenvolvedores novos em Python ou que precisam de referência rápida para padrões específicos do Python, nossa folha de referência do Python fornece lembretes úteis de sintaxe ao lado desses frameworks.
Comparação Detalhada: BAML vs Instructor
Experiência de Desenvolvimento
BAML requer uma etapa de build adicional e configuração de ferramentas. Você escreve arquivos .baml, executa o gerador e importa o código gerado. Isso cria uma separação clara entre engenharia de prompts e lógica de aplicação, o que pode ser benéfico para equipes maiores.
Instructor tem atrito zero de configuração — basta instalar via pip e você está pronto. Seus prompts vivem ao lado do seu código, tornando a iteração rápida mais fácil para projetos menores ou protótipos.
Segurança de Tipos e Validação
BAML oferece verificação de tipos em tempo de compilação no código gerado. Sua IDE sabe exatamente quais campos estão disponíveis antes de você executar qualquer coisa. A consistência entre linguagens é garantida, pois o mesmo arquivo .baml gera clientes para todas as linguagens suportadas.
Instructor oferece validação em tempo de execução através do Pydantic. Embora as dicas de tipo do Python forneçam suporte à IDE, os erros surgem durante a execução. Isso é padrão para o Python, mas significa menos garantia estática do que o código gerado pelo BAML.
Trabalhando com LLMs Locais
Ambos os frameworks suportam modelos locais, o que é crucial para privacidade, controle de custos e desenvolvimento offline. Ao usar Ollama ou outros provedores de LLM locais, você mantém os mesmos benefícios de saída estruturada sem dependências de API externas. Para uma análise mais profunda sobre constranger LLMs com saída estruturada usando Ollama, Qwen3, Python ou Go, esses frameworks fornecem abstrações prontas para produção sobre as APIs de nível inferior.
BAML conecta-se ao Ollama configurando o cliente no seu arquivo .baml:
# No seu arquivo .baml:
client OllamaLocal {
provider ollama
options {
model "llama2"
base_url "http://localhost:11434"
}
}
Instructor funciona com o Ollama através da API compatível com OpenAI:
from openai import OpenAI
from instructor import from_openai
client = from_openai(OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # chave fictícia
))
Observe que ao trabalhar com modelos locais, você deve estar ciente de potenciais problemas de saída estruturada com Ollama e modelos GPT-OSS, pois nem todos os modelos lidam com saídas estruturadas com a mesma confiabilidade.
Tratamento de Erros e Retentativas
BAML lida com retentativas no nível do framework com estratégias configuráveis. Erros na validação do schema disparam uma nova solicitação automática com contexto de erro.
Instructor fornece lógica de retentativa decorativa com ganchos para comportamento personalizado. Você pode definir validadores que disparam retentativas com prompts modificados:
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}]
)
Testes e Observabilidade
BAML inclui um framework de testes onde você pode escrever casos de teste diretamente em arquivos .baml, validando o comportamento do prompt em diferentes entradas. O playground oferece depuração visual.
Instructor integra-se com frameworks de teste padrão do Python. Você pode usar fixtures do pytest, bibliotecas de mocking e auxiliares de asserção como em qualquer código Python.
Considerações de Desempenho
O desempenho em tempo de execução é comparável — ambos os frameworks, em última análise, fazem as mesmas chamadas de API do LLM. A sobrecarga para validação e parsing é insignificante em comparação com a latência de rede e o tempo de inferência do modelo.
A velocidade de desenvolvimento difere significativamente:
- A geração de código do BAML significa melhor autocompletamento e detecção de erros mais cedo, mas requer uma etapa de build
- A abordagem de decorador do Instructor significa iteração mais rápida, mas descoberta de erros em tempo de execução
Para sistemas de produção processando milhões de solicitações, ambos os frameworks lidam com a carga igualmente bem. Sua escolha depende mais das preferências do fluxo de trabalho de desenvolvimento do que das características de desempenho.
Quando Escolher o BAML
Selecione o BAML quando você precisar de:
- Suporte a múltiplas linguagens: Acesso aos mesmos contratos de LLM de serviços Python, TypeScript e Ruby
- Desenvolvimento baseado em contratos: Desenvolvimento estilo API onde as interfaces de LLM são projetadas antes da implementação
- Colaboração em equipe: Separação de workflows de engenharia de prompts do desenvolvimento de aplicações
- Garantias de tipagem forte: Verificações em tempo de compilação em toda a sua stack
- Desenvolvimento visual de prompts: Iteração de prompts impulsionada pelo playground
Quando Escolher o Instructor
Escolha o Instructor quando você quiser:
- Projetos apenas em Python: Sem necessidade de consistência entre linguagens
- Prototipagem rápida: Configação mínima para fazer saídas estruturadas funcionarem
- Integração com Pydantic: Aproveitamento de modelos e validadores Pydantic existentes
- Implantação simples: Sem etapas de build ou código gerado para gerenciar
- Ecossistema Python rico: Uso de bibliotecas e padrões específicos do Python
Combinando Abordagens
Alguns projetos se beneficiam de usar ambos os frameworks. Por exemplo, você pode usar o BAML para APIs voltadas ao cliente que precisam de clientes entre linguagens, enquanto usa o Instructor para serviços internos em Python que necessitam de iteração rápida.
Você também pode fazer a transição entre frameworks conforme seu projeto amadurece — começando com o Instructor para validação rápida e, em seguida, migrando para o BAML quando precisar de suporte a linguagens mais amplo ou contratos mais estritos.
Casos de Uso do Mundo Real
Pipeline de Extração de Dados (BAML)
Um sistema de processamento de documentos usa o BAML para extrair dados estruturados de faturas, contratos e recibos. As definições .baml servem como contratos entre a equipe de ML e os serviços de backend, com clientes TypeScript para o painel web e clientes Python para processamento em lote.
Bot de Suporte ao Cliente (Instructor)
Um bot de suporte usa o Instructor para classificar tickets, extrair intenções do usuário e gerar respostas. A equipe itera rapidamente sobre prompts usando modelos Pydantic, com validadores garantindo que números de telefone, e-mails e IDs de tickets atendam aos requisitos de formato.
Agente de IA Multimodal (Ambos)
Um sistema de agente de IA usa o BAML para contratos de comunicação entre agentes, garantindo segurança de tipos em todo o sistema distribuído, enquanto agentes individuais usam o Instructor internamente para processamento flexível e nativo do Python de entradas do usuário. Padrões semelhantes se aplicam ao construir servidores MCP em Python, onde saídas estruturadas permitem integração de ferramentas confiável com assistentes de IA.
Caminhos de Migração e Integração
Se você já estiver usando parsing básico de JSON com LLMs, ambos os frameworks oferecem caminhos de migração diretos:
De JSON para BAML: Converta seus schemas JSON em definições de tipo BAML, mova os prompts para arquivos .baml, gere clientes e substitua o parsing manual por tipos gerados.
De JSON para Instructor: Adicione modelos Pydantic correspondendo à sua estrutura JSON, instale o instructor, aplique o patch no seu cliente OpenAI e substitua o parsing JSON por parâmetros response_model.
Ambas as migrações podem ser incrementais — você não precisa converter toda a sua base de código de uma vez.
Perspectivas Futuras e Comunidade
Ambos os frameworks são desenvolvidos ativamente com comunidades fortes:
BAML (BoundaryML) foca em expandir o suporte a linguagens, melhorar o playground e aprimorar as capacidades de teste. O apoio comercial sugere estabilidade a longo prazo.
Instructor mantém uma forte presença de código aberto com atualizações frequentes, documentação extensa e adoção crescente. O projeto é bem mantido por Jason Liu e colaboradores.
Conclusão
O BAML e o Instructor representam duas abordagens excelentes, mas distintas, para saídas estruturadas de LLMs. A filosofia de contrato primeiro e multi-linguagem do BAML se adequa a equipes construindo sistemas distribuídos com requisitos de tipo estritos. A abordagem nativa do Python e baseada em Pydantic do Instructor se encaixa no desenvolvimento rápido e stacks centrados em Python.
Nenhum é universalmente melhor — sua escolha depende do tamanho da sua equipe, preferências de linguagem, fluxo de trabalho de desenvolvimento e requisitos de segurança de tipos. Muitas equipes descobrirão que começar com o Instructor para prototipagem e, em seguida, adotar o BAML para arquiteturas de produção de múltiplos serviços, oferece o melhor dos dois mundos.
Links Úteis
Artigos relacionados neste site
- Constranger LLMs com Saída Estruturada: Ollama, Qwen3 & Python ou Go
- Comparação de saída estruturada entre provedores populares de LLM - OpenAI, Gemini, Anthropic, Mistral e AWS Bedrock
- Problemas de Saída Estruturada do Ollama GPT-OSS
- Construindo Servidores MCP em Python: WebSearch & Scrape
- Folha de Referência do Python
- Folha de Referência do Ollama