Geração de Textos com Referências usando LLMs

Geração de Textos com Referências usando LLMs

6 min de leitura

A geração de texto com modelos de linguagem grandes (LLMs) tem revolucionado a forma como criamos conteúdo. No entanto, um dos maiores desafios é garantir que as informações geradas sejam verificáveis e confiáveis. Neste artigo, vou mostrar uma técnica universal para gerar qualquer tipo de conteúdo estruturado com referências verificáveis, combinando busca avançada (Tavily) com LLMs. Usarei biografias como exemplo prático, mas a técnica se aplica a relatórios, artigos, análises e qualquer outro conteúdo baseado em fatos.

O Problema: Alucinações em LLMs

LLMs são incríveis para gerar textos coerentes e bem escritos, mas frequentemente “alucinam” - inventam informações que parecem plausíveis mas não são verdadeiras. A solução? Fornecer ao modelo informações verificadas e exigir que ele cite suas fontes para cada afirmação.

A Solução: Busca + Geração Estruturada

Vamos construir um sistema que: 1. Busca informações reais sobre um tópico usando a API Tavily 2. Usa um LLM com suporte a saída estruturada (neste exemplo, Google Gemini) para gerar um texto estruturado 3. Exige que cada sentença do texto tenha uma referência específica

Nota importante: Qualquer provedor de LLM que suporte saída estruturada pode ser usado nesta abordagem - OpenAI, Anthropic, Google, Azure OpenAI, etc. O princípio é o mesmo: fornecer um schema JSON e exigir que o modelo retorne dados nesse formato.

Instalação das Dependências

Primeiro, precisamos instalar as bibliotecas necessárias:

1
pip install google-genai tavily-python

Buscando Informações com Tavily

A Tavily é uma API de busca otimizada para agentes de IA e RAG (Retrieval-Augmented Generation). Ao contrário de APIs de busca tradicionais, ela retorna conteúdo limpo e estruturado ideal para alimentar LLMs.

Para este exemplo, vamos buscar informações sobre um artista para criar uma biografia, mas você pode adaptar a query para qualquer tópico:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from tavily import TavilyClient

artist_name = "Silvio Santos"

tavily_client = TavilyClient()

tavily_response = tavily_client.search(
    query=artist_name + " biografia",
    max_results=5,
    include_raw_content=True,
    search_depth="advanced"
)

O parâmetro search_depth="advanced" faz com que a Tavily realize uma busca mais profunda e precisa, essencial para obter informações confiáveis.

Estruturando a Resposta com Pydantic

Para garantir que o LLM retorne dados no formato que precisamos, usamos Pydantic para definir a estrutura esperada. A estrutura abaixo é específica para biografias, mas você pode criar estruturas similares para qualquer tipo de conteúdo (relatórios, artigos de pesquisa, análises de mercado, etc.):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import BaseModel, Field


class Reference(BaseModel):
    ''' A reference that supports the information in a sentence. '''
    title: str = Field(..., description="The title of the reference")
    url: str = Field(..., description="The URL of the reference")
    excerpt: str = Field(..., description="A brief excerpt from the reference that supports the information in the sentence.")


class Sentence(BaseModel):
    ''' A sentence with an associated reference that supports the information in the sentence. '''
    reference: Reference = Field(..., description="The reference that supports the information in the sentence")
    text: str = Field(..., description="The text of the sentence")


class ArtistBiography(BaseModel):
    ''' A biography of an artist, consisting of multiple sentences with associated references. '''
    name: str = Field(..., description="The name of the artist")
    sentences: list[Sentence] = Field(..., description="A list of sentences that make up the biography, each with an associated reference")

Esta estrutura garante que: - Cada sentença (Sentence) tenha um texto e uma referência - Cada referência (Reference) contenha título, URL e um trecho que suporta a informação - A biografia completa (ArtistBiography) seja uma lista de sentenças estruturadas

Gerando o Conteúdo com LLM e Saída Estruturada

Agora vamos construir o prompt e usar um LLM para gerar o conteúdo. Neste exemplo, usamos o Google Gemini para gerar uma biografia, mas qualquer modelo que suporte structured output funcionaria (OpenAI com response_format, Anthropic Claude, etc.) e você pode adaptar o prompt para gerar qualquer tipo de conteúdo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import json

prompt = f'''Given the following search results, write a concise and informative biography of {artist_name}. 
For each sentence in the biography, provide a reference that supports the information in that sentence. 
The reference should include the title, URL, and a brief excerpt from the source that supports the information in the sentence.
Write the biography in pt-br.

<Search Results>
{json.dumps(tavily_response['results'], indent=2, ensure_ascii=False)}
</Search Results>
'''

Agora chamamos o Gemini com o schema JSON da nossa estrutura Pydantic:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from google import genai

client = genai.Client()

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=prompt,
    config={
        "response_mime_type": "application/json",
        "response_schema": ArtistBiography.model_json_schema(),
    },
)

artist_biography = ArtistBiography.model_validate_json(response.text)

O parâmetro response_schema é o segredo aqui - ele força o modelo a retornar dados exatamente no formato que definimos com Pydantic.

Alternativas de Provedores

Você pode usar outros provedores de LLM com abordagens similares:

OpenAI:

1
2
3
4
5
6
7
8
from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": prompt}],
    response_format={"type": "json_schema", "json_schema": {...}}
)

Anthropic Claude:

1
2
3
4
5
6
7
8
import anthropic
client = anthropic.Anthropic()

# Claude requer uma abordagem ligeiramente diferente via prompt engineering
response = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    messages=[{"role": "user", "content": prompt}]
)

O importante é que o provedor escolhido suporte a geração de saída estruturada em JSON.

Exibindo o Resultado

Por fim, podemos exibir a biografia gerada com suas referências:

1
2
3
4
5
6
7
print(f'# {artist_biography.name}\n')

for sentence in artist_biography.sentences:
    print(sentence.text)
    print(f"    >Reference: {sentence.reference.title} - {sentence.reference.url}")
    print(f"    >Excerpt: {sentence.reference.excerpt}")
    print()

Resultado Esperado

O código acima vai gerar uma saída como:

# Silvio Santos

Silvio Santos, nome artístico de Senor Abravanel, nasceu em 12 de dezembro de 1930 no Rio de Janeiro.
    >Reference: Silvio Santos - Wikipedia - https://pt.wikipedia.org/wiki/Silvio_Santos
    >Excerpt: Senor Abravanel, mais conhecido como Silvio Santos, nasceu em 12 de dezembro de 1930...

Foi um dos maiores apresentadores e empresários da televisão brasileira...
    >Reference: A trajetória de Silvio Santos - Portal G1
    >Excerpt: O apresentador construiu um império na TV brasileira...

Por Que Isso é Importante?

Esta abordagem resolve vários problemas comuns na geração de texto com IA:

  1. Rastreabilidade: Cada afirmação tem uma fonte verificável
  2. Confiabilidade: As informações vêm de buscas reais, não da memória do LLM
  3. Estruturação: O formato Pydantic garante dados consistentes
  4. Verificação: Usuários podem clicar nos links e verificar as informações

Casos de Uso

Esta técnica pode ser aplicada em diversos cenários:

  • Geração de relatórios de pesquisa
  • Criação de artigos jornalísticos
  • Resumos executivos com fontes
  • Fichas técnicas de produtos
  • Análises de mercado documentadas

Conclusão

Combinar busca avançada com geração estruturada nos permite criar sistemas de IA que são tanto criativos quanto confiáveis. A técnica demonstrada aqui com biografias é apenas um exemplo - você pode adaptar o mesmo padrão para:

  • Relatórios técnicos: Cada parágrafo com referências a documentação oficial
  • Artigos de opinião: Argumentos suportados por estudos e notícias
  • Resumos de pesquisa: Insights extraídos de múltiplos papers acadêmicos
  • Análises de produtos: Características verificadas com fontes oficiais
  • Conteúdo educacional: Conceitos explicados com referências confiáveis

O princípio é sempre o mesmo: buscar informações verificadas, estruturar os dados com Pydantic, e exigir que cada afirmação tenha uma fonte. Isso reduz drasticamente o problema de alucinações em LLMs.

Recursos Adicionais


Gostou do artigo? Tem alguma dúvida ou sugestão? Entre em contato!