Ollama официально запустила встроенную поддержку веб-поиска через REST API. Это не просто внешний плагин — это часть экосистемы: API интегрирован в Python и JavaScript SDK, а также доступен через MCP (Model Control Protocol) сервер. Цель — снизить галлюцинации и дать моделям доступ к свежим данным без ручного RAG-пайплайна.

Факты по делу:

  • Поиск возвращает контент объёмом до нескольких тысяч токенов, поэтому рекомендуемое контекстное окно — минимум 32K токенов.

  • Поддержка есть для любых моделей, включая open-weight, например Qwen 3 (4B) — в официальном примере как раз на нём строится простой search agent.

  • Интеграция возможна через:

    • Прямой вызов REST API

    • Python/JS библиотеки Ollama

    • OpenAI-совместимый endpoint (полезно для gpt-oss и подобных)

    • MCP-сервер — для совместимости с Cline, Goose, Codex и другими инструментами.

Важный нюанс: в документации нет информации о rate limits. Неясно, сколько запросов в минуту/день разрешено, особенно для self-hosted или cloud-версий. Пока предполагаем, что лимиты мягкие — но это нужно тестировать. Как сказано в официальном блог-посте:

Ollama provides a generous free tier of web searches for individuals to use, and higher rate limits are available via Ollama’s cloud.

Если что, стоимость Ollama Cloud – 20$ в месяц, и пока что сервис находится в preview.

Вот как выглядит простой поиск:

curl https://ollama.com/api/web_search \
  --header "Authorization: Bearer $OLLAMA_API_KEY" \
  -d '{
    "query": "what is ollama?"
  }'

А вот так выглядит полноценный агент, который ходит в интернет:

from ollama import chat, web_fetch, web_search

available_tools = {'web_search': web_search, 'web_fetch': web_fetch}

messages = [{'role': 'user', 'content': "what is ollama's new engine"}]

while True:
  response = chat(
    model='qwen3:4b',
    messages=messages,
    tools=[web_search, web_fetch],
    think=True
    )
  if response.message.thinking:
    print('Thinking: ', response.message.thinking)
  if response.message.content:
    print('Content: ', response.message.content)
  messages.append(response.message)
  if response.message.tool_calls:
    print('Tool calls: ', response.message.tool_calls)
    for tool_call in response.message.tool_calls:
      function_to_call = available_tools.get(tool_call.function.name)
      if function_to_call:
        args = tool_call.function.arguments
        result = function_to_call(**args)
        print('Result: ', str(result)[:200]+'...')
        # Result is truncated for limited context lengths
        messages.append({'role': 'tool', 'content': str(result)[:2000 * 4], 'tool_name': tool_call.function.name})
      else:
        messages.append({'role': 'tool', 'content': f'Tool {tool_call.function.name} not found', 'tool_name': tool_call.function.name})
  else:
    break

Блог-пост | Документация

Русскоязычное сообщество про AI в разработке

Друзья! Эту новость подготовила команда ТГК «AI for Devs» — канала, где мы рассказываем про AI-ассистентов, плагины для IDE, делимся практическими кейсами и свежими новостями из мира ИИ. Подписывайтесь, чтобы быть в курсе и ничего не упустить!