SEO-плагины на DeepSeek Harness: что переезжает из Claude Code, а что нет

Год подряд SEO-плагины к нейросети сводились у меня к одной схеме: Claude Code и несколько MCP-серверов — Search Console, DataForSEO, отчёт краулера. Модель тягает цифры сама, а не сочиняет их. Затем DeepSeek выпустил собственный агентный харнесс, DeepSeek Harness (dsh), и появился вопрос: уедет ли весь набор целиком, чтобы платить по тарифам DeepSeek и не переучивать ни себя, ни проекты.

Ответ короткий — да, почти без потерь. Подробности ниже, по слоям.

Что такое dsh

Это запускатель профилей. Профиль — упорядоченная стопка плагинов и собственный слой настроек сверху, файл cordis.patch.yml в папке профиля. В комплекте веб-интерфейс, headless для разовых заданий и режимы автоматизации. Устанавливается из npm, пакет @deepseek-ai/dsh.

Оговорка: на момент написания это версия 0.1.5, релиз-кандидат. Документация подробная, но для боевых задач я держал бы под рукой привычный клиент — на случай изменений между версиями.

SEO-набор в любом харнессе состоит из трёх слоёв: откуда брать данные, по каким правилам с ними работать и что делать, если модель ушла не туда. Прохожусь по каждому.

Слой первый: данные через MCP

За это отвечает плагин dsh-mcp-client. Одна запись — один сервер, без обёрток. DataForSEO, запущенный локально, выглядит так:

- insert:
    - id: mcp-dataforseo
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: dataforseo
        transport: stdio
        command: npx
        args: ['-y', 'dataforseo-mcp-server']
        env:
          DATAFORSEO_LOGIN: !!js process.env.DATAFORSEO_LOGIN
          DATAFORSEO_PASSWORD: !!js process.env.DATAFORSEO_PASSWORD

Облачные серверы, например Ahrefs или Semrush, подключаются так же — меняется только stdio на transport: streamable-http и адрес. Ключи идут через переменные окружения, в файл профиля их класть не нужно.

Инструменты называются так же, как в Claude Code: mcp__dataforseo__.... Поэтому всё, что завязано на эти имена — правила разрешений, привычные формулировки задач, — переносится без правок.

Перед переездом стоит знать три вещи:

  • Мост пропускает только инструменты. MCP-ресурсы и заготовленные подсказки (prompts) не поддерживаются. Если сервер Search Console отдаёт отчёты ресурсами, модель их не увидит.

  • У вызова таймаут 60 секунд по умолчанию. Тяжёлая выгрузка выдачи пачкой ключей может в него не поместиться. Исправляется полем toolCallTimeoutMs.

  • Если сервер не поднялся, харнесс стартует без него — инструментов нет, ошибка в логе. Для ночного прогона это опасно: задание отработает без данных. Ставьте failOnStartupError: true, чтобы падало явно.

Ноутбук с открытым кодом крупным планом. Фото: Marc Mueller, Unsplash, CC0
Ноутбук с открытым кодом крупным планом. Фото: Marc Mueller, Unsplash, CC0

Слой второй: правила дома в навыках

Сервер даёт цифры, но не знает ваших договорённостей: какой длины заголовки, что делать с дублями, по какому признаку фразы разводятся на разные посадочные. Раньше это лежало в длинной подсказке, которую каждый писал по-своему. В dsh для этого есть навыки — те же skills из Claude Code.

Навык — папка с файлом SKILL.md или просто файл <имя>.md в одном из корней, которые сканирует харнесс:

  • .dsh/skills в корне проекта;

  • .agents/skills там же;

  • $DSH_HOME/skills — общие навыки пользователя.

В начале файла — шапка с обязательными полями name и description. По описанию модель решает, когда навык нужен, а тело подгружает только в этот момент. Пример:

---
name: semantika-klastery
description: Разбор выгрузки Вордстата на группы под посадочные страницы
---
1. Читай выгрузку целиком, не кусками.
2. Фразы на одну страницу, только если выдача по ним совпадает.
3. В конце сверь число строк на входе и на выходе. Не сошлось — задача не сделана.

Третий пункт я теперь вставляю в каждую пакетную задачу. Модель умеет молча обработать сто строк из пятисот и отчитаться, будто сделала всё. Счётчик на входе и выходе ловит такое надёжнее, чем внимательное чтение отчёта.

Две детали. Тело навыка перечитывается при каждой загрузке, поэтому правило можно поправить посреди работы, без перезапуска. И второе: папку .claude/skills харнесс по умолчанию не сканирует. Если навыки уже лежат там, укажите её в customSkillDirs — копировать не нужно.

Слой третий: страховка через хуки

Главное, что я вынес из года работы с плагинами: первые месяц-два не давать модели права записи. Пусть смотрит и предлагает, а меняет человек. В Claude Code это держится на хуках, и здесь есть сюрприз: у dsh есть мост dsh-hooks-claude-code, который исполняет готовый hooks.json без переписывания.

- insert:
    - name: '@deepseek-ai/dsh-hooks-claude-code'
      config:
        configPath: ./.claude/hooks.json
        projectDir: .

Работают основные события: PreToolUse может запретить вызов инструмента или потребовать подтверждение, PostToolUse — вернуть результат модели с замечанием, Stop — заставить сделать ещё шаг, если проверка не пройдена. Хук «не трогай CMS без меня» и хук «не заканчивай, пока не сошлись счётчики» переезжают как есть. Ограничение одно: мост понимает только командные хуки — те, что вызывают внешнюю программу.

Ночной аудит без интерфейса

Для регулярных задач есть профиль headless: одно задание, один ответ, выход.

dsh --profile headless "Сверь страницы из карты сайта с кодами ответа и закрытием в robots. Итог — таблица."

Такую строку легко поставить в планировщик раз в неделю. Задача запускается в текущей папке — в ней лежат навыки проекта, — а сессия сохраняется, так что утром можно открыть и посмотреть, что агент делал и где споткнулся.

Где тут экономия

DeepSeek дешевле не только по прайсу. У агента, который долго работает в одном проекте, почти весь вход — повторное чтение кэша: инструкции, описания инструментов, история шагов. Кэш у DeepSeek стоит копейки, особенно вне пиковых часов.

Но у MCP есть обратная сторона: описания всех инструментов подключённого сервера едут в каждый запрос. Сервер на полсотни инструментов — постоянная прибавка к каждому шагу. Пока список не меняется, эта часть остаётся одинаковой и попадает в кэш. Если сервер поменял список инструментов, кэш сбивается с этого места и дальше.

Правило отсюда: не подключать всё сразу. Держите отдельный профиль под семантику и отдельный под технический аудит, в каждом — только нужные серверы. Для dsh это естественно: профиль и есть такая стопка.

Что в итоге

Переезд на DeepSeek Harness для SEO-набора — скорее перенос файлов, чем переделка:

  • MCP-серверы подключаются одной записью, имена инструментов те же, что в Claude Code;

  • навыки — тот же формат SKILL.md, старую папку можно просто указать в настройках;

  • хуки из hooks.json работают через мост, если они командные;

  • не переезжают MCP-ресурсы и заготовленные подсказки — проверьте, не держится ли на них что-то важное;

  • для регулярных отчётов есть headless, для разных задач — разные профили.

И то, что не меняется ни от какого харнесса: модель приносит строки, а не решения. Что развивать, от чего отказаться и что сказать клиенту — по-прежнему ваша работа.

Комментарии (1)


  1. ig_novvv
    23.09.2026 13:35

    Спасибо за разбор, отдельно за failOnStartupError. У нас в команде похожая тихая поломка случилась на стороне самого DeepSeek. Мы ходим в его API с серверным web_search, и поиск перестал вызываться: 16 ответов из 16 пришли без вызова поиска, в том числе с tool_choice: required. А ранее было 19 из 20. Запрос не падает, модель отвечает по памяти, и снаружи это выглядит как обычный ответ.

    С тех пор перед каждым пакетом делаем одну пробу за пару рублей и смотрим, был ли в ответе вызов поиска. Ноль — в прогон не ставим.

    Про хуки согласен: проверку, о которой можно забыть, держим в хуке, а не в тексте инструкции. Таких у нас сейчас шестнадцать.