Skip to main content
Modelos de linguagem são bons em resumir texto e ruins em memorizar fatos. Este tutorial tira os fatos da memória do modelo e os coloca no prompt, para que cada frase da saída possa ser rastreada até uma página que você buscou momentos antes. Vamos construir uma ferramenta de linha de comando que responde a uma pergunta com um resumo curto e com citações:
Ao longo do caminho iremos:
  1. Buscar na web ao vivo com /augment/search
  2. Decidir quais desses resultados vale a pena ler
  3. Converter as páginas selecionadas para Markdown com /augment/scrape
  4. Pedir a um modelo de chat que escreva o resumo, citando as fontes por número
  5. Conectar as quatro etapas em um único script
Fazer a recuperação nós mesmos, em vez de deixar o modelo fazer, é o que torna o resultado auditável. Mantemos a lista exata de páginas que entraram no prompt e podemos mostrar ao leitor de onde veio cada afirmação. Se você preferir que a Venice cuide da recuperação dentro de uma única requisição, defina venice_parameters.enable_web_search em um chat completion. O guia Busca e Extração Web compara as duas abordagens.

Configuração

Você precisa do Python 3.9 ou mais recente, do pacote requests e de uma chave de API Venice. Consulte Gerando uma chave de API caso ainda não tenha uma.
Crie research.py e comece com os imports e um bloco de cabeçalho compartilhado que todas as chamadas reutilizam:

1. Buscar na web

/augment/search recebe uma consulta e retorna até 20 resultados ranqueados. O Brave é o provedor padrão e aplica Zero Data Retention. O Google também está disponível e é encaminhado via proxy pela Venice, então a consulta nunca é vinculada a você.
Cada resultado é um objeto com quatro campos:
Duas coisas sobre essa resposta valem a pena saber antes de construir em cima dela. O campo content chega com HTML, porque o provedor envolve os termos correspondentes em tags <strong>. A substituição HTML_TAG acima as remove para que o trecho chegue ao modelo como texto puro. O campo date frequentemente é uma string vazia. Muitas páginas não publicam uma data em formato legível por máquina, então trate date como uma dica que você pode usar quando estiver presente, em vez de um campo pelo qual você pode ordenar ou filtrar.
limit deve estar entre 1 e 20, e query deve ter entre 1 e 400 caracteres. Valores fora dessas faixas retornam HTTP 400 com um corpo de validação. Eles não são ajustados automaticamente para você.

2. Escolher quais fontes ler

Extrair todos os dez resultados seria lento, caro e, em grande parte, redundante. Buscadores retornam várias páginas do mesmo site, e sites de documentação em particular retornam a mesma página em diversos idiomas, então o mesmo conteúdo pode aparecer três ou quatro vezes sob URLs diferentes. Manter apenas o resultado mais bem ranqueado por domínio remove a maior parte dessa duplicação em poucas linhas:
Executando isso nos dez resultados acima, reduzimos para quatro sites distintos:
Este é o lugar natural para acrescentar seu próprio julgamento. Você pode criar uma allowlist de domínios em que confia, descartar resultados cujo trecho nunca menciona os termos-chave ou preferir resultados que carreguem um date recente. Cada filtro que você aplicar aqui é uma decisão que o modelo não tem mais a chance de errar.

3. Extrair as páginas selecionadas

/augment/scrape busca uma URL pública e a retorna como Markdown. Ele primeiro pede ao site uma representação nativa em Markdown e recorre a uma extração baseada em navegador quando não há nenhuma. Algumas páginas irão falhar, e uma ferramenta de pesquisa deve tratar isso como algo rotineiro, e não fatal:
As duas verificações justificam seu lugar. A verificação de status captura sites que recusam acesso automatizado, e a verificação de comprimento captura páginas que retornam 200 mas devolvem um banner de cookies ou um esqueleto vazio em vez de um artigo.
Falhas de scrape retornam um corpo simples {"error": "..."} com uma mensagem legível, por exemplo X (formerly Twitter) blocks automated access to their content. X e Reddit são bloqueados diretamente. Para incluir posts do X em uma resposta, use venice_parameters.enable_x_search em um chat completion.
As requisições não dependem umas das outras, então execute-as em paralelo. Já que estamos aqui, vamos limitar o quanto mantemos de cada página:
A terceira página voltou com exatamente 12000 caracteres, o que significa que era mais longa do que o orçamento e foi truncada.
O char_budget não é um mero detalhe. Resultados de busca regularmente incluem páginas agregadas como sitemaps, changelogs e arquivos llms-full.txt, e uma única dessas pode retornar perto de um milhão de caracteres. Sem um limite, um resultado infeliz decide quanto vai custar a requisição inteira.

4. Escrever o resumo

Agora entregamos ao modelo as páginas que coletamos, numeradas, e pedimos citações que se refiram a esses números. A numeração no prompt é o que permite depois transformar um [2] na saída de volta em uma URL.
Uma temperature baixa mantém a redação próxima do texto de origem. Definir enable_web_search como off corresponde ao padrão, mas deixá-lo explícito garante que o modelo não possa introduzir silenciosamente uma fonte que esteja ausente da nossa lista de referências.

5. Juntando tudo

A última peça executa as etapas em ordem e acrescenta a lista de referências que resolve os números de citação:
As mensagens de progresso vão para o stderr, então você pode redirecionar apenas o resumo para um arquivo:
Aqui está o começo do resumo que ele produziu, abreviado:
Note que a fonte 3 nunca é citada neste trecho. Esse é o comportamento que queremos. O modelo usou as fontes que eram relevantes e deixou as demais de lado, e como as citações são numeradas você pode ver isso de relance.

Ajustando o pipeline

A maior parte do tempo de execução vai para o chat completion final, já que quatro páginas extraídas somam dezenas de milhares de tokens. Estas são as alavancas que vale a pena mexer primeiro:

Próximos passos

O pipeline que você tem agora é uma base, não um produto acabado. Algumas direções que vale a pena explorar:
  • Faça cache do Markdown extraído por URL para que perguntas repetidas não busquem novamente as mesmas páginas.
  • Armazene o Markdown como vetores com Embeddings e recupere trechos em vez de páginas inteiras.
  • Deixe o modelo planejar várias consultas antes de buscar, como faz a demo do Agente de Pesquisa Privada.
  • Leia o resumo em voz alta canalizando-o para Narração de Artigos com Texto para Fala.

Busca e Extração Web

Referência para os endpoints Search e Scrape.

Narração de Artigos com Texto para Fala

Transforme o texto que você acabou de gerar em áudio.

Embeddings

Indexe o Markdown extraído em vez de buscá-lo novamente.

Agente de Pesquisa Privada

Um agente maior que planeja suas próprias buscas.