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 attentionUma 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 keptDiversidade 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 outOrdenaçã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 questionAvaliaçã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.0Um 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
- Além do RAG ingênuo
- Reordenando trechos recuperados
- Compressão de contexto
- Reformulação de consultas e HyDE