11. 生图插件配置

目标

让 QQ 机器人可以通过 LangBot 插件调用 OpenAI 兼容的生图接口。

本次实际使用的是中转站接口:

https://image.codesonline.dev/v1/images/generations

接口返回格式为:

{
  "data": [
    {
      "url": "https://free.codesonline.dev/p/img/..."
    }
  ]
}

因此 LangBot 插件只需要拿到 data[0].url,再把图片或图片链接返回 QQ。

路线选择

一开始尝试过 Dify 工作流:

QQ -> LangBot -> Dify workflow -> 生图中转站 -> image_url

Dify 工作流本身能跑通,curl 调用 Dify API 也能返回:

{
  "data": {
    "outputs": {
      "image_url": "https://free.codesonline.dev/p/img/..."
    }
  }
}

但 LangBot 内置 Dify runner 在 workflow streaming/chunked 场景下出现过:

httpx.RemoteProtocolError: peer closed connection without sending complete message body

所以生图最终不走 Dify,改为:

QQ -> LangBot 插件 -> OpenAI 兼容图片接口

这条链路更短,也更容易排错。

官方插件

LangBot 官方 demo 里有一个可用插件:

AIImagePlugin

仓库:

https://github.com/langbot-app/langbot-plugin-demo/tree/main/AIImagePlugin

插件结构:

AIImagePlugin
├── main.py
├── manifest.yaml
├── requirements.txt
├── assets
├── components
│   └── commands
│       ├── draw.py
│       └── draw.yaml
└── readme

默认命令:

!draw prompt

例如:

!draw a cute cat

如果群聊流水线要求 @ 机器人,则使用:

@机器人 !draw a cute cat

安装插件

在服务器执行:

cd /tmp
rm -rf langbot-plugin-demo
git clone https://github.com/langbot-app/langbot-plugin-demo.git

如果没有 git,可以用压缩包:

cd /tmp
rm -rf langbot-plugin-demo langbot-plugin-demo.tar.gz langbot-plugin-demo-main
curl -L https://github.com/langbot-app/langbot-plugin-demo/archive/refs/heads/main.tar.gz -o langbot-plugin-demo.tar.gz
tar -xzf langbot-plugin-demo.tar.gz
mv langbot-plugin-demo-main langbot-plugin-demo

复制插件:

cp -r /tmp/langbot-plugin-demo/AIImagePlugin /root/qq-bot/data/langbot/plugins/

确认:

ls -lah /root/qq-bot/data/langbot/plugins/AIImagePlugin

修改 manifest

插件配置在:

/root/qq-bot/data/langbot/plugins/AIImagePlugin/manifest.yaml

先备份:

cd /root/qq-bot/data/langbot/plugins/AIImagePlugin
cp manifest.yaml manifest.yaml.bak.$(date +%F-%H%M%S)

把默认 API 地址改为:

default: https://image.codesonline.dev/v1

可以用命令:

sed -i 's#default: https://api.qhaigc.net/v1#default: https://image.codesonline.dev/v1#' manifest.yaml

如果要把模型选项改成 gpt-image-2,需要在 model_nameoptions 下加:

    - name: gpt-image-2
      label:
        en_US: gpt-image-2
        zh_Hans: gpt-image-2

并把默认值改成:

default: gpt-image-2

如果要加 16:9,需要在 image_sizeoptions 下加:

    - name: 16:9
      label:
        en_US: 16:9
        zh_Hans: 16:9

并把默认值改成:

default: 16:9

注意 YAML 缩进。正确结构是:

    - name: gpt-image-2
      label:
        en_US: gpt-image-2
        zh_Hans: gpt-image-2

错误结构会导致插件消失或加载失败:

    - name: gpt-image-2
        label:
          en_US: gpt-image-2

检查 YAML 关键行:

nl -ba manifest.yaml | sed -n '70,100p'
nl -ba manifest.yaml | sed -n '120,145p'

如果日志出现:

Failed to load component manifest manifest.yaml

优先检查缩进。

数据库配置

LangBot 插件配置保存在 SQLite:

/root/qq-bot/data/langbot/langbot.db

表名:

plugin_settings

查看表结构:

sqlite3 /root/qq-bot/data/langbot/langbot.db "PRAGMA table_info(plugin_settings);"

查看 AIImagePlugin 配置:

sqlite3 /root/qq-bot/data/langbot/langbot.db \
"SELECT plugin_author, plugin_name, enabled, config FROM plugin_settings WHERE plugin_author='langbot-team' AND plugin_name='AIImagePlugin';"

示例配置结构:

{
  "api_base_url": "https://image.codesonline.dev/v1",
  "openai_api_key": "不要写真实 key 到笔记",
  "model_name": "gpt-image-2",
  "image_size": "1024x1024"
}

如果后台保存后插件暂时从列表消失,可以绕过后台,直接改数据库后重启:

sqlite3 /root/qq-bot/data/langbot/langbot.db \
"UPDATE plugin_settings
 SET config = json_set(
   config,
   '$.api_base_url', 'https://image.codesonline.dev/v1',
   '$.model_name', 'gpt-image-2',
   '$.image_size', '1024x1024'
 )
 WHERE plugin_author='langbot-team' AND plugin_name='AIImagePlugin';"

然后重启:

cd /root/qq-bot
docker restart qqbot-langbot langbot_plugin_runtime
sleep 15

本次实际观察到:

后台点击保存配置 -> 插件可能暂时从列表消失
重启 LangBot 和 plugin runtime -> 插件重新出现

所以调试阶段可以先不反复点插件页的保存按钮。

日志检查

查看插件运行时日志:

docker logs --tail 200 langbot_plugin_runtime | grep -iE "AIImage|plugin|插件|error|traceback|openai|image|Failed to load"

查看 LangBot 主容器日志:

docker logs --tail 300 qqbot-langbot | grep -iE "AIImage|AI Image|绘图|draw|plugin|插件|Failed|error|traceback"

完整搜索 AIImage:

docker logs langbot_plugin_runtime 2>&1 | grep -i "AIImage" | tail -80
docker logs qqbot-langbot 2>&1 | grep -i "AIImage" | tail -80

如果看到类似:

GET /api/v1/plugins/langbot-team/AIImagePlugin
GET /api/v1/plugins/langbot-team/AIImagePlugin/config
PUT /api/v1/plugins/langbot-team/AIImagePlugin/config

说明后台已经识别并访问了插件。

QQ 流水线调用

插件能在调试里跑通后,要在 QQ 里调用,需要两层匹配:

第一层:LangBot 流水线触发条件命中 QQ 消息
第二层:AIImagePlugin 的 Command 组件识别 !draw

主流水线可以直接启用插件,然后测试:

@机器人 !draw a cute cat

如果流水线允许前缀触发,可以配置 ! 前缀,之后群里直接发:

!draw a cute cat

官方 demo 默认命令是 draw,因此不是:

/draw prompt
!画图 prompt

而是:

!draw prompt

如果 QQ 里没反应,先看主容器日志是否有:

Processing request from group_xxx
No pipeline_uuid for query

如果没有进入流水线,检查:

  • 机器人是否绑定流水线。
  • 群聊是否要求 @。
  • 流水线是否配置了 ! 前缀。
  • 插件是否在这条流水线可用。

常见问题

保存配置后插件消失

现象:

后台保存 AIImagePlugin 配置后,插件列表里暂时看不到它。
重启后又出现。

判断:

插件目录和数据库配置通常没坏,可能是保存后的热重载/刷新阶段异常。

处理:

cd /root/qq-bot
docker restart qqbot-langbot langbot_plugin_runtime
sleep 15

必要时直接改 plugin_settings.config,不要反复在后台保存。

YAML 缩进错误

日志:

Failed to load component manifest manifest.yaml
mapping values are not allowed here
expected <block end>, but found '-'

处理:

nl -ba /root/qq-bot/data/langbot/plugins/AIImagePlugin/manifest.yaml | sed -n '70,100p'
nl -ba /root/qq-bot/data/langbot/plugins/AIImagePlugin/manifest.yaml | sed -n '120,145p'

检查新增 model_nameimage_size 选项的缩进。

KeyError: owner

日志里可能看到:

KeyError: 'owner'

本次观察中,这个错误不是 AIImagePlugin 独有,之前其他插件也出现过。若机器人主功能正常,可先作为插件存储相关噪声处理。

API Key 安全

不要把中转站 API Key 写入笔记或公开日志。

如果 key 已经在聊天、截图或公开文本中暴露,应到中转站后台重置新 key。

后续优化

官方 demo 使用 openai.AsyncOpenAI

response = await self.plugin.openai_client.images.generate(
    model=model,
    prompt=description,
    size=size,
    n=1,
)

如果官方插件对 16:9qualitystylebackground 等参数支持不好,可以基于官方插件改一个极简版:

不用 OpenAI SDK
直接 httpx.post("/images/generations")
传 model / prompt / n / size / quality / style / background
读取 data[0].url
返回 image_url

这样更贴近中转站文档,也更容易兼容其他 OpenAI 格式图片接口。