12-03-01 — Metricas: latencia, custo (tokens), qualidade
TL;DR
Toda aplicacao LLM em producao precisa medir latencia (experiencia do usuario), custo por token (viabilidade financeira) e qualidade (utilidade real). As tres sao independentes e frequentemente em tensao: menor latencia geralmente significa modelo menor e pior qualidade; melhor qualidade custa mais tokens. Defina SLOs claros para cada dimensao antes de ir para producao.
Dimensao 1: Latencia
Latencia em aplicacoes LLM tem caracteristicas distintas de APIs tradicionais:
- Time to First Token (TTFT): Quanto tempo ate o usuario ver a primeira palavra. Critico para streaming.
- Time to Last Token (TTLT): Latencia total da resposta completa.
- End-to-End (E2E): TTLT + retrieval + pos-processamento + rede.
SLOs recomendados por tipo de aplicacao
| Tipo | TTFT | E2E P95 |
|---|---|---|
| Chat em tempo real | <800ms | <5s |
| Analise/relatorio | <2s | <30s |
| Processamento batch | N/A | sem SLO |
| Agente com tools | <1s | <15s |
import time
from dataclasses import dataclass
@dataclass
class LatencyMetrics:
ttft_ms: float
ttlt_ms: float
e2e_ms: float
retrieval_ms: float
llm_ms: float
def medir_latencia_streaming(query: str) -> LatencyMetrics:
start = time.monotonic()
retrieval_start = start
# Retrieval
docs = retriever.invoke(query)
retrieval_ms = (time.monotonic() - retrieval_start) * 1000
# LLM com streaming
llm_start = time.monotonic()
first_token_time = None
full_response = ""
stream = openai_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"{docs}\n{query}"}],
stream=True
)
for chunk in stream:
if first_token_time is None and chunk.choices[0].delta.content:
first_token_time = time.monotonic()
if chunk.choices[0].delta.content:
full_response += chunk.choices[0].delta.content
llm_ms = (time.monotonic() - llm_start) * 1000
ttft_ms = (first_token_time - llm_start) * 1000 if first_token_time else llm_ms
e2e_ms = (time.monotonic() - start) * 1000
return LatencyMetrics(
ttft_ms=ttft_ms,
ttlt_ms=llm_ms,
e2e_ms=e2e_ms,
retrieval_ms=retrieval_ms,
llm_ms=llm_ms
)
Dimensao 2: Custo (tokens)
O custo de uma aplicacao LLM e diretamente proporcional ao numero de tokens processados. Principais alavancas de controle:
Calculo de custo por requisicao
# Tabela de precos GPT-4o (Abril 2025, Azure OpenAI)
PRICES = {
"gpt-4o": {"input": 0.0025, "output": 0.010}, # por 1K tokens
"gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
"gpt-4-turbo": {"input": 0.010, "output": 0.030},
}
def calcular_custo(model: str, input_tokens: int, output_tokens: int) -> float:
prices = PRICES.get(model, PRICES["gpt-4o"])
cost = (input_tokens / 1000 * prices["input"]) + \
(output_tokens / 1000 * prices["output"])
return round(cost, 6)
# Exemplo: requisicao tipica de RAG
custo = calcular_custo("gpt-4o", input_tokens=2500, output_tokens=400)
print(f"Custo por requisicao: USD {custo:.4f}") # ~USD 0.010
print(f"Custo por 10.000 requisicoes/dia: USD {custo * 10000:.2f}/dia")
Estrategias de reducao de custo
- Model routing: Use GPT-4o-mini para perguntas simples, GPT-4o para complexas
- Context compression: Resuma historico longo antes de incluir no prompt
- Caching semantico: Perguntas similares retornam resposta em cache (Helicone, Redis + embeddings)
- Limite de output tokens: Configure
max_tokensapropriado para cada caso de uso
Dimensao 3: Qualidade
Qualidade e a mais complexa das tres dimensoes porque nao tem uma metrica unica. E composta por:
Sub-metricas de qualidade
| Sub-metrica | O que mede | Como medir |
|---|---|---|
| Corretude | A resposta e factualmente correta? | Ground truth, LLM-judge |
| Relevancia | A resposta responde a pergunta? | LLM-judge, RAGAS |
| Completude | A resposta cobre todos os aspectos? | LLM-judge com criterios |
| Groundedness | A resposta e suportada pelo contexto RAG? | RAGAS, Phoenix eval |
| Seguranca | Sem conteudo toxico ou prejudicial? | Azure Content Safety |
Score de qualidade composto
def calcular_quality_score(
corretude: float, # 0.0 a 1.0
relevancia: float,
groundedness: float,
seguranca: float
) -> dict:
"""Score composto ponderado por importancia para o negocio."""
pesos = {
"corretude": 0.35,
"relevancia": 0.30,
"groundedness": 0.25,
"seguranca": 0.10
}
score_final = (
corretude * pesos["corretude"] +
relevancia * pesos["relevancia"] +
groundedness * pesos["groundedness"] +
seguranca * pesos["seguranca"]
)
return {
"score": round(score_final, 3),
"nivel": "ALTO" if score_final >= 0.8 else "MEDIO" if score_final >= 0.6 else "BAIXO",
"detalhes": {
"corretude": corretude,
"relevancia": relevancia,
"groundedness": groundedness,
"seguranca": seguranca
}
}
SLOs e alertas recomendados
✅ SLO baseline para agente RAG corporativo
— Latencia E2E P95 < 8s
— Custo medio por sessao < USD 0.05
— Score de qualidade medio > 0.75
— Taxa de erros tecnicos < 1%
Revise e ajuste esses valores depois de 2 semanas em producao.
— Latencia E2E P95 < 8s
— Custo medio por sessao < USD 0.05
— Score de qualidade medio > 0.75
— Taxa de erros tecnicos < 1%
Revise e ajuste esses valores depois de 2 semanas em producao.
Como isso se conecta
- 12-01-01 Por que IA e diferente: Essas tres dimensoes sao o que o APM classico nao cobre
- 12-03-02 Avaliacoes offline: Como medir qualidade de forma sistematica antes de producao
- 12-03-04 Drift detection: Monitorar degradacao dessas metricas ao longo do tempo
- 12-03-05 Desafio RAG: Aplica essas metricas em um cenario concreto