# OpenAI function calling: dê ao modelo uma ferramenta search_web

> Pesquisa na web para OpenAI function calling: um JSON schema de search_web, o loop da Responses API em Python e a ferramenta no Agents SDK. Sem KYC, cripto.

- URL: https://llmwebsearch.com/pt/docs/openai/
- Última atualização: 2026-10-22
- Editor: LLMWebSearch (https://llmwebsearch.com)

Descreva uma função `search_web` para o modelo, execute a chamada que ele pede contra nossa API e devolva as fontes. O modelo então responde com citações. Esta página mostra o JSON schema, o loop da Responses API e a versão mais curta com o OpenAI Agents SDK.

**Resposta rápida — Como adiciono pesquisa na web a um modelo OpenAI com function calling?**

Declare uma função `search_web` com um JSON schema e, quando o modelo a chamar, envie a consulta via POST para o `https://llmwebsearch.com/api/v1/search` da **LLMWebSearch**. Retorne as fontes numeradas, com as 3 principais páginas em Markdown, como um `function_call_output`; o modelo responde e as cita. Uma pesquisa custa 1 crédito, a partir de US$ 1,20/1K pesquisas em outubro de 2026. Sem KYC; pague com cripto.

## O que você precisa

| Atributo | Valor |
| --- | --- |
| Pacotes | `openai` e `requests` (ou `openai-agents` para a versão com o Agents SDK) |
| Chaves | `OPENAI_API_KEY` para o modelo, `LLMWEBSEARCH_API_KEY` para a pesquisa |
| Modelo | Qualquer modelo que suporte function calling, definido em `OPENAI_MODEL` |
| API usada | Responses API: `client.responses.create` com `tools` e `input` |
| Cobrança do nosso lado | Um crédito paga uma pesquisa: até 20 resultados classificados, com as páginas dos 3 primeiros lidas e devolvidas em Markdown. Ler de 4 a 10 páginas custa 2 créditos. Uma chamada que termina em erro não custa nada |

## Como é o schema da ferramenta?

Uma function tool tem um `name`, um `description` e um JSON Schema `parameters`. Mantenha a descrição concreta: o que a ferramenta retorna, e que as fontes devem ser citadas por número. Dois parâmetros bastam para a maioria dos agentes: a `query`, e quantos resultados principais retornar `read` por inteiro.

O modelo nunca vê sua chave de API. Ele apenas propõe argumentos; seu código decide como chamar a API e o que enviar de volta.

## Como funciona o loop de chamadas?

Envie a mensagem do usuário com as ferramentas. Se a resposta contiver itens do tipo `function_call`, faça o parse do JSON `arguments` de cada um, execute a pesquisa e anexe um `function_call_output` com o mesmo `call_id`. Depois chame o modelo de novo com a lista de entrada mais longa. Quando uma resposta não contiver nenhuma chamada de função, o texto dela é a resposta.

O loop abaixo para após cinco rodadas, uma proteção contra um modelo que fica pesquisando. O guia de function calling da OpenAI descreve os mesmos itens `function_call` e `function_call_output`, lido em 22 de outubro de 2026.

*search_tool_loop.py (Responses API)*

```python
import json
import os

import requests
from openai import OpenAI

client = OpenAI()
MODEL = os.environ["OPENAI_MODEL"]  # any model that supports function calling
SEARCH = "https://llmwebsearch.com/api/v1/search"

tools = [
    {
        "type": "function",
        "name": "search_web",
        "description": "Search the live web. Returns numbered sources with URLs; the first `read` include page text. Cite sources as [1], [2].",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "What to search for, as a person would type it."},
                "read": {"type": "integer", "minimum": 0, "maximum": 10, "description": "How many top results to read in full."},
            },
            "required": ["query"],
            "additionalProperties": False,
        },
    }
]


def search_web(query, read=3):
    resp = requests.post(
        SEARCH,
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": read, "max_chars": 5000},
        timeout=60,
    )
    if resp.status_code != 200:
        return "Search failed: " + resp.json().get("error", {}).get("code", str(resp.status_code))
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


input_list = [{"role": "user", "content": "How should I size a Postgres connection pool?"}]
for _ in range(5):
    response = client.responses.create(model=MODEL, tools=tools, input=input_list)
    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        print(response.output_text)
        break
    input_list += response.output
    for item in calls:
        args = json.loads(item.arguments)
        output = search_web(args["query"], int(args.get("read", 3)))
        input_list.append({"type": "function_call_output", "call_id": item.call_id, "output": output})

```

## Existe uma versão mais curta com o Agents SDK?

Sim. O OpenAI Agents SDK transforma uma função Python em ferramenta com um decorator e executa o loop de chamadas para você. A documentação de tools dele, lida em 22 de outubro de 2026, mostra o decorator `@tool` de `agents.decorators`, com a descrição tirada da docstring e a descrição de cada argumento da sua seção `Args`. A mesma página também menciona o formato `@function_tool`.

`Runner.run_sync` executa o agente até ele produzir uma resposta final, chamando `search_web` quantas vezes o modelo pedir.

*search_agent.py (OpenAI Agents SDK)*

```python
import os

import requests
from agents import Agent, Runner
from agents.decorators import tool


@tool
def search_web(query: str, read: int = 3) -> str:
    """Search the live web and return numbered sources with their URLs.

    Args:
        query: What to search for, as a person would type it.
        read: How many top results to read in full, from 0 to 10.
    """
    resp = requests.post(
        "https://llmwebsearch.com/api/v1/search",
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000},
        timeout=60,
    )
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


agent = Agent(
    name="Researcher",
    instructions="Answer from search_web results only and cite them as [1], [2].",
    tools=[search_web],
)
result = Runner.run_sync(agent, "How should I size a Postgres connection pool?")
print(result.final_output)

```

## Por que usar uma ferramenta de API em vez da busca na web integrada da OpenAI?

Principalmente pelo controle sobre o que o modelo lê e quanto custa. Nossa ferramenta entrega ao seu código as fontes brutas, com URLs e o texto da página, para que você decida o que entra no contexto, possa registrar e armazenar. Não treinamos nenhum modelo com as suas consultas ou com o que a API retorna, e não adicionamos nenhuma regra própria contra armazenar resultados; os direitos dos sites cujas páginas você lê continuam valendo.

O preço também é fixo por pesquisa, em vez de depender de quanto conteúdo recuperado o modelo lê. A [comparação das ferramentas integradas](https://llmwebsearch.com/pt/compare/built-in-web-search-tools/) coloca lado a lado os preços por chamada da OpenAI, Anthropic, Google e outros, com datas.

## Como impeço o modelo de pesquisar demais?

Diga isso nas instruções: pesquise uma vez, leia as fontes, pesquise de novo só se elas divergirem ou fugirem do assunto. Limite o número de rodadas no seu próprio loop, como o script acima faz com cinco.

Mantenha `max_chars` modesto. Três páginas de 5.000 caracteres dão cerca de 4.000 tokens por pesquisa, e cada rodada os soma à entrada da próxima chamada ao modelo.

## OpenAI function calling: perguntas frequentes

### Isso funciona com a API Chat Completions?

Sim, com o formato mais antigo `tools` da Chat Completions, em que a função fica dentro de um objeto `function` e os resultados voltam como mensagens `tool`. A função de pesquisa em si não muda.

### O modelo consegue ler uma página que encontra em uma fonte?

Adicione uma segunda função, `read_urls`, que envia URLs para `https://llmwebsearch.com/api/v1/extract`. Ler páginas cujas URLs você já tem custa 1 crédito por cada grupo iniciado de 3 páginas devolvidas com conteúdo, até 20 URLs por chamada; URLs recusadas ou com falha não são contadas.

### Qual modelo devo usar?

Qualquer modelo que suporte function calling. Teste dois ou três com suas próprias perguntas: a resposta depende das fontes tanto quanto do modelo, e um modelo menor custa menos por rodada.

## Fontes

1. [Function calling](https://developers.openai.com/api/docs/guides/function-calling) — OpenAI API docs (read 2026-10-22)
2. [Ferramentas (OpenAI Agents SDK)](https://openai.github.io/openai-agents-python/tools/) — OpenAI Agents SDK docs (read 2026-10-22)

---

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.
