BAML vs Instrutor: Saídas de LLM Estruturadas

Saída de LLM segura do ponto de vista do tipo com BAML e Instructor

Conteúdo da página

Quando se trabalha com Modelos de Linguagem de Grande Porte em produção, obter saídas estruturadas e com segurança de tipos é crítico. Dois frameworks populares - BAML e Instructor - abordam esse problema de formas diferentes.

Essa comparação ajuda você a escolher a ferramenta certa para suas aplicações Python LLM.

circular-flow

Entendendo os Desafios das Saídas Estruturadas

LLMs geram naturalmente texto não estruturado, mas as aplicações modernas precisam de dados previsíveis e parseá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 livres.

Ambos, BAML e Instructor, abordam esse desafio, mas com filosofias fundamentalmente diferentes: BAML usa uma abordagem baseada em contrato com geração de código, enquanto 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ídas estruturadas entre diferentes provedores de LLM, entender esses frameworks torna-se ainda mais valioso.

BAML: Linguagem Específica de Domínio para LLMs

BAML (BoundaryML’s language) introduz uma linguagem de domínio específico dedicada à definição de interações com LLMs. Você escreve arquivos .baml que declaram seus prompts, tipos e funções, depois o BAML gera código de cliente seguro de tipos para múltiplos idiomas, incluindo Python.

Recursos Principais do BAML

Segurança de Tipos em Vários Idiomas: O BAML gera clientes para Python, TypeScript e Ruby a partir das mesmas definições .baml, garantindo consistência em toda sua pilha.

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.

Ferramenta de Teste Integrada: O BAML inclui ferramentas de teste para validar o comportamento dos prompts antes do depósito, identificando problemas cedo no desenvolvimento.

Interface de Playground: O playground do BAML permite que você itere sobre os 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 #"
    Extraia informações da pessoa de: {{ text }}
    Retorne dados estruturados.
  "#
}

O cliente gerado em Python fornece acesso seguro 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")
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 formas de dados em limites de idiomas.

Instructor: Framework Nativo do Python

O Instructor adota uma abordagem baseada no Python, estendendo modelos Pydantic com capacidades de LLM. Sua sintaxe é natural para desenvolvedores de Python que já usam Pydantic para validação e dicas de tipo.

Recursos Principais do Instructor

Zero Boilerplate: O Instructor funciona diretamente com seus modelos Pydantic existentes usando decoradores simples. Nenhuma geração de código ou etapas de construção são necessárias.

Validação Rica: Aproveite a completa ecologia de validação do Pydantic — validadores personalizados, restrições de campo, campos computados e estruturas aninhadas complexas.

Suporte a Múltiplos Provedores: Funciona de forma fluida com OpenAI, Anthropic, Google e Ollama através de uma interface unificada.

Suporte a Streaming: Suporte de primeira classe para respostas de streaming com atualizações incrementais dos modelos Pydantic.

Lógica de Recuperação: Mecanismos integrados de recuperação 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="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")

# Patches o 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"Extraia as informações da pessoa: {text}"}
    ]
)

print(f"{result.name} tem {result.age} anos")
print(f"Habilidades: {', '.join(result.skills)}")

A força do Instructor reside em sua simplicidade e integração com a ecologia do Python. Se você já está usando Pydantic, a curva de aprendizado é mínima. Para desenvolvedores novos no Python ou que precisam de referência rápida para padrões específicos do Python, nosso cheatsheet do Python fornece recordações úteis de sintaxe ao lado desses frameworks.

Comparação Detalhada: BAML vs Instructor

Experiência de Desenvolvimento

BAML requer uma etapa adicional de construção e configuração de ferramentas. Você escreve arquivos .baml, executa o gerador, depois 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 fricção de configuração — instale com pip e você já 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 fornece verificação de tipo 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 idiomas é garantida, pois o mesmo arquivo .baml gera clientes para todos os idiomas suportados.

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 aparecem durante a execução. Isso é padrão para 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 APIs externas. Para uma imersão mais profunda em 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 trabalha 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:11线434/v1",
    api_key="ollama"  # chave dummy
))

Note 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 Recuperação

BAML lida com recuperação no nível do framework com estratégias configuráveis. Erros na validação de esquema desencadeiam reprompting automático com contexto de erro.

Instructor fornece lógica de recuperação decorativa com ganchos para comportamento personalizado. Você pode definir validadores que desencadeiem recuperação 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 dos prompts em diferentes entradas. O playground fornece depuração visual.

Instructor integra-se com os frameworks de teste padrão do Python. Você pode usar fixtures do pytest, bibliotecas de mocking e ajudantes de asserção como qualquer código Python.

Considerações sobre Desempenho

O desempenho em tempo de execução é comparável — ambos os frameworks, no fim, fazem as mesmas chamadas de API do LLM. O overhead para validação e parsing é insignificante em comparação com a latência de rede e o tempo de inferência do modelo.

Velocidade de desenvolvimento difere significativamente:

  • A geração de código do BAML significa melhor autocompletar e detecção de erro mais cedo, mas requer uma etapa de construção
  • A abordagem decorativa 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 BAML

Escolha o BAML quando você precisar de:

  • Suporte multilíngua: Acesso aos mesmos contratos de LLM de serviços em Python, TypeScript e Ruby
  • Desenvolvimento baseado em contrato: Desenvolvimento estilo API onde interfaces de LLM são projetadas antes da implementação
  • Colaboração em equipe: Fluxos de trabalho separados de engenharia de prompts de desenvolvimento de aplicação
  • Garantias de tipagem fortes: Verificações de tempo de compilação em toda sua pilha
  • Desenvolvimento visual de prompts: Iteração no playground de prompts

Quando Escolher Instructor

Escolha o Instructor quando você quiser:

  • Projetos exclusivamente em Python: Nenhuma necessidade de consistência entre idiomas
  • Prototipagem rápida: Configuração mínima para obter saídas estruturadas funcionando
  • Integração com Pydantic: Aproveitando modelos e validadores Pydantic existentes
  • Implantação simples: Nenhuma etapa de construção ou código gerado para gerenciar
  • Ecologia rica do Python: Usando 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 BAML para APIs orientadas ao cliente que precisam de clientes multilíngua, enquanto usa Instructor para serviços internos em Python que precisam de iteração rápida.

Você também pode migrar entre os frameworks conforme seu projeto matura — começando com o Instructor para validação rápida, depois migrando para o BAML quando precisar de suporte multilíngua ou contratos mais rígidos.

Casos de Uso Reais

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 o 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 Multimodal (Ambos)

Um sistema de agentes de IA usa o BAML para contratos de comunicação entre agentes, garantindo segurança de tipo em todo o sistema distribuído, enquanto agentes individuais usam o Instructor internamente para processamento flexível de entradas do usuário com Python nativo. Padrões semelhantes se aplicam ao construir servidores MCP em Python, onde saídas estruturadas permitem a integração confiável de ferramentas com assistentes de IA.

Caminhos de Migração e Integração

Se você já estiver usando a análise básica de JSON com LLMs, ambos os frameworks oferecem caminhos de migração diretos:

De JSON para BAML: Converta seus esquemas JSON para definições de tipo BAML, mova prompts para arquivos .baml, gere clientes e substitua a análise manual por tipos gerados.

De JSON para Instructor: Adicione modelos Pydantic que correspondam à estrutura do seu JSON, instale o instructor, patche seu cliente OpenAI e substitua a análise de JSON pelos parâmetros response_model.

Ambas as migrações podem ser incrementais — você não precisa converter seu código inteiro de uma vez.

Perspectiva Futura e Comunidade

Ambos os frameworks são ativamente desenvolvidos com comunidades fortes:

BAML (BoundaryML) se concentra em expandir o suporte a idiomas, melhorar o playground e aumentar as capacidades de teste. O apoio comercial sugere estabilidade a longo prazo.

Instructor mantém uma forte presença aberta-source com atualizações frequentes, documentação extensa e adesã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 de primeiro contrato e suporte multilíngua do BAML é adequada para equipes construindo sistemas distribuídos com requisitos de tipo rigorosos. A abordagem nativa do Python e baseada em Pydantic do Instructor se encaixa em desenvolvimento rápido e pilhas centrais em Python.

Nenhum é universalmente melhor — sua escolha depende do tamanho da sua equipe, preferências de idioma, fluxo de trabalho de desenvolvimento e requisitos de segurança de tipo. Muitas equipes encontrarão que iniciar com o Instructor para prototipagem e depois adotar o BAML para arquiteturas de multi-serviços em produção oferece o melhor de ambos os mundos.

Artigos relacionados neste site

Referências externas