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

建立影片生成 Provider 外掛

影片生成 provider 外掛註冊一個後端來處理每一個 video_generate 工具呼叫。內建的 provider(xAI、FAL)以外掛形式發佈。你可以透過在 plugins/video_gen/<name>/ 中放入一個目錄來新增一個新的,或覆寫一個已有的。

提示

影片生成幾乎逐行對應 Image Generation Provider Plugins — 如果你已經建構過圖片生成後端,你就已經知道格式了。主要差異:一個 capabilities() 方法廣告模態/寬高比/時長,以及一個路由慣例(傳遞 image_url 以使用圖生影片,省略它以使用文生影片 — provider 在內部選擇正確的端點)。

統一介面(一個工具,兩種模態)

video_generate 工具透過一個參數暴露兩種模態:

  • 文生影片 — 只使用 prompt 呼叫。Provider 路由到其文生影片端點。
  • 圖生影片 — 使用 prompt + image_url 呼叫。Provider 路由到其圖生影片端點。

編輯和擴展有意不在範圍內。大多數後端不支援它們,而且不一致會迫使每個後端的描述文字進入代理程式的工具描述中。

發現機制如何運作

Hermes 在三個位置掃描影片生成後端:

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

每個外掛的 register(ctx) 函式呼叫 ctx.register_video_gen_provider(...)。啟用的 provider 由 config.yaml 中的 video_gen.provider 選擇;hermes tools → Video Generation 引導使用者進行選擇。與 image_generate 不同,沒有樹內的舊式後端 — 每個 provider 都是外掛。

目錄結構

plugins/video_gen/my-backend/
├── __init__.py      # VideoGenProvider 子類別 + register()
└── plugin.yaml      # 帶有 kind: backend 的 Manifest

VideoGenProvider ABC

繼承 agent.video_gen_provider.VideoGenProvider。必要:name 屬性和 generate() 方法。

# plugins/video_gen/my-backend/__init__.py
from typing import Any, Dict, List, Optional
import os

from agent.video_gen_provider import (
    VideoGenProvider,
    error_response,
    success_response,
)

class MyVideoGenProvider(VideoGenProvider):
    @property
    def name(self) -> str:
        return "my-backend"

    @property
    def display_name(self) -> str:
        return "My Backend"

    def is_available(self) -> bool:
        return bool(os.environ.get("MY_API_KEY"))

    def list_models(self) -> List[Dict[str, Any]]:
        # 每個條目是一個模型系列 — 使用者選擇一次的名稱。
        # 你的 provider 的 generate() 根據是否傳遞了 image_url
        # 在系列內路由。
        return [
            {
                "id": "fast",
                "display": "Fast",
                "speed": "~30s",
                "strengths": "Cheapest tier",
                "price": "$0.05/s",
                "modalities": ["text", "image"],  # 諮詢性
            },
        ]

    def default_model(self) -> Optional[str]:
        return "fast"

    def capabilities(self) -> Dict[str, Any]:
        return {
            "modalities": ["text", "image"],
            "aspect_ratios": ["16:9", "9:16"],
            "resolutions": ["720p", "1080p"],
            "min_duration": 1,
            "max_duration": 10,
            "supports_audio": False,
            "supports_negative_prompt": True,
            "max_reference_images": 0,
        }

    def get_setup_schema(self) -> Dict[str, Any]:
        return {
            "name": "My Backend",
            "badge": "paid",
            "tag": "在 `hermes tools` 中顯示的簡短描述",
            "env_vars": [
                {
                    "key": "MY_API_KEY",
                    "prompt": "My Backend API key",
                    "url": "https://mybackend.example.com/keys",
                },
            ],
        }

    def generate(
        self,
        prompt: str,
        *,
        model: Optional[str] = None,
        image_url: Optional[str] = None,
        reference_image_urls: Optional[List[str]] = None,
        duration: Optional[int] = None,
        aspect_ratio: str = "16:9",
        resolution: str = "720p",
        negative_prompt: Optional[str] = None,
        audio: Optional[bool] = None,
        seed: Optional[int] = None,
        **kwargs: Any,  # 始終忽略未知 kwargs 以實現向前相容
    ) -> Dict[str, Any]:
        # 路由:image_url 的存在決定端點。
        if image_url:
            endpoint = "my-backend/image-to-video"
            modality_used = "image"
        else:
            endpoint = "my-backend/text-to-video"
            modality_used = "text"

        # ... 呼叫你的 API ...

        return success_response(
            video="https://your-cdn/output.mp4",
            model=model or "fast",
            prompt=prompt,
            modality=modality_used,
            aspect_ratio=aspect_ratio,
            duration=duration or 5,
            provider=self.name,
        )

def register(ctx) -> None:
    ctx.register_video_gen_provider(MyVideoGenProvider())

外掛 Manifest

# plugins/video_gen/my-backend/plugin.yaml
name: my-backend
version: 1.0.0
description: "My video generation backend"
author: Your Name
kind: backend
requires_env:
  - MY_API_KEY

video_generate Schema

工具在每個後端上暴露一個統一的 schema。Provider 會忽略它們不支援的參數。

參數功能
prompt文字指令(必填)
image_url設定時 → 圖生影片;省略時 → 文生影片
reference_image_urls風格/角色參考(取決於 provider)
duration秒數 — provider 會限制
aspect_ratio"16:9""9:16""1:1"…… — provider 會限制
resolution"480p" / "540p" / "720p" / "1080p" — provider 會限制
negative_prompt要避免的內容(僅 Pixverse/Kling)
audio原生音訊(Veo3 / Pixverse 定價層級)
seed可重現性
model覆寫啟用的模型/系列

Provider 的 capabilities() 廣告哪些參數被遵循。代理程式在工具描述中看到啟用後端的能力,當使用者透過 hermes tools 切換後端時會動態重建。

模型系列和端點路由(FAL 模式)

當你的後端每個「模型」有多個端點時 — 像 FAL,每個系列(Veo 3.1、Pixverse v6、Kling O3)都有 /text-to-video/image-to-video URL — 將每個系列表示為一個目錄條目。你的 generate() 根據是否傳遞了 image_url 選擇正確的端點:

FAMILIES = {
    "veo3.1": {
        "text_endpoint": "fal-ai/veo3.1",
        "image_endpoint": "fal-ai/veo3.1/image-to-video",
        # ... 系列特定的能力標誌 ...
    },
}

def generate(self, prompt, *, image_url=None, model=None, **kwargs):
    family_id, family = _resolve_family(model)
    endpoint = family["image_endpoint"] if image_url else family["text_endpoint"]
    # ... 從系列宣告的能力標誌建構載荷,呼叫端點 ...

使用者在 hermes tools 中選擇一次 veo3.1。代理程式永遠不需要考慮端點 — 它只傳遞(或不傳遞)image_url

選擇優先順序

對於每個實例的模型旋鈕(參見 plugins/video_gen/fal/__init__.py):

  1. 工具呼叫中的 model= 關鍵字
  2. <PROVIDER>_VIDEO_MODEL 環境變數
  3. config.yaml 中的 video_gen.<provider>.model
  4. config.yaml 中的 video_gen.model(當它是你的 ID 之一時)
  5. Provider 的 default_model()

回應格式

success_response()error_response() 產生每個後端回傳的字典格式。使用它們 — 不要手動製作字典。

成功金鑰:successvideo(URL 或絕對路徑)、modelpromptmodality"text""image")、aspect_ratiodurationprovider,加上 extra

錯誤金鑰:successvideo(None)、errorerror_typemodelpromptaspect_ratioprovider

儲存工件的位置

如果你的後端回傳 base64,使用 save_b64_video() 寫入 $HERMES_HOME/cache/videos/ 下。對於後續 HTTP 取得的原始位元組,使用 save_bytes_video()。 otherwise 直接回傳上游 URL — 閘道器在遞送時解析遠端 URL。

測試

tests/plugins/video_gen/test_<name>_plugin.py 下放置一個冒煙測試。xAI 和 FAL 測試展示了模式 — 註冊、驗證目錄、在有和沒有 image_url 的情況下測試路由、斷言缺少認證時的乾淨錯誤回應。



Web Search Provider Plugins