# OpenAI function calling: daj modelowi narzędzie search_web

> Wyszukiwanie w sieci dla OpenAI function calling: schemat JSON search_web, pętla Responses API w Pythonie i to samo narzędzie w Agents SDK. Kryptowaluta.

- URL: https://llmwebsearch.com/pl/docs/openai/
- Ostatnia aktualizacja: 2026-10-22
- Wydawca: LLMWebSearch (https://llmwebsearch.com)

Opisz modelowi funkcję `search_web`, wykonaj wywołanie, o które prosi, względem naszego API i odeślij źródła. Model odpowiada wtedy z cytatami. Ta strona pokazuje schemat JSON, pętlę Responses API i krótszą wersję OpenAI Agents SDK.

**Szybka odpowiedź — Jak dodać wyszukiwanie w sieci do modelu OpenAI za pomocą function calling?**

Zadeklaruj funkcję `search_web` ze schematem JSON, a gdy model ją wywoła, wyślij zapytanie POST do `https://llmwebsearch.com/api/v1/search` w **LLMWebSearch**. Zwróć ponumerowane źródła, z 3 najlepszymi stronami jako Markdown, jako `function_call_output`; model odpowiada i je cytuje. Wyszukiwanie kosztuje 1 kredyt, od 1,20 USD/1K wyszukiwań według stanu na październik 2026. Bez KYC; płatność kryptowalutą.

## Co potrzebujesz

| Atrybut | Wartość |
| --- | --- |
| Pakiety | `openai` i `requests` (lub `openai-agents` dla wersji Agents SDK) |
| Klucze | `OPENAI_API_KEY` dla modelu, `LLMWEBSEARCH_API_KEY` dla wyszukiwania |
| Model | Dowolny model obsługujący function calling, ustawiony w `OPENAI_MODEL` |
| Używane API | Responses API: `client.responses.create` z `tools` i `input` |
| Rozliczanie po naszej stronie | Jeden kredyt opłaca jedno wyszukiwanie: do 20 wyników z rankingiem, przy czym strony z pierwszych 3 są odczytywane i zwracane jako Markdown. Odczyt od 4 do 10 stron to 2 kredyty. Wywołanie zakończone błędem nic nie kosztuje |

## Jak wygląda schemat narzędzia?

Narzędzie funkcyjne ma `name`, `description` i JSON Schema `parameters`. Trzymaj opis konkretny: co zwraca narzędzie i że źródła należy cytować według numeru. Dwa parametry wystarczą dla większości agentów: `query` i ile najlepszych wyników `read` w całości.

Model nigdy nie widzi Twojego klucza API. Proponuje tylko argumenty; Twój kod decyduje, jak wywołać API i co odesłać.

## Jak działa pętla wywołań?

Wyślij wiadomość użytkownika wraz z narzędziami. Jeśli odpowiedź zawiera elementy typu `function_call`, przeanalizuj JSON `arguments` każdego z nich, wykonaj wyszukiwanie i dołącz `function_call_output` z tym samym `call_id`. Następnie wywołaj model ponownie z dłuższą listą wejściową. Gdy odpowiedź nie zawiera wywołania funkcji, jej tekst jest odpowiedzią.

Poniższa pętla zatrzymuje się po pięciu rundach, jako zabezpieczenie przed modelem, który wyszukuje bez końca. Przewodnik OpenAI po function calling opisuje te same elementy `function_call` i `function_call_output`, czytany 22 października 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})

```

## Czy istnieje krótsza wersja z Agents SDK?

Tak. OpenAI Agents SDK zamienia funkcję Pythona w narzędzie za pomocą dekoratora i sam uruchamia pętlę wywołań. Jego dokumentacja narzędzi, czytana 22 października 2026, pokazuje dekorator `@tool` z `agents.decorators`, z opisem pobranym z docstringa i z opisem każdego argumentu z jego sekcji `Args`. Ta sama strona wspomina też formę `@function_tool`.

`Runner.run_sync` uruchamia agenta, aż ten wytworzy finalną odpowiedź, wywołując `search_web` tak często, jak prosi model.

*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)

```

## Dlaczego używać narzędzia API zamiast wbudowanego wyszukiwania webowego OpenAI?

Głównie dla kontroli nad tym, co model czyta i ile to kosztuje. Nasze narzędzie przekazuje Twojemu kodowi surowe źródła, z URL-ami i tekstem strony, więc to Ty decydujesz, co trafia do kontekstu, możesz to logować i przechowywać. Nie trenujemy żadnego modelu na Twoich zapytaniach ani na tym, co zwraca API, i nie dodajemy własnej reguły przeciwko przechowywaniu wyników; nadal obowiązują prawa witryn, których strony czytasz.

Cena jest też stała za wyszukiwanie, zamiast zależeć od tego, ile pobranej treści przeczyta model. [Porównanie wbudowanych narzędzi](https://llmwebsearch.com/pl/compare/built-in-web-search-tools/) zestawia obok siebie ceny za wywołanie OpenAI, Anthropic, Google i innych, z datami.

## Jak powstrzymać model przed nadmiernym wyszukiwaniem?

Powiedz to w instrukcjach: wyszukaj raz, przeczytaj źródła, wyszukaj ponownie tylko jeśli się nie zgadzają lub mijają z tematem. Ogranicz liczbę rund we własnej pętli, tak jak powyższy skrypt robi to z pięcioma.

Utrzymuj `max_chars` na rozsądnym poziomie. Trzy strony po 5 000 znaków to około 4 000 tokenów na wyszukiwanie, a każda runda dodaje je do wejścia kolejnego wywołania modelu.

## OpenAI function calling: najczęstsze pytania

### Czy to działa z Chat Completions API?

Tak, ze starszym formatem `tools` w Chat Completions, gdzie funkcja siedzi wewnątrz obiektu `function`, a wyniki wracają jako wiadomości `tool`. Sama funkcja wyszukiwania się nie zmienia.

### Czy model może przeczytać stronę znalezioną w źródle?

Dodaj drugą funkcję, `read_urls`, która wysyła URL-e do `https://llmwebsearch.com/api/v1/extract`. Odczyt stron, których adresy URL już masz, kosztuje 1 kredyt za każdą rozpoczętą grupę 3 stron zwróconych z treścią, do 20 adresów URL na wywołanie; adresy URL odrzucone lub nieudane nie są liczone.

### Którego modelu powinienem użyć?

Dowolnego modelu, który obsługuje function calling. Wypróbuj dwa lub trzy na własnych pytaniach: odpowiedź zależy od źródeł tak samo jak od modelu, a mniejszy model kosztuje mniej za rundę.

## Źródła

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

---

LLMWebSearch: LLMWebSearch to web search API dla agentów AI, który zwraca uszeregowane wyniki wraz z treścią najlepszych stron w formacie Markdown, z płatnością kryptowalutą i bez przesyłania dokumentu tożsamości. Kredyty przedpłacone od 1,20 USD/1K wyszukiwań nigdy nie wygasają. Bez KYC — bez dokumentu, bez selfie, bez zaświadczeń. Płatność kryptowalutą.
