Como usar o Instructor para extrair dados estruturados de LLMs
1. Introdução ao Instructor e sua importância na extração estruturada
O Instructor é uma biblioteca Python que revoluciona a forma como extraímos dados estruturados de Large Language Models (LLMs). Em vez de depender de prompts verbosos e parsing manual de JSON, o Instructor permite definir esquemas de dados com Pydantic e garante que a saída do modelo seja validada automaticamente.
Em sistemas de produção, a extração estruturada é essencial para automação, integração com APIs legadas e manutenção de consistência entre sistemas. Abordagens tradicionais como prompts com "responda em JSON" frequentemente falham devido a inconsistências de formatação, campos ausentes ou valores fora do tipo esperado. O Instructor resolve isso ao aplicar validação rigorosa e re-prompt automático quando a saída não corresponde ao esquema definido.
2. Instalação, configuração básica e primeiros passos
A instalação é simples via pip:
pip install instructor pydantic
Para dependências específicas de provedores:
pip install instructor[openai] # Para OpenAI
pip install instructor[anthropic] # Para Anthropic
pip install instructor[ollama] # Para Ollama local
Configuração básica com OpenAI:
import instructor
from openai import OpenAI
from pydantic import BaseModel
# Configura o cliente
client = instructor.from_openai(OpenAI())
# Define o modelo de saída
class Pessoa(BaseModel):
nome: str
idade: int
# Extrai dados de um texto não estruturado
texto = "João tem 28 anos e mora em São Paulo."
pessoa = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Pessoa,
messages=[{"role": "user", "content": f"Extraia os dados: {texto}"}]
)
print(pessoa.nome) # João
print(pessoa.idade) # 28
3. Modelagem de dados com Pydantic para definição de esquemas
A verdadeira potência do Instructor está na modelagem com Pydantic. É possível criar estruturas complexas com validações personalizadas:
from pydantic import BaseModel, Field, validator
from typing import List, Optional
from datetime import date
class Experiencia(BaseModel):
empresa: str
cargo: str
inicio: date
fim: Optional[date] = None
descricao: str = Field(..., min_length=10)
class Habilidade(BaseModel):
nome: str
nivel: str = Field(..., pattern="^(iniciante|intermediário|avançado)$")
class Curriculo(BaseModel):
nome_completo: str
email: str
telefone: Optional[str] = None
habilidades: List[Habilidade]
experiencias: List[Experiencia]
@validator('email')
def email_valido(cls, v):
if '@' not in v:
raise ValueError('Email inválido')
return v
# Exemplo de extração
texto_curriculo = """
Maria Silva, maria@email.com, (11) 99999-8888
Habilidades: Python (avançado), SQL (intermediário), Docker (iniciante)
Experiência: Engenheira de Dados na DataCorp (2020-2023) - Desenvolvimento de pipelines ETL
"""
curriculo = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Curriculo,
messages=[{"role": "user", "content": f"Extraia os dados deste currículo:\n{texto_curriculo}"}]
)
4. Extração de dados com modos de resposta (JSON, Tools, Function Calling)
O Instructor suporta diferentes modos de extração, cada um com vantagens específicas:
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
class Email(BaseModel):
remetente: str
destinatario: str
assunto: str
data: datetime
corpo: str
prioridade: Optional[str] = None
# Modo JSON (mais simples)
email_json = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Email,
mode="json",
messages=[{"role": "user", "content": "Extraia os dados do email..."}]
)
# Modo tools (mais preciso para modelos que suportam function calling)
email_tools = client.chat.completions.create(
model="gpt-4",
response_model=Email,
mode="tools",
messages=[{"role": "user", "content": "Extraia os dados do email..."}]
)
# Modo function_calling (legado, compatível com versões anteriores)
email_fc = client.chat.completions.create(
model="gpt-3.5-turbo-0613",
response_model=Email,
mode="function_calling",
messages=[{"role": "user", "content": "Extraia os dados do email..."}]
)
5. Validação avançada, correção automática e iteração
Uma das funcionalidades mais poderosas é a iteração para extrair múltiplos registros:
from typing import List
from pydantic import BaseModel, Field
class ItemNota(BaseModel):
descricao: str
quantidade: int = Field(gt=0)
valor_unitario: float = Field(gt=0)
valor_total: float = Field(gt=0)
class NotaFiscal(BaseModel):
cnpj_emitente: str = Field(pattern=r'^\d{14}$')
cnpj_destinatario: str = Field(pattern=r'^\d{14}$')
valor_total: float = Field(gt=0)
itens: List[ItemNota]
# Extrai múltiplas notas de uma vez
texto_notas = """
NF 001: Emitente 11222333000181, Destinatário 44555666000199
Itens: Teclado (2x R$150,00 = R$300,00), Mouse (1x R$80,00 = R$80,00)
Total: R$380,00
NF 002: Emitente 77888999000111, Destinatário 11222333000181
Itens: Monitor (1x R$1200,00 = R$1200,00)
Total: R$1200,00
"""
# Usando Iteration para extrair múltiplos registros
from instructor import Iteration
notas = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Iteration[NotaFiscal],
messages=[{"role": "user", "content": f"Extraia todas as notas fiscais:\n{texto_notas}"}]
)
for nota in notas:
print(f"NF: {nota.cnpj_emitente} - Total: R${nota.valor_total:.2f}")
6. Integração com sistemas legados e armazenamento dos dados extraídos
Após extrair os dados, é crucial integrá-los com sistemas existentes:
import sqlite3
import json
# Conecta ao banco SQLite
conn = sqlite3.connect('crm.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS contatos (
id INTEGER PRIMARY KEY,
nome TEXT,
email TEXT,
telefone TEXT,
cargo TEXT,
empresa TEXT,
metadata TEXT
)
''')
# Extrai dados de texto de CRM
texto_crm = """
Cliente: Roberto Lima, roberto@techcorp.com, (21) 98888-7777
Cargo: CTO na TechCorp Solutions
"""
class ContatoCRM(BaseModel):
nome: str
email: str
telefone: str
cargo: str
empresa: str
contato = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=ContatoCRM,
messages=[{"role": "user", "content": f"Extraia os dados do contato:\n{texto_crm}"}]
)
# Insere no banco
cursor.execute('''
INSERT INTO contatos (nome, email, telefone, cargo, empresa, metadata)
VALUES (?, ?, ?, ?, ?, ?)
''', (
contato.nome,
contato.email,
contato.telefone,
contato.cargo,
contato.empresa,
json.dumps(contato.dict())
))
conn.commit()
conn.close()
# Exporta para CSV
import csv
with open('contatos_extraidos.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['Nome', 'Email', 'Telefone', 'Cargo', 'Empresa'])
writer.writerow([contato.nome, contato.email, contato.telefone, contato.cargo, contato.empresa])
7. Boas práticas, limitações e otimização de custos
Para obter melhores resultados, siga estas práticas:
# Boa prática: prompts claros e específicos
prompt_eficaz = """
Extraia os dados estruturados do seguinte texto.
Seja preciso e não invente informações.
Texto: {texto}
"""
# Estratégia de cache para reduzir custos
import hashlib
import json
cache = {}
def extrair_com_cache(texto, modelo):
hash_texto = hashlib.md5(texto.encode()).hexdigest()
if hash_texto in cache:
return cache[hash_texto]
resultado = client.chat.completions.create(
model=modelo,
response_model=modelo,
messages=[{"role": "user", "content": prompt_eficaz.format(texto=texto)}]
)
cache[hash_texto] = resultado
return resultado
Limitações importantes:
- Modelos pequenos (GPT-3.5-turbo) podem falhar em extrações complexas
- Ambiguidade em textos mal escritos reduz a precisão
- Custo por token pode ser alto para extrações em larga escala
- Latência aumenta com esquemas muito complexos
8. Casos de uso reais e próximos passos
O Instructor é ideal para:
- Extração de dados de contratos jurídicos
- Processamento de formulários escaneados
- Análise de logs de sistemas
- Estruturação de e-mails não formatados
- Extração de dados de documentos financeiros
Comparado com alternativas como LangChain e LlamaIndex, o Instructor oferece maior simplicidade e validação mais rigorosa. Enquanto JSON mode nativo dos LLMs requer parsing manual, o Instructor automatiza todo o processo.
Próximos passos incluem integração com agentes como CrewAI para pipelines autônomos, uso com plataformas no-code como Dify, e combinação com bancos vetoriais para memória de longo prazo.
Referências
- Documentação Oficial do Instructor — Guia completo com exemplos, modos de extração e integrações com diferentes LLMs
- Pydantic Documentation - Models — Referência oficial sobre modelagem de dados com Pydantic, base do Instructor
- OpenAI Function Calling Guide — Documentação oficial sobre function calling, utilizado pelo Instructor em modo tools
- Instructor GitHub Repository — Código-fonte, issues, exemplos avançados e contribuições da comunidade
- Tutorial: Extração Estruturada com Instructor — Curso prático da DeepLearning.AI sobre extração de dados com LLMs
- Anthropic Claude Tool Use Documentation — Documentação sobre uso de ferramentas com Claude, compatível com Instructor
- SQLite Python Documentation — Referência oficial para integração de dados extraídos com bancos SQLite