LLM Helper
Visão Geral
O LLMHelper permite fazer chamadas de completion para LLMs diretamente dentro de actions, seguindo o padrão LiteLLM/OpenAI chat completions. Oferece suporte a modelos customizáveis, controle de temperatura e retorno estruturado JSON, além de gerar automaticamente generations no LangFuse para observabilidade.
Características Principais
- 🔌 Padrão OpenAI: Interface compatível com chat completions
- 🎯 Retorno estruturado: JSON schemas para dados organizados
- 🌡️ Controle de temperatura: Ajuste de criatividade (0.0 a 1.0)
- 🔍 Observabilidade: Generations automáticas no LangFuse
- ⚙️ Flexível: Suporte a modelos customizados e parâmetros extras
🚀 Método Principal
completion(system_prompt, user_prompt, response_format=None, model=None, temperature=0.3, generation_name="llm-helper-completion", **kwargs)
Executa completion de LLM com suporte a retorno estruturado e observabilidade automática.
Parâmetros:
system_prompt(str): Obrigatório - Instruções e contexto para o modelouser_prompt(str): Obrigatório - Mensagem/query do usuárioresponse_format(Dict): Schema JSON para retorno estruturado (opcional)model(str): Modelo específico a usar (opcional, usa o mesmo modelo do agent se não passado)temperature(float): Criatividade do modelo, 0.0 a 1.0 (padrão: 0.3)generation_name(str): Nome do span no LangFuse (padrão: "llm-helper-completion")**kwargs: Parâmetros adicionais (max_tokens, top_p, etc.)
Quando utilizar:
- Processar dados complexos dentro de actions
- Gerar conteúdo estruturado (JSON)
- Análise de textos ou documentos
- Transformações e extrações de dados
- Qualquer tarefa que precise de LLM durante execução
Resultado esperado:
- Com response_format: Objeto JSON parseado automaticamente
- Sem response_format:
{"content": "texto_da_resposta"} - Generation automática no LangFuse para tracking
📝 Exemplos Práticos
Exemplo 1: Retorno Estruturado (JSON Schema)
Baseado no exemplo de geração de nome pirata:
def gerar_nome_pirata(name: str):
# Schema JSON para resposta estruturada
pirate_response_schema = {
"type": "json_schema",
"json_schema": {
"name": "pirate_name_response",
"schema": {
"type": "object",
"properties": {
"pirate_name": {
"type": "string",
"description": "Nome de pirata gerado"
},
"pirate_title": {
"type": "string",
"description": "Título ou alcunha do pirata"
},
"origin_explanation": {
"type": "string",
"description": "Explicação de como o nome foi derivado"
},
"pirate_backstory": {
"type": "string",
"description": "Breve história de fundo do pirata"
},
"ship_name": {
"type": "string",
"description": "Nome do navio pirata"
}
},
"required": ["pirate_name", "pirate_title", "origin_explanation"],
"additionalProperties": False
}
}
}
system_prompt = """Você é um criativo gerador de nomes piratas.
Crie um nome pirata baseado no nome fornecido, inclua título/alcunha,
explique a derivação, crie história de fundo e nome do navio.
Seja criativo e divertido! Responda SEMPRE em português brasileiro."""
user_prompt = f"""Transforme o nome "{name}" em um nome de pirata épico.
Crie: nome pirata, título, explicação da derivação, história e nome do navio."""
# Chamada com retorno estruturado
llm_result = llm_helper.completion(
system_prompt=system_prompt,
user_prompt=user_prompt,
response_format=pirate_response_schema,
temperature=0.8, # Mais criativo
generation_name="pirate-name-generation"
)
# Resultado já é um objeto JSON parseado
pirate_name = llm_result['pirate_name']
pirate_title = llm_result['pirate_title']
backstory = llm_result['pirate_backstory']
return llm_result # Objeto completo com todos os campos
Exemplo 2: Retorno Simples (Texto)
def analisar_documento(text: str):
system_prompt = """Você é um especialista em análise de documentos.
Analise o texto fornecido e identifique se é um documento válido,
seu tipo e pontos importantes."""
user_prompt = f"Analise este documento:\n\n{text}"
# Chamada simples sem estrutura
result = llm_helper.completion(
system_prompt=system_prompt,
user_prompt=user_prompt,
temperature=0.1, # Mais determinístico
generation_name="document-analysis"
)
# Resultado: {"content": "Análise do documento..."}
analysis_text = result['content']
return analysis_text
Exemplo 3: Modelo e Parâmetros Customizados
def processar_com_modelo_especifico(data: str):
system_prompt = "Você é um assistente especializado."
user_prompt = f"Processe estes dados: {data}"
result = llm_helper.completion(
system_prompt=system_prompt,
user_prompt=user_prompt,
model="gpt-4o", # Modelo específico
temperature=0.7,
generation_name="custom-processing",
max_tokens=1000, # Parâmetro adicional
top_p=0.9, # Parâmetro adicional
)
return result['content']
🎯 Schemas JSON Estruturados
Formato do Response Format
# Estrutura básica do schema
response_format = {
"type": "json_schema",
"json_schema": {
"name": "nome_do_schema",
"schema": {
"type": "object",
"properties": {
"campo1": {
"type": "string",
"description": "Descrição do campo"
},
"campo2": {
"type": "number",
"description": "Campo numérico"
}
},
"required": ["campo1"],
"additionalProperties": False
}
}
}
Exemplos de Schemas Úteis
Extração de Dados Pessoais
personal_data_schema = {
"type": "json_schema",
"json_schema": {
"name": "personal_data_extraction",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string", "description": "Nome completo"},
"cpf": {"type": "string", "description": "CPF encontrado"},
"email": {"type": "string", "description": "Email encontrado"},
"phone": {"type": "string", "description": "Telefone encontrado"},
"address": {"type": "string", "description": "Endereço completo"},
"confidence": {"type": "number", "description": "Confiança na extração (0-1)"}
},
"required": ["name", "confidence"],
"additionalProperties": False
}
}
}
Classificação de Documentos
document_classification_schema = {
"type": "json_schema",
"json_schema": {
"name": "document_classification",
"schema": {
"type": "object",
"properties": {
"document_type": {
"type": "string",
"enum": ["RG", "CPF", "CNH", "Passport", "Unknown"],
"description": "Tipo do documento identificado"
},
"is_valid": {"type": "boolean", "description": "Se o documento é válido"},
"extracted_info": {
"type": "object",
"description": "Informações extraídas do documento"
},
"confidence_score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Score de confiança"
}
},
"required": ["document_type", "is_valid", "confidence_score"],
"additionalProperties": False
}
}
}
💡 Casos de Uso Comuns
✅ Processamento de Formulários
def extrair_dados_formulario(form_text: str):
schema = {
"type": "json_schema",
"json_schema": {
"name": "form_data",
"schema": {
"type": "object",
"properties": {
"nome": {"type": "string"},
"email": {"type": "string"},
"telefone": {"type": "string"},
"endereco": {"type": "string"},
"servico_solicitado": {"type": "string"},
"observacoes": {"type": "string"}
},
"required": ["nome", "email"],
"additionalProperties": False
}
}
}
return llm_helper.completion(
system_prompt="Extraia dados estruturados deste formulário.",
user_prompt=form_text,
response_format=schema,
temperature=0.1
)
✅ Análise de Sentimento
def analisar_sentimento(message: str):
schema = {
"type": "json_schema",
"json_schema": {
"name": "sentiment_analysis",
"schema": {
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positive", "negative", "neutral"]
},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"emotions": {
"type": "array",
"items": {"type": "string"}
},
"summary": {"type": "string"}
},
"required": ["sentiment", "confidence"],
"additionalProperties": False
}
}
}
return llm_helper.completion(
system_prompt="Analise o sentimento desta mensagem.",
user_prompt=message,
response_format=schema,
generation_name="sentiment-analysis"
)
✅ Validação de Dados
def validar_cpf_com_llm(cpf: str, nome: str):
system_prompt = """Você é um validador de dados.
Analise se o CPF está no formato correto e se faz sentido
com o nome fornecido."""
result = llm_helper.completion(
system_prompt=system_prompt,
user_prompt=f"CPF: {cpf}, Nome: {nome}",
response_format={
"type": "json_schema",
"json_schema": {
"name": "cpf_validation",
"schema": {
"type": "object",
"properties": {
"is_valid_format": {"type": "boolean"},
"seems_legitimate": {"type": "boolean"},
"issues": {"type": "array", "items": {"type": "string"}},
"confidence": {"type": "number"}
},
"required": ["is_valid_format", "seems_legitimate"],
"additionalProperties": False
}
}
},
temperature=0.2
)
return result
⚠️ Considerações Importantes
Controle de Temperature
# Temperature baixa (0.0 - 0.3) - Mais determinístico
result = llm_helper.completion(
system_prompt="Extraia dados precisos...",
user_prompt=text,
temperature=0.1 # Para tarefas que precisam de precisão
)
# Temperature média (0.4 - 0.7) - Balanceado
result = llm_helper.completion(
system_prompt="Analise e sugira...",
user_prompt=text,
temperature=0.5 # Para análises balanceadas
)
# Temperature alta (0.8 - 1.0) - Mais criativo
result = llm_helper.completion(
system_prompt="Seja criativo...",
user_prompt=text,
temperature=0.8 # Para geração criativa
)
Tratamento de Erros
def chamada_segura_llm():
try:
result = llm_helper.completion(
system_prompt="...",
user_prompt="...",
response_format=schema,
temperature=0.3
)
return result
except Exception as e:
# Log automático já foi feito pelo LLMHelper
return {"error": f"Falha na chamada LLM: {str(e)}"}
Boas Práticas
# ✅ Bom - Schema bem definido
schema = {
"type": "json_schema",
"json_schema": {
"name": "clear_schema_name",
"schema": {
"type": "object",
"properties": {
"field": {
"type": "string",
"description": "Descrição clara"
}
},
"required": ["field"],
"additionalProperties": False # Importante!
}
}
}
# ✅ Bom - Generation names descritivos
llm_helper.completion(
system_prompt="...",
user_prompt="...",
generation_name="document-classification-cpf" # Específico
)
# ❌ Evitar - Schema muito complexo ou sem required
# ❌ Evitar - Temperature muito alta para dados estruturados
# ❌ Evitar - Prompts muito longos sem estrutura
O LLMHelper cria automaticamente generations no LangFuse para cada chamada, permitindo rastreamento completo de performance, custos e qualidade das respostas LLM dentro das Actions.
Para dados estruturados e extrações precisas, use temperature baixa (0.0-0.3). Para tarefas criativas, use temperature alta (0.7-1.0). O padrão 0.3 é um bom equilíbrio para a maioria dos casos.
O LLMHelper oferece uma interface poderosa e flexível para integrar capacidades de LLM diretamente nas actions, com observabilidade completa e suporte a dados estruturados!
📚 Links Úteis
JSON Schema
- What is JSON Schema? - Documentação oficial sobre JSON Schema, padrão utilizado para definir estruturas de dados no
response_format
OpenAI Structured Outputs
- Structured Outputs Guide - Guia oficial da OpenAI sobre como usar saídas estruturadas com JSON Schema