Validando e Analisando Respostas Estrutadas em Python
Definir um esquema é apenas metade do trabalho - você também precisa transformar a resposta que recebe de volta em um objeto Python utilizável e saber o que fazer quando essa resposta não está completa.
Esta página cobre client.messages.parse(), o helper baseado em Pydantic que faz a validação e desserialização para você, além do caminho manual com client.messages.create() para quando você precisar de mais controle.
Resumo
client.messages.parse() é a maneira recomendada de consumir uma saída estruturada em Python: passe um esquema (tipicamente de um modelo Pydantic) e ele retorna uma resposta cuja atributo parsed_output já é uma instância validada desse modelo.
Isso substitui a sequência manual de extrair texto da resposta, chamar json.loads() e, em seguida, construir seu próprio objeto a partir do dict.
Você ainda pode usar client.messages.create() diretamente quando quiser o conteúdo bruto da resposta, por exemplo, para inspecionar stop_reason antes de decidir se a saída é segura para analisar.
Ambos os caminhos usam o mesmo output_config.format de esquema por baixo dos panos - parse() é uma camada de conveniência, não um recurso de API diferente.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
from pydantic import BaseModel
from anthropic import Anthropic
class Invoice(BaseModel):
vendor: str
total: float
currency: str
client = Anthropic()
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": Invoice.model_json_schema()}},
messages=[{"role": "user", "content": "Extrair: Acme Corp faturou $1.240,50 USD."}],
)
invoice: Invoice = response.parsed_output
print(invoice.vendor, invoice.total, invoice.currency)Quando usar isso:
- Você já tem (ou quer) um modelo Pydantic representando os dados que está extraindo.
- Você quer um objeto tipado de volta, não um dict que você tem que indexar.
- Você está construindo um pipeline onde o valor analisado será passado diretamente para outro código Python tipado.
- Você quer que a validação e a análise ocorram em uma etapa em vez de duas.
Exemplo de Trabalho
from pydantic import BaseModel, ValidationError
from anthropic import Anthropic, APIStatusError
class SupportTicket(BaseModel):
subject: str
urgency: str
customer_email: str
client = Anthropic()
def extract_ticket(raw_text: str) -> SupportTicket | None:
try:
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={
"format": {"type": "json_schema", "schema": SupportTicket.model_json_schema()}
},
messages=[{"role": "user", "content": f"Extrair campos de ticket de:\n\n{raw_text}"}],
)
except APIStatusError as e:
print(f"Erro de API: {e.status_code} {e.message}")
return None
if response.stop_reason == "max_tokens":
print("Resposta foi truncada antes de completar - não é seguro confiar.")
return None
if response.stop_reason == "refusal":
print("Claude recusou-se a produzir uma resposta para esta entrada.")
return None
return response.parsed_output
ticket = extract_ticket(
"De: jane@example.com\nAssunto: Não consigo fazer login\n\n"
"Fui bloqueado da minha conta desde esta manhã, por favor ajude o mais rápido possível."
)
if ticket:
print(ticket.subject, ticket.urgency, ticket.customer_email)O que isso demonstra:
stop_reasoné verificado antes de confiar emresponse.parsed_output, porque uma resposta truncada ou recusada não garante um valor analisado utilizável.APIStatusErrorcaptura falhas de rede/API separadamente de problemas de nível de conteúdo, como truncamento ou recusa.- A função retorna
Noneem qualquer caminho de falha em vez de deixar uma exceção de uma resposta parcialmente formada propagar inesperadamente. response.parsed_outputsó é lido depois que todas as verificações anteriores foram aprovadas.
Mergulho Profundo
Como Funciona
client.messages.parse()envia a mesma solicitação queclient.messages.create(), com o esquema construído a partir do seu modelo Pydantic (ou dict bruto) passado viaoutput_config.format.- Assim que a resposta retorna, o SDK valida o texto JSON retornado contra o esquema e constrói uma instância do modelo que você forneceu, expondo-a como
response.parsed_output. - O objeto
responsesubjacente ainda tem os mesmos campos de umMessagenormal -stop_reason,usage,content-parsed_outputé aditivo, não uma substituição. - A validação neste nível confirma que a resposta corresponde à forma descrita pelo esquema; ela não verifica se os valores estão factualmente corretos.
create() vs. parse()
client.messages.create() | client.messages.parse() | |
|---|---|---|
| Retorna | Message bruto com conteúdo de texto | Message mais um parsed_output validado |
| Você ainda faz | json.loads() e construção manual | Nada extra - já é um objeto |
| Uso Típico | Você precisa de texto bruto ou quer controle manual sobre a análise | Você tem um modelo Pydantic e quer o objeto finalizado |
Lidando com uma Resposta que Não Foi Analisada Corretamente
import json
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {"summary": {"type": "string"}},
"required": ["summary"],
"additionalProperties": False,
}
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=64, # deliberadamente pequeno - provavelmente truncará em uma resposta longa
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Escreva um resumo extremamente detalhado de vários parágrafos."}],
)
raw_text = response.content[0].text
if response.stop_reason == "max_tokens":
print("Truncado - não tente json.loads() nisso, tente novamente com mais max_tokens em vez disso.")
else:
data = json.loads(raw_text)
print(data["summary"])- Usar
create()diretamente aqui torna a verificação de truncamento explícita e visível, o que é útil quando você deseja controle total sobre o caminho de falha em vez de depender do tratamento interno deparse(). - Chamar
json.loads()em uma string conhecida como truncada levantarájson.JSONDecodeError- verificarstop_reasonprimeiro evita atingir essa exceção no fluxo de controle normal.
Notas Python
from pydantic import BaseModel, field_validator
class Invoice(BaseModel):
vendor: str
total: float
@field_validator("total")
@classmethod
def total_must_be_positive(cls, v: float) -> float:
if v < 0:
raise ValueError("total must be non-negative")
return v- Validadores Pydantic ainda são executados quando
client.messages.parse()constróiparsed_output- uma resposta válida de esquema que falha em um validador personalizado levanta umpydantic.ValidationError, que é um modo de falha distinto de uma resposta de API malformada. - Isso é útil para restrições que a camada JSON Schema não impõe (como intervalos numéricos), permitindo que Pydantic capture o que a garantia de nível de esquema não pode.
Armadilhas
- Ler
response.parsed_outputantes de verificarstop_reason. Em uma resposta truncada, o valor analisado pode estar ausente ou o próprio passo de análise pode ter falhado. Correção: verifiquestop_reason != "max_tokens"(e!= "refusal") antes de acessarparsed_output. - Assumir que
parse()ecreate()precisam de esquemas diferentes. Eles usam exatamente o mesmo esquemaoutput_config.format- a única diferença é o que o SDK faz com a resposta depois. Correção: defina o esquema uma vez e passe-o para qualquer chamada que você usar. - Não capturar
pydantic.ValidationErrorquando você tem validadores personalizados no modelo. Uma resposta válida de esquema ainda pode falhar em uma restrição de nível Pydantic, como umfield_validatorpersonalizado. Correção: envolva a chamadaparse()em umtry/exceptque capture tanto erros de API quanto erros de validação Pydantic se o seu modelo tiver lógica de validação personalizada. - Tratar uma análise bem-sucedida como prova de que os dados estão corretos. A validação confirma a forma e quaisquer restrições de nível Pydantic, não que os valores extraídos sejam factualmente precisos. Correção: adicione uma etapa de revisão ou verificação posterior para qualquer coisa de alto risco.
- Esquecer que
create()ainda retorna texto que você devejson.loads()você mesmo. Desenvolvedores às vezes esperam quecreate()analise automaticamente da maneira queparse()faz. Correção: useparse()quando quiser o objeto; usecreate()apenas quando você especificamente quiser o texto bruto ou mais controle manual sobre o tratamento da resposta.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
client.messages.parse() | Você tem um modelo Pydantic e quer um objeto validado em uma chamada | Você precisa inspecionar o texto bruto da resposta ou transmitir a resposta |
client.messages.create() + json.loads() manual | Você quer controle total sobre o fluxo de análise e tratamento de erros | Você quer apenas o objeto finalizado com o mínimo de código |
Extração de JSON feita manualmente a partir de texto livre (sem output_config.format) | Código legado que você ainda não migrou | Qualquer nova integração - não oferece garantia de confiabilidade sobre saídas estruturadas |
FAQs
Qual é a diferença real entre create() e parse()?
- Ambos enviam a mesma forma de solicitação com o mesmo esquema
output_config.format. parse()adicionalmente valida e desserializa a resposta emresponse.parsed_output;create()deixa você para chamarjson.loads()você mesmo.
Preciso de um modelo Pydantic para usar parse()?
- Um modelo Pydantic é o padrão comum porque
model_json_schema()gera o esquema e lhe dá um valor de retorno tipado. - Um dict de esquema bruto também funciona com
parse(), mas você perde a conveniência do objeto tipado -parsed_outputse torna um dict simples nesse caso.
Devo verificar stop_reason antes ou depois de chamar parse()?
- Verifique no objeto
responseretornado antes de confiar emparsed_output, da mesma forma que faria comcreate(). - Um motivo de parada
max_tokensourefusalsignifica que o conteúdo pode não estar completo ou utilizável, independentemente de qual método você chamou.
Que tipos de exceção devo capturar em torno de uma chamada parse()?
- Falhas de nível de API (rede, autenticação, limites de taxa) aparecem como
anthropic.APIStatusErrore suas subclasses. - Problemas de nível de conteúdo, como um validador Pydantic personalizado falhando, aparecem como
pydantic.ValidationError- capture ambos se o seu modelo tiver validação personalizada.
É garantido que response.parsed_output não seja None?
- Somente quando a resposta foi concluída com sucesso e passou na validação - sempre verifique
stop_reasone trate exceções antes de assumir que está preenchido.
Posso ainda acessar o texto bruto ao lado de parsed_output?
- Sim - o objeto
responseretornado porparse()ainda carrega o campocontentnormal com os blocos de texto brutos, além deparsed_output.
parse() tenta novamente automaticamente em caso de truncamento?
- Não -
parse()não tenta novamente automaticamente com ummax_tokensmaior. Você precisa detectar o truncamento viastop_reasone implementar sua própria lógica de retentativa.
Validadores Pydantic podem rejeitar uma resposta que é válida em esquema?
- Sim - um
field_validatoroumodel_validatorem seu modelo Pydantic é executado após a verificação do JSON Schema passar, então ele ainda pode rejeitar valores que o próprio esquema permitiu.
É mais lento usar parse() em vez de create()?
- A chamada da API é idêntica -
parse()apenas adiciona uma etapa de validação/desserialização no lado do cliente após a resposta chegar, o que é insignificante em comparação com a latência da rede.
Como fica parsed_output se eu passar um dict de esquema bruto em vez de um modelo Pydantic?
- É um
dictPython simples que corresponde à forma do esquema, em vez de uma instância de modelo tipada. - Use um modelo Pydantic quando quiser acesso a atributos e tipagem estática em vez de indexação de dict.
Posso reutilizar o mesmo modelo Pydantic para parse() e json.loads() manual?
data = json.loads(raw_text)
invoice = Invoice.model_validate(data)- Sim -
Model.model_validate(data)faz a mesma etapa de validação queparse()faz internamente, útil se você estiver no caminho manualcreate()mas ainda quiser um objeto tipado.
Relacionado
- Noções Básicas de Saídas Estruturadas - a primeira introdução a client.messages.parse.
- Definindo um JSON Schema para output_config.format - como o esquema que esta página analisa é construído.
- Lidando com Saída JSON Malformada ou Truncada - um olhar mais aprofundado sobre as verificações de stop_reason usadas nesta página.
- Referência de Tipos de Campo e Restrições de Saída Estruturada - quais construções de esquema são seguras para confiar antes de chegar à análise.
Versões da Stack: Escrito contra a linha de modelos Claude atual a partir de ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão), e Claude Haiku 4.5 - e o SDK oficial
anthropicpara Python (última versão 0.x). Nomes de modelos, versões de SDK e preços mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.