Generation — passar contexto ao LLM com citação

TL;DR

Geração é onde RAG vira resposta com citação. Estrutura padrão de prompt: trechos delimitados + pergunta + regras explícitas (citar trecho usado, devolver “não sei” se contexto não cobre). Citação não é nice-to-have — é a feature que diferencia RAG de chatbot. Cuidado com faithfulness: LLM pode misturar contexto com conhecimento próprio. Padrões: structured output com source ID, system prompt restritivo, validação de citação no post-processing.

A estrutura do prompt

SYSTEM:
Você responde apenas com base nos trechos fornecidos. Cite [N] cada
afirmação usando o número do trecho. Se trechos não cobrem a pergunta,
responda: "Não encontrei essa informação."
 
USER:
Trechos:
[1] {chunk_1_text}
[2] {chunk_2_text}
[3] {chunk_3_text}
 
Pergunta: {user_question}

3 elementos cruciais:

  1. Delimitação — trechos numerados, separados
  2. Regra de citação — explícita
  3. Regra de fallback — “não sei” como opção válida

Construção de contexto — o elo entre retrieval e geração

Retrieval certo ≠ resposta certa

Recuperar o documento certo não garante resposta certa. Quando o chunk correto está no contexto e a resposta ainda erra, o gargalo está entre recuperar e gerar — não é “o LLM alucinou, melhore o prompt”. As 5 causas possíveis estão mapeadas em 09 - Evaluation de RAG; aqui tratamos das três que vivem na construção do contexto.

Ordenação importa (Lost in the Middle)

LLMs aproveitam melhor o que está no início e no fim do contexto e tendem a ignorar o meio — a curva de atenção em U. Um chunk relevante jogado no meio de um top-K longo pode ser desprezado mesmo tendo sido recuperado e bem ranqueado.

  • Posicione os chunks de maior score nas pontas do contexto, não no meio.
  • Poucos chunks bem ordenados > muitos chunks “na ordem crua do retrieval”.

Menos é mais — ruído dilui evidência

Empilhar o chunk certo junto com N chunks irrelevantes (ou desatualizados/conflitantes) piora a resposta. Não é hallucination — é confusão de evidência: o modelo tem o material certo, mas afogado em ruído.

  • Priorize precisão sobre volume (ver context_precision em 09 - Evaluation de RAG).
  • 3 chunks de alta relevância costumam bater 10 chunks “por garantia”.

Extrair antes de gerar (extract-then-generate)

Para queries difíceis, não passe chunks crus direto pro LLM. Insira uma etapa que extrai os spans de suporte exatos (as sentenças que de fato respondem à pergunta) e gere a resposta só a partir delas. Menos texto cru = menos espaço para o modelo improvisar.

Pipeline de geração robusto

Quando a resposta exige juntar fatos espalhados em vários chunks, a geração vira um fluxo multi-etapa, não uma chamada única:

retrieve → rerank → extrair evidência → resolver conflitos → gerar → verificar contra evidência
  • Resolver conflitos — quando chunks discordam (ex.: versões diferentes da mesma doc), reconcilie antes de gerar (a regra 4 do system prompt restritivo, abaixo, é a semente disso).
  • Verificar contra evidência — checar se cada afirmação da resposta é suportada por algum trecho recuperado é o gate de faithfulness (09 - Evaluation de RAG). Frameworks como Self-RAG e Corrective RAG (CRAG) automatizam essa auto-checagem; o CRAG ainda dispara correção (ex.: nova busca) quando o retrieval vem fraco.

Por que citação importa

Sem citação:

  • Usuário não sabe se LLM inventou
  • Compliance (medical, legal, finance) inviável
  • Auditoria impossível
  • Confiança limitada

Com citação:

  • Usuário verifica fonte
  • Audit trail natural
  • Compliance facilitado
  • Confiança aumenta

Patterns de prompt

Pattern 1 — Numbered citations (default)

Trechos:
[1] FastAPI suporta async desde a versão 0.5...
[2] Para criar endpoint async, use async def...
[3] Connection pooling melhora performance...

Resposta esperada:
"FastAPI suporta async [1]. Para criar endpoints, use async def [2]. Para
performance, considere connection pooling [3]."

Simples, fácil de validar (regex \[\d+\]).

Pattern 2 — Structured output

from pydantic import BaseModel
 
class Citation(BaseModel):
    text: str
    sources: list[int]  # IDs dos chunks
 
class RAGResponse(BaseModel):
    answer: list[Citation]
    confidence: Literal["high", "medium", "low"]
    is_supported: bool

LLM retorna JSON válido. Validação automática.

Pattern 3 — XML delimiters

<context>
  <doc id="1">...</doc>
  <doc id="2">...</doc>
</context>
<question>...</question>

XML reduz prompt injection (ver Segurança e Guardrails).

System prompt restritivo

Padrão consolidado:

You are a {domain} assistant. Answer ONLY based on the provided context.

Rules:
1. Cite each claim with [N] referencing the source chunk.
2. If context does not contain the answer, respond: "I cannot answer
   based on available information."
3. Do NOT use external knowledge, even if you "know" the answer.
4. If chunks contradict, point out the contradiction.
5. Quote directly when accuracy is critical.

Context:
[1] {chunk_1}
[2] {chunk_2}
...

Question: {user_question}

A regra 3 é crítica — LLM tende a complementar com conhecimento próprio. System prompt restritivo reduz mas não elimina.

Faithfulness — o problema central

Faithfulness: a resposta é fiel ao contexto (sem inventar)?

Modos comuns de falha:

FalhaExemplo
Mistura de fontesResposta combina dois chunks contraditórios sem notar
Inferência não-suportadaContexto diz “FastAPI suporta async”. LLM diz “FastAPI é mais rápido que Flask” (não no contexto)
GeneralizaçãoContexto sobre v3, LLM responde sobre todas as versões
Citação erradaCita [2] mas info está em [1]
Halucinação totalInventa info não presente em nenhum chunk

Mitigações:

  • System prompt restritivo (acima)
  • Reduzir temperature (0 ou 0.2 para tarefas factuais)
  • Validação automática (LLM-as-judge: a resposta usa info do contexto?)
  • Estimativa de confidence (LLM declara confidence)

Detalhes em 09 - Evaluation de RAG.

Quando dizer “não sei”

Devolver "não sei" é feature, não falha

RAG-bom é melhor que RAG-tudo-respondendo. Condições para “não sei”:

  • Reranker top-1 score <0.6 (07 - Reranking)
  • Contexto não cobre a pergunta semanticamente
  • Pergunta fora do escopo do dataset

LLM-as-judge auxiliar:

def is_answerable(question, chunks):
    prompt = f"""
    Os trechos abaixo são suficientes para responder?
    Pergunta: {question}
    Trechos: {chunks}
 
    Responda: yes/no/partial
    """
    return llm.complete(prompt)

Output formatting

Resposta direta + citações inline

"FastAPI suporta async desde a versão 0.5 [1]. Para criar um endpoint async,
use async def antes da função handler [2]."

Mais usado. Boa UX.

Resposta + sources separados

{
  "answer": "FastAPI suporta async desde a versão 0.5...",
  "sources": [
    {"chunk_id": 1, "page": 42},
    {"chunk_id": 2, "page": 51}
  ]
}

Útil para UIs com tooltips ou expansíveis.

Quote-driven

> "FastAPI fully supports async since v0.5"
> — manual.md, page 42

> "Endpoints can be made async by using `async def`..."
> — manual.md, page 51

Em domínios legal ou medical, citações textuais reduzem ambiguidade.

Modelos para generation

ModeloForte em RAGCusto
Claude Sonnet 4.6Excelente em seguir instruções restritivasMédio
GPT-5Muito bom, costuma “complementar” maisMédio
Gemini 2.5 ProLong context, multimodalMédio
Haiku / Flash / GPT-4o-miniBom para QA simples, baratoBaixo
Llama 3.3 70BSelf-hosted$$ infra

Tiering em RAG

Use Haiku/Flash para 90% das perguntas simples. Escala para Sonnet/Opus quando confidence baixa ou pergunta complexa.

Latência típica

ComponenteLatência
Generation com 5 chunks de 500 tokens500ms-2s
Streaming (TTFT)200-500ms
Total user-facing (com retrieval)1-3s

Streaming é crucial para UX em RAG — usuário vê resposta começando imediatamente.

Métricas

MétricaAlvo
Faithfulness (LLM-as-judge)>90%
Citation accuracy (citação aponta info correta)>95%
% respostas “não sei” apropriadas5-15%
Latência generation<2s (p95)
Cost por resposta<$0.005

Anti-patterns

  • Sem regra de citação — LLM responde sem fontes
  • Sem regra de “não sei” — força resposta mesmo sem info
  • Temperature alta (>0.5) em RAG factual — mais hallucination
  • Não validar citações — citação errada passa
  • Modelo grande para tudo — Haiku resolve a maioria
  • Sem streaming — UX ruim
  • Prompt sem delimitação — confusão entre context e instruction

Veja também

Referências

  • AnthropicCitations API (2024)
  • Eugene YanPatterns for Building LLM-based Systems (2024)
  • OpenAIStructured outputs guide (2026)
  • Liu et al.Lost in the Middle: How Language Models Use Long Contexts (arXiv 2307.03172, TACL 2024)
  • Asai et al.Self-RAG: Learning to Retrieve, Generate and Critique through Self-Reflection (arXiv 2310.11511, 2023)
  • Yan et al.Corrective Retrieval Augmented Generation (CRAG) (arXiv 2401.15884, 2024)