API: LLM Usage¶
Visão Geral¶
Endpoints para monitoramento de uso de LLM (tokens e custos). Permite visualizar consumo agregado por modelo, tipo de operação, tenant e período.
A seção "By Operation" agrupa por OperationType + Model, permitindo visualizar qual modelo foi utilizado em cada tipo de operação.
O tracking é feito automaticamente pelo sistema em todas as chamadas aos LLMs (Claude e OpenAI) e armazena: - Provider e modelo utilizado - Tipo de operação (Chat, Vision, Transcription, etc.) - Tokens de entrada e saída - Custo estimado (baseado na tabela de preços configurada) - Metadados estruturados em JSONB (agentId, traceId, conversationId, whatsAppMessageIds e campos específicos por operação)
Autorização e Rate Limiting¶
Todos os endpoints de LLM Usage requerem autorização SuperAdmin (RequireAuthorization(AuthConstants.Roles.SuperAdmin)) e estão sob a política de rate limiting SuperAdmin (RateLimitPolicies.SuperAdmin): 20 requisições por 60 segundos.
Endpoints¶
GET /api/admin/llm-usage/summary¶
Retorna um sumário agregado do uso de LLM no período especificado.
Query Parameters:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| startDate | DateTime | Sim | Data inicial do período (UTC) |
| endDate | DateTime | Sim | Data final do período (UTC) |
| provider | string | Não | Filtrar por provider (Anthropic, OpenAI) |
| operationType | string | Não | Filtrar por tipo de operação |
| tenantId | Guid | Não | Filtrar por tenant |
Response (200 OK):
{
"totalRequests": 542,
"totalInputTokens": 1250000,
"totalOutputTokens": 380000,
"totalCost": 12.45,
"cacheHitRequests": 310,
"totalCacheReadTokens": 450000,
"totalCacheWriteTokens": 120000
}
GET /api/admin/llm-usage/by-model¶
Retorna o uso de LLM agrupado por provider e modelo.
Query Parameters:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| startDate | DateTime | Sim | Data inicial do período (UTC) |
| endDate | DateTime | Sim | Data final do período (UTC) |
| provider | string | Não | Filtrar por provider (Anthropic, OpenAI) |
| operationType | string | Não | Filtrar por tipo de operação |
| tenantId | Guid | Não | Filtrar por tenant |
Response (200 OK):
[
{
"provider": "Anthropic",
"model": "claude-3-5-sonnet-20241022",
"totalRequests": 450,
"totalInputTokens": 1000000,
"totalOutputTokens": 300000,
"totalCost": 9.50
},
{
"provider": "OpenAI",
"model": "gpt-4o-mini",
"totalRequests": 92,
"totalInputTokens": 250000,
"totalOutputTokens": 80000,
"totalCost": 2.95
}
]
GET /api/admin/llm-usage/by-operation¶
Retorna o uso de LLM agrupado por tipo de operação e modelo.
Query Parameters:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| startDate | DateTime | Sim | Data inicial do período (UTC) |
| endDate | DateTime | Sim | Data final do período (UTC) |
| provider | string | Não | Filtrar por provider (Anthropic, OpenAI) |
| operationType | string | Não | Filtrar por tipo de operação |
| tenantId | Guid | Não | Filtrar por tenant |
Response (200 OK):
[
{
"operationType": "Chat",
"model": "claude-3-5-sonnet-20241022",
"totalRequests": 480,
"totalTokens": 1500000,
"totalCost": 11.00
},
{
"operationType": "Vision",
"model": "claude-3-5-sonnet-20241022",
"totalRequests": 62,
"totalTokens": 130000,
"totalCost": 1.45
}
]
GET /api/admin/llm-usage/by-tenant¶
Retorna o uso de LLM agrupado por tenant, com paginação.
Query Parameters:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| startDate | DateTime | Sim | Data inicial do período (UTC) |
| endDate | DateTime | Sim | Data final do período (UTC) |
| provider | string | Não | Filtrar por provider (Anthropic, OpenAI) |
| operationType | string | Não | Filtrar por tipo de operação |
| tenantId | Guid | Não | Filtrar por tenant |
| page | int | Sim | Página (default: 1) |
| pageSize | int | Sim | Itens por página (default: 10) |
Response (200 OK):
{
"items": [
{
"tenantId": "110e8400-e29b-41d4-a716-446655440099",
"tenantName": "Pizzaria Exemplo",
"totalRequests": 450,
"totalInputTokens": 1000000,
"totalOutputTokens": 300000,
"totalCost": 9.50
}
],
"totalCount": 15
}
GET /api/admin/llm-usage/margin¶
Retorna dados de margem por tenant (custo LLM vs créditos consumidos/adicionados e preço da assinatura).
Autorização: SuperAdmin
Query Parameters:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| startDate | DateTime | Sim | Data inicial do período (UTC) |
| endDate | DateTime | Sim | Data final do período (UTC) |
| provider | string | Não | Filtrar por provider (Anthropic, OpenAI) |
| operationType | string | Não | Filtrar por tipo de operação |
| tenantId | Guid | Não | Filtrar por tenant |
| page | int | Sim | Página (default: 1) |
| pageSize | int | Sim | Itens por página (default: 10) |
Response (200 OK):
{
"items": [
{
"tenantId": "110e8400-e29b-41d4-a716-446655440099",
"tenantName": "Pizzaria Exemplo",
"totalCostUsd": 8.50,
"creditsConsumed": 150,
"creditsAdded": 500,
"monthlyPriceBrl": 199.90,
"costPerCreditUsd": 0.057
}
],
"totalCount": 15
}
Tipos de Operação (LlmOperationType)¶
| Valor | Descrição |
|---|---|
| Chat | Resposta em conversa (pipelines aggregation, deferred, outgoing) |
| Vision | Descrição de imagem via Claude Vision |
| Transcription | Transcrição de áudio via OpenAI Whisper |
| Embedding | Geração de embeddings para busca semântica (knowledge, faq, search) |
| Chunking | Processamento de knowledge blocks |
| Playground | Testes no playground do agente |
| AiAssistant | Assistente IA para configuração de agentes |
| QueryRewrite | Reescrita de queries para busca semântica |
| IntentClassification | Classificação de intenção da mensagem |
Providers (LlmProvider)¶
| Valor | Descrição |
|---|---|
| Anthropic | Claude API |
| OpenAI | OpenAI API |
Configuração de Preços¶
Os preços são configurados em appsettings.json na seção LlmPricing:
{
"LlmPricing": {
"Models": [
{ "Model": "claude-opus-4-5-20251101", "InputPricePerMillion": 5.00, "OutputPricePerMillion": 25.00 },
{ "Model": "claude-sonnet-4-5-20251001", "InputPricePerMillion": 3.00, "OutputPricePerMillion": 15.00 },
{ "Model": "claude-haiku-4-5-20251001", "InputPricePerMillion": 1.00, "OutputPricePerMillion": 5.00 },
{ "Model": "claude-3-5-sonnet-20241022", "InputPricePerMillion": 3.00, "OutputPricePerMillion": 15.00 },
{ "Model": "gpt-4-turbo", "InputPricePerMillion": 10.00, "OutputPricePerMillion": 30.00 },
{ "Model": "gpt-4o", "InputPricePerMillion": 2.50, "OutputPricePerMillion": 10.00 },
{ "Model": "gpt-4o-mini", "InputPricePerMillion": 0.15, "OutputPricePerMillion": 0.60 },
{ "Model": "gpt-3.5-turbo", "InputPricePerMillion": 0.50, "OutputPricePerMillion": 1.50 }
]
}
}
Cálculo de Custo¶
O custo é calculado automaticamente pelo LlmPricingService:
EstimatedCost = (InputTokens / 1_000_000) * InputPricePerMillion
+ (OutputTokens / 1_000_000) * OutputPricePerMillion
Se o modelo não estiver configurado na tabela de preços, EstimatedCost será null.
Tracking Automático¶
O tracking é feito via LlmUsageTracker (fire-and-forget com Channel) + LlmUsageBackgroundService (consumer que persiste no banco).
Campos comuns são injetados automaticamente pelo Track():
- agentId — parâmetro obrigatório
- traceId — capturado de Activity.Current
- conversationId — capturado de Activity.Current.GetTagItem("ciba.conversationId")
- whatsAppMessageIds — capturado de Activity.Current.GetTagItem("ciba.whatsAppMessageIds")
Campos específicos por operação são passados via metadata records tipados (ChatUsageMetadata, VisionUsageMetadata, etc.).
Multi-tenancy¶
Os dados de LlmUsage respeitam o filtro de tenant:
- Cada registro tem TenantId
- Query filter global filtra automaticamente por tenant
- SuperAdmins podem ver dados de todos os tenants
Índices¶
A tabela llm_usages possui índices otimizados para:
- (tenant_id, created_at) — Consultas por tenant e período
- (tenant_id, operation_type, created_at) — Consultas por tipo de operação
- (created_at) — Consultas globais por período