Files
admin/.wiki/concepts/omniroute-combo-deepseek-web-tuning.md

11 KiB
Raw Blame History

title: OmniRoute: настройка web-комбо под агентскую работу (deepseek-web + тулы) type: concept tags: [omniroute, deepseek-web, tool-calling, combo, pi, web-cookie, qwen-web, baxia-waf] sources: [../sources/omniroute-session-2026-08-22.md] updated: 2026-08-22

OmniRoute: настройка web-комбо под агентскую работу

Диагностика и настройка комбо deepseek-v4-flash-web / deepseek-v4-pro-web (провайдер deepseek-web = веб-чат chat.deepseek.com через userToken, 3 аккаунта megan/yulia/vitya). Сессия 2026-08-22.

Архитектура

pi (клиент) → omniroute (localhost:20128, Next.js + sqlite + MCP) → combo → deepseek-web executor → chat.deepseek.com/api/v0/chat/completion
  • Веб-чат DeepSeek не имеет нативного function calling — omniroute эмулирует: сериализует tools[] в текстовый контракт <tool>{"name":"...","arguments":{...}}</tool> в промпт, модель пишет блоки текстом, парсер (open-sse/translator/deepseekWebTools.ts, 486 строк) разбирает зоопарк форматов обратно в OpenAI tool_calls.
  • toolCalling: "emulated" в src/shared/constants/providers/web-cookie.ts — маркер эмуляции (claude-web = "none", grok-web = нативный true).
  • Executor: open-sse/executors/deepseek-web.ts (1147 строк): userToken→accessToken, PoW-челлендж, создание/удаление сессий, SSE-парсинг фрагментов (THINK/ANSWER), эмуляция тулов.
  • Управление: REST http://127.0.0.1:20128/api/combos (GET список, PUT /api/combos/[id]). MCP-тулы omniroute в pi-сессии отваливаются с Unknown Mcp-Session-Id — работать через HTTP напрямую.

Найденные причины вылетов агента (по убыванию важности)

1. system_message override убивает скилы pi

applyComboAgentMiddleware (open-sse/services/comboAgentMiddleware.ts) удаляет ВСЕ system-сообщения от pi (скилы, AGENTS.md, инструкции) и ставит свой system_message комбо. Модель физически не видит скилы. Фикс: PUT /api/combos/[id] с "system_message": "" — пустая строка = override не применяется (trim()-проверка), промпт pi проходит.

2. tool_filter_regex режет инструменты

Было ^(bash|computer)$ — из 339 тулов pi оставалось 2, модель слепая (не могла звать read/write/edit/MCP). Фикс: ^(bash|read|write|edit|grep|glob|list|describe_image|mcp__[a-z0-9_]+)$ — базовые + все MCP (filesystem, projects_meta, interns, books_ops...). Проверено: 339→25 тулов, все имена матчатся.

3. search-режим модели ломает tool-calling

deepseek-v4-flash-think-search (суффикс -search) включает веб-поиск чата: при URL модель сама лезет «читать» (сообщение «Link reading is unavailable in Expert Mode» — это веб-чат, не pi), генерит токены DEEP_SEARCH/SEARCHING в стриме → валидатор качества режет → Upstream response failed quality validation: streaming upstream error. Фикс: модель в комбо → deepseek-v4-flash-think (без search; thinking остаётся).

4. streaming upstream error — валидатор качества

open-sse/services/combo/validateQuality.ts isStreamingUpstreamError(): SSE-фрейм с eventType === "error" / parsed.error != null / type:"error" до контента → стрим режется, все 3 аккаунта round-robin фейлятся → «All models failed». Через API не настраивается — патч кода.

5. 503 chat_admission_busy — лимит веб-чата DeepSeek

Перегрузка их серверов / слишком частые запросы (агентный цикл pi = серия быстрых запросов). Не настройка omniroute, а capacity провайдера. Фикс: config.maxRetries: 4, config.retryDelayMs: 4000 (было 12 / 15002000). Также qwen-web падал по DNS (EAI_AGAIN chat.qwen.ai) — сетевой глюк, не ключ.

6. Пустые tool_calls (arguments: {}, name: undefined)

Модель иногда генерит <tool>{"name":"bash","arguments":{}}</tool> без аргументов → pi-валидация падает (command: must have required properties command). Следствие длинного контекста + слабого контракта. Сокращение тулов (фикс №2) снижает частоту.

Что работает после фиксов (проверено тестами)

  • Эмуляция tool-calling исправна: тест с 1 тулом и с 25 тулами (stream=true и false) возвращает корректные tool_calls ({"name":"read","arguments":{"path":...}}).
  • То, что выглядит как «модель пишет read("...") текстом» — это reasoning_content (мысли модели), pi их показывает, реальный tool_call при этом корректный.
  • Скиллы видны после удаления system_message.

Web-провайдеры с tool calling (для кастомного провайдера)

Из кода omniroute (web-cookie.ts + executors). Эмуляция ("emulated") у: deepseek-web, qwen-web, gemini-web, chatgpt-web, kimi-web, t3-web, perplexity-web, blackbox-web, muse-spark-web, inner-ai, adapta-web. Нативный (true): grok-web. "none": claude-web (не стоит скрейпить).

Бесплатные без подписки: deepseek-web ( есть), qwen-web ( ключ есть, DNS-глюк), gemini-web (Google-аккаунт), kimi-web (свободный лимит), grok-web (free-тир).

План кастомного провайдера (идея, не реализовано)

OmniRoute для 2 комбо — overkill (Next.js + sqlite + дашборд + MCP). Идея: вытащить готовые executor/deepseek-web.ts + translator/deepseekWebTools.ts из omniroute (они работают), завернуть в минимальный OpenAI-совместимый сервер:

  • POST /v1/chat/completions + GET /v1/models (pi подключается как провайдер)
  • round-robin по аккаунтам из конфига (отдельное комбо на провайдера — не смешивать в одном)
  • без quality validation (убирает все streaming upstream error)
  • persistSession: true (переиспользование сессии → меньше 503)
  • ~300 строк обвязки + 2 готовых файла
  • Плюс: поддержать qwen-web / gemini-web / kimi-web / grok-web как отдельные комбо (один парсер webTools.ts, разные executors)

Ключевые файлы omniroute

  • src/shared/constants/providers/web-cookie.ts — реестр web-провайдеров, toolCalling
  • open-sse/executors/deepseek-web.ts — executor веб-чата DeepSeek
  • open-sse/translator/deepseekWebTools.ts + webTools.ts — эмуляция/парсинг тулов
  • open-sse/services/combo/validateQuality.ts — валидатор качества (режет стримы)
  • open-sse/services/comboAgentMiddleware.ts — system_message override + tool_filter_regex
  • src/shared/validation/schemas/combo.tsupdateComboSchema (PUT-поля)
  • Данные: docker volume omniroute-data/app/data/storage.sqlite, логи /app/data/logs/application/app.log, call_logs /app/data/call_logs/

Связанное

qwen-web: стена baxia-WAF (2026-08-22, llm-web-proxy подзадача)

Попытка добавить qwen-web в llm-web-proxy упёрлась в анти-бот:

  • Симптом: completion возвращает HTTP 200 с JSON-эневелопом {"ret":["FAIL_SYS_USER_VALIDATE","RGV587_ERROR::SM::哎哟喂,被挤爆啦,请稍后重试"],"data":{"url":".../_____tmd_____/punish?x5secdata=...&action=captcha"}} — слайдер-капча Alibaba baxia-WAF. RGV587 = punish-flow, требует решить капчу в браузере (получить x5secdata).
  • Проверено (все — капча): Node-fetch с полным свежим cookie-jar (включая token/cna/ssxmod_itna), со всеми браузерными заголовками (sec-ch-ua, sec-fetch-*, Accept: text/event-stream), со статическим bx-umidtoken / без него. Даже настоящий Chrome (CDP :9222, залогиненная сессия, капча разгадана вручную): chats/new проходит (браузерный фингерпринт), но chat/completions виснет → капча возвращается.
  • Вывод: капча привязана к device-фингерпринту запроса (bx-umidtoken минтится JS из sg-wum.alibaba.com), не к cookie. Прямой API-scraping из Node — мёртвая ветка.
  • Зацепка: «из под omniroute работает» — в контейнере omniroute лежит рабочая версия open-sse/executors/qwen-web.ts (≠ GitHub main, который портировали в lwp). Сравнить и/или взять подход оттуда (возможно решённый punish-flow / живой браузерный путь). Ключ/сессия qwen хранится в omniroute DB (provider_connections, зашифрован enc.v1. + STORAGE_ENCRYPTION_KEY из /app/data/server.env).
  • Статус: подзадача [llm-web-proxy-qwen-web] 🟡 paused, next-сессия — юзер покажет рабочий подход.
  • 2026-08-22 вечер: находка-подтверждение. Аккаунт ForgetMeAI (FreeQwenApi, 212) гоняет qwen через браузер и работает: чат-запрос исполняется внутри страницы (page.evaluate(fetch(...))) — запрос несёт настоящий bx-umidtoken + canvas-фингерпринт + same-origin → baxia-WAF пропускает. Плюс тяжёлый stealth-спуфинг (navigator/canvas-noise/задержки событий). Вывод: Node-fetch-путь мёртв окончательно, рабочий сценарий = браузерный executor (puppeteer/playwright). Референс: forgetmeai-free-web-chat-proxies + lwp docs/reference/forgetmeai/.