Como Construir um Payload Compatível para a API de Mensagens da Anthropic: Evite Erros
Introdução
Ao trabalhar com a API da Anthropic, especificamente o endpoint de mensagens, os desenvolvedores frequentemente encontram o erro invalid_request_error
. Este erro pode ocorrer devido a várias razões relacionadas à estrutura do payload enviado para a API. Neste artigo, exploraremos como construir um payload compatível para evitar este erro e garantir uma comunicação suave com a API da Anthropic.
Entendendo os Requisitos da API da Anthropic
A API da Anthropic tem requisitos específicos para a estrutura dos payloads de mensagens. Esses requisitos garantem que o modelo de IA possa processar o contexto da conversa corretamente. Os principais pontos a considerar são:
- As mensagens devem alternar entre os papéis de usuário e assistente.
- A primeira e a última mensagem devem ser do usuário.
- Chamadas de função são mensagens do assistente e as respostas são mensagens do usuário.
Solução
Para abordar esta questão, usaremos uma classe auxiliar chamada LLMProvider
. Esta classe contém um método getStandardMessagesStructure
que processa o array de mensagens para garantir que esteja em conformidade com os requisitos da Anthropic.
Nosso esquema de array $messages
se parece com isto:
class MessageSchema
{
const string table = 'messages';
const string id = 'id';
const string message = 'message';
const string caption = 'caption';
const string role = 'role'; // admin, contact, bot, function
const string function_id = 'function_id';
const string function_name = 'function_name';
const string function_arguments = 'function_arguments';
const string message_type = 'message_type'; // text, image, function_call, function_response
const string created_at = 'created_at';
const string updated_at = 'updated_at';
const string deleted_at = 'deleted_at';
}
O objetivo deste esquema é ser flexível o suficiente para que possa ser usado como um banco de dados de mensagens de chatbot e, ao mesmo tempo, compatível com múltiplos LLMs como OpenAI e Google Gemini, mas para o escopo deste artigo, vamos nos concentrar em abordar erros de solicitação com a API da Anthropic.
Sinta-se à vontade para adaptar o código abaixo à forma como você estrutura suas mensagens no banco de dados antes de enviá-las a um provedor terceirizado.
Passo 1: Implementar o Método getStandardMessagesStructure
private static function getStandardMessagesStructure(array $messages): array
{
// Remove mensagens do início até que a primeira mensagem com papel 'contact' seja encontrada
$messages = self::removeMessagesUntilFirstContact($messages);
// Garante que o papel 'contact' seja sempre precedido por um papel 'bot', a menos que seja o primeiro elemento
$messages = self::ensureContactPrecededByBot($messages);
// Remove mensagens do final até que a última mensagem seja:
// - papel 'contact' com message_type 'text' ou 'image'
// - papel 'function' com message_type 'function_response'
return self::removeMessagesFromEndUntilValid($messages);
}
Este método chama três funções auxiliares para processar o array de mensagens:
Passo 2: Implementar removeMessagesUntilFirstContact
private static function removeMessagesUntilFirstContact(array $messages): array
{
while (!empty($messages) && $messages[0][MessageSchema::role] !== 'contact') {
array_shift($messages);
}
return $messages;
}
Esta função garante que a primeira mensagem no array seja do usuário (papel 'contact').
Passo 3: Implementar ensureContactPrecededByBot
private static function ensureContactPrecededByBot(array $messages): array
{
for ($i = 1; $i < count($messages); $i++) {
if ($messages[$i][MessageSchema::role] === 'contact' && $messages[$i - 1][MessageSchema::role] !== 'bot') {
while ($i > 0 && $messages[$i - 1][MessageSchema::role] !== 'bot') {
array_splice($messages, $i - 1, 1);
$i--;
}
}
}
return $messages;
}
Esta função garante que as mensagens alternem entre os papéis de usuário e assistente.
Passo 4: Implementar removeMessagesFromEndUntilValid
private static function removeMessagesFromEndUntilValid(array $messages): array
{
while (!empty($messages)) {
$last_message = $messages[count($messages) - 1];
$role = $last_message[MessageSchema::role];
$message_type = $last_message[MessageSchema::message_type] ?? 'text';
$is_contact_with_valid_type = $role === 'contact' && in_array($message_type, ['text', 'image']);
$is_function_with_valid_type = $role === 'function' && $message_type === 'function_response';
if ($is_contact_with_valid_type || $is_function_with_valid_type) {
break;
}
array_pop($messages);
}
return $messages;
}
Esta função garante que a última mensagem seja do usuário ou uma resposta de função válida.
Passo 5: Usar o getStandardMessagesStructure em Sua Chamada de API
Ao fazer uma chamada para a API da Anthropic, use o método getStandardMessagesStructure
para processar seu array de mensagens:
$messages = self::getStandardMessagesStructure($messages);
$response = AnthropicProvider::chat(
model: AnthropicProvider::CLAUDE_3_SONNET,
messages: $messages,
max_tokens: $max_tokens,
system: $system,
temperature: $temperature,
tools: $tools
);
Dentro da classe AnthropicProvider
, mapeamos o array $messages
para uma estrutura de mensagem compatível com a Anthropic em uma função chamada getParsedMessages
. Aqui está uma seção disso para referência:
private static function getParsedMessages(array $messages): array
{
return array_map(function ($m) {
$role = $m[MessageSchema::role];
switch ($role) {
case 'contact':
$role = 'user';
break;
case 'admin':
case 'bot':
case 'function':
$role = 'assistant';
break;
}
$message = $m[MessageSchema::message];
... // outros mapeamentos
return [
'content' => $message,
'role' => $role,
];
Exemplo: Antes e Depois do Processamento
Vamos ver um exemplo de como a estrutura do payload de mensagens muda após o processamento:
Antes do processamento:
$messages = [
['role' => 'bot', 'message' => 'Olá!'],
['role' => 'contact', 'message' => 'Oi!'],
['role' => 'contact', 'message' => 'Como você está?'],
['role' => 'bot', 'message' => 'Estou bem, obrigado!'],
['role' => 'bot', 'message' => 'Como posso ajudar você hoje?'],
];
Depois do processamento:
$messages = [
['role' => 'contact', 'message' => 'Oi!'],
['role' => 'bot', 'message' => 'Estou bem, obrigado!'],
['role' => 'contact', 'message' => 'Como você está?'],
];
Melhores Práticas para Estruturação de Mensagens
Para minimizar a necessidade de processamento extensivo, considere estas melhores práticas ao estruturar suas mensagens:
- Sempre inicie as conversas com uma mensagem do usuário.
- Alterne entre mensagens do usuário e do assistente.
- Termine as conversas com uma mensagem do usuário ou uma resposta de função válida.
- Lide com chamadas de função em conversas de IA apropriadamente dentro do fluxo da conversa.
Tratamento de Erros
Quando você encontrar um invalid_request_error
, é crucial registrar os detalhes do erro e o payload que o causou. Isso pode ajudar na depuração e na melhoria da sua lógica de processamento de mensagens. Considere implementar um bloco try-catch:
use Illuminate\Support\Facades\Log;
...
try {
$response = AnthropicProvider::chat(/* ... */);
} catch (Exception $e) {
if (str_contains($e->getMessage(), 'invalid_request_error')) {
// Registra o erro e o payload
Log::error('Erro de solicitação inválida: ' . json_encode($messages));
}
throw $e;
}
Conclusão
Ao implementar esses métodos e usá-los para processar seu array de mensagens antes de enviá-lo para a API da Anthropic, você pode evitar o invalid_request_error
e garantir que seu payload esteja em conformidade com os requisitos da API. Esta abordagem lida com a alternância de mensagens do usuário e do assistente, garante a estrutura adequada para chamadas de função e respostas, e mantém a ordem correta das mensagens.
Lembre-se de adaptar as constantes MessageSchema
e outros detalhes específicos para corresponder à estrutura do seu projeto. Com esta solução implementada, você deve ser capaz de se comunicar com o modelo Claude da Anthropic de forma confiável.
Embora esta abordagem seja eficaz, é importante notar que ela pode remover algumas mensagens do histórico da conversa. Em cenários onde preservar toda a conversa é crucial, você deve implementar um sistema mais sofisticado que garanta a conformidade sem perder o contexto.