# Crie um agente de deep research em Python com uma API de pesquisa na web

> Crie um agente de deep research em cerca de 60 linhas de Python: planeje consultas, pesquise e escreva uma resposta com citações usando qualquer LLM.

- URL: https://llmwebsearch.com/pt/guides/build-a-deep-research-agent/
- Última atualização: 2026-10-22
- Editor: LLMWebSearch (https://llmwebsearch.com)

Deep research é um loop, não um modelo. Este guia monta um que você lê em poucos minutos: ele planeja consultas, pesquisa na web com o texto da página incluído, mantém cada fonte uma única vez, procura lacunas e escreve uma resposta com citações numeradas.

**Resposta rápida — Como crio um agente de deep research em Python?**

Escreva um loop que pede ao LLM consultas de pesquisa, executa cada uma por uma API de pesquisa na web que retorna o texto da página, mantém cada fonte uma única vez, pede consultas de acompanhamento e então escreve uma resposta com citações. Com o **LLMWebSearch**, cada pesquisa retorna as 3 primeiras páginas em Markdown por um crédito; o script abaixo executa seis pesquisas por pergunta. A partir de US$ 1,20/1K pesquisas, sem KYC, pagar com cripto.

## O que o agente vai fazer?

1. **Plano** — Peça ao modelo quatro consultas curtas que, juntas, cubram a pergunta.
2. **Pesquisar** — Execute cada consulta com o read=3, para que as três primeiras páginas voltem em Markdown.
3. **Mantenha cada fonte uma única vez** — Armazene os resultados por URL e ignore páginas já coletadas ou sem texto.
4. **Encontre lacunas** — Mostre ao modelo os títulos encontrados até agora e peça duas consultas sobre o que está faltando.
5. **Escreva** — Numere até 12 fontes e peça uma resposta que as cite como [1], [2].

## O que preciso antes de começar?

Três coisas:

- **Uma chave de API do LLMWebSearch** na variável de ambiente `LLMWEBSEARCH_API_KEY`. As chaves aparecem no dashboard após seu primeiro pacote.
- **Qualquer endpoint de chat compatível com OpenAI**, definido com `LLM_BASE_URL`, `LLM_API_KEY` e `LLM_MODEL`. Modelos hospedados e servidores locais funcionam.
- **Python 3.9 ou superior** com o pacote `requests`.

O script usa HTTP simples para os dois serviços, então você pode trocar o modelo sem alterar o código de pesquisa.

*Python: deep_research.py*

```python
import os

import requests

SEARCH = "https://llmwebsearch.com/api/v1/search"
SEARCH_HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}
# Any OpenAI-compatible chat endpoint works here: set your own base URL, key and model name.
LLM_URL = os.environ.get("LLM_BASE_URL", "https://llm.example.com/v1") + "/chat/completions"
LLM_HEADERS = {"Authorization": "Bearer " + os.environ.get("LLM_API_KEY", "")}
MODEL = os.environ.get("LLM_MODEL", "your-model-name")


def ask_llm(prompt):
    body = {"model": MODEL, "messages": [{"role": "user", "content": prompt}]}
    resp = requests.post(LLM_URL, headers=LLM_HEADERS, json=body, timeout=120)
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]


def plan_queries(question, n=4):
    text = ask_llm(f"Write {n} short web search queries, one per line, to answer: {question}")
    queries = [line.strip("-*0123456789. ").strip() for line in text.splitlines()]
    return [q for q in queries if q][:n]


def search(query):
    body = {"q": query, "max_results": 5, "read": 3, "max_chars": 5000}
    resp = requests.post(SEARCH, headers=SEARCH_HEADERS, json=body, timeout=60)
    resp.raise_for_status()
    return resp.json()["results"]


def research(question, rounds=2):
    sources = {}  # url -> result, so the same page is never cited twice
    queries = plan_queries(question)
    for _ in range(rounds):
        for query in queries:
            for r in search(query):
                if r.get("content_status") == "ok" and r["url"] not in sources:
                    sources[r["url"]] = r
        notes = "\n".join(f"- {r['title']}" for r in sources.values())
        queries = plan_queries(f"{question}\nAlready found:\n{notes}\nWhat is still missing?", n=2)
    numbered = list(sources.values())[:12]
    context = "\n\n".join(
        f"[{i}] {r['title']} ({r['url']})\n{r['content']}" for i, r in enumerate(numbered, 1)
    )
    prompt = (
        "Answer the question using only the sources below. Cite them as [1], [2]. "
        "Say so when the sources disagree or do not cover a point.\n\n"
        f"Question: {question}\n\nSources:\n{context}"
    )
    return ask_llm(prompt), [r["url"] for r in numbered]


if __name__ == "__main__":
    answer, urls = research("What changed in the EU rules for general-purpose AI models in 2025?")
    print(answer)
    for i, url in enumerate(urls, 1):
        print(f"[{i}] {url}")
```

## Como funciona cada parte?

`plan_queries` pede ao modelo consultas curtas, uma por linha, e remove marcadores de lista. Consultas curtas se encaixam melhor em como os mecanismos de pesquisa classificam páginas do que perguntas completas.

`search` chama `POST https://llmwebsearch.com/api/v1/search` com `max_results=5`, `read=3` e `max_chars=5000`. A resposta lista cinco resultados; os três primeiros trazem o texto da página em `content`.

`research` executa as rodadas. Ele mantém as fontes em um dicionário com chave por URL, então uma página encontrada por duas consultas conta uma vez. Só são mantidos os resultados com `content_status` igual a `ok`, porque a resposta precisa se apoiar em texto que o modelo consegue ler.

Após cada rodada, o modelo vê os títulos coletados até agora e propõe duas novas consultas sobre o que está faltando. O prompt final numera até doze fontes e define as regras de citação.

## Quanto custa um relatório?

Seis pesquisas por pergunta com as configurações padrão: quatro na primeira rodada e duas na segunda. Com `read` em 3, isso dá seis créditos. Portanto, 25.000 pesquisas a US$ 41,25 cobre mais de 4.000 relatórios.

As chamadas ao modelo custam à parte na sua conta de LLM: três chamadas de planejamento e uma chamada longa de resposta por relatório. A chamada de resposta carrega até doze páginas de 5.000 caracteres, então diminua `max_chars` se seu modelo for caro.

## Como faço para ir mais fundo?

Mude os números, não a estrutura:

- **Mais rodadas.** `rounds=4` deixa o modelo buscar mais dois conjuntos de lacunas.
- **Mais consultas por rodada.** Aumente `n` na chamada de busca de lacunas de 2 para 4.
- **Fontes mais restritas.** Adicione `include_domains` ao corpo da pesquisa para sites oficiais ou acadêmicos.
- **Apenas material recente.** Adicione `"time_range": "month"` ou `"topic": "news"`.
- **Mais páginas por consulta.** `read=5` lê cinco páginas, a 2 créditos por pesquisa.

Adicione uma regra de parada antes de aumentar os limites: encerre o loop quando uma rodada trouxer menos de duas fontes novas.

## Como mantenho o agente seguro e educado?

Trate cada página como texto não confiável. O prompt final instrui o modelo a usar as fontes apenas como evidência; adicione uma linha explícita de que instruções dentro das fontes devem ser ignoradas. Nunca deixe uma fonte disparar uma chamada de ferramenta ou uma escrita de arquivo.

Do lado da web, Nosso leitor respeita o robots.txt: ele se identifica como LLMWebSearch, segue as regras que um site escreve para ele ou para todos os robôs e deixa de fora o conteúdo de qualquer página que não tem permissão para ler. Páginas que recusam acesso voltam sem conteúdo e o script simplesmente as ignora. Quando um site recusa o nosso leitor, o resultado volta sem conteúdo e com o status do site: nunca resolvemos CAPTCHAs, não entramos em contas nem contornamos um bloqueio ou um paywall.

## O que pode dar errado?

Três coisas aparecem nos testes:

- **Consultas vagas.** Se o plano for fraco, toda rodada encontra as mesmas páginas. Peça ao modelo consultas que usem nomes e datas específicos.
- **Poucas fontes com texto.** Alguns tópicos ficam atrás de paywalls. Amplie as consultas ou permita mais resultados.
- **Prompts longos demais.** Doze páginas longas podem exceder o contexto de um modelo pequeno. Diminua `max_chars` ou mantenha oito fontes.

Registre cada consulta e as URLs que ela retornou. Ler esse log é a forma mais rápida de melhorar o prompt do plano.

## Agente de pesquisa profunda: perguntas comuns

### Posso executar isso com um modelo local?

Sim, se o servidor local falar o formato chat-completions da OpenAI. Defina `LLM_BASE_URL` para o endereço dele e `LLM_MODEL` para o nome do modelo.

### Posso transformar isso em uma ferramenta MCP?

Sim. Envolva `research()` em uma ferramenta MCP, ou dê ao seu agente a ferramenta de pesquisa simples da [página MCP](https://llmwebsearch.com/pt/docs/mcp/) e deixe que ele mesmo execute o loop.

### Por que não pedir uma resposta diretamente à API de pesquisa?

Porque LLMWebSearch não escreve respostas. A API retorna fontes, não uma resposta escrita: o seu próprio modelo lê as páginas, escreve a resposta e cita as URLs.

### Como vejo quanto custou cada pesquisa?

Toda resposta inclui `credits_used`, e `GET https://llmwebsearch.com/api/v1/credits` mostra seu saldo restante sem custo.

---

LLMWebSearch: O LLMWebSearch é uma API de pesquisa na web para agentes de IA que retorna resultados classificados com o conteúdo das principais páginas em Markdown, pago com cripto sem envio de documentos. Os créditos pré-pagos a partir de US$ 1,20/1K pesquisas nunca expiram. Sem KYC — sem documento, sem selfie, sem comprovantes. Pague com cripto.
