0Pricing
AI Prompt Engineering · Aula

Reordenando trechos recuperados

Reordenação com codificador cruzado.

Reordenando trechos recuperados é uma aula grátis de AI Prompt Engineering no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Prompt Engineering, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Prompt Engineering inclui 4 aulas no total.

Por que reclassificar?

A recuperação da primeira etapa (densa ou esparsa) otimiza a revocação em grande escala: colocar o fragmento de referência em algum lugar entre os 50 primeiros. Ela é rápida, mas aproximada. Um reclassificador da segunda etapa então reordena essa lista reduzida para obter precisão, trazendo os fragmentos realmente relevantes para o topo.

Esse padrão de recuperar amplamente e depois reclassificar com precisão é a base do RAG avançado.

def two_stage(query, k_retrieve=50, k_final=5):
    candidates = first_stage_retrieve(query, k_retrieve)  # high recall
    reranked = rerank(query, candidates)                  # high precision
    return reranked[:k_final]

Codificador duplo versus codificador cruzado

Um codificador duplo codifica a consulta e o documento separadamente em vetores e os compara por cosseno: é rápido e pode ser indexado, mas perde a interação entre consulta e documento. Um codificador cruzado envia a consulta e um candidato juntos pelo modelo e produz uma pontuação de relevância, capturando interações detalhadas.

Os codificadores cruzados são muito mais precisos, mas não podem ser pré-computados; por isso, são executados apenas na lista reduzida.

# Bi-encoder: score = cos(enc(q), enc(d))     -> precomputable
# Cross-encoder: score = model(q, d) -> 0..1   -> per-pair, no index
def cross_encode(query, doc):
    return cross_encoder.predict([(query, doc)])[0]  # joint attention

Uma etapa de reclassificação com codificador cruzado

O reclassificador atribui uma pontuação a cada candidato em relação à consulta e depois os ordena em ordem decrescente. Como o codificador cruzado presta atenção à consulta e ao documento em conjunto, ele resolve aspectos sutis de relevância que o codificador duplo não captou: negação, necessidades de correspondência exata e distinções entre resposta e tópico.

Essa etapa normalmente aumenta a precisão da resposta mais do que qualquer outra melhoria individual do RAG.

def rerank(query, candidates):
    pairs = [(query, c.text) for c in candidates]
    scores = cross_encoder.predict(pairs)        # batched
    for c, s in zip(candidates, scores):
        c.rerank_score = s
    return sorted(candidates, key=lambda c: c.rerank_score, reverse=True)

LLM como reclassificador

Quando nenhum codificador cruzado treinado se adapta ao seu domínio, um LLM pode reclassificar. A solicitação por lista pede que o modelo ordene uma lista de passagens por relevância em uma única chamada; a solicitação por item atribui uma pontuação a cada passagem de forma independente.

A abordagem por lista captura comparações relativas e usa poucas unidades de texto, mas é preciso observar o viés de posição e garantir que a interpretação da saída seja robusta caso o modelo omita ou duplique identificadores.

def llm_listwise(query, candidates):
    passages = '\n'.join(
        '[' + str(i) + '] ' + c.text for i, c in enumerate(candidates)
    )
    prompt = (
        'Rank the passages by relevance to the query. '
        'Return only IDs, most relevant first.\nQuery: ' + query +
        '\n' + passages
    )
    order = parse_ids(llm(prompt, temperature=0))
    return [candidates[i] for i in order]

Latência e tamanho da lista reduzida

O custo da reclassificação aumenta de acordo com o tamanho da lista restrita. Um codificador cruzado com 50 candidatos é muito mais barato do que com 500. Escolha um k da primeira etapa grande o suficiente para incluir o trecho correto (valide recall@k), mas pequeno o suficiente para realizar a reclassificação dentro do seu orçamento de latência.

Agrupe a pontuação dos pares e execute-a em hardware acelerado; os codificadores cruzados são bem paralelizados entre os pares.

def tune_shortlist(eval_set, ks=(20, 50, 100, 200)):
    # find smallest k where recall@k saturates -> rerank fewer pairs
    return {k: (recall_at_k(eval_set, k), rerank_latency(k)) for k in ks}

Primeira etapa híbrida com reclassificação

A maior cobertura vem de uma etapa inicial híbrida (densa + BM25 combinadas), alimentando uma única lista reduzida sem duplicatas para o reclassificador. A recuperação densa encontra paráfrases; a esparsa recupera identificadores exatos; o codificador cruzado então ordena a união por relevância real.

Essa combinação é robusta para vários tipos de consulta, desde perguntas em linguagem natural até buscas literais.

def hybrid_then_rerank(query, k_final=6):
    dense = dense_retrieve(query, 50)
    sparse = bm25_retrieve(query, 50)
    fused = dedup(rrf(dense, sparse))     # reciprocal rank fusion
    return rerank(query, fused)[:k_final]

Limiares e limites de pontuação

As pontuações do reclassificador podem ser calibradas. Em vez de sempre selecionar os n primeiros, aplique um limiar de relevância: mantenha os trechos acima de uma determinada pontuação e, se nenhum se qualificar, informe honestamente que não há resposta. Isso evita preencher as instruções com conteúdo apenas fracamente relevante.

Ajuste o limiar em um conjunto de validação para equilibrar a cobertura de respostas possíveis com a inclusão de distratores.

def threshold_select(reranked, tau=0.3, max_n=8):
    kept = [c for c in reranked if c.rerank_score >= tau][:max_n]
    if not kept:
        return None        # signal: no sufficiently relevant context
    return kept

Diversidade após a reclassificação

Uma ordenação puramente por relevância pode retornar vários trechos quase duplicados do mesmo documento, desperdiçando o orçamento de contexto. Aplique MMR ou limites por documento após a reclassificação para garantir que o conjunto final abranja aspectos e fontes distintos.

Isso é importante para perguntas de múltiplas etapas cuja resposta se estende por vários documentos.

def diversify(reranked, max_per_doc=2, k=6):
    out, per_doc = [], {}
    for c in reranked:
        d = c.meta['doc_id']
        if per_doc.get(d, 0) < max_per_doc:
            out.append(c)
            per_doc[d] = per_doc.get(d, 0) + 1
        if len(out) == k:
            break
    return out

Ordenação para o gerador

Depois de selecionar os trechos principais, posicione-os para aproveitar a atenção. Dado o efeito de perda no meio, coloque o único trecho com a pontuação mais alta no início ou no fim do contexto, em vez de enterrá-lo entre os demais.

Alguns pipelines ordenam os trechos por relevância crescente para que o melhor fique mais próximo da pergunta, reproduzindo a estratégia de recência de poucos exemplos.

def order_for_llm(chunks):
    chunks = sorted(chunks, key=lambda c: c.rerank_score)  # ascending
    return chunks                 # most relevant chunk ends up last,
                                  # nearest the trailing question

Avaliação do reclassificador

Meça o reclassificador com métricas de ordenação, principalmente NDCG e MRR, usando dados rotulados de relevância entre consultas e trechos, e depois avalie a precisão da resposta resultante. Um reclassificador que melhora o NDCG, mas não as respostas, pode estar apenas reorganizando trechos que o gerador já sabia tratar.

Feche sempre o ciclo avaliando a qualidade da tarefa final, não apenas as métricas de ordenação.

import math

def ndcg_at_k(relevances, k):
    dcg = sum(r / math.log2(i + 2) for i, r in enumerate(relevances[:k]))
    ideal = sorted(relevances, reverse=True)
    idcg = sum(r / math.log2(i + 2) for i, r in enumerate(ideal[:k]))
    return dcg / idcg if idcg else 0.0

Um pipeline de reclassificação para produção

De ponta a ponta: faça uma recuperação híbrida de uma lista reduzida com 50 candidatos, remova duplicatas, reclassifique com um codificador cruzado, aplique um limiar de pontuação, diversifique por documento, ordene para aproveitar a atenção e gere com citações. Use o limiar para retornar honestamente respostas do tipo “não há resposta”.

Armazene em cache as representações vetoriais e as pontuações do reclassificador por (consulta, trecho) quando houver repetição no tráfego, reduzindo os custos.

def pipeline(query):
    shortlist = hybrid_then_rerank(query, k_final=20)
    kept = threshold_select(shortlist, tau=0.3, max_n=8)
    if kept is None:
        return 'No relevant information found.'
    ctx = order_for_llm(diversify(kept))
    return generate_with_citations(query, ctx)

Verificação rápida

Escolha a arquitetura correta de reclassificação.

Recapitulação

Principais conclusões:

  • Recupere amplamente para obter cobertura e depois reclassifique a lista reduzida para ganhar precisão.
  • Codificadores cruzados pontuam conjuntamente pares de consulta e documento (são precisos, mas não podem ser indexados); bi-codificadores são rápidos, porém imprecisos.
  • A reclassificação de listas ou de itens por LLM é uma alternativa de reserva; observe o viés de posição e a análise dos resultados.
  • Ajuste o tamanho da lista reduzida até saturar a cobertura dentro do orçamento de latência; combine isso com a recuperação híbrida na primeira etapa.
  • Aplique limiares de pontuação, diversifique por documento, ordene os trechos para aproveitar a atenção e avalie com NDCG e a precisão posterior da resposta.

Perguntas Frequentes

A aula “Reordenando trechos recuperados” é grátis?

Sim — o texto completo de “Reordenando trechos recuperados” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Prompt Engineering, atualize para CoddyKit PRO. O curso de AI Prompt Engineering inclui 4 aulas no total.

O que vou aprender em “Reordenando trechos recuperados”?

Reordenação com codificador cruzado. Você pratica AI Prompt Engineering com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Prompt Engineering?

Nenhuma experiência prévia é necessária. AI Prompt Engineering no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Reordenando trechos recuperados”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Prompt Engineering?

Sim. Cada aula de AI Prompt Engineering inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Além do RAG ingênuo
  2. Reordenando trechos recuperados
  3. Compressão de contexto
  4. Reformulação de consultas e HyDE
← Voltar para AI Prompt Engineering