temporality
Изменить страницу↗
Инженерные документы

Веб-исследования агентов (Web Research)

#1. Цель

Дать агентам Temporality полноценный доступ к внешним знаниям: поиск, чтение страниц, просмотр изображений и интерактивное исследование сайтов — с сохранением принципов наблюдаемости (каждое действие — событие в журнале), гейтов возможностей (capabilities) и сетевой безопасности (SSRF-защита).

Развитие идёт тремя фазами:

Фаза Содержание Статус
1 web_fetch + web_search (self-hosted SearXNG) реализовано
2 Vision: images как content-блоки, view_image / fetch_image реализовано
3 Headless-браузер за CDP-контрактом (Lightpanda) реализовано

#2. Фаза 1 — web_fetch и web_search (реализовано)

#2.1. web_fetch

Загружает http(s)-страницу и возвращает агенту чистый markdown.

Контракт:

#2.2. web_search

Метапоиск через self-hosted SearXNG (решение: свой инстанс — без внешних поисковых API, ключей и лимитов; JSON-формат включён в searxng-settings.yml).

Контракт:

#2.3. Гейты и безопасность

#2.4. Конфигурация

Переменная Значение Default
KERNEL_SEARXNG_URL базовый URL SearXNG http://searxng:8080 (compose), пусто — web_search выключен
KERNEL_WEB_FETCH_ALLOW_PRIVATE разрешить web_fetch в приватные сети пусто (выключено)
KERNEL_WEB_SEARCH_PER_MIN глобальный бюджет web_search на процесс ядра в минуту 30 (0 — без лимита)

Docker-compose поднимает сервис searxng (порт хоста 127.0.0.1:8889 — только для инспекции оператором).

Внутренние параметры: кап загрузки 2 MiB, таймауты 30s/15s, кэш выдачи 10 минут / 64 записи в рамках процесса ядра.

#2.5. Нагрузка, баны поисковиков и лимиты

Self-hosted SearXNG — это метапоиск: один запрос агента веером расходится по десяткам движков, и поисковые системы (особенно Google) банят не агента, а IP сервера капчами. Защита строится слоями:

  1. Разнообразие движков. SearXNG с use_default_settings: true опрашивает весь дефолтный набор (DuckDGo, Brave, Qwant, Bing, Mojeek, Wikipedia, ...) параллельно и мержит результаты — нагрузка на каждый отдельный движок остаётся низкой. Движок, начавший отвечать капчами, автоматически приостанавливается, выдача продолжает собираться из остальных.
  2. Глобальный лимит на стороне ядра. KERNEL_WEB_SEARCH_PER_MIN (default
    1. — скользящее окно на весь процесс ядра, не на ран и не на проект: runaway-цикл одного агента не может исчерпать чужой IP. Превышение — NonRetryable-ошибка SearchRateLimited с подсказкой, через сколько секунд можно повторить.
  3. Кэш одинаковых запросов. Идентичные (query, max_results) в течение 5 минут обслуживаются из кэша и не тратят бюджет лимита.
  4. Прокси для масштабирования. При крупном флоте агентов — исходящий трафик движков через ротацию прокси (секция outgoing.proxies в настройках SearXNG).

#3. Фаза 2 — Vision (реализовано)

Мультимодальные модели потребляют изображения как content-блоки. OpenAI-совместимый API принимает image-части только в user-сообщениях — не в tool-результатах. Поэтому контракт разделён: тул возвращает в content только метаданные, а блоб — в ToolResult.Images; workflow после того, как все tool-ответы хода легли в историю (делегаты включительно), инжектирует блоки одним следующим user-сообщением («Image(s) produced by this turn's tool calls…»). Инжекция append-only — совместима с prompt-cache; дедуп-повтор вызова не ре-инжектирует (блок уже в истории).

#3.1. view_image

#3.2. fetch_image

#3.3. Пайплайн подготовки блока (prepareImageBlock)

#3.4. Ограничения v1

#4. Фаза 3 — Headless-браузер (реализовано)

Headless-браузинг для JS-рендеринга, скриншотов и интерактива. Контракт — Playwright-образное подмножество поверх CDP, поэтому бэкенды взаимозаменяемы: Lightpanda (по умолчанию, легковесный), Playwright-сервер или Chrome — без изменения тула.

#4.1. Тул browser

Один тул с параметром action:

Action Аргументы Что делает
open url Навигация таба рана + ожидание readyState=complete (бюджет 15s), возвращает финальный URL и title
click selector scrollIntoView → координаты центра элемента → синтетический mousePressed+mouseReleased
fill selector, text focus + очистка → Input.insertText (генерирует настоящие input-события, работает с SPA)
evaluate expression Runtime.evaluate c returnByValue+awaitPromise; исключение — не ошибка тула, а результат exception: …
content — outerHTML отрендеренного DOM → readability → markdown (тот же пайплайн, что у web_fetch)
screenshot — Page.captureScreenshot (PNG) → пайплайн фазы 2 → vision-блок в следующем user-сообщении
close — Закрывает таб рана

Одна вкладка на ран живет между вызовами (cookies/JS-состояние сохраняются до close) — подтверждено E2E живым JS-логином.

#4.2. Бюджеты и наблюдаемость

#4.3. Сеть и изоляция

#4.4. Конфигурация

Переменная Значение Default
KERNEL_BROWSER_CDP_URL базовый http(s) URL CDP-бэкенда; пусто — тул не регистрируется http://lightpanda:9222 (compose), пусто в bare-окружении
KERNEL_BROWSER_PER_MIN глобальный бюджет действий/мин на ядро 60

Регистрация: только при network_access рана + сконфигурированном бэкенде.

#4.5. Ограничения v1

#5. Наблюдаемость

#6. Критерии готовности фазы 1 (выполнены)