06 - Capturando feedback do usuário como sinal

TL;DR

Feedback do usuário é o sinal mais rico e mais ruidoso que entra no Improvement Loop. Dividir em explícito (thumbs up/down, star rating, free-text complaint) e implícito (re-prompt rate, abandonment, edit-after-paste, copy/share, time-to-action). Cada sinal tem custo de coleta diferente e noise-to-signal diferente; tratá-los uniformemente é erro comum. Pegadinhas: confirmation bias (usuário fica feliz com resposta confirmadora mas errada), popularity ≠ qualidade (resposta mais reaproveitada pode ser a mais genérica). Quando feedback contradiz eval automatizado: depende do que cada um mede. Eval mede alinhamento com rubrica; feedback mede utilidade percebida. Os dois importam, mas servem decisões diferentes. Tools 2026: Langfuse, Braintrust, Helicone têm feedback API nativa; rolar próprio é tabela feedbacks com FK no trace + endpoint.

Por que feedback do usuário entra no loop

Eval offline mede alinhamento com rubrica: rubrica diz que resposta boa tem 3 bullets factuais, dataset tem ground truth, judge confirma. Eval responde “isso é correto?“.

Feedback do usuário mede utilidade percebida: a resposta tecnicamente correta foi útil? Resolveu o problema? Conectou com o contexto do usuário? Feedback responde “isso ajudou?“.

Sistema de IA em produção precisa dos dois. Sistema sem feedback otimiza pra benchmark e degrada UX; sistema sem eval otimiza pra “sensação boa” e vira chatbot bajulador (o sycophancy problem).

Explícito vs implícito

Sinal explícito

Usuário declara o feedback. Custo de coleta: alto pra usuário (precisa parar e clicar). Sinal: forte mas esparso (90%+ dos usuários ignoram).

SinalComo coletaCusto cognitivoNoise
Thumbs up/downBotão ao lado da respostaBaixo (1 clique)Médio (clica sem ler com cuidado)
Star rating (1-5)Modal ou inlineMédioAlto (escala não calibrada entre usuários)
Free-text complaintModal “o que deu errado?”AltoBaixo no conteúdo, mas baixo volume
Bug report estruturadoForm com categoriaMuito altoMuito baixo (quem responde, sabe o que tá fazendo)

Padrão pragmático: thumbs simples como default, free-text opcional depois de thumbs down (“conta mais?”). Thumbs binário evita debate de escala; free-text captura categoria de falha.

Sinal implícito

Comportamento do usuário revela o feedback sem precisar declarar. Custo de coleta: zero pra usuário. Sinal: rico mas exige interpretação.

SinalO que sugereConfounders
Re-prompt rateUsuário não ficou satisfeito; tentou de novoPode estar refinando, não reclamando
AbandonmentUsuário fechou sem agirPode ter conseguido o que queria e saiu
Edit-after-pasteOutput foi usado mas precisou consertoPode ser edição estilística natural
Copy/shareOutput foi útil o suficiente pra mover adiantePode ser arquivar pra revisar depois
Time-to-actionDemora pra agir = usuário processando ou desistindoSinal ambíguo sem contexto
Continuação da sessãoMais turns = engajamentoMais turns = também pode ser “ainda procurando”
Retorno após N diasSistema gerou valor o suficiente pra voltarSinal lento, alta latência

Implícito é mais volume, mais ruído. Precisa de modelagem (taxa por cohort, comparação com baseline) pra virar sinal acionável.

Weighting — cada sinal vale o quê

Erro comum: tratar todos os feedbacks como iguais. Realidade: cada sinal tem custo-pra-coletar diferente e noise-pra-signal diferente.

Heurísticas de weighting:

Tipo de sinalPeso típicoPor quê
Bug report estruturadoAltoBaixo volume, baixo noise; quem reporta sabe o que viu
Free-text complaintAltoEsforço sinaliza intensidade real
Thumbs downMédioVolume razoável, noise médio
Thumbs upBaixoConfirmation bias forte; usuário clica em qualquer coisa que parece OK
Re-promptMédio-altoAção implícita forte; usuário não tá satisfeito
AbandonmentBaixo-médioAmbíguo; precisa cruzar com outros sinais
Edit-after-pasteMédioIndica refinamento, pode ser estilo
Copy/shareMédio-baixoIndica utilidade, mas não confirma qualidade do conteúdo

Cálculo prático: peso × frequência por categoria = ranking de problemas. Categoria que aparece em 5 bug reports detalhados ≈ categoria que aparece em 500 thumbs down.

Confounders — onde feedback engana

Sinais humanos têm vieses sistemáticos. Os principais no contexto de IA:

Confirmation bias

Usuário tende a thumbs up em resposta que concorda com sua hipótese prévia, mesmo que esteja errada. Exemplo: “Existe relação entre X e Y?” → resposta confirma, usuário curte; resposta nega, usuário não curte. Sistema treinado em thumbs up vira sycophant — concorda com tudo.

Mitigação: pesar thumbs up menos que thumbs down; combinar com eval factual; treinar judges pra detectar sycophancy.

Popularity ≠ qualidade

Resposta mais copiada/compartilhada pode ser a mais genérica (encaixa em vários contextos) e menos a mais útil pra um caso específico. “Top resposta” pelo signal de copy pode ser exatamente a que o usuário quer com baixo esforço cognitivo, não a melhor.

Mitigação: medir por cohort/contexto, não global; cruzar com métricas de resolução do problema downstream.

Selection bias na coleta

Quem dá feedback explícito tem perfil diferente do usuário médio. Outliers (super-fãs ou super-decepcionados) sobrerepresentados. Sinal não é amostra aleatória da base.

Mitigação: combinar explícito com implícito (que cobre todo mundo); modelar quem tá dando feedback (cohort analysis).

Reciprocidade percebida

Usuário pode dar thumbs up por “educação” ou por gostar do produto em geral, não daquela resposta específica.

Mitigação: thumbs anônimo, sem identificação social; sinais implícitos como contrapeso.

Anchoring na resposta anterior

Em sessão multi-turn, usuário avalia resposta N comparando com resposta N-1. Resposta N pode ser absolutamente boa mas parecer ruim porque N-1 foi excepcional.

Mitigação: análise por turn isolado quando possível; modelar contexto de sessão.

Combinando com eval automatizado — quando cada um vence

Frequentemente os dois sinais concordam. Quando não concordam:

Eval alta, feedback baixo

  • Eval diz “resposta correta segundo rubrica”
  • Usuários reclamam consistentemente
  • Provável causa: rubrica não cobre algo importante (UX, tom, completude pra caso real, formato esperado)
  • Ação: rubrica precisa ser estendida; feedback é o sinal que vence aqui

Eval baixa, feedback alto

  • Eval diz “resposta tem problemas”
  • Usuários curtem
  • Provável causa: sycophancy, bajulação, resposta verbosa que parece esforçada
  • Ação: investigar tipo de erro que eval pegou; se for sycophancy, eval vence
  • Atenção: feedback positivo em resposta tecnicamente errada é o sinal mais perigoso — perpetua erro

Eval e feedback concordam

  • Sinal forte; trate como confirmação
  • Use a magnitude pra priorizar

Discordância por subgrupo

  • Eval e feedback médios são parecidos; mas feedback no segmento X é negativo
  • Provável causa: distribuição não capturada no golden set (idioma, vertical, persona)
  • Ação: dataset precisa adicionar amostras desse segmento

A regra honesta: nenhum dos dois vence universalmente. Eval mede “correto”; feedback mede “útil”. Decisão de produto precisa pesar os dois. Decisão técnica (regressão de prompt) costuma pesar eval; decisão de UX (formato, tom) costuma pesar feedback.

Tools 2026

Built-in em frameworks de eval/observability

ToolComo funciona
LangfuseScore API — langfuse.score(trace_id, name="user_thumbs", value=1). Score vincula ao trace, dashboard mostra por prompt_version.
BraintrustFeedback API similar; integra com eval comparison view.
HeliconeFeedback endpoint via proxy; UI mostra correlação com prompt/model.
Arize PhoenixFeedback como annotation no span; útil pra training de judge.

Rolar próprio

Quando o stack é caseiro ou tem requisitos específicos:

# tabela mínima
CREATE TABLE feedbacks (
    id UUID PRIMARY KEY,
    trace_id TEXT NOT NULL,        -- FK pro trace
    user_id TEXT,                  -- opcional, anonimizado quando preciso
    feedback_type TEXT NOT NULL,   -- "thumb", "star", "free_text", "bug"
    value JSONB NOT NULL,          -- {"thumb": "up"} | {"stars": 4} | {"text": "..."}
    metadata JSONB,                -- contexto adicional (cohort, segment)
    created_at TIMESTAMPTZ DEFAULT now()
);
 
CREATE INDEX idx_feedbacks_trace ON feedbacks(trace_id);
CREATE INDEX idx_feedbacks_type_time ON feedbacks(feedback_type, created_at);
# endpoint mínimo
@app.post("/feedback")
def submit_feedback(payload: FeedbackPayload):
    db.insert("feedbacks", {
        "trace_id": payload.trace_id,
        "user_id": hash_user(payload.user_id),  # privacy by default
        "feedback_type": payload.type,
        "value": payload.value,
        "metadata": payload.metadata,
    })
    # opcional: webhook pra Slack em casos críticos (e.g., free_text)
    if payload.type == "free_text" and payload.value.get("sentiment") == "negative":
        notify_team(payload)

Decisão pragmática: time pequeno usa o que vier com framework já adotado (Langfuse Score API, Braintrust Feedback); time grande com privacidade rígida ou stack misto costuma rolar próprio.

Anti-padrões

  • Coletar tudo, analisar nada — feedback acumula em tabela, ninguém olha
  • Tratar todo feedback como igual — thumbs up de usuário aleatório == bug report detalhado de power user
  • Ignorar implícito — só thumbs/stars; perde 90% do sinal
  • Treinar judge em feedback bruto — sycophancy in, sycophancy out
  • Não anonimizar — privacidade vira problema legal antes do feedback virar valor
  • Feedback sem trace_id — não dá pra ligar feedback à versão do prompt/modelo que gerou
  • Sem postmortem regular — feedback fica em dashboard, nunca vira backlog
  • Mostrar agregado sem cohort — média esconde regressão em segmento específico
  • Reagir a feedback isolado em produção crítica — UM bug report dispara mudança no prompt sem investigar

Operacionalizando — do feedback à mudança

O feedback vira parte do loop quando segue um fluxo:

1. Coleta: API + framework de tracing vinculam feedback ao trace + prompt_version
2. Agregação: dashboard por categoria, cohort, segmento
3. Triagem: revisar amostras (humano), categorizar tipos de falha
4. Backlog: tipos de falha viram itens com prioridade (volume × peso)
5. Eval gap: tipos que eval não pega vão pra extensão do golden set
6. Hipótese de mudança: diff no prompt, novo few-shot, novo guardrail
7. A/B + canary: valida que a mudança resolve a categoria
8. Métrica de fechamento: feedback negativo daquela categoria cai depois do ship

Sem o passo 4 (backlog), feedback nunca vira ação. Sem o passo 8 (métrica de fechamento), o time não sabe se resolveu mesmo.

Fontes

Veja também