Создание плагина провайдера веб-поиска
Плагины провайдеров веб-поиска регистрируют бэкенд, который обслуживает вызовы инструментов web_search, web_extract и (опционально) глубокого обхода. Встроенные провайдеры — Firecrawl, SearXNG, Tavily, Exa, Parallel, Brave Search (бесплатный тариф), xAI и DDGS — поставляются как плагины в plugins/web/<name>/. Вы можете добавить новый или переопределить встроенный, поместив рядом с ними свою директорию.
Веб-поиск — один из нескольких бэкенд-плагинов, которые поддерживает VibeOS. Другие (со своими ABC) — это Плагины провайдеров генерации изображений, Плагины провайдеров генерации видео, Плагины провайдеров памяти, Плагины контекстных движков и Плагины провайдеров моделей. Общие плагины инструментов/хуков/CLI описаны в разделе Создание плагина VibeOS.
Сегодняшние встроенные веб-бэкенды: Firecrawl, SearXNG, Tavily, Exa, Parallel, Brave Search (бесплатный тариф), xAI, DDGS и Yandex Search.
Как работает обнаружение
VibeOS сканирует веб-бэкенды в трёх местах:
- Встроенные —
<repo>/plugins/web/<name>/(автозагрузка сkind: backend, всегда доступны) - Пользовательские —
~/.vibeos/plugins/web/<name>/(включаются черезplugins.enabledилиvibeos plugins enable <name>) - Pip — пакеты, объявляющие точку входа
vibeos_agent.plugins
Функция register(ctx) каждого плагина вызывает ctx.register_web_search_provider(...) — это помещает экземпляр в реестр в agent/web_search_registry.py. Активный провайдер для каждой возможности выбирается конфигурацией:
| Возможность | Ключ конфига | Запасной вариант |
|---|---|---|
web_search | web.search_backend | web.backend |
web_extract | web.extract_backend | web.backend |
Режимы глубокого обхода внутри web_extract | web.extract_backend | web.backend |
Если ни один ключ не установлен, VibeOS автоматически определяет бэкенд по тому, какой API-ключ/URL присутствует в окружении. vibeos tools проведёт пользователя через выбор.
Структура директории
plugins/web/my-backend/
├── __init__.py # Точка входа register()
├── provider.py # Подкласс WebSearchProvider
└── plugin.yaml # Манифест с kind: backend и provides_web_providers
brave_free/ и ddgs/ — самые маленькие эталонные реализации: brave_free для провайдера только поиска с API-ключом, ddgs — для провайдера без ключа, который лениво устанавливает свой SDK.
ABC WebSearchProvider
Создайте подкласс agent.web_search_provider.WebSearchProvider. Обязательными членами являются только name, is_available() и те из search() / extract(), которые вы реализуете. (Глубокий обход — не отдельный метод, а режим extract().)
# plugins/web/my-backend/provider.py
from __future__ import annotations
import os
from typing import Any, Dict, List
from agent.web_search_provider import WebSearchProvider
class MyBackendWebSearchProvider(WebSearchProvider):
"""Минимальный провайдер только поиска через HTTP API My Backend."""
@property
def name(self) -> str:
# Стабильный идентификатор, используемый в ключах конфига
# web.search_backend / web.extract_backend / web.backend.
# Нижний регистр, без пробелов; дефисы разрешены.
return "my-backend"
@property
def display_name(self) -> str:
# Человеческое название, показываемое в `vibeos tools`. По умолчанию — `name`.
return "My Backend"
def is_available(self) -> bool:
# Дешёвая проверка — наличие переменной окружения, импортируемость опциональной зависимости и т.д.
# НЕ ДОЛЖНА делать сетевые вызовы (выполняется при каждой отрисовке `vibeos tools`).
return bool(os.getenv("MY_BACKEND_API_KEY", "").strip())
def supports_search(self) -> bool:
return True
def supports_extract(self) -> bool:
return False
def search(self, query: str, limit: int = 5) -> Dict[str, Any]:
import httpx
api_key = os.environ["MY_BACKEND_API_KEY"]
try:
resp = httpx.get(
"https://api.example.com/search",
params={"q": query, "count": max(1, min(int(limit), 20))},
headers={"Authorization": f"Bearer {api_key}"},
timeout=15,
)
resp.raise_for_status()
data = resp.json()
except httpx.HTTPError as exc:
return {"success": False, "error": str(exc)}
# Формат ответа фиксирован — см. «Формат ответа» ниже.
return {
"success": True,
"data": {
"web": [
{
"title": item.get("title", ""),
"url": item.get("url", ""),
"description": item.get("snippet", ""),
"position": idx + 1,
}
for idx, item in enumerate(data.get("results", []))
],
},
}
# plugins/web/my-backend/__init__.py
from plugins.web.my_backend.provider import MyBackendWebSearchProvider
def register(ctx) -> None:
"""Точка входа плагина — вызывается один раз при загрузке."""
ctx.register_web_search_provider(MyBackendWebSearchProvider())
plugin.yaml
name: web-my-backend
version: 1.0.0
description: "Веб-поиск My Backend — REST API с Bearer-аутентификацией"
author: Ваше Имя
kind: backend
provides_web_providers:
- my-backend
requires_env:
- MY_BACKEND_API_KEY
| Ключ | Назначение |
|---|---|
kind: backend | Направляет плагин через путь загрузки бэкендов |
provides_web_providers | Список name провайдеров, которые регистрирует этот плагин — используется загрузчиком для рекламы плагина в vibeos tools ещё до выполнения register() |
requires_env | Интерактивный запрос учётных данных во время vibeos plugins install (см. Создание плагина VibeOS → Проверка переменных окружения для полного формата) |
Справочник по ABC
Полный контракт в agent/web_search_provider.py. Методы, которые вы можете переопределить:
| Член | Обязателен | По умолчанию | Назначение |
|---|---|---|---|
name | ✅ | — | Стабильный идентификатор, используемый в конфиге web.*_backend |
display_name | — | name | Название, показываемое в vibeos tools |
is_available() | ✅ | — | Дешёвый шлюз доступности — переменные окружения, опциональные зависимости |
supports_search() | — | True | Флаг возможности для маршрутизации web_search |
supports_extract() | — | False | Флаг возможности для маршрутизации web_extract |
search(query, limit) | условно | вызывает исключение | Обязателен, если supports_search() возвращает True |
extract(urls, **kwargs) | условно | вызывает исключение | Обязателен, если supports_extract() возвращает True |
Провайдеры могут рекламировать несколько возможностей из одного класса — Firecrawl, Tavily, Exa и Parallel реализуют и поиск, и извлечение. Brave Search и DDGS — только поиск; SearXNG — только поиск с документированным рабочим процессом «соедините меня с провайдером извлечения».
Формат ответа
Обёртка инструмента ожидает фиксированную структуру, чтобы не требовалось преобразование между бэкендами.
Успешный поиск:
{
"success": True,
"data": {
"web": [
{"title": str, "url": str, "description": str, "position": int},
...
],
},
}
Успешное извлечение:
{
"success": True,
"data": [
{
"url": str,
"title": str,
"content": str,
"raw_content": str,
"metadata": dict, # опционально
"error": str, # опционально, только при ошибке для конкретного URL
},
...
],
}
Любая возможность, при ошибке:
{"success": False, "error": "понятное человеку сообщение"}
}
Оба метода `search()` и `extract()` могут быть `async def` — диспетчер определяет функции-корутины через `inspect.iscoroutinefunction` и ожидает их соответственно. Синхронные реализации, выполняющие блокирующий ввод-вывод (HTTP, вызовы SDK), подходят для небольших бэкендов; диспетчер обрабатывает многопоточность.
## Флаги возможностей
VibeOS направляет вызовы к нужному провайдеру на основе флагов `supports_*`. Типичная многопровайдерная настройка:
```yaml
# ~/.vibeos/config.yaml
web:
search_backend: "brave-free" # только поиск, быстро, бесплатно 2k/мес
extract_backend: "firecrawl" # извлечение + обход, платная квота
Когда web.search_backend или web.extract_backend не заданы, оба используют web.backend как запасной. Если и он не задан, VibeOS выбирает первый доступный провайдер, поддерживающий запрошенную возможность, на основе наличия переменных окружения.
Если ваш провайдер поддерживает только одну возможность, оставьте другие флаги по умолчанию (False), и реестр пропустит его для этого инструмента — пользователи не увидят вводящих в заблуждение ошибок «провайдер X не сработал», когда они используют X только для поиска, а просят агента выполнить извлечение.
Как VibeOS подключает это к инструментам
Инструменты web_search и web_extract находятся в tools/web_tools.py. Во время вызова они:
- Читают соответствующий ключ конфига (
web.search_backendдляweb_search,web.extract_backendдляweb_extract) - Запрашивают у реестра провайдера с этим
name - Проверяют
is_available()и соответствующий флагsupports_*() - Выполняют
search()/extract()(глубокий обход работает как режим внутриextract()), ожидая, если метод является корутиной - Сериализуют ответную структуру в JSON и передают её LLM
Ошибки отображаются как результат инструмента; LLM решает, как их объяснить. Если ни один провайдер не зарегистрирован (или каждый доступный не проходит проверку возможности), инструмент возвращает полезную ошибку со ссылкой на vibeos tools.
Ленивая установка опциональных зависимостей
Если ваш провайдер оборачивает сторонний SDK (как DDGS делает с пакетом ddgs), не импортируйте его на верхнем уровне модуля. Используйте tools.lazy_deps.ensure(...) внутри is_available() или search() — VibeOS установит пакет при первом использовании, под контролем security.allow_lazy_installs. См. Создание плагина VibeOS → Ленивая установка для модели безопасности.
Эталонные реализации
plugins/web/brave_free/— маленький HTTP-провайдер только поиска с API-ключом. Хороший стартовый шаблон.plugins/web/ddgs/— провайдер без ключа, лениво устанавливающий свой SDK. Полезный паттерн для бэкендов, оборачивающих Python-пакет.plugins/web/firecrawl/— полноценный многозадачный провайдер (поиск + извлечение + обход) с несколькими режимами форматирования.plugins/web/searxng/— самостоятельно размещаемый бэкенд, настраиваемый через URL, без аутентификации.plugins/web/xai/— поиск на основе LLM через серверный инструментweb_searchот Grok. Показывает, как повторно использовать существующую поверхность учётных данных OAuth/переменных окружения (tools/xai_http.py) без добавления новых переменных, и как написать дешёвыйis_available(), соблюдающий контракт без сетевых вызовов.
Распространение через pip
# pyproject.toml
[project.entry-points."vibeos_agent.plugins"]
my-backend-web = "my_backend_web_package"
my_backend_web_package должен предоставлять функцию register на верхнем уровне. См. Распространение через pip в общем руководстве по плагинам для полной настройки.
Связанные страницы
- Веб-поиск — пользовательская документация по функции и настройка для каждого бэкенда
- Обзор плагинов — все типы плагинов на одном экране
- Создание плагина VibeOS — общее руководство по инструментам/хукам/slash-командам