H繁中版
文件開發者指南web search provider plugin
<!-- Source: https://hermesbible.com/docs/developer-guide/web-search-provider-plugin -->

建立網頁搜尋 Provider 外掛

網頁搜尋 provider 外掛註冊一個後端來處理 web_searchweb_extract 和(選擇性的)深層爬蟲工具呼叫。內建的 provider — Firecrawl、SearXNG、Tavily、Exa、Parallel、Brave Search(免費層級)、xAI 和 DDGS — 都以外掛形式發佈在 plugins/web/<name>/ 下。你可以透過在它們旁邊放入一個目錄來新增一個新的,或覆寫一個已有的。

提示

網頁搜尋是 Hermes 支援的多種後端外掛之一。其他類型(具有各自的 ABC)包括 Image Generation Provider PluginsVideo Generation Provider PluginsMemory Provider PluginsContext Engine PluginsModel Provider Plugins。通用的工具/鉤子/CLI 外掛請見 Build a Hermes Plugin

發現機制如何運作

Hermes 在三個位置掃描網頁搜尋後端:

  1. 內建<repo>/plugins/web/<name>/(自動載入,kind: backend,始終可用)
  2. 使用者~/.hermes/plugins/web/<name>/(透過 plugins.enabledhermes plugins enable <name> 選擇性啟用)
  3. Pip — 宣告 hermes_agent.plugins 入口點的套件

每個外掛的 register(ctx) 函式呼叫 ctx.register_web_search_provider(...) — 這會將實例放入 agent/web_search_registry.py 的 registry 中。每個功能的啟用 provider 由設定選擇:

功能設定金鑰回退到
web_searchweb.search_backendweb.backend
web_extractweb.extract_backendweb.backend
web_extract 內的深層爬蟲模式web.extract_backendweb.backend

當兩個金鑰都未設定時,Hermes 從環境中存在的 API key/URL 自動偵測後端。hermes tools 引導使用者進行選擇。

目錄結構

plugins/web/my-backend/
├── __init__.py     # register() 入口點
├── provider.py     # WebSearchProvider 子類別
└── plugin.yaml     # 帶有 kind: backend 和 provides_web_providers 的 Manifest

brave_free/ddgs/ 是最小的樹內參考 — brave_free 用於 API key 門控的純搜尋 provider,ddgs 用於無需金鑰的 provider,它會延遲安裝其 SDK。

WebSearchProvider ABC

繼承 agent.web_search_provider.WebSearchProvider。唯一必要的成員是 nameis_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):
    """針對 My Backend HTTP API 的最小搜尋專用 provider。"""

    @property
    def name(self) -> str:
        # web.search_backend / web.extract_backend / web.backend
        # 設定金鑰中使用的穩定 ID。小寫,不含空格;允許連字元。
        return "my-backend"

    @property
    def display_name(self) -> str:
        # `hermes tools` 中顯示的人類標籤。預設為 `name`。
        return "My Backend"

    def is_available(self) -> bool:
        # 低成本檢查 — 環境變數存在、選用依賴可匯入等。
        # 不能有網路呼叫(在每次 `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)}

        # 回應格式是固定的 — 見下方「回應格式」。
        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 web search — Bearer-auth REST API"
author: Your Name
kind: backend
provides_web_providers:
  - my-backend
requires_env:
  - MY_BACKEND_API_KEY
金鑰用途
kind: backend將外掛路由到後端載入路徑
provides_web_providers此外掛註冊的 provider name 列表 — 載入器在 register() 執行前就用它來在 hermes tools 中廣告此外掛
requires_envhermes plugins install 期間的互動式認證提示(見 Build a Hermes Plugin 了解完整格式)

ABC 參考

完整契約在 agent/web_search_provider.py 中。你可能覆寫的方法:

成員必要預設值用途
nameweb.*_backend 設定中使用的穩定 ID
display_namenamehermes tools 中顯示的標籤
is_available()低成本可用性閘門 — 環境變數、選用依賴
supports_search()Trueweb_search 路由的功能標誌
supports_extract()Falseweb_extract 路由的功能標誌
search(query, limit)有條件引發異常supports_search() 回傳 True 時必要
extract(urls, **kwargs)有條件引發異常supports_extract() 回傳 True 時必要

Provider 可以從單個類別廣告多種功能 — Firecrawl、Tavily、Exa 和 Parallel 都同時實作了搜尋和擷取。Brave Search 和 DDGS 是純搜尋;SearXNG 是純搜尋,有文件記錄的「與擷取 provider 配對使用」工作流程。

回應格式

工具包裝器期望一個固定的信封,這樣它就不必在後端之間翻譯。

搜尋成功:

{
    "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": "human-readable message"}

search()extract() 都可以是 async def — 分派器透過 inspect.iscoroutinefunction 偵測協程函式並相應地等待。執行阻塞 I/O(HTTP、SDK 呼叫)的同步實作對小型後端來說沒問題;分派器會處理執行緒。

功能標誌

Hermes 根據 supports_* 標誌將呼叫路由到正確的 provider。常見的多 provider 設定:

# ~/.hermes/config.yaml
web:
  search_backend: "brave-free"     # 純搜尋,快速,免費 2k/月
  extract_backend: "firecrawl"     # 擷取 + 爬蟲,付費額度

web.search_backendweb.extract_backend 未設定時,兩者都會回退到 web.backend。如果那也未設定,Hermes 會根據環境變數的存在選擇第一個支援請求功能的可用 provider。

如果你的 provider 只支援一種功能,將另一個標誌保持在預設值(False),registry 會為該工具跳過它 — 當使用者只使用 X 進行搜尋而要求代理程式擷取時,不會看到誤導性的「provider X 失敗」錯誤。

Hermes 如何將其連接到工具

web_searchweb_extract 工具位於 tools/web_tools.py 中。在呼叫時它們:

  1. 讀取相關的設定金鑰(web_searchweb.search_backendweb_extractweb.extract_backend
  2. 向 registry 請求具有該 name 的 provider
  3. 檢查 is_available() 和匹配的 supports_*() 標誌
  4. 分派到 search() / extract()(深層爬蟲作為 extract() 內的一種模式運行),如果方法是協程則等待
  5. 將回應信封 JSON 序列化並交回 LLM

錯誤作為工具結果呈現;LLM 決定如何解釋它們。如果沒有已註冊的 provider(或每個可用的都未通過功能閘門),工具會回傳一個有用的錯誤,指向 hermes tools

延遲安裝選用依賴

如果你的 provider 封裝了第三方 SDK(像 DDGS 封裝 ddgs 套件),不要在模組頂層 import 它。在 is_available()search() 內使用 tools.lazy_deps.ensure(...) — Hermes 會在首次使用時安裝套件,由 security.allow_lazy_installs 門控。安全模型請見 Build a Hermes Plugin → Lazy-install

參考實作

  • plugins/web/brave_free/ — 小型、API key 門控、純搜尋的 HTTP provider。良好的起始模板。
  • plugins/web/ddgs/ — 無需金鑰、延遲安裝其 SDK 的 provider。對封裝 Python 套件的後端有用的模式。
  • plugins/web/firecrawl/ — 完整的多功能 provider(搜尋 + 擷取 + 爬蟲)帶有多種格式模式。
  • plugins/web/searxng/ — 自架設、URL 設定的後端,無需認證。
  • plugins/web/xai/ — 透過 Grok 伺服端 web_search 工具的 LLM 支援搜尋。展示如何重用現有的 OAuth/環境變數認證介面(tools/xai_http.py)而不新增環境變數,以及如何編寫遵循無網路契約的低成本 is_available()

透過 pip 分發

# pyproject.toml
[project.entry-points."hermes_agent.plugins"]
my-backend-web = "my_backend_web_package"

my_backend_web_package 必須暴露一個頂層的 register 函式。完整設定請見通用外掛指南中的 Distribute via pip

相關頁面



CLI Commands Reference