Documentação oficial desta página · v0.20.6
Criar um plugin de provedor de busca na web
Os plugins de provedor de busca na web registram um backend que atende às chamadas de ferramenta web_search, web_extract e (opcionalmente) de deep crawl. Os provedores embutidos — Firecrawl, SearXNG, Tavily, Exa, Parallel, Brave Search (camada gratuita), xAI e DDGS — vêm todos como plugins em plugins/web/<nome>/. Você pode adicionar um novo, ou substituir um dos que já vêm juntos, colocando um diretório ao lado deles.
A busca na web é um dos vários plugins de backend que o Hermes suporta. Os outros (cada um com sua própria ABC) são os plugins de provedor de geração de imagem, os plugins de provedor de geração de vídeo, os plugins de provedor de memória, os plugins de motor de contexto e os plugins de provedor de modelo. Os plugins gerais de ferramenta/hook/CLI ficam em Criar um plugin do Hermes.
Como funciona a descoberta
O Hermes procura backends de busca na web em três lugares:
- Embutidos —
<repo>/plugins/web/<nome>/(carregados automaticamente comkind: backend, sempre disponíveis) - Do usuário —
~/.hermes/plugins/web/<nome>/(opt-in viaplugins.enabledouhermes plugins enable <nome>) - Via pip — pacotes que declaram um entry point
hermes_agent.plugins
A função register(ctx) de cada plugin chama ctx.register_web_search_provider(...) — isso coloca a instância no registro em agent/web_search_registry.py. O provedor ativo de cada capacidade é escolhido pela configuração:
| Capacidade | Chave de configuração | Cai para |
|---|---|---|
web_search | web.search_backend | web.backend |
web_extract | web.extract_backend | web.backend |
Modos de deep crawl dentro de web_extract | web.extract_backend | web.backend |
Quando nenhuma das duas chaves está definida, o Hermes detecta o backend sozinho, a partir da chave de API ou URL que estiver presente no ambiente. O hermes tools guia o usuário pela escolha.
Estrutura de diretórios
plugins/web/meu-backend/
├── __init__.py # entry point register()
├── provider.py # subclasse de WebSearchProvider
└── plugin.yaml # manifesto com kind: backend e provides_web_providers
brave_free/ e ddgs/ são as menores referências dentro do repositório — brave_free para um provedor só de busca protegido por chave de API, ddgs para um provedor sem chave que instala o SDK sob demanda.
A ABC WebSearchProvider
Faça uma subclasse de agent.web_search_provider.WebSearchProvider. Os únicos membros obrigatórios são name, is_available() e aquele que você implementar entre search() / extract(). (O deep crawl não é um método separado — é um modo do extract().)
# plugins/web/meu-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):
"""Provedor mínimo, só de busca, contra a API HTTP do My Backend."""
@property
def name(self) -> str:
# Id estável usado nas chaves de configuração web.search_backend /
# web.extract_backend / web.backend. Minúsculas, sem espaço; hífen pode.
return "my-backend"
@property
def display_name(self) -> str:
# Rótulo legível exibido no `hermes tools`. O padrão é `name`.
return "My Backend"
def is_available(self) -> bool:
# Checagem barata — variável de ambiente presente, dependência opcional importável etc.
# NÃO PODE fazer chamada de rede (roda a cada repintura do `hermes 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)}
# O formato da resposta é fixo — veja "Formato da resposta" abaixo.
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/meu-backend/__init__.py
from plugins.web.my_backend.provider import MyBackendWebSearchProvider
def register(ctx) -> None:
"""Entry point do plugin — chamado uma vez, na hora do carregamento."""
ctx.register_web_search_provider(MyBackendWebSearchProvider())
plugin.yaml
name: web-my-backend
version: 1.0.0
description: "Busca na web do My Backend — API REST com autenticação Bearer"
author: Seu Nome
kind: backend
provides_web_providers:
- my-backend
requires_env:
- MY_BACKEND_API_KEY
| Chave | Para que serve |
|---|---|
kind: backend | Roteia o plugin pelo caminho de carregamento de backend |
provides_web_providers | Lista dos names de provedor que este plugin registra — o carregador usa isso para anunciar o plugin no hermes tools mesmo antes de o register() rodar |
requires_env | Pergunta interativa de credencial durante o hermes plugins install (veja Criar um plugin do Hermes para o formato completo) |
Referência da ABC
O contrato completo está em agent/web_search_provider.py. Métodos que você pode sobrescrever:
| Membro | Obrigatório | Padrão | Para que serve |
|---|---|---|---|
name | ✅ | — | Id estável usado na configuração web.*_backend |
display_name | — | name | Rótulo exibido no hermes tools |
is_available() | ✅ | — | Portão barato de disponibilidade — variáveis de ambiente, dependências opcionais |
supports_search() | — | True | Sinalizador de capacidade para o roteamento do web_search |
supports_extract() | — | False | Sinalizador de capacidade para o roteamento do web_extract |
search(query, limit) | condicional | levanta erro | Obrigatório quando supports_search() devolve True |
extract(urls, **kwargs) | condicional | levanta erro | Obrigatório quando supports_extract() devolve True |
Um provedor pode anunciar várias capacidades a partir de uma única classe — Firecrawl, Tavily, Exa e Parallel implementam busca e extração. Brave Search e DDGS são só de busca; o SearXNG é só de busca, com um fluxo documentado de "combine comigo um provedor de extração".
Formato da resposta
O wrapper da ferramenta espera um envelope fixo, para não ter que traduzir entre backends.
Busca bem-sucedida:
{
"success": True,
"data": {
"web": [
{"title": str, "url": str, "description": str, "position": int},
...
],
},
}
Extração bem-sucedida:
{
"success": True,
"data": [
{
"url": str,
"title": str,
"content": str,
"raw_content": str,
"metadata": dict, # opcional
"error": str, # opcional, só em caso de falha por URL
},
...
],
}
Qualquer uma das capacidades, em caso de falha:
{"success": False, "error": "mensagem legível para humanos"}
Tanto search() quanto extract() podem ser async def — o dispatcher detecta funções corrotina via inspect.iscoroutinefunction e faz o await na medida. Implementações síncronas que fazem E/S bloqueante (HTTP, chamadas de SDK) servem para backends pequenos; o dispatcher cuida das threads.
Sinalizadores de capacidade
O Hermes roteia as chamadas para o provedor certo com base nos sinalizadores supports_*. Uma configuração comum com vários provedores:
# ~/.hermes/config.yaml
web:
search_backend: "brave-free" # só busca, rápido, 2 mil grátis por mês
extract_backend: "firecrawl" # extração + crawl, cota paga
Quando web.search_backend ou web.extract_backend não estão definidos, os dois caem para web.backend. Quando esse também não está definido, o Hermes escolhe o primeiro provedor disponível que suporte a capacidade pedida, com base na presença das variáveis de ambiente.
Se o seu provedor só suporta uma capacidade, deixe os outros sinalizadores no padrão (False) e o registro vai ignorá-lo naquela ferramenta — os usuários não vão ver erros enganosos de "o provedor X falhou" quando estiverem usando o X só para busca e pedirem uma extração ao agente.
Como o Hermes liga isso às ferramentas
As ferramentas web_search e web_extract ficam em tools/web_tools.py. Na hora da chamada, elas:
- Leem a chave de configuração relevante (
web.search_backendpara oweb_search,web.extract_backendpara oweb_extract) - Pedem ao registro o provedor com aquele
name - Conferem
is_available()e o sinalizadorsupports_*()correspondente - Despacham para
search()/extract()(o deep crawl roda como um modo dentro doextract()), fazendo await se o método for uma corrotina - Serializam o envelope de resposta em JSON e devolvem para o LLM
Os erros aparecem como resultado da ferramenta; o LLM decide como explicá-los. Se nenhum provedor estiver registrado (ou se todos os disponíveis falharem no portão de capacidade), a ferramenta devolve um erro útil apontando para o hermes tools.
Instalar dependências opcionais sob demanda
Se o seu provedor embrulha um SDK de terceiros (como o DDGS faz com o pacote ddgs), não faça o import no topo do módulo. Use tools.lazy_deps.ensure(...) dentro de is_available() ou de search() — o Hermes instala o pacote no primeiro uso, controlado por security.allow_lazy_installs. Veja Criar um plugin do Hermes → instalação sob demanda para o modelo de segurança.
Implementações de referência
plugins/web/brave_free/— provedor HTTP pequeno, protegido por chave de API, só de busca. Bom modelo para começar.plugins/web/ddgs/— provedor sem chave que instala o SDK sob demanda. Padrão útil para backends que embrulham um pacote Python.plugins/web/firecrawl/— provedor completo, com várias capacidades (busca + extração + crawl) e vários modos de formato.plugins/web/searxng/— backend auto-hospedado, configurado por URL e sem autenticação.plugins/web/xai/— busca apoiada em LLM pela ferramentaweb_searchdo lado do servidor do Grok. Mostra como reaproveitar uma superfície de credencial OAuth/variável de ambiente já existente (tools/xai_http.py) sem acrescentar variáveis novas, e como escrever umis_available()barato que respeita o contrato de não fazer rede.
Distribuir via pip
# pyproject.toml
[project.entry-points."hermes_agent.plugins"]
my-backend-web = "my_backend_web_package"
O my_backend_web_package precisa expor uma função register no nível de topo. Veja Distribuir via pip no guia geral de plugins para a configuração completa.
Páginas relacionadas
- Busca na web — documentação do recurso para o usuário e configuração de cada backend
- Visão geral dos plugins — todos os tipos de plugin de relance
- Criar um plugin do Hermes — guia geral de ferramentas/hooks/comandos de barra