> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lyceum.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Web search

> Let open models search the web and cite their sources

Serverless models can search the web while they answer. You ask for search in the request, and Lyceum runs the searches, gives the model the results, and returns an answer that cites its sources. You don't need a search provider or API key of your own.

## Chat Completions

Add `web_search_options` to a chat completion. An empty object turns search on:

> [tab] Python
>
> ```python theme={null}
> from openai import OpenAI
>
> client = OpenAI(
>     api_key="lk_...",
>     base_url="https://api.lyceum.technology/openai/v1",
> )
>
> resp = client.chat.completions.create(
>     model="z-ai/glm-5.3",
>     web_search_options={},
>     messages=[{"role": "user", "content": "What changed in the latest Python release?"}],
> )
> message = resp.choices[0].message
> print(message.content)
> for annotation in message.annotations or []:
>     print(annotation.url_citation.url)
> ```

> [tab] curl
>
> ```bash theme={null}
> curl https://api.lyceum.technology/openai/v1/chat/completions \
>   -H "Authorization: Bearer lk_..." \
>   -H "Content-Type: application/json" \
>   -d '{
>     "model": "z-ai/glm-5.3",
>     "web_search_options": {},
>     "messages": [{"role": "user", "content": "What changed in the latest Python release?"}]
>   }'
> ```

The model cites results as `[1]`, `[2]` and so on. Each cited source comes back as a `url_citation` annotation on the message, with the position of the citation in the text:

```json theme={null}
"annotations": [{
  "type": "url_citation",
  "url_citation": {"start_index": 112, "end_index": 115, "url": "https://docs.python.org/...", "title": "What's New In Python"}
}]
```

When you stream, the annotations arrive in the last chunk before the finish reason. Set `stream_options.include_usage` to `true` to get the token usage as well.

### Options

| Option | Effect |
| - | - |
| `search_context_size` | Results per search: `low` 5, `medium` 8 (default), `high` 12. |
| `user_location` | Accepted for compatibility. It doesn't change the results. |

Your own function tools work alongside search. The model can't search when `tool_choice` is `"none"` or forces one of your functions. The search runs as a function named `web_search`, so give your own functions other names.

## Responses API

Add the `web_search` tool:

```python theme={null}
resp = client.responses.create(
    model="z-ai/glm-5.3",
    tools=[{"type": "web_search"}],
    input="What changed in the latest Python release?",
)
print(resp.output_text)
```

Each search shows in `output` as a `web_search_call` item, and the answer's text carries `url_citation` annotations. The tool takes `search_context_size` and `filters.allowed_domains`, which limits results to the domains you list. Set `max_tool_calls` to cap the number of searches.

## Coding tools

How you turn on search depends on the tool:

| Tool | Web search with Lyceum |
| - | - |
| [Codex](https://docs.lyceum.technology/docs/agents/codex.md) | Built in, with nothing to set up |
| [aider](https://docs.lyceum.technology/docs/agents/aider.md) | Add `web_search_options` to `.aider.model.settings.yml` |
| [goose](https://docs.lyceum.technology/docs/agents/goose.md) | Add `web_search_options` to a custom provider file |
| [Hermes Agent](https://docs.lyceum.technology/docs/agents/hermes.md) | Switch off Hermes's own web tools, then add `web_search_options` to the provider |
| [Kilo Code](https://docs.lyceum.technology/docs/agents/kilo-code.md) | Add `web_search_options` to each model in `kilo.jsonc` |
| [opencode](https://docs.lyceum.technology/docs/agents/opencode.md) | Add `web_search_options` to each model in `opencode.json` |
| [Vercel AI SDK](https://docs.lyceum.technology/docs/agents/vercel-ai-sdk.md) | Pass `web_search_options` in the provider options, or use the `web_search` tool |
| [Claude Code](https://docs.lyceum.technology/docs/inference/claude-code.md), [Cline](https://docs.lyceum.technology/docs/agents/cline.md), [Cursor](https://docs.lyceum.technology/docs/inference/cursor.md), [GitHub Copilot](https://docs.lyceum.technology/docs/agents/github-copilot.md), [Zed](https://docs.lyceum.technology/docs/agents/zed.md) | Not available. Most of these read pages you give them with their own fetch tools |

## Models

Search works best with models that call tools reliably. We've tested it with:

* `z-ai/glm-5.3`
* `z-ai/glm-5.3-flash`
* `deepseek/deepseek-v4.1-flash`
* `deepseek/deepseek-v4-flash-0731`
* `qwen/qwen3.8-27b`
* `moonshotai/kimi-k3.1-pro`

Other models accept the request, but may answer without searching.

## Limits

* A model can search in up to 4 turns, with up to 5 searches per turn. After that it has to answer from what it found.
* Results are cut to fit the model's context: each excerpt is at most 1,500 characters.
* If a search fails, the model is told so and answers without it.

## Pricing

You pay for the tokens of every model turn, including the turns that read search results, at the model's usual price. Each search that returns results costs **\$0.00625**. Searches that find nothing are free.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.