Всё начиналось в отрыве от реальных данных. ИИ анализировал целевую аудиторию и предлагал поисковые запросы.
Мы подключили Wordstat по API, чтобы агент сам проверял свои предположения и собирал ответ по данным сервиса. Получился read-only-пакет на Python: четыре метода Wordstat, командная строка и MCP-сервер. Код и тесты доступны в открытом репозитории.
Содержание
Агент возвращает фразы с частотностями Wordstat
В примере нас интересовала проверка спроса на автоматизацию маркетинга. Основная часть запроса в чат:
Посмотри в Wordstat, как пользователи в России искали
автоматизацию маркетинга за последний месяц.
Покажи пять самых частотных формулировок.
В ответе Codex — пять формулировок с частотностями из Wordstat. Их написание и числа можно сверить с результатом инструмента:

Раньше после анализа аудитории нам приходилось открывать Wordstat и проверять предложенные моделью формулировки вручную. Теперь агент получает частотности через инструмент и возвращает их в том же диалоге. Проверка спроса больше не требует переноса данных между сервисом и чатом.
Этот пример закрывает одну задачу — получение фраз и частотностей. Для отбора ключей в конкретную кампанию потребуются сведения о продукте, посадочной странице и целях рекламы.
Воспроизвести интеграцию можно из зафиксированного тега
Для статьи мы создали тег wordstat-v0.1.1. Если main изменится, команды и код ниже останутся привязаны к версии статьи.
git clone --branch wordstat-v0.1.1 --depth 1 `
https://github.com/akulemin/ai-marketing-integrations.git
cd ai-marketing-integrationspackagesyandex-wordstat
python -m venv .venv
..venvScriptspython.exe -m pip install -e ".[dev]"
Copy-Item .env.example .env
В .env нужны тип авторизации, ключ и ID каталога:
WORDSTAT_AUTH_TYPE=api_key
WORDSTAT_API_KEY=<secret>
WORDSTAT_FOLDER_ID=<folder-id>
Сервисному аккаунту назначается роль search-api.webSearch.user, а API-ключ создаётся со scope yc.search-api.execute. Контрольный запрос из каталога пакета:
..venvScriptswordstat.exe top "автоматизация маркетинга" --region 225 --limit 5
Для подключения к Codex настройка добавляется в проектный .codex/config.toml:
[mcp_servers.yandex-wordstat]
command = 'C:absolutepathai-marketing-integrationspackagesyandex-wordstat.venvScriptswordstat-mcp.exe'
cwd = 'C:absolutepathai-marketing-integrationspackagesyandex-wordstat'
enabled_tools = [
"wordstat_top",
"wordstat_dynamics",
"wordstat_regions_distribution",
"wordstat_regions_tree",
]
Пути заменяются на абсолютные пути установки. cwd указывает на каталог пакета с локальным .env; ключей в TOML нет. Запуск проверен через stdio: инициализация MCP, список инструментов и чтение тестового кэша без HTTP-обращений. Формат command, args, cwd и списка разрешённых инструментов описан в документации Codex MCP.
Агенту нужен узкий инструмент с предсказуемым ответом
Для этого понадобилось отделить получение данных от их интерпретации. В ответе инструмента должны сохраняться исходные фразы и частотности, чтобы можно было сопоставить с ними выводы модели.
Мы решили дать агенту четыре отдельных инструмента, которые повторяют методы официального Wordstat API:
|
Инструмент |
Что возвращает |
Для чего используем |
|---|---|---|
|
|
Популярные и связанные фразы за последние 30 дней |
Проверить формулировки спроса и найти соседние запросы |
|
|
Частотность по дням, неделям или месяцам |
Увидеть сезонность и не принять месячный всплеск за постоянный спрос |
|
|
Количество, долю и индекс интереса по регионам |
Проверить, где запрос выражен сильнее |
|
|
Иерархию поддерживаемых регионов |
Преобразовать название территории в ID для следующего вызова |
Все четыре операции только читают данные. Пакет не меняет рекламные кампании и не требует контура согласования, который нужен для записи в Директ.
Архитектура получилась короткой:
ИИ-клиент ── MCP ──┐
├── WordstatService ── WordstatClient ── Yandex Cloud
терминал ─── CLI ──┘ │ │
│ ├── повтор временных ошибок
Python-код ───────────────────┘ └── файловый кэш
CLI и MCP вызывают один сервисный слой. Поэтому в них одинаковая валидация, кэш и обработка ошибок, а расхождения между «ручным» и агентным запросом проще ловить в тестах.
Один полный проход по Wordstat стоит 9 копеек
По тарифу Yandex Search API, проверенному 23 октября 2026 года, цены в рублях включают НДС и указаны за 1000 вызовов:
|
Метод |
За 1000 вызовов |
За один вызов |
|---|---|---|
|
|
20 ₽ |
0,02 ₽ |
|
|
20 ₽ |
0,02 ₽ |
|
|
50 ₽ |
0,05 ₽ |
|
|
Без оплаты |
Без оплаты |
По одному успешному вызову трёх платных методов — 0,09 ₽: 0,02 + 0,02 + 0,05 ₽. Это стоимость Wordstat; расходы на ИИ-клиент и модель считаются отдельно.
Десять одинаковых исследовательских проходов стоят 0,90 ₽, а 10 000 проходов — 900 ₽. На ручной проверке экономия невелика, но автономный агент может повторять один и тот же вызов в цикле. Поэтому кэш появился в первой версии: он ограничивает лишние обращения к API и фиксирует снимок данных для текущего разбора.
Ключ кэша — SHA256 от имени метода и нормализованного JSON-запроса:
material = json.dumps(
{"method": method, "payload": payload},
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
)
digest = hashlib.sha256(material.encode("utf-8")).hexdigest()
По умолчанию обычные ответы хранятся семь дней, дерево регионов — 30 дней. Пока запись действительна, одинаковые параметры возвращают локальный результат без обращения к API. Изменение лимита, региона или фильтра устройств создаёт другой ключ. Флаг refresh=true явно обходит кэш.
Кэш сохраняет один снимок для повторного разбора. Он также сокращает лишние обращения, но отдельного лимита расходов у пакета пока нет: агент может обходить кэш или менять параметры.
Клиент валидирует ответ до того, как его увидит модель
Yandex Cloud принимает REST-запросы синхронно. Для доступа нужны каталог, API-ключ или IAM-токен и роль search-api.webSearch.user. Секреты читаются из переменных окружения и не входят в параметры MCP-инструментов.
Внутри клиент собирает типизированную модель запроса, проверяет кэш и только затем обращается к API:
def get_top(self, phrase, *, num_phrases=50, regions=None, devices=None, refresh=False):
request = TopRequest(
phrase=phrase,
numPhrases=num_phrases,
regions=regions or [],
devices=devices or [],
folderId=self.settings.folder_id,
)
return self._call("topRequests", request, TopResponse, refresh=refresh)
Pydantic проверяет типы полей и ограничения запроса. Например, неподдерживаемое значение устройства вызывает ошибку валидации до отправки HTTP-запроса. Проверка не доказывает полноту ответа: дополнительные поля допускаются, а у некоторых полей есть значения по умолчанию. Изменения API всё равно требуют проверки контракта.
Для кодов 429, 500, 502, 503 и 504 клиент повторяет запрос с экспоненциальной задержкой. Числовой Retry-After имеет приоритет. Сообщение об ошибке проходит отдельную очистку: API-ключ, IAM-токен и folder ID заменяются на <redacted> до того, как исключение попадёт в терминал или чат.
Пользователь отвечает за .env, права сервисного аккаунта и логи ИИ-клиента. Пакет не добавляет секреты в схему инструмента и очищает известные значения из текста HTTP-ошибок. Это не изоляция ключей от агента, у которого есть доступ к файлам локального проекта.
MCP получает четыре инструмента вместо универсального HTTP-доступа
Можно было дать агенту URL, заголовки и общий инструмент http_post. Мы отказались от этого варианта: модели пришлось бы каждый раз собирать служебный JSON, а область доступа стала бы шире.
MCP-сервер публикует четыре функции с явными параметрами. Например, инструмент топа выглядит так:
@mcp.tool()
def wordstat_top(
phrase: str,
regions: list[str] | None = None,
devices: list[str] | None = None,
limit: int = 50,
refresh: bool = False,
) -> dict:
if limit > 200:
raise ValueError(
"MCP output is limited to 200 phrases; use the CLI for larger exports"
)
return _service().top(
phrase,
limit=limit,
regions=regions,
devices=devices,
refresh=refresh,
)
Лимит в 200 относится к параметру топа в MCP. Ассоциации API возвращает отдельным массивом; ограничения общего объёма ответа в токенах у сервера нет. Для больших выборок в CLI доступно до 2000 фраз: результат можно сохранить в JSON или CSV, а в контекст модели передать нужную часть.
Агенту предстоит выбрать метод и превратить описание территории в ID. Карточка вызова показывает, какие параметры он собрал, — здесь их можно проверить независимо от последующего объяснения.
В первой сессии агент ошибся в параметре устройства
В сессии Codex 20 октября модель передала devices: ["all"]. Клиент ожидает значения перечисления Device, в том числе DEVICE_ALL, и отклонил запрос до обращения к Wordstat. В той сессии данные в итоге получили через CLI. Поэтому сам факт появления инструмента в клиенте ещё не подтверждал, что агент правильно им пользуется.
23 октября мы повторили вызов через MCP с корректными параметрами:
{
"phrase": "автоматизация маркетинга",
"regions": ["225"],
"limit": 5,
"refresh": false
}
Фильтр устройств здесь не задан. Перед вызовом мы отдельно проверили доступность записи кэша, запретив HTTP-обращения в проверочном клиенте. MCP вернул тот же снимок, сохранённый 20 октября. Это подтверждает работу MCP и повторное чтение данных; доступность API на 23 октября этим вызовом не проверялась.
Эта ошибка подсказала следующую доработку: описать допустимые устройства прямо в схеме MCP-инструмента через enum. Сейчас публичная функция принимает list[str], поэтому модель узнаёт об ограничении только из ошибки внутренней валидации.
Тесты не ходят в платный API
В опубликованном теге wordstat-v0.1.1 двенадцать модульных тестов. Они проверяют модели, заголовок авторизации, кэш, повтор запросов после 429, очистку секретов, состав и схему MCP-инструментов. HTTP-ответы замоканы, поэтому этот набор не обращается к платному API.
..venvScriptspython.exe -m pytest -q
Контрольный прогон публичного пакета 23 октября: 12 passed in 2.03s. Дополнительно мы запустили сервер через stdio, выполнили MCP-инициализацию и вызвали инструмент чтения дерева регионов из тестового кэша. Все четыре инструмента доступны; HTTP-обращения в этой проверке были запрещены.
Ограничения текущей версии
Пакет поддерживает все четыре REST-метода Wordstat, два типа авторизации, JSON и CSV, повтор временных ошибок и локальный кэш. У первой версии остаются ограничения:
-
нет общей схемы исследовательского отчёта, которая объединяет топ, динамику и географию;
-
нет автоматической кластеризации фраз;
-
параметр топа в MCP ограничен 200 фразами; общего ограничения объёма ответов нет;
-
схема MCP пока принимает устройства как строки; допустимые значения проверяет внутренний клиент;
-
интеграционный тест с живым API нельзя безопасно запускать в публичном CI без секрета и оплаты;
-
файловый кэш рассчитан на одного пользователя и не координирует параллельные процессы на нескольких машинах.
Следующая доработка — уточнить схему устройств. Для исследовательского отчёта также нужно явно возвращать дату получения данных и признак попадания в кэш. Сейчас сам JSON-ответ этих полей не содержит, поэтому их приходится проверять отдельно.
Код версии статьи доступен в репозитории ai-marketing-integrations. Начать можно с одной фразы и пяти результатов: проверить параметры вызова, сверить числа с ответом инструмента и посмотреть, какие выводы модель сделала сверх этих данных.
Автор: akulemin
