跳到主要内容

构建图像生成提供商插件

图像生成提供商插件会注册一个后端,用于处理每一次 image_generate 工具调用——无论是 DALL·E、gpt-image、Grok、Flux、Imagen、Stable Diffusion、fal、Replicate,还是一套本地 ComfyUI 环境,任何后端都可以。内置的提供商(OpenAI、OpenAI-Codex、xAI)都作为插件发布。你可以通过在 plugins/image_gen/<name>/ 目录下放入一个新目录来添加新提供商,或覆盖一个已捆绑的提供商。

提示

图像生成是 Hermes 支持的几种后端插件之一。其他插件(拥有更特化的抽象基类)包括 内存提供商插件上下文引擎插件模型提供商插件。通用的工具/钩子/CLI 插件位于 构建 Hermes 插件

发现机制如何工作

Hermes 在三个位置扫描图像生成后端:

  1. 捆绑式 —— <repo>/plugins/image_gen/<name>/(以 kind: backend 自动加载,始终可用)
  2. 用户式 —— ~/.hermes/plugins/image_gen/<name>/(通过 plugins.enabled 选择启用)
  3. Pip 安装式 —— 声明了 hermes_agent.plugins 入口点的包

每个插件的 register(ctx) 函数调用 ctx.register_image_gen_provider(...) —— 这会将其放入 agent/image_gen_registry.py 中的注册表。活动提供商由 config.yaml 中的 image_gen.provider 选择;hermes tools 会引导用户进行选择。

image_generate 工具包装器从注册表请求活动提供商并分派调用。如果没有注册任何提供商会,该工具会显示一条有用的错误信息,并指向 hermes tools

目录结构

plugins/image_gen/my-backend/
├── __init__.py # ImageGenProvider 子类 + register()
└── plugin.yaml # 清单文件,kind: backend

至此,捆绑插件即告完成。用户插件位于 ~/.hermes/plugins/image_gen/<name>/,需要将其添加到 config.yamlplugins.enabled 中(或运行 hermes plugins enable <name>)。

ImageGenProvider 抽象基类

继承 agent.image_gen_provider.ImageGenProvider。唯一必须的成员是 name 属性和 generate() 方法——其他一切都有合理的默认值:

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

from agent.image_gen_provider import (
DEFAULT_ASPECT_RATIO,
ImageGenProvider,
error_response,
resolve_aspect_ratio,
save_b64_image,
success_response,
)


class MyBackendImageGenProvider(ImageGenProvider):
@property
def name(self) -> str:
# 用于 image_gen.provider 配置的稳定 ID。小写,无空格。
return "my-backend"

@property
def display_name(self) -> str:
# 在 `hermes tools` 中显示的用户友好名称。如果省略,默认为 name.title()。
return "My Backend"

def is_available(self) -> bool:
# 如果缺少凭据或依赖项,则返回 False。
# 工具的可用性网关在调度前会调用此方法。
if not os.environ.get("MY_BACKEND_API_KEY"):
return False
try:
import my_backend_sdk # noqa: F401
except ImportError:
return False
return True

def list_models(self) -> List[Dict[str, Any]]:
# 在 `hermes tools` 模型选择器中显示的目录。
return [
{
"id": "my-model-fast",
"display": "My Model (Fast)",
"speed": "~5s",
"strengths": "快速迭代",
"price": "$0.01/图像",
},
{
"id": "my-model-hq",
"display": "My Model (HQ)",
"speed": "~30s",
"strengths": "最高保真度",
"price": "$0.04/图像",
},
]

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

def get_setup_schema(self) -> Dict[str, Any]:
# `hermes tools` 选择器的元数据——设置时需要提示的键。
return {
"name": "My Backend",
"badge": "paid", # 可选;在选择器中显示为简短标签
"tag": "在名称下方显示的一行描述",
"env_vars": [
{
"key": "MY_BACKEND_API_KEY",
"prompt": "My Backend API 密钥",
"url": "https://my-backend.example.com/api-keys",
},
],
}

def generate(
self,
prompt: str,
aspect_ratio: str = DEFAULT_ASPECT_RATIO,
**kwargs: Any,
) -> Dict[str, Any]:
prompt = (prompt or "").strip()
aspect_ratio = resolve_aspect_ratio(aspect_ratio)

if not prompt:
return error_response(
error="需要提供提示词",
error_type="invalid_input",
provider=self.name,
prompt="",
aspect_ratio=aspect_ratio,
)

# 模型选择优先级:环境变量 → 配置 → 默认值。内置 openai 插件中的辅助函数
# _resolve_model() 是一个很好的参考。
model_id = kwargs.get("model") or self.default_model() or "my-model-fast"

try:
import my_backend_sdk
client = my_backend_sdk.Client(api_key=os.environ["MY_BACKEND_API_KEY"])
result = client.generate(
prompt=prompt,
model=model_id,
aspect_ratio=aspect_ratio,
)

# 支持两种返回格式:
# - URL 字符串:作为 `image` 返回
# - base64 数据:通过 save_b64_image() 保存到 $HERMES_HOME/cache/images/
if result.get("image_b64"):
path = save_b64_image(
result["image_b64"],
prefix=self.name,
extension="png",
)
image = str(path)
else:
image = result["image_url"]

return success_response(
image=image,
model=model_id,
prompt=prompt,
aspect_ratio=aspect_ratio,
provider=self.name,
)
except Exception as exc:
return error_response(
error=str(exc),
error_type=type(exc).__name__,
provider=self.name,
model=model_id,
prompt=prompt,
aspect_ratio=aspect_ratio,
)


def register(ctx) -> None:
"""插件入口点 — 加载时调用一次。"""
ctx.register_image_gen_provider(MyBackendImageGenProvider())

plugin.yaml

name: my-backend
version: 1.0.0
description: 我的图像后端 — 通过 My Backend SDK 实现文生图
author: Your Name
kind: backend
requires_env:
- MY_BACKEND_API_KEY

kind: backend 是将插件路由到图像生成注册路径的关键。requires_env 会在 hermes plugins install 期间提示用户设置。

抽象基类参考

完整契约位于 agent/image_gen_provider.py。你通常会重写以下方法:

成员必需默认值用途
name用于 image_gen.provider 配置的稳定 ID
display_namename.title()hermes tools 中显示的标签
is_available()True检查缺失的凭据或依赖项
list_models()[]hermes tools 模型选择器的目录
default_model()list_models() 的第一项未配置模型时的回退选项
get_setup_schema()最小结构选择器元数据 + 环境变量提示
generate(prompt, aspect_ratio, **kwargs)核心调用

响应格式

generate() 必须返回一个通过 success_response()error_response() 构建的字典。两者都位于 agent/image_gen_provider.py

成功:

success_response(
image=<url-or-absolute-path>,
model=<model-id>,
prompt=<echoed-prompt>,
aspect_ratio="landscape" | "square" | "portrait",
provider=<your-provider-name>,
extra={...}, # 可选,后端特定字段
)

错误:

error_response(
error="人类可读的消息",
error_type="provider_error" | "invalid_input" | "<异常类名>",
provider=<your-provider-name>,
model=<model-id>,
prompt=<prompt>,
aspect_ratio=<resolved aspect>,
)

工具包装器会对字典进行 JSON 序列化,并将其交给 LLM。错误作为工具结果呈现;LLM 决定向用户解释的方式。

处理 base64 与 URL 输出

一些后端返回图像 URL(fal, Replicate);另一些返回 base64 载荷(OpenAI gpt-image-2)。对于 base64 情况,使用 save_b64_image() — 它会写入 $HERMES_HOME/cache/images/<prefix>_<timestamp>_<uuid>.<ext> 并返回绝对路径。将该路径(作为 str)传递给 success_response()image= 参数。网关传递(Telegram 图片气泡、Discord 附件)可以识别 URL 和绝对路径。

用户覆盖

将用户插件放在 ~/.hermes/plugins/image_gen/<name>/,其 name 属性与捆绑插件相同,并通过 hermes plugins enable <name> 启用——注册表采用最后写入者获胜策略,因此你的版本会替换内置版本。这对于将 openai 插件指向私有代理,或替换自定义模型目录非常有用。

测试

export HERMES_HOME=/tmp/hermes-imggen-test
mkdir -p $HERMES_HOME/plugins/image_gen/my-backend
# …将 __init__.py + plugin.yaml 复制到该目录…

export MY_BACKEND_API_KEY=your-test-key
hermes plugins enable my-backend

# 将其设置为活动提供商
echo "image_gen:" >> $HERMES_HOME/config.yaml
echo " provider: my-backend" >> $HERMES_HOME/config.yaml

# 测试它
hermes -z "生成一张柯基犬穿太空服的图像"

或交互式运行:hermes tools → "Image Generation" → 选择 my-backend → 如果提示则输入 API 密钥。

参考实现

  • plugins/image_gen/openai/__init__.py — gpt-image-2 以低/中/高三个虚拟模型 ID 的形式呈现,共享一个 API 模型,使用不同的 quality 参数。这是单一后端下分级模型以及 config.yaml 优先级链的好例子。
  • plugins/image_gen/xai/__init__.py — 通过 xAI 使用 Grok Imagine。格式不同(URL 输出,更简单的目录)。
  • plugins/image_gen/openai-codex/__init__.py — Codex 风格的 Responses API 变体,重用 OpenAI SDK,但使用不同的路由基础 URL。

通过 pip 分发

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

my_backend_imggen_package 必须暴露一个顶层的 register 函数。有关完整设置,请参阅通用插件指南中的 通过 pip 分发

相关页面