Snel antwoord
Hoe voeg ik webzoekopdrachten toe aan een OpenAI-model met function calling?
Declareer een search_web-functie met een JSON-schema, en wanneer het model die aanroept, POST je de zoekopdracht naar de https://llmwebsearch.com/api/v1/search van LLMWebSearch. Stuur de genummerde bronnen terug, met de top 3 pagina's als Markdown, als een function_call_output; het model antwoordt en citeert ze. Een zoekopdracht kost 1 credit, vanaf US$ 1,20/1K zoekopdrachten per oktober 2026. Zonder KYC; betalen met crypto.
Wat je nodig hebt
| Packages | openai en requests (of openai-agents voor de Agents SDK-versie) |
|---|---|
| Sleutels | OPENAI_API_KEY voor het model, LLMWEBSEARCH_API_KEY voor zoeken |
| Model | Elk model dat function calling ondersteunt, ingesteld in OPENAI_MODEL |
| Gebruikte API | Responses API: client.responses.create met tools en input |
| Facturering aan onze kant | Eén credit betaalt één zoekopdracht: tot 20 gerangschikte resultaten, waarbij de pagina's van de eerste 3 worden gelezen en als Markdown teruggegeven. Het lezen van 4 tot 10 pagina's kost 2 credits. Een call die op een fout eindigt, kost niets |
Hoe ziet het tool-schema eruit?
Een function tool heeft een name, een description en JSON Schema-parameters. Houd de beschrijving concreet: wat de tool teruggeeft, en dat bronnen op nummer geciteerd moeten worden. Twee parameters zijn genoeg voor de meeste agents: de query, en hoeveel topresultaten volledig moeten worden read.
Het model ziet je API-sleutel nooit. Het stelt alleen argumenten voor; jouw code bepaalt hoe de API wordt aangeroepen en wat er wordt teruggestuurd.
Hoe werkt de call-loop?
Stuur het bericht van de gebruiker mee met de tools. Als de response items van het type function_call bevat, parse je de JSON-arguments van elk, voer je de zoekopdracht uit en voeg je een function_call_output toe met dezelfde call_id. Roep het model dan opnieuw aan met de langere invoerlijst. Als een response geen function call bevat, is de tekst ervan het antwoord.
De loop hieronder stopt na vijf rondes, een vangnet tegen een model dat blijft zoeken. OpenAI's function-calling-gids beschrijft dezelfde function_call- en function_call_output-items, gelezen op 22 oktober 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})
Is er een kortere versie met de Agents SDK?
Ja. De OpenAI Agents SDK maakt van een Python-functie een tool met een decorator en voert de call-loop voor je uit. De tools-documentatie, gelezen op 22 oktober 2026, toont de @tool-decorator uit agents.decorators, met de beschrijving uit de docstring en de beschrijving van elk argument uit zijn Args-sectie. Dezelfde pagina noemt ook de @function_tool-vorm.
Runner.run_sync voert de agent uit tot hij een definitief antwoord produceert, en roept search_web zo vaak aan als het model vraagt.
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)
Waarom een API-tool gebruiken in plaats van de ingebouwde webzoekfunctie van OpenAI?
Vooral voor controle over wat het model leest en wat het kost. Onze tool geeft je code de ruwe bronnen, met URL's en paginatekst, zodat jij bepaalt wat in de context komt, het kunt loggen en kunt opslaan. We trainen geen enkel model op je zoekopdrachten of op wat de API teruggeeft, en we voegen geen eigen regel toe tegen het opslaan van resultaten; de rechten van de sites waarvan je pagina's leest, gelden nog steeds.
De prijs ligt ook vast per zoekopdracht in plaats van afhankelijk te zijn van hoeveel opgehaalde inhoud het model leest. De vergelijking van ingebouwde tools zet de prijzen per aanroep van OpenAI, Anthropic, Google en anderen naast elkaar, met data.
Hoe voorkom ik dat het model te veel zoekt?
Zeg het in de instructions: zoek één keer, lees de bronnen, zoek alleen opnieuw als ze elkaar tegenspreken of het punt missen. Beperk het aantal rondes in je eigen loop, zoals het script hierboven doet met vijf.
Houd max_chars bescheiden. Drie pagina's van 5.000 tekens is ongeveer 4.000 tokens per zoekopdracht, en elke ronde voegt ze toe aan de input van de volgende modelaanroep.
OpenAI function calling: veelgestelde vragen
Werkt dit met de Chat Completions API?
Ja, met het oudere tools-formaat van Chat Completions, waarbij de function in een function-object zit en resultaten terugkomen als tool-berichten. De zoekfunctie zelf verandert niet.
Kan het model een pagina lezen die het in een bron vindt?
Voeg een tweede function toe, read_urls, die URL's naar https://llmwebsearch.com/api/v1/extract post. Het lezen van pagina's waarvan je de URL's al hebt, kost 1 credit per begonnen groep van 3 pagina's die met inhoud worden teruggegeven, tot 20 URL's per call; geweigerde of mislukte URL's tellen niet mee.
Welk model moet ik gebruiken?
Elk model dat function calling ondersteunt. Probeer er twee of drie op je eigen vragen: het antwoord hangt net zo goed van de bronnen af als van het model, en een kleiner model kost minder per ronde.
Bronnen (2)
- Function calling — OpenAI API docs (read 2026-10-22)
- Tools (OpenAI Agents SDK) — OpenAI Agents SDK docs (read 2026-10-22)