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

Compreendendo os Desafios das Saídas Estruturadas
Os LLMs geram naturalmente texto não estruturado, mas os aplicativos modernos 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 “contrato primeiro” 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ê estiver interessado em um contexto mais amplo sobre abordagens de saída estruturada em diferentes provedores de LLM, entender esses frameworks torna-se ainda mais valioso. Para validação, recusas e fixtures do pytest abaixo de qualquer camada de framework, consulte Validação de saída estruturada de LLM em Python que se sustenta.
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 então o BAML gera código cliente com segurança de tipos para várias linguagens, incluindo Python.
Principais Recursos do BAML
Segurança de Tipos entre Linguagens: O BAML gera clientes para Python, TypeScript e Ruby a partir das mesmas definições .baml, garantindo consistência em toda a sua pilha tecnológica.
Controle de Versão para Prompts: Seus prompts vivem em arquivos .baml, tornando-os fáceis de rastrear, revisar e testar independentemente do código da aplicação.
Framework de Teste Integrado: O BAML inclui ferramentas de teste para validar o comportamento dos prompts antes da implantação, identificando problemas precocemente no desenvolvimento.
Interface de Playground: O playground do BAML permite iterar sobre prompts visualmente com feedback imediato, acelerando os ciclos de desenvolvimento.
Exemplo de Implementação do BAML
# Primeiro, defina seu esquema 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} is {result.age} years old")
print(f"Skills: {', '.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 as formas dos dados através de fronteiras de linguagens.
Instructor: Framework Python Nativo com Pydantic
O Instructor adota uma abordagem centrada no Python, estendendo modelos Pydantic com capacidades de LLM. Parece natural para desenvolvedores Python que já usam Pydantic para validação e dicas de tipo.
Principais Recursos 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 compilação.
Validação Rica: Aproveite todo o ecossistema de validação do Pydantic — validadores personalizados, restrições de campo, 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 do modelo Pydantic.
Lógica de Retentativa: Mecanismos de retentativa integrados com backoff exponencial e recuperação de erros baseada em validadores.
Exemplo de Implementação do 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="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 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} is {result.age} years old")
print(f"Skills: {', '.join(result.skills)}")
A força do Instructor reside em sua simplicidade e integração com o ecossistema Python. Se você já usa Pydantic, a curva de aprendizado é mínima. Para desenvolvedores novos em Python ou que precisam de uma referência rápida para padrões específicos do Python, nosso guia de referência Python fornece lembretes úteis de sintaxe ao lado destes frameworks.
Comparação Detalhada: BAML vs Instructor
Experiência de Desenvolvimento
BAML requer uma etapa de compilação adicional e configuração de ferramentas. Você escreve arquivos .baml, executa o gerador e então 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 zero atrito de configuração — instale via pip e você está pronto. Seus prompts vivem junto com seu código, facilitando iterações rápidas para projetos menores ou protótipos.
Segurança de Tipos e Validação
BAML fornece verificação de tipos em tempo de compilação no código gerado. Seu 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 ao 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 do 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 externa. Para uma análise mais aprofundada sobre restringir LLMs com saída estruturada usando Ollama, Qwen3 e 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 em seu arquivo .baml:
# Em 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 possíveis 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 esquema acionam re-prompting automático com contexto de erro.
Instructor fornece lógica de retentativa decorativa com ganchos para comportamento personalizado. Você pode definir validadores que acionam 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 teste onde você pode escrever casos de teste diretamente em arquivos .baml, validando o comportamento do prompt através de diferentes entradas. O playground fornece depuração visual.
Instructor integra-se com frameworks de teste Python padrão. Você pode usar fixtures do pytest, bibliotecas de mock 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 ultimately fazem as mesmas chamadas de API do LLM. O overhead para validação e análise é negligenciável em comparação com a latência da 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 autocompletar e detecção de erros mais cedo, mas requer uma etapa de compilação
- A abordagem de decoradores 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 de fluxo de trabalho de desenvolvimento do que das características de desempenho.
Quando Escolher o BAML
Selecione o BAML quando você precisar de:
- Suporte multi-linguagem: Acessar os mesmos contratos de LLM de serviços Python, TypeScript e Ruby
- Desenvolvimento “contrato primeiro”: Desenvolvimento estilo API onde as interfaces de LLM são projetadas antes da implementação
- Colaboração em equipe: Separar fluxos de trabalho de engenharia de prompts do desenvolvimento de aplicações
- Garantias de tipagem forte: Verificações em tempo de compilação em toda a sua pilha
- Desenvolvimento visual de prompts: Iteração orientada por playground nos prompts
Quando Escolher o Instructor
Escolha o Instructor quando você quiser:
- Projetos apenas em Python: Sem necessidade de consistência entre linguagens
- Prototipagem rápida: Configuração mínima para fazer saídas estruturadas funcionarem
- Integração com Pydantic: Aproveitar modelos e validadores Pydantic existentes
- Implantação simples: Sem etapas de compilação ou código gerado para gerenciar
- Ecossistema Python Rico: Usar bibliotecas e padrões específicos do Python
Combinando Abordagens
Alguns projetos se beneficiam do uso de ambos os frameworks. Por exemplo, você pode usar o BAML para APIs voltadas ao cliente que precisam de clientes multi-linguagem, enquanto usa o Instructor para serviços internos Python que precisam de iteração rápida.
Você também pode transitar entre frameworks à medida que seu projeto amadurece — começando com o Instructor para validação rápida e depois migrando para o BAML quando precisar de suporte a linguagens mais amplos ou contratos mais rigorosos.
Casos de Uso no 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 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 ticket atendam aos requisitos de formato.
Agente de IA Multi-Modal (Ambos)
Um sistema de agente de IA usa o BAML para contratos de comunicação básicos 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.
Migração e Caminhos de Integração
Se você já está usando análise básica de JSON com LLMs, ambos os frameworks oferecem caminhos de migração straightforward:
De JSON para BAML: Converta seus esquemas JSON para definições de tipo BAML, mova os prompts para arquivos .baml, gere clientes e substitua a análise manual por tipos gerados.
De JSON para Instructor: Adicione modelos Pydantic correspondendo à sua estrutura JSON, instale o instructor, faça patch no seu cliente OpenAI e substitua a análise de 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 ativamente desenvolvidos com comunidades fortes:
BAML (BoundaryML) foca em expandir o suporte a linguagens, melhorar o playground e aprimorar as capacidades de teste. O respaldo comercial sugere estabilidade a longo prazo.
Instructor mantém uma forte presença open-source com atualizações frequentes, documentação extensa e adoção crescente. O projeto é bem mantido por Jason Liu e colaboradores.
Conclusão
BAML e Instructor representam duas abordagens excelentes, mas distintas, para saídas estruturadas de LLMs. A filosofia “contrato primeiro” e multi-linguagem do BAML atende equipes que constroem sistemas distribuídos com requisitos rigorosos de tipo. A abordagem nativa do Python e baseada em Pydantic do Instructor se encaixa no desenvolvimento rápido e em pilhas centradas no 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 depois adotar o BAML para arquiteturas de produção multi-serviço oferece o melhor dos dois mundos.
Links Úteis
Artigos relacionados neste site
- Restringindo 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 com Ollama GPT-OSS
- Construindo Servidores MCP em Python: WebSearch & Scrape
- Guia de Referência Python
- Guia de Referência Ollama