LANGCHAIN_CHAT_OPENAI - Chat com OpenAI via LangChain
O que é este Node?
O LANGCHAIN_CHAT_OPENAI é o node responsável por integrar modelos de chat da OpenAI (GPT-3.5, GPT-4, etc.) através do framework LangChain, permitindo conversas inteligentes com memória contextual, function calling e templates de prompt avançados.
Por que este Node existe?
A integração com modelos OpenAI é essencial para criar assistentes conversacionais avançados. O LANGCHAIN_CHAT_OPENAI existe para:
- Conversas Inteligentes: Criar chatbots com capacidade de compreensão de contexto e respostas naturais
- Memória Contextual: Manter histórico de conversas para respostas mais relevantes
- Function Calling: Permitir que o modelo execute funções e ferramentas durante a conversa
- Templates Reutilizáveis: Criar prompts dinâmicos com variáveis e formatação consistente
- Controle Avançado: Ajustar temperatura, tokens, penalidades e outros parâmetros do modelo
- Moderação: Implementar filtros de conteúdo e segurança nas respostas
- RAG (Retrieval Augmented Generation): Enriquecer respostas com dados de bases vetoriais
Como funciona internamente?
Quando o LANGCHAIN_CHAT_OPENAI é executado, o sistema:
- Valida Configuração: Verifica se provider (openai), model, apiKey e prompts estão configurados
- Constrói Prompt: Monta o prompt final usando templates, variáveis de contexto e system/user messages
- Configura Parâmetros: Define temperature, maxTokens, topP, frequencyPenalty, presencePenalty e stopSequences
- Adiciona Functions: Se enableFunctions estiver ativo, adiciona as funções disponíveis ao payload
- Envia Request: Faz chamada POST para https://api.openai.com/v1/chat/completions com autenticação Bearer
- Processa Resposta: Extrai o conteúdo da resposta e formata conforme outputFormat (text/json/structured)
- Retorna Resultado: Devolve o conteúdo gerado, tokens usados e tempo de execução
- Se erro 401: Retorna erro de autenticação inválida
- Se erro 429: Retorna erro de rate limit excedido
Código interno (langchain-chat-executor.service.ts:311-352):
private async executeOpenAI(data: LangChainChatNodeData, prompt: string): Promise<any> {
const baseUrl = data.baseUrl || 'https://api.openai.com/v1';
const headers: any = {
'Authorization': `Bearer ${data.apiKey}`,
'Content-Type': 'application/json'
};
if (data.organization) {
headers['OpenAI-Organization'] = data.organization;
}
const payload: any = {
model: data.model,
messages: [
...(data.systemPrompt ? [{ role: 'system', content: data.systemPrompt }] : []),
{ role: 'user', content: data.userMessage || prompt }
],
temperature: data.temperature || 0.7,
max_tokens: data.maxTokens,
top_p: data.topP,
frequency_penalty: data.frequencyPenalty || 0,
presence_penalty: data.presencePenalty || 0,
stop: data.stopSequences,
stream: false
};
if (data.enableFunctions && data.functions) {
payload.functions = data.functions.map(func => ({
name: func.name,
description: func.description,
parameters: func.parameters
}));
}
const response: AxiosResponse = await axios.post(`${baseUrl}/chat/completions`, payload, {
headers,
timeout: data.timeout || 30000
});
return response.data;
}
Quando você DEVE usar este Node?
Use LANGCHAIN_CHAT_OPENAI sempre que precisar de conversas com IA usando modelos OpenAI:
Casos de uso
- Atendimento ao Cliente: "Criar um assistente que responde perguntas sobre produtos e serviços"
- Análise de Sentimento: "Analisar se a mensagem do cliente está feliz, neutro ou insatisfeito"
- Geração de Conteúdo: "Criar descrições de produtos, posts para redes sociais ou emails marketing"
- Tradução Contextual: "Traduzir mensagens mantendo tom e contexto da conversa"
- Classificação de Intenção: "Identificar se o cliente quer comprar, reclamar, tirar dúvidas ou cancelar"
- Extração de Informações: "Extrair dados estruturados de mensagens em linguagem natural"
- Suporte Técnico: "Diagnosticar problemas e sugerir soluções baseado em descrições do cliente"
Quando NÃO usar LANGCHAIN_CHAT_OPENAI
- Respostas Fixas: Use NODE MESSAGE para respostas predefinidas
- Outros Provedores: Use LANGCHAIN_CHAT_ANTHROPIC para Claude, LANGCHAIN_CHAT_GOOGLE para Gemini
- Cálculos Simples: Use NODE CALCULATOR para operações matemáticas básicas
- Validação de Dados: Use NODE VALIDATOR para validações determinísticas
Parâmetros Detalhados
provider (string, obrigatório)
O que é: O provedor de IA que será usado. Para este node, deve ser sempre "openai".
Padrão: N/A (obrigatório)
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Provider",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Chat OpenAI",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"systemPrompt": "Você é um assistente prestativo.",
"userMessage": "Olá, como você está?"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar Resposta",
"parameters": {
"message": "Resposta da IA: {{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Importe o flow e envie qualquer mensagem. O sistema responderá com a saída da OpenAI.
model (string, obrigatório)
O que é: O modelo específico da OpenAI a ser usado (ex: gpt-3.5-turbo, gpt-4, gpt-4-turbo-preview).
Padrão: N/A (obrigatório)
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Model",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "GPT-4 Turbo",
"parameters": {
"provider": "openai",
"model": "gpt-4-turbo-preview",
"apiKey": "sk-sua-chave-aqui",
"systemPrompt": "Você é um especialista em tecnologia.",
"userMessage": "Explique o que é Kubernetes em uma frase."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Resposta",
"parameters": {
"message": "{{langchain_1.content}}\n\nTokens usados: {{langchain_1.tokensUsed}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. O sistema usará GPT-4 Turbo para responder e mostrará os tokens consumidos.
apiKey (string, obrigatório)
O que é: A chave de API da OpenAI para autenticação. Obtida em https://platform.openai.com/api-keys
Padrão: N/A (obrigatório)
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - API Key",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Teste Autenticação",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "{{config.openai_api_key}}",
"systemPrompt": "Responda apenas: OK",
"userMessage": "teste"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Status",
"parameters": {
"message": "✅ Autenticação bem-sucedida!\n\nResposta: {{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Configure sua API key da OpenAI nas variáveis. Se válida, receberá "OK" como resposta.
systemPrompt (string, opcional)
O que é: A instrução de sistema que define o comportamento, personalidade e regras do assistente.
Padrão: Nenhum
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - System Prompt",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Assistente Pirata",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"systemPrompt": "Você é um pirata do século XVII. Responda sempre como um pirata falaria, usando gírias e expressões da época. Seja divertido e criativo!",
"userMessage": "Como você está hoje?"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Resposta Pirata",
"parameters": {
"message": "🏴☠️ O pirata disse:\n\n{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. O assistente responderá como um pirata.
userMessage (string, opcional)
O que é: A mensagem do usuário que será enviada ao modelo. Pode conter variáveis de contexto.
Padrão: Nenhum
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - User Message",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Capturar Pergunta",
"parameters": {
"message": "Digite sua pergunta:",
"variable": "user_question"
}
}
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Processar Pergunta",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"systemPrompt": "Você é um professor paciente e didático.",
"userMessage": "{{user_question}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Resposta",
"parameters": {
"message": "{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Digite "O que é fotossíntese?" e receba uma explicação didática.
temperature (number, opcional)
O que é: Controla a criatividade/aleatoriedade das respostas. 0 = determinístico, 2 = muito criativo.
Padrão: 0.7
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Temperature",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Temperatura Baixa (0.1)",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"temperature": 0.1,
"systemPrompt": "Você é um assistente técnico.",
"userMessage": "Escreva uma história sobre um robô."
}
}
},
{
"id": "langchain_2",
"type": "langchain_chat",
"position": { "x": 300, "y": 250 },
"data": {
"label": "Temperatura Alta (1.8)",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"temperature": 1.8,
"systemPrompt": "Você é um escritor criativo.",
"userMessage": "Escreva uma história sobre um robô."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 175 },
"data": {
"label": "Comparar Respostas",
"parameters": {
"message": "📊 TEMPERATURA BAIXA (0.1) - Mais previsível:\n{{langchain_1.content}}\n\n🎨 TEMPERATURA ALTA (1.8) - Mais criativo:\n{{langchain_2.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 175 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "start_1", "target": "langchain_2" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "langchain_2", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. Compare como a temperatura afeta a criatividade das respostas.
maxTokens (number, opcional)
O que é: Número máximo de tokens (palavras/pedaços) que a resposta pode ter. Controla o tamanho da resposta.
Padrão: Sem limite (usa o máximo do modelo)
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Max Tokens",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Resposta Curta (50 tokens)",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"maxTokens": 50,
"systemPrompt": "Você é um escritor.",
"userMessage": "Conte uma história longa sobre dragões."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar Resposta Limitada",
"parameters": {
"message": "Resposta (limitada a 50 tokens):\n\n{{langchain_1.content}}\n\n⚠️ Tokens usados: {{langchain_1.tokensUsed}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. A resposta será cortada em aproximadamente 50 tokens.
topP (number, opcional)
O que é: Nucleus sampling - considera apenas os tokens cuja probabilidade acumulada seja menor que topP. Alternativa à temperature.
Padrão: 1.0
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Top P",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Top P Baixo (0.1)",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"topP": 0.1,
"systemPrompt": "Você é criativo.",
"userMessage": "Invente um nome para uma empresa de tecnologia."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar Nome",
"parameters": {
"message": "Nome sugerido (com topP=0.1, mais conservador):\n\n{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Execute várias vezes. Com topP baixo, verá nomes mais previsíveis e comuns.
frequencyPenalty (number, opcional)
O que é: Penaliza tokens que já foram usados, reduzindo repetição. Valores de -2.0 a 2.0.
Padrão: 0
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Frequency Penalty",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Com Penalidade Alta",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"frequencyPenalty": 1.5,
"systemPrompt": "Liste frutas.",
"userMessage": "Liste 10 frutas diferentes."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar Lista",
"parameters": {
"message": "Frutas listadas (com alta penalidade para repetição):\n\n{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. Verá uma lista com frutas variadas sem repetições.
presencePenalty (number, opcional)
O que é: Penaliza tokens já mencionados, incentivando novos tópicos. Valores de -2.0 a 2.0.
Padrão: 0
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Presence Penalty",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Explore Tópicos",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"presencePenalty": 1.8,
"systemPrompt": "Você é criativo e diverso.",
"userMessage": "Fale sobre esportes."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Ver Diversidade",
"parameters": {
"message": "{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. Verá o modelo explorando diferentes aspectos dos esportes.
stopSequences (array, opcional)
O que é: Lista de sequências de texto que, quando geradas, fazem o modelo parar de responder.
Padrão: Nenhum
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Stop Sequences",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Parar em FIM",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"stopSequences": ["FIM", "###"],
"systemPrompt": "Conte uma história mas termine com a palavra FIM.",
"userMessage": "Conte uma história curta sobre um gato."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar História",
"parameters": {
"message": "{{langchain_1.content}}\n\n(Parou ao encontrar 'FIM' ou '###')"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. A resposta parará quando o modelo gerar "FIM" ou "###".
useTemplate (boolean, opcional)
O que é: Ativa o modo de template de prompts, permitindo usar variáveis dinâmicas no promptTemplate.
Padrão: false
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Use Template",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Nome do Produto",
"parameters": {
"message": "Digite o nome do produto:",
"variable": "produto"
}
}
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Gerar Descrição",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"useTemplate": true,
"promptTemplate": "Crie uma descrição de marketing para o produto: {produto}. A descrição deve ter 3 parágrafos e ser persuasiva.",
"templateVariables": [
{
"name": "produto",
"value": "{{produto}}",
"type": "string"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Mostrar Descrição",
"parameters": {
"message": "📦 Descrição do produto {{produto}}:\n\n{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Digite "Smartphone XYZ" e receba uma descrição de marketing personalizada.
outputFormat (string, opcional)
O que é: Define como a resposta será formatada: "text" (texto puro), "json" (parse JSON), "structured" (com metadata).
Padrão: "text"
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Output Format",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Resposta JSON",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"outputFormat": "json",
"systemPrompt": "Responda SEMPRE em JSON válido.",
"userMessage": "Retorne um objeto JSON com: nome (João), idade (30), cidade (São Paulo)"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Acessar JSON",
"parameters": {
"message": "Nome: {{langchain_1.nome}}\nIdade: {{langchain_1.idade}}\nCidade: {{langchain_1.cidade}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. O JSON será parseado e você poderá acessar os campos diretamente.
enableFunctions (boolean, opcional)
O que é: Habilita function calling, permitindo que o modelo execute funções definidas durante a conversa.
Padrão: false
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Function Calling",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Com Funções",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"enableFunctions": true,
"functions": [
{
"name": "get_weather",
"description": "Obtém a previsão do tempo para uma cidade",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Nome da cidade"
}
},
"required": ["city"]
}
}
],
"systemPrompt": "Você tem acesso à função get_weather para consultar o tempo.",
"userMessage": "Qual a previsão do tempo para São Paulo?"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Mostrar Resposta",
"parameters": {
"message": "{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Envie qualquer mensagem. O modelo identificará que precisa usar get_weather e retornará os parâmetros da função.
organization (string, opcional)
O que é: ID da organização OpenAI. Usado quando você tem múltiplas organizações na mesma conta.
Padrão: Nenhum
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Organization",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Com Organization",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"organization": "org-sua-organizacao",
"systemPrompt": "Você é um assistente.",
"userMessage": "Olá"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Resposta",
"parameters": {
"message": "{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Configure seu organization ID. Os custos serão contabilizados na organização especificada.
timeout (number, opcional)
O que é: Tempo máximo de espera pela resposta da API em milissegundos.
Padrão: 30000 (30 segundos)
Flow completo para testar:
{
"name": "Teste LangChain OpenAI - Timeout",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Timeout Curto",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "sk-sua-chave-aqui",
"timeout": 5000,
"systemPrompt": "Você é rápido.",
"userMessage": "Olá"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Resposta",
"parameters": {
"message": "{{langchain_1.content}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Se a API demorar mais de 5 segundos, receberá erro de timeout.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| provider | string | Sim | Provedor de IA (deve ser "openai") |
| model | string | Sim | Modelo OpenAI (gpt-3.5-turbo, gpt-4, etc) |
| apiKey | string | Sim | Chave de API da OpenAI |
| baseUrl | string | Não | URL base customizada (padrão: https://api.openai.com/v1) |
| organization | string | Não | ID da organização OpenAI |
| systemPrompt | string | Não | Instrução de sistema que define o comportamento |
| userMessage | string | Não | Mensagem do usuário para o modelo |
| temperature | number | Não | Criatividade (0-2, padrão: 0.7) |
| maxTokens | number | Não | Limite de tokens na resposta |
| topP | number | Não | Nucleus sampling (padrão: 1.0) |
| frequencyPenalty | number | Não | Penalidade por repetição (-2 a 2, padrão: 0) |
| presencePenalty | number | Não | Penalidade por tópicos já mencionados (-2 a 2, padrão: 0) |
| stopSequences | array | Não | Sequências que param a geração |
| useTemplate | boolean | Não | Usar template de prompt (padrão: false) |
| promptTemplate | string | Não | Template com variáveis |
| templateVariables | array | Não | Variáveis para substituir no template |
| outputFormat | string | Não | Formato da saída: text/json/structured (padrão: text) |
| enableFunctions | boolean | Não | Habilitar function calling (padrão: false) |
| functions | array | Não | Funções disponíveis para o modelo |
| timeout | number | Não | Timeout em ms (padrão: 30000) |
Exemplo 1: Assistente de Atendimento com Contexto
Objetivo: Criar um assistente que responde perguntas sobre produtos usando contexto da empresa.
JSON para Importar
{
"name": "Assistente de Atendimento OpenAI",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "message_1",
"type": "message",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Boas-vindas",
"parameters": {
"message": "Olá! Sou o assistente virtual da TechStore. Como posso ajudar você hoje?"
}
}
},
{
"id": "input_1",
"type": "input",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Capturar Pergunta",
"parameters": {
"message": "Digite sua pergunta:",
"variable": "customer_question"
}
}
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Processar com OpenAI",
"parameters": {
"provider": "openai",
"model": "gpt-4",
"apiKey": "{{config.openai_key}}",
"temperature": 0.3,
"maxTokens": 300,
"systemPrompt": "Você é um assistente de atendimento da TechStore, uma loja de eletrônicos. Seja prestativo, profissional e objetivo. Informações da empresa:\n- Entrega: 5-10 dias úteis para todo Brasil\n- Garantia: 12 meses para todos os produtos\n- Troca: Até 7 dias após recebimento\n- Formas de pagamento: Cartão, PIX, boleto\n- Horário de atendimento: Segunda a sexta, 9h-18h\nSe não souber algo, seja honesto e ofereça contato com um humano.",
"userMessage": "{{customer_question}}"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Enviar Resposta",
"parameters": {
"message": "{{langchain_1.content}}\n\n---\nPosso ajudar com mais alguma coisa?"
}
}
},
{
"id": "input_2",
"type": "input",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Continuar?",
"parameters": {
"message": "Digite SIM para fazer outra pergunta ou NÃO para encerrar:",
"variable": "continue"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Verificar Continuação",
"parameters": {
"variable": "continue",
"operator": "equals",
"value": "SIM"
}
}
},
{
"id": "message_3",
"type": "message",
"position": { "x": 1500, "y": 200 },
"data": {
"label": "Despedida",
"parameters": {
"message": "Obrigado por entrar em contato! Até breve! 👋"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "message_1" },
{ "source": "message_1", "target": "input_1" },
{ "source": "input_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_2" },
{ "source": "message_2", "target": "input_2" },
{ "source": "input_2", "target": "condition_1" },
{ "source": "condition_1", "target": "input_1", "label": "true" },
{ "source": "condition_1", "target": "message_3", "label": "false" },
{ "source": "message_3", "target": "end_1" }
]
}
Saída esperada:
Sistema: Olá! Sou o assistente virtual da TechStore. Como posso ajudar você hoje?
Sistema: Digite sua pergunta:
Usuário: Qual o prazo de entrega?
Sistema: O prazo de entrega da TechStore é de 5 a 10 dias úteis para todo o Brasil. O prazo pode variar dependendo da sua localização e da disponibilidade do produto. Assim que seu pedido for despachado, você receberá um código de rastreamento para acompanhar a entrega.
---
Posso ajudar com mais alguma coisa?
Sistema: Digite SIM para fazer outra pergunta ou NÃO para encerrar:
Usuário: SIM
Sistema: Digite sua pergunta:
Usuário: Como funciona a garantia?
Sistema: Todos os produtos da TechStore possuem garantia de 12 meses contra defeitos de fabricação. A garantia cobre problemas técnicos que não tenham sido causados por mau uso. Para acionar a garantia, entre em contato com nosso atendimento informando o número do pedido e descrevendo o problema. Faremos a análise e, se for um caso coberto pela garantia, realizaremos o reparo ou troca do produto.
---
Posso ajudar com mais alguma coisa?
Sistema: Digite SIM para fazer outra pergunta ou NÃO para encerrar:
Usuário: NÃO
Sistema: Obrigado por entrar em contato! Até breve! 👋
Exemplo 2: Análise de Sentimento em Feedback
Objetivo: Analisar o sentimento de feedbacks de clientes e classificar como positivo, neutro ou negativo.
JSON para Importar
{
"name": "Análise de Sentimento com OpenAI",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "message_1",
"type": "message",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Solicitar Feedback",
"parameters": {
"message": "Por favor, envie seu feedback sobre nosso atendimento:"
}
}
},
{
"id": "input_1",
"type": "input",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Capturar Feedback",
"parameters": {
"message": "Aguardando seu feedback...",
"variable": "customer_feedback"
}
}
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Analisar Sentimento",
"parameters": {
"provider": "openai",
"model": "gpt-3.5-turbo",
"apiKey": "{{config.openai_key}}",
"temperature": 0.1,
"maxTokens": 200,
"outputFormat": "json",
"systemPrompt": "Você é um analisador de sentimentos. Analise o feedback e retorne APENAS um JSON válido com:\n{\n \"sentimento\": \"positivo\" | \"neutro\" | \"negativo\",\n \"confianca\": 0-100,\n \"aspectos_positivos\": [lista],\n \"aspectos_negativos\": [lista],\n \"resumo\": \"breve resumo\"\n}",
"userMessage": "Feedback do cliente: {{customer_feedback}}"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 900, "y": 100 },
"data": {
"label": "É Positivo?",
"parameters": {
"variable": "langchain_1.sentimento",
"operator": "equals",
"value": "positivo"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 1100, "y": 50 },
"data": {
"label": "Resposta Positiva",
"parameters": {
"message": "😊 Que ótimo! Ficamos felizes com seu feedback positivo!\n\n{{langchain_1.resumo}}\n\n⭐ Confiança da análise: {{langchain_1.confianca}}%\n\nMuito obrigado por compartilhar sua experiência!"
}
}
},
{
"id": "condition_2",
"type": "condition",
"position": { "x": 900, "y": 200 },
"data": {
"label": "É Negativo?",
"parameters": {
"variable": "langchain_1.sentimento",
"operator": "equals",
"value": "negativo"
}
}
},
{
"id": "message_3",
"type": "message",
"position": { "x": 1100, "y": 150 },
"data": {
"label": "Resposta Negativa",
"parameters": {
"message": "😔 Sentimos muito pela experiência negativa.\n\n{{langchain_1.resumo}}\n\n⚠️ Aspectos a melhorar:\n{{langchain_1.aspectos_negativos}}\n\nUm gerente entrará em contato em até 24h para resolver a situação."
}
}
},
{
"id": "message_4",
"type": "message",
"position": { "x": 1100, "y": 250 },
"data": {
"label": "Resposta Neutra",
"parameters": {
"message": "📊 Obrigado pelo seu feedback!\n\n{{langchain_1.resumo}}\n\nSua opinião é importante para continuarmos melhorando."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1300, "y": 150 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "message_1" },
{ "source": "message_1", "target": "input_1" },
{ "source": "input_1", "target": "langchain_1" },
{ "source": "langchain_1", "target": "condition_1" },
{ "source": "condition_1", "target": "message_2", "label": "true" },
{ "source": "condition_1", "target": "condition_2", "label": "false" },
{ "source": "condition_2", "target": "message_3", "label": "true" },
{ "source": "condition_2", "target": "message_4", "label": "false" },
{ "source": "message_2", "target": "end_1" },
{ "source": "message_3", "target": "end_1" },
{ "source": "message_4", "target": "end_1" }
]
}
Saída esperada:
Sistema: Por favor, envie seu feedback sobre nosso atendimento:
Sistema: Aguardando seu feedback...
Usuário: O atendente foi super educado e resolveu meu problema rapidamente! Adorei o serviço!
Sistema: 😊 Que ótimo! Ficamos felizes com seu feedback positivo!
O cliente teve uma experiência extremamente positiva, destacando a educação do atendente e a rapidez na resolução do problema.
⭐ Confiança da análise: 95%
Muito obrigado por compartilhar sua experiência!
Exemplo 3: Gerador de Descrições de Produtos com Template
Objetivo: Gerar descrições de marketing personalizadas para produtos usando templates.
JSON para Importar
{
"name": "Gerador de Descrições OpenAI",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Nome do Produto",
"parameters": {
"message": "Digite o nome do produto:",
"variable": "produto_nome"
}
}
},
{
"id": "input_2",
"type": "input",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Categoria",
"parameters": {
"message": "Digite a categoria (ex: smartphone, notebook, fone):",
"variable": "produto_categoria"
}
}
},
{
"id": "input_3",
"type": "input",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Características",
"parameters": {
"message": "Liste as principais características separadas por vírgula:",
"variable": "produto_caracteristicas"
}
}
},
{
"id": "langchain_1",
"type": "langchain_chat",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Gerar Descrição",
"parameters": {
"provider": "openai",
"model": "gpt-4",
"apiKey": "{{config.openai_key}}",
"temperature": 0.8,
"maxTokens": 500,
"useTemplate": true,
"promptTemplate": "Crie uma descrição de marketing persuasiva e profissional para o seguinte produto:\n\nProduto: {produto_nome}\nCategoria: {produto_categoria}\nCaracterísticas: {produto_caracteristicas}\n\nA descrição deve:\n1. Ter um título chamativo\n2. Incluir 3 parágrafos: introdução, benefícios e call-to-action\n3. Destacar as características de forma atrativa\n4. Usar linguagem persuasiva mas não exagerada\n5. Ter entre 150-200 palavras",
"templateVariables": [
{
"name": "produto_nome",
"value": "{{produto_nome}}",
"type": "string"
},
{
"name": "produto_categoria",
"value": "{{produto_categoria}}",
"type": "string"
},
{
"name": "produto_caracteristicas",
"value": "{{produto_caracteristicas}}",
"type": "string"
}
]
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Mostrar Descrição",
"parameters": {
"message": "📦 DESCRIÇÃO GERADA\n━━━━━━━━━━━━━━━━━━━━\n\n{{langchain_1.content}}\n\n━━━━━━━━━━━━━━━━━━━━\n⏱️ Tempo: {{langchain_1.executionTime}}ms\n🔢 Tokens: {{langchain_1.tokensUsed}}"
}
}
},
{
"id": "input_4",
"type": "input",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Gerar Outra?",
"parameters": {
"message": "Deseja gerar outra descrição? (SIM/NÃO)",
"variable": "continuar"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 1500, "y": 100 },
"data": {
"label": "Verificar",
"parameters": {
"variable": "continuar",
"operator": "equals",
"value": "SIM"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "input_2" },
{ "source": "input_2", "target": "input_3" },
{ "source": "input_3", "target": "langchain_1" },
{ "source": "langchain_1", "target": "message_1" },
{ "source": "message_1", "target": "input_4" },
{ "source": "input_4", "target": "condition_1" },
{ "source": "condition_1", "target": "input_1", "label": "true" },
{ "source": "condition_1", "target": "end_1", "label": "false" }
]
}
Saída esperada:
Sistema: Digite o nome do produto:
Usuário: UltraSound Pro X1
Sistema: Digite a categoria (ex: smartphone, notebook, fone):
Usuário: fone de ouvido
Sistema: Liste as principais características separadas por vírgula:
Usuário: cancelamento de ruído ativo, 40 horas de bateria, bluetooth 5.3, driver de 50mm, resistente à água IPX7
Sistema: 📦 DESCRIÇÃO GERADA
━━━━━━━━━━━━━━━━━━━━
🎧 UltraSound Pro X1: Sua Nova Experiência em Áudio Premium
Prepare-se para redefinir sua experiência sonora com o UltraSound Pro X1, o fone de ouvido que combina tecnologia de ponta com conforto excepcional. Com cancelamento de ruído ativo inteligente, você mergulha em seu mundo musical sem interferências externas, seja no metrô lotado ou no escritório agitado.
Equipado com drivers de 50mm de alta fidelidade e conectividade Bluetooth 5.3, o UltraSound Pro X1 entrega áudio cristalino com graves profundos e agudos nítidos. Sua bateria extraordinária de 40 horas garante que a música nunca pare, enquanto a certificação IPX7 oferece proteção total contra água e suor - perfeito para treinos intensos ou dias chuvosos.
Não perca a oportunidade de elevar seu padrão de áudio. O UltraSound Pro X1 é mais do que um fone de ouvido: é seu companheiro para momentos inesquecíveis. Adquira já o seu e descubra como o som de qualidade profissional pode transformar seu dia a dia!
━━━━━━━━━━━━━━━━━━━━
⏱️ Tempo: 3456ms
🔢 Tokens: 387
Sistema: Deseja gerar outra descrição? (SIM/NÃO)
Resposta do Node
{
"success": true,
"data": {
"content": "Texto da resposta do modelo",
"raw": {
"choices": [
{
"message": {
"role": "assistant",
"content": "Texto da resposta do modelo"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 45,
"completion_tokens": 120,
"total_tokens": 165
}
}
},
"tokensUsed": 165,
"executionTime": 2340,
"logs": ["LangChain Chat completed with openai/gpt-3.5-turbo"]
}
Boas Práticas
✅ SIM:
- Use temperature baixa (0.1-0.3) para respostas factuais e consistentes
- Use temperature alta (0.8-1.2) para geração criativa de conteúdo
- Defina maxTokens para controlar custos e evitar respostas muito longas
- Use systemPrompt para definir comportamento, tom e regras do assistente
- Implemente validação da API key antes de usar em produção
- Use outputFormat: "json" quando precisar processar dados estruturados
- Configure timeout adequado para prompts complexos (60-90 segundos)
- Use frequencyPenalty para evitar repetições em listas e enumerações
- Monitore tokensUsed para controlar custos de API
- Use templates para prompts reutilizáveis e consistentes
❌ NÃO:
- Não exponha a API key em prompts ou mensagens ao usuário
- Não use temperature > 1.5 para tarefas que exigem precisão
- Não envie dados sensíveis (senhas, cartões) nos prompts
- Não dependa 100% da resposta sem validação adicional
- Não use maxTokens muito baixo (<50) para perguntas abertas
- Não faça múltiplas chamadas sequenciais desnecessárias (use memory)
- Não ignore os erros 429 (rate limit) - implemente retry com backoff
- Não use gpt-4 quando gpt-3.5-turbo for suficiente (custo 10-20x maior)
Dicas
💡 Dica 1 - Custos: GPT-3.5-turbo custa ~$0.002/1K tokens. GPT-4 custa ~$0.03-0.06/1K tokens. Para tarefas simples, prefira GPT-3.5-turbo.
💡 Dica 2 - System Prompt Efetivo: Seja específico no systemPrompt. Em vez de "Você é prestativo", use "Você é um assistente de suporte técnico especializado em roteadores. Responda de forma clara, em até 3 parágrafos, e sempre ofereça próximos passos."
💡 Dica 3 - Controle de Tokens: Para estimar tokens, conte aproximadamente 4 caracteres = 1 token em português. Use maxTokens para evitar surpresas na fatura.
💡 Dica 4 - JSON Confiável: Quando usar outputFormat: "json", sempre instrua o modelo no systemPrompt: "SEMPRE retorne JSON válido sem texto adicional".
💡 Dica 5 - Function Calling: Use function calling quando o modelo precisa executar ações (consultar banco, buscar API, fazer cálculos). É mais confiável que tentar extrair informações do texto.
💡 Dica 6 - Temperature vs TopP: Use temperature OU topP, não ambos simultaneamente. Temperature é mais intuitivo para a maioria dos casos.
💡 Dica 7 - Timeout em Produção: Em produção, use timeout de 60-90 segundos. Prompts complexos podem demorar mais que o padrão de 30s.
💡 Dica 8 - Moderação: Para ambientes públicos, use um node CONDITION depois do LangChain para filtrar respostas inadequadas antes de enviar ao usuário.
Próximos Nodes
→ LANGCHAIN_CHAT_ANTHROPIC - Chat com Claude usando Anthropic → LANGCHAIN_CHAT_GOOGLE - Chat com Gemini usando Google AI → CONDITION - Criar lógica condicional baseada nas respostas → VARIABLE - Armazenar respostas para uso posterior → MESSAGE - Enviar respostas ao usuário