OpenAI function calling with web search

Give an OpenAI model real-time web search with ODEN via function calling: define one tool, run the call, and return a synthesized answer with citations.

Use case1 min readUpdated 2026-07-30

OpenAI models can call functions you define. Define one function that calls ODEN, and your model gains real-time web search that returns a synthesized answer plus citations — no scraping, no extra infrastructure.

Define the tool#

tools = [{
    "type": "function",
    "function": {
        "name": "web_search",
        "description": "Search the live web for current information and return a synthesized answer with citations.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "The search query"}
            },
            "required": ["query"],
        },
    },
}]

Run the loop#

Call the model; when it asks for the tool, call ODEN and feed the result back:

import os, json, requests
from openai import OpenAI

client = OpenAI()

def oden_search(query: str) -> str:
    r = requests.post(
        "https://api.oden-api.com/search",
        headers={"Authorization": f"Bearer {os.environ['ODEN_KEY']}"},
        json={"query": query, "include_snippets": True},
        timeout=30,
    )
    r.raise_for_status()
    d = r.json()["results"]
    return json.dumps({
        "answer": d.get("answer"),
        "citations": [{"title": c["title"], "url": c["url"]} for c in d["citations"]],
    })

messages = [{"role": "user", "content": "What are the latest EU AI Act deadlines?"}]
first = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = oden_search(args["query"])
        messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
    final = client.chat.completions.create(model="gpt-4o", messages=messages)
    print(final.choices[0].message.content)

Notes#

  • Returning the citations as JSON lets the model quote titles and URLs back to the user. Ask it in your system prompt to cite inline.
  • One tool is usually enough; the model decides when a query needs the live web.
  • For agent frameworks that manage the loop for you, the same function definition drops straight in.

FAQ#

Which OpenAI models support function calling?#

The current GPT-4o and GPT-4.1 families and their mini variants all support tool/function calling. The snippet uses the Chat Completions API; the Responses API works the same way with one tool.

Can the model call ODEN multiple times?#

Yes. If the model emits several tool_calls, call ODEN for each and append each result before the final completion.

Does this work with Azure OpenAI?#

Yes — the function-calling contract is the same. Only the client setup differs.

Build it on the free tier
1,000 searches a month, no card required.