Skip to content

Web search

Any catalog model can search the web on demand. Ask for it in the request and Keln runs the search on its side, feeds the results to the model, bills the search, and returns the answer with citations and, when you ask, the sources it saw. It works the same on all three surfaces, with each surface's native shape, so Codex, Claude Code, and the OpenAI and Anthropic SDKs need no extra setup.

Price: $10 per 1,000 searches, on top of tokens. A search is one query, whatever the number of results. Errors, capped attempts, and searches the model did not run are never billed.

Turning it on

Search is off unless the request asks for it.

Either of these, they are equivalent:

{ "model": "zai-org/glm-5.3", "messages": [...], "web_search_options": {} }
{ "model": "zai-org/glm-5.3", "messages": [...], "plugins": [{ "id": "web" }] }

OpenAI's hosted tool, unchanged. Codex sends this by default.

{ "model": "zai-org/glm-5.3", "input": "...", "tools": [{ "type": "web_search" }] }

Anthropic's server tool, unchanged. Claude Code's WebSearch sends this.

{ "model": "zai-org/glm-5.3", "messages": [...],
  "tools": [{ "type": "web_search_20250305", "name": "web_search", "max_uses": 5 }] }

What comes back

The model decides when to search, and may search more than once in a turn. Results reach the model as ranked excerpts, up to 10 per search. What you see:

Surface Search activity Citations Sources on request
Chat completions in usage only message.annotations[], OpenAI's url_citation shape plus content, the excerpt the claim rests on web_search_options.include_sources: truemessage.web_search_sources[]
Responses a web_search_call item per search, with its lifecycle events and action.query url_citation annotations on output_text include: ["web_search_call.action.sources"]action.sources on the item
Anthropic server_tool_use and web_search_tool_result blocks, results included citations on the text block always, in the result block

Citations are the links the model wrote. Keln asks the model to cite as markdown links named by the domain, keeps the link visible in the text, and turns each one into an annotation with real character offsets. Keln never adds a citation the model did not make.

usage carries the count on every surface: usage.web_search_requests on chat and Responses, usage.server_tool_use.web_search_requests on Anthropic. usage.cost includes the fee.

Limits and knobs

  • Searches per turn: 5 by default, 10 at most. Set web_search_options.max_uses on chat, or the tool's max_uses on Anthropic. Past the cap the model is asked to answer with what it has.
  • Results per search: 10, fixed.
  • Your own tools still work. Search is offered alongside them under tool_choice: "auto". With "none" or a forced choice, search is not offered and the request is served as before, named on the x-keln-inert-params header. A function tool of yours named web_search together with the opt-in is refused with 400 web_search_name_reserved.
  • Search results do not persist across turns on chat and Responses, same as OpenAI: the model's answer carries what it learned. On the Anthropic surface the result block you receive is the state, so sending it back restores the results for the next turn.
  • Accepted, not applied: search_context_size, user_location and domain filters are named on the x-keln-inert-params header and otherwise ignored.

Privacy

Search queries go to a third-party search engine and nowhere else. Results are relayed, not stored. Keln's logs record the length of a query and the number of results, never the text. Nothing about your account turns search on by default.

Errors

Code Meaning
web_search_name_reserved the request opts into search and also defines a function tool named web_search
web_search_unavailable search is not enabled on this deployment

A search that fails on the engine side is not an error to you: the model is told, answers with what it knows, and the search is not billed.