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
| 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.
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.
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 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 (2)
- Function calling — OpenAI API docs (read 2026-10-22)
- Narzędzia (OpenAI Agents SDK) — OpenAI Agents SDK docs (read 2026-10-22)