Загрузка...

Веб-поиск в Claude Code

AI

Введение

Claude Code — CLI-агент для разработки. У него есть встроенные инструменты WebSearch и WebFetch. Проблема: в продакшен-окружениях их часто блокируют:

  • Переменная CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
  • Кастомные API-прокси, которые не пробрасывают эти инструменты
  • Enterprise security policies

Нужно научить Claude Code искать в интернете. На рынке есть три подхода. Разберём каждый.


Вариант 1. Встроенные WebSearch / WebFetch

Как работает

Claude Code вызывает свой внутренний WebSearch, получает результаты, потом WebFetch загружает страницы.

Плюсы

  • Настроен из коробки — не надо ничего ставить
  • WebFetch обрабатывается маленькой моделью — не тратит токены основной сессии
  • Поддержка параллельных запросов — можно загрузить 4 страницы одновременно

Минусы

  • Не работает за прокси — если API-прокси не пробрасывает эти инструменты, они мертвы
  • Зависит от переменной окруженияCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 отключает полностью
  • Нет контроля над поисковиком — нельзя выбрать Brave, Yandex или другой движок
  • Enterprise-блокировкиskipWebFetchPreflight может потребоваться для обхода blocklist-проверки

Вердикт

Идеально, когда работает. Но в продакшене часто не работает вообще.


Вариант 2. MCP-серверы (Brave Search MCP, Tavily MCP, Exa MCP)

Как работает

Подключаешь MCP-сервер через settings.json:

{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-server-brave-search"],
      "env": { "BRAVE_API_KEY": "..." }
    }
  }
}

Claude Code подключается к MCP-серверу по stdio, получает список инструментов, вызывает их через JSON-RPC.

Плюсы

  • Красивая интеграция — инструмент появляется в списке доступных, как нативный
  • Автономность — Claude сам решает когда и как вызвать поиск
  • Структурированный ответ — MCP возвращает готовые данные, не нужно парсить JSON

Минусы

Токеновый оверхед

MCP-сервер — это дополнительное звено в цепочке. Каждый запрос проходит:

  1. Claude формирует JSON-RPC запрос → ~200 токенов
  2. MCP-сервер принимает, вызывает API → 0 токенов (но Node.js-процесс ест RAM)
  3. MCP-сервер формирует JSON-RPC ответ → ~300 токенов
  4. Claude получает ответ, переформулирует → ~500 токенов

Итого: ~1000 токенов на каждый поисковый запрос только на протокол MCP. Сам ответ поисковика — это ещё 500–1000 токенов.

Итого за сессию

Операция Токенов (MCP) Токенов (curl)
1 поисковый запрос ~1000 ~50
3 поиска + 2 загрузки ~3500 ~150
Сессия из 10 запросов ~10 000 ~500
День активной работы (30 запросов) ~30 000 ~1500

При стоимости Sonnet $3/1M входных токенов: MCP стоит $0.09/день, curl — $0.0045/день. Не критично для одного разработчика, но в масштабах команды — разница в 20×.

Зависимости

  • Node.js — каждый MCP-сервер это npxnpm install → запуск процесса
  • RAM — каждый запущенный MCP-сервер ест 50–150 МБ
  • Время запуска — при старте Claude Code подключается ко всем MCP-серверам, это 3–10 секунд на каждый

Сложность отладки

MCP-сервер молчит при ошибке. JSON-RPC вернул error: "internal" — и что? Логи MCP-сервера нужно смотреть отдельно. А curl сразу показывает 401 Unauthorized.

Вердикт

Красиво, но избыточно для задачи «сделать HTTP-запрос к поисковому API». MCP-сервер нужен, когда инструмент сложный (Playwright для браузера, база данных, файловая система). Для простого REST API — это overengineering.


Вариант 3. Skill + curl (рекомендуемый)

Как работает

Skill — это markdown-файл с инструкциями для Claude Code. Он описывает:

  1. Какой API вызывать
  2. Какую команду curl выполнить
  3. Как разобрать ответ через jq
  4. Что делать с результатами
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+auth&count=10" 
  -H "X-Subscription-Token: $BRAVE_API_KEY" 
  -H "Accept: application/json" | jq -r '.web.results[] | "[(.title)]((.url)) — (.description)"'

Плюсы

Нулевой токеновый оверхед на поиск

Bash — это просто команда. Её вызов не тратит токены. Claude Code не отправляет запрос к API-провайдеру когда выполняет curl — он просто запускает процесс. Результат возвращается как stdout, и только он попадает в контекст.

Что Токенов
Вызов Bash(curl) 0
stdout результат (10 результатов) ~300
Итого ~300

Сравните с MCP: ~1000 токенов на тот же запрос.

Skill кэшируется

Skill загружается один раз при старте сессии и кэшируется. Описание методов поиска (3–5 KB) не повторяется в каждом запросе.

Нет зависимостей

  • curl — уже стоит на любом Linux/macOS
  • jqapt install jq или brew install jq
  • Никаких Node.js-процессов, никаких npm-пакетов

Быстрый старт

Claude Code не тратит секунды на подключение MCP-серверов при старте. Сессия начинается мгновенно.

Прозрачная отладка

Ошибка? Ты видишь точный curl-запрос и ответ. 401 — ключ неверный. 429 — кончилась квота. 0 results — запрос кривой.

Работает за любым прокси

Не зависит от CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. Не зависит от поддержки WebFetch в API-прокси. curl работает всегда, пока есть сеть.

Плюсы (дополнительные)

  • Предсказуемость — Claude не вызывает поиск «сам», только когда ты просишь или явно вызываешь skill. Это плюс: никаких неожиданных API-запросов, полный контроль над каждым вызовом.
  • stdout попадает в контекст — результат curl виден в транскрипте (это плюс — прозрачность)

Минусы

  • Требует jq — без него парсить JSON сложнее (но можно через grep + sed)

Вердикт

Минимальное решение. 0 токенов на оверхед, 0 зависимостей, 0 MCP-серверов. Для задачи «поиск по API» — это ровно столько сложности, сколько нужно.


Сравнительная таблица

Критерий WebSearch/WebFetch MCP-сервер Skill + curl
Токены на запрос ~500–1000 ~1000–1500 ~300
Зависимости Нет Node.js + npm пакет curl + jq
Работает за прокси
Время старта Мгновенно 3–10 сек на сервер Мгновенно
RAM 0 50–150 МБ 0
Отладка Логи прокси Логи MCP-процесса stdout/stderr
Выбор поисковика Фиксированный Любой Любой
Кэширование Встроенное Нет Skill кэшируется
Настройка 0 строк 10+ строк JSON 3 строки env
Автономность Вызов по запросу

Почему именно Brave или Tavily

Google Custom Search не подошёл:

  • Требует включённый Custom Search API в Cloud Console — который не всегда активируется
  • Programmable Search Engine не даёт включить «Search the entire web» без обходных путей
  • Нужен billing-аккаунт даже для бесплатного тира
  • 403-ошибка на JSON API даже после включения — API может требовать enterprise-доступа

Brave Search API:

  • Бесплатно $5 кредитов каждый месяц (≈ 1000 запросов)
  • Регистрация — нужна валютная карта, спишут $1 для верификации
  • Тариф: $5 за 1000 запросов сверх бесплатных кредитов
  • Качество результатов на уровне Google для технических запросов
  • Простой REST API: один эндпоинт, один header (GET)

Tavily Search API:

  • Researcher (Free): 1000 кредитов/мес, без карты, только email
  • Pay as you go: $0.008 за кредит, платишь только за использование
  • Регистрация без карты (только email)
  • Оптимизирован для AI-аентов — возвращает сразу title, url, content
  • POST REST API: один эндпоинт, ключ в body
  • Бонус: Tavily возвращает извлечённый контент страниц — не нужен отдельный curl для загрузки статей

Практическая настройка за 3 минуты

Вариант A: Brave Search API

  1. Зайти на api.search.brave.com → создать API-ключ (нужна карта, спишут $1)
  2. Добавить в ~/.claude/settings.json:
{
  "env": {
    "BRAVE_API_KEY": "BSAxxxxx"
  }
}

Вариант B: Tavily Search API (без карты)

  1. Зайти на app.tavily.com → создать API-ключ (только email)
  2. Добавить в ~/.claude/settings.json:
{
  "env": {
    "TAVILY_API_KEY": "tvly-xxxxx"
  }
}

Общее

# Убрать CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC если есть
# Установить jq
sudo apt install jq   # Ubuntu/Debian
brew install jq       # macOS

Skill уже установлен. Запрос в чат: «найди лучшие практики аутентификации в Laravel» — и через секунду результаты.

Сравнение Brave и Tavily для curl

Критерий Brave Tavily
Метод GET POST
Ключ Header X-Subscription-Token Body api_key
Результаты title + url + description title + url + content
Контент страниц Отдельный curl на каждую Встроен в ответ (include_raw_content)
Регистрация Карта + $1 Только email
Бесплатно $5 кредитов/мес (~1000) 1000 кредитов/мес (Researcher, без карты)
Платно $5/1000 запросов $0.008/кредит (pay as you go)

Когда MCP всё-таки нужен

Skill + curl не заменяет MCP-серверы полностью. MCP незаменим когда:

  • Нужен stateful инструмент — браузер (Playwright MCP), база данных, SSH-сессия
  • Сложная логика — несколько шагов, аутентификация, retries, fallbacks
  • Автономность — Claude должен сам решать когда и как использовать инструмент
  • Инструмент работает с файловой системой — чтение/запись, watching, watching changes

Но для простого REST API — одного HTTP-запроса — skill + curl быстрее, дешевле и надёжнее.


Сам skill

Skill — это markdown-файл, который Claude Code загружает при старте сессии. Вот что получилось в итоге:

---
name: web-search
description: Поиск информации в интернете через Tavily API (предпочтительно) или Brave Search API (curl/bash). Используй когда нужно найти актуальную информацию, документацию, ответы на вопросы, новости или любой контент из интернета.
---

# Web Search

Поиск через Tavily API (предпочтительно) или Brave Search API (fallback). Bash + curl, без MCP.

## Когда использовать

- Нужна актуальная информация из интернета
- Поиск документации, руководств, примеров
- Поиск новостей, статей, блогов
- Проверка фактов и поиск источников
- Поиск решений проблем (StackOverflow, GitHub Issues)

## Приоритет API

1. **Tavily** — предпочтительно. Возвращает контент страниц, не нужны отдельные запросы.
2. **Brave** — fallback если Tavily не работает (429, 401).

---

## Tavily Search API (основной)

### Эндпоинт

```
POST https://api.tavily.com/search
Content-Type: application/json
```

### Body (JSON)

```json
{
  "api_key": "$TAVILY_API_KEY",
  "query": "запрос",
  "search_depth": "basic",
  "max_results": 10,
  "include_answer": true
}
```

### Параметры

| Параметр | Описание |
|---|---|
| `api_key` | API-ключ (из env `TAVILY_API_KEY`) |
| `query` | Поисковый запрос |
| `search_depth` | `basic` (быстро) или `advanced` (глубже, медленнее) |
| `max_results` | Количество результатов (1-20) |
| `include_answer` | `true` — включить AI-генерированный summary |
| `include_raw_content` | `true` — включить контент страниц (~1000 слов на страницу) |
| `days` | Ограничение по свежести (дни) |
| `topic` | Тема: `general` или `news` |

### Структура ответа

```json
{
  "query": "Laravel auth",
  "answer": "AI-generated summary",
  "results": [
    {
      "title": "Заголовок",
      "url": "https://example.com/page",
      "content": "Извлечённый контент"
    }
  ],
  "response_time": 2.5
}
```

### Квоты

- **Free**: 1000 запросов/мес
- **Pro**: $69/мес, 5000 запросов
- Регистрация без карты (только email)

---

## Brave Search API (fallback)

### Эндпоинт

```
GET https://api.search.brave.com/res/v1/web/search?q={query}&count=10
```

### Заголовки

| Заголовок | Описание |
|---|---|
| `X-Subscription-Token` | API-ключ (из env `BRAVE_API_KEY`) |
| `Accept` | `application/json` |

### Параметры

| Параметр | Описание |
|---|---|
| `q` | Поисковый запрос |
| `count` | Количество результатов (1-20) |
| `offset` | Смещение (0, 20, 40...) |
| `country` | Страна: `ru`, `us`, `de`... |
| `search_lang` | Язык поиска: `en`, `ru`... |
| `freshness` | `pd` (день), `pw` (неделя), `pm` (месяц), `py` (год) |

### Квоты

- **Бесплатно**: $5 кредитов/мес (~1000 запросов)
- **Сверх кредита**: $5/1000 запросов
- Регистрация требует карту (спишут $1)

---

## Пошаговый процесс

### Шаг 1: Поиск (Tavily, 1 вызов)

```bash
curl -s -X POST https://api.tavily.com/search \
  -H "Content-Type: application/json" \
  -d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"Laravel 12 authentication\",\"max_results\":10,\"include_answer\":true}" | jq -r '(.answer + "\n") // "", (.results[] | "[\(.title)](\(.url)) — \(.content[:200])")'
```

Если Tavily вернул 429 или 401 — использовать Brave:

```bash
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+12+authentication&count=10&country=us&search_lang=en" \
  -H "X-Subscription-Token: $BRAVE_API_KEY" \
  -H "Accept: application/json" | jq -r '.web.results[] | "[\(.title)](\(.url)) — \(.description)"'
```

### Шаг 2: Выбрать релевантные URL

Из вывода выбрать 2-4 наиболее релевантных. Критерии:
- Совпадение ключевых слов
- Авторитетность домена
- Свежесть

### Шаг 3: Загрузить контент (параллельно)

Для Tavily: если нужен подробный контент, повторить запрос с `"include_raw_content": true` — и отдельные запросы не нужны.

Для Brave: использовать WebFetch или curl:

```
WebFetch:
  url: {найденный_url}
  prompt: "Извлеки ключевую информацию по теме {тема}. Верни краткую сводку."
```

Если WebFetch недоступен:
```bash
curl -sL "https://example.com/page" | html2text 2>/dev/null | head -200
```

### Шаг 4: Представить результат

1. Краткая сводка (2-4 предложения)
2. Ключевые findings с указанием источника
3. Ссылки для дальнейшего чтения

---

## Примеры

### Техническая документация (Tavily)
```bash
curl -s -X POST https://api.tavily.com/search \
  -H "Content-Type: application/json" \
  -d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"Laravel 12 validation rules custom\",\"max_results\":10,\"include_answer\":true}"
```

### Свежие новости (Tavily)
```bash
curl -s -X POST https://api.tavily.com/search \
  -H "Content-Type: application/json" \
  -d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"PHP 9 release\",\"max_results\":10,\"topic\":\"news\",\"days\":30}"
```

### С контентом страниц (Tavily — замена WebFetch)
```bash
curl -s -X POST https://api.tavily.com/search \
  -H "Content-Type: application/json" \
  -d "{\"api_key\":\"$TAVILY_API_KEY\",\"query\":\"PostgreSQL jsonb performance\",\"max_results\":5,\"include_raw_content\":true,\"search_depth\":\"advanced\"}"
```

### Русскоязычный поиск (Brave)
```bash
curl -s "https://api.search.brave.com/res/v1/web/search?q=Laravel+авторизация+Socialite&count=10&country=ru&search_lang=ru" \
  -H "X-Subscription-Token: $BRAVE_API_KEY" | jq -r '.web.results[] | "[\(.title)](\(.url)) — \(.description)"'
```

---

## Обработка ошибок

### Tavily 401 Unauthorized
Проверить ключ: `echo $TAVILY_API_KEY` → [app.tavily.com](https://app.tavily.com/home)

### Tavily 429 Too Many Requests
Лимит исчерпан → переключиться на Brave

### Brave 401
Проверить ключ: `echo $BRAVE_API_KEY` → [api.search.brave.com](https://api.search.brave.com/app/keys)

### curl возвращает пустой результат
1. Проверить сеть: `curl -sI https://api.tavily.com | head -5`
2. Попробовать запрос на английском
3. Убрать `country`/`search_lang`

### WebFetch не может загрузить страницу
```bash
curl -sL "https://example.com/page" | html2text 2>/dev/null | head -300
```

---

## Советы

- Пиши запросы на английском для лучших результатов
- Tavily: используй `include_raw_content` чтобы получить контент страниц без отдельных запросов
- Tavily: `include_answer` даёт готовый AI-summary — можно использовать как краткий ответ
- Добавляй год к запросам для актуальности (например "2026")
- Для технических вопросов Tavily и Brave лучше чем Google Custom Search
- `max_results`/`count` по умолчанию 10, максимум 20


Почему skill работает лучше чем описание в CLAUDE.md

Можно было бы описать поиск в CLAUDE.md или ~/.claude/CLAUDE.md. Почему skill лучше:

Критерий CLAUDE.md Skill
Загрузка в контекст Всегда, каждую сессию Только при вызове /web-search или когда Claude решает использовать
Токены на описание Тратятся каждый запрос Тратятся один раз при активации
Структура Смешивается с правилами проекта Изолирован, можно обновлять независимо
Вызов Claude может забыть /web-search — явный trigger

Для задачи, которая нужна не каждый запрос, skill экономит токены и не загрязняет основной контекст.


Итог

Подход Когда выбирать
WebSearch/WebFetch Когда работает из коробки (нет прокси, нет блокировок)
MCP-сервер Когда нужен stateful или сложный инструмент
Skill + curl Для HTTP API-запросов (поиск, погода, курсы валют, мониторинг)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *