koishi-plugin-image-prompt 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +3 -46
- package/lib/index.js +44 -244
- package/package.json +1 -1
- package/readme.md +502 -531
- package/src/index.ts +3190 -3477
package/readme.md
CHANGED
|
@@ -1,532 +1,503 @@
|
|
|
1
|
-
# koishi-plugin-image-prompt
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/koishi-plugin-image-prompt)
|
|
4
|
-
|
|
5
|
-
🎯 **一键将图片转换为手办风格!**
|
|
6
|
-
|
|
7
|
-
基于 OpenAI 兼容的 Chat Completions 接口,支持多种 AI 绘图模型,让你的图片瞬间变成精美手办。
|
|
8
|
-
|
|
9
|
-
**特色能力**:**Agent 模式**(把「查不查图库 / 要不要追问 / 什么时候开画」全交给模型,像 NeoBot 一样多轮对话)·
|
|
10
|
-
参考图片分组 + 关键词检索 · 用户附加需求融合进提示词 · 提示词回显(QQ 走 markdown 代码块)·
|
|
11
|
-
**指令一触发就回「收到」** ·
|
|
12
|
-
后台绘图 + 完成推送 · 参考图描述 AI 自动生成 · 429/限流自动退避重试。
|
|
13
|
-
|
|
14
|
-
## ⚙️ 插件设置
|
|
15
|
-
|
|
16
|
-
直接在 Koishi 控制台的插件设置中填写「API 设置」即可:
|
|
17
|
-
|
|
18
|
-
| 配置项 | 说明 | 默认值 |
|
|
19
|
-
|---|---|---|
|
|
20
|
-
| API 服务器地址(baseUrl) | OpenAI 兼容的 Chat Completions 接口地址 | `https://api.gptgod.online/v1/chat/completions` |
|
|
21
|
-
| 使用的模型(model) | 生成图片所使用的模型名称 | `gemini-2.5-flash-image` |
|
|
22
|
-
| API 密钥(apiKey) | 你的 API Key(请求会携带 `Authorization: Bearer <key>`) | 空 |
|
|
23
|
-
| 最大重试次数 | 请求失败后的最大重试次数 | 3 |
|
|
24
|
-
| 重试间隔(毫秒) | 每次重试之间的等待时间 | 1000 |
|
|
25
|
-
|
|
26
|
-
建议前往[gptgod](https://gptgod.online/register/n7iydg8nf09ghbikik3jytod)获取你的api key
|
|
27
|
-
|
|
28
|
-
> 注意:请填写支持图片输入(vision / image)的模型,否则无法正常生成图片。
|
|
29
|
-
|
|
30
|
-
## 📖 使用说明
|
|
31
|
-
|
|
32
|
-
配置完成后即可使用内置指令生成图片,例如:
|
|
33
|
-
|
|
34
|
-
- 手办化
|
|
35
|
-
- 手办化2
|
|
36
|
-
- 手办化3
|
|
37
|
-
- coser化
|
|
38
|
-
- mc化
|
|
39
|
-
- 合并图片(自定义指令,允许附带自定义提示词)
|
|
40
|
-
- 修图(自定义指令)
|
|
41
|
-
|
|
42
|
-
## 🤖 Agent 模式(默认开启,推荐)
|
|
43
|
-
|
|
44
|
-
指令一触发,插件就把「用户说了什么 + 指令自带的提示词 + 可用的参考图」全部交给**对话模型**,
|
|
45
|
-
由模型自己决定下一步 —— 这套写法参考 NeoBot 的 agent(`neobot_chat/runtime/agent.py`):
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
指令触发
|
|
49
|
-
↓
|
|
50
|
-
「收到,正在准备...」 ← 立刻回,不让用户干等
|
|
51
|
-
↓
|
|
52
|
-
模型拿到 3 个工具,自己决定怎么走:
|
|
53
|
-
├─ gallery_search(关键词) → 自己想关键词、自己搜图库
|
|
54
|
-
├─ ask_user(问题) → 自己开口问、自己等用户回话
|
|
55
|
-
└─ draw(prompt, references) → 自己写提示词、自己挑参考图、开画
|
|
56
|
-
↓
|
|
57
|
-
模型说最后一句话 → 发给用户
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
也就是说:**参考图选谁、要不要追问、什么时候开画,全部是模型自己决定的**。
|
|
61
|
-
插件不再写死「需求分析 → 关键词召回 → 逐图打分 → 阈值兜底」这套流程,
|
|
62
|
-
也不再自己判断「用户回的是不是确认」。模型想搜几次图库、想和你来回几轮都行,
|
|
63
|
-
直到它认为可以画了为止。
|
|
64
|
-
|
|
65
|
-
| 工具 | 作用 |
|
|
66
|
-
|---|---|
|
|
67
|
-
| `gallery_search` | 按关键词搜参考图库(关键词由模型自己拟,空格分隔多词)。返回每条的 `id`,写进 `draw` 的 `references` |
|
|
68
|
-
| `ask_user` | 把一句话发给用户**并等他的下一条消息**(他发的图片也会一起带回来,会拿到新编号) |
|
|
69
|
-
| `draw` | 真正开画。传最终提示词 + 参考图编号,画好自动发到群里 |
|
|
70
|
-
|
|
71
|
-
### 工作规则(写进提示词,由模型执行)
|
|
72
|
-
|
|
73
|
-
1. **涉及角色时先搜图库**:有立绘就填进 `references`;没有就如实说「图库里没有这个立绘,将按描述创作」,然后正常画。
|
|
74
|
-
2. 用户明说「不用参考 / 随意画 / 自由发挥」→ 跳过搜索,一次都不搜。
|
|
75
|
-
3. **信息不够才开口**,而且一次只问一个最关键的问题(不连珠炮、不顺带聊别的)。
|
|
76
|
-
4. **开画前先问一句**(默认开):把「这次参考哪几张图 + 大致画成什么样」告诉你,你点头它才画。
|
|
77
|
-
5. 画面上要出文字(台词/标题/招牌)→ 原样写进提示词,并说明「必须原样出现,不能变形或自创字形」。
|
|
78
|
-
6. 只填它确认存在的编号,**不许编造 id**(编了会被丢掉并告诉它不存在)。
|
|
79
|
-
|
|
80
|
-
### Agent 配置
|
|
81
|
-
|
|
82
|
-
| 配置项 | 说明 | 默认值 |
|
|
83
|
-
|---|---|---|
|
|
84
|
-
| 启用 Agent 模式 | 关掉就退化成「指令提示词 + 用户附加需求直接画」,不查图库也不追问 | 开 |
|
|
85
|
-
| 开画前先问一句 | 让模型把「参考哪几张图 + 大致画面」告诉你,你点头才画 | 开 |
|
|
86
|
-
| 最多来回轮数 | 每轮 = 一次模型请求 + 它要调的工具。防死循环的天花板 | 8 |
|
|
87
|
-
| 一次最多参考几张图 | 模型给多了会被截断到这个数 | 3 |
|
|
88
|
-
| 单次搜索返回条数 | `gallery_search` 一次最多回多少条 | 12 |
|
|
89
|
-
| 询问等待时间(秒) | `ask_user` 等用户回复的秒数,超时会告诉模型「用户没回」 | 120 |
|
|
90
|
-
| 单次请求超时(秒) | — | 120 |
|
|
91
|
-
| 采样温度 | — | 0.3 |
|
|
92
|
-
| 输出长度上限 | **推理模型会把额度耗在思考上**,太小会一个字都生成不出来。0 = 不限制 | 8000 |
|
|
93
|
-
| 记住最近几轮对话 | 同一频道记住最近 N 轮,「再画一张」「换个风格」才能接上;0 = 不记忆(重启即失效) | 6 |
|
|
94
|
-
| 工具调用日志 | 把每一轮的模型输出与工具调用写进日志,排查用 | 关 |
|
|
95
|
-
| agent 专用模型 / 地址 / 密钥 | 留空则复用「AI 模型接口」里的配置 | 留空 |
|
|
96
|
-
| 指令模板 | 只写「有哪些工具 + 什么时候用」,别写死流程。占位符 `{confirmRule}` 等 | 内置模板 |
|
|
97
|
-
|
|
98
|
-
**关于模型选型**:agent 需要模型支持 **function calling(工具调用)**。
|
|
99
|
-
不支持也没关系 —— 插件内置了「一行 JSON」兜底协议:接口拒了 `tools` 参数时会自动改用它,
|
|
100
|
-
模型只要输出 `{"tool":"draw","args":{"prompt":"...","references":["ref1"]}}` 就能照常跑流程。
|
|
101
|
-
|
|
102
|
-
已知能用的:各家 `gpt-4o` / `gpt-4.1` 系、`Qwen` 的 `-Instruct` 新版、`DeepSeek-V3` 及之后
|
|
103
|
-
(带 tool 支持的版本)、`glm-4` 系等。老的小模型(如 `Qwen2.5-7B-Instruct`)可能不支持工具调用,
|
|
104
|
-
这时就走 JSON 兜底协议,效果取决于模型听不听话。
|
|
105
|
-
|
|
106
|
-
### 🖼️ 参考图片组 / 图库
|
|
107
|
-
|
|
108
|
-
参考图以**分组**的方式注册,agent 通过 `gallery_search` 按需搜。
|
|
109
|
-
|
|
110
|
-
#### 1. 注册参考图片组
|
|
111
|
-
|
|
112
|
-
在插件配置 → **参考图片组** 中新增分组:
|
|
113
|
-
|
|
114
|
-
| 字段 | 说明 |
|
|
115
|
-
|---|---|
|
|
116
|
-
| 组名称 | 在指令中通过该名称引用,例如 `角色A` |
|
|
117
|
-
| 是否启用 | 关闭后不再参与搜索 |
|
|
118
|
-
| 图片链接 | 参考图的 URL |
|
|
119
|
-
| 图片描述 | **关键**:agent 就是靠这句描述搜到它的,写得越具体越好(发色发型、服装、动作、画风) |
|
|
120
|
-
|
|
121
|
-
#### 2. 在指令中引用组
|
|
122
|
-
|
|
123
|
-
| 指令配置项 | 说明 |
|
|
124
|
-
|---|---|
|
|
125
|
-
| 引用的参考图片组名称 | 可填多个组名,agent 只能在这些组里搜 |
|
|
126
|
-
| 是否走 agent | `跟随全局 / 走 agent / 不走 agent`,可针对单条指令覆盖 |
|
|
127
|
-
|
|
128
|
-
> 指令留空组名时,是否搜索全部组由「AI 模型接口 → 指令未指定组时允许搜索全部组」决定(默认开启)。
|
|
129
|
-
> 没有配任何参考图片组的指令,agent 依然可以纯文生图(不参考任何图)。
|
|
130
|
-
|
|
131
|
-
#### 3. AI 模型接口
|
|
132
|
-
|
|
133
|
-
| 配置项 | 说明 | 默认值 |
|
|
134
|
-
|---|---|---|
|
|
135
|
-
| 对话接口地址 | OpenAI 兼容 Chat Completions,留空复用绘图接口地址 | 空(复用) |
|
|
136
|
-
| 对话接口密钥 | 留空复用绘图 API 密钥 | 空(复用) |
|
|
137
|
-
| 对话模型 | agent 循环、提示词优化、生成描述都用它 | `Qwen/Qwen2.5-7B-Instruct` |
|
|
138
|
-
| 采样温度 / 超时 / 重试次数 / 重试间隔 | 同前,429 会自动指数退避并优先遵循 `Retry-After` | — |
|
|
139
|
-
| 指令未指定组时允许搜索全部组 | — | 开 |
|
|
140
|
-
| 把指令默认图片也纳入可搜索参考图 | — | 关 |
|
|
141
|
-
| 生成描述相关(指令名 / 模型 / 提示词 / 批量上限) | 见下方「自动生成参考图描述」 | — |
|
|
142
|
-
|
|
143
|
-
### 4. 一次完整的交互长什么样
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
你:手办化 白发少女
|
|
147
|
-
|
|
148
|
-
bot:收到,正在准备...
|
|
149
|
-
bot:这次参考 ref1(白发少女 双马尾 水手服),画成桌上的摆件可以吗?
|
|
150
|
-
你:可以
|
|
151
|
-
bot:```
|
|
152
|
-
a white-hair girl figure on a desk, ...
|
|
153
|
-
```
|
|
154
|
-
bot:
|
|
155
|
-
bot:画好啦,按 ref1 的立绘做的~
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
- 你回「算了」/ 不回 → 模型自己决定这次不画,**不会白画一张**。
|
|
159
|
-
- 你直接发图 → 图会被登记成 `user1`、`user2`…,模型可以照样填进 `references`。
|
|
160
|
-
- 「收到」那条不会重复发,提示词也只回显一次。
|
|
161
|
-
|
|
162
|
-
### 📝 提示词回显
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
>
|
|
177
|
-
>
|
|
178
|
-
>
|
|
179
|
-
>
|
|
180
|
-
>
|
|
181
|
-
>
|
|
182
|
-
>
|
|
183
|
-
>
|
|
184
|
-
>
|
|
185
|
-
>
|
|
186
|
-
>
|
|
187
|
-
>
|
|
188
|
-
>
|
|
189
|
-
>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
|
199
|
-
|
|
|
200
|
-
|
|
|
201
|
-
|
|
|
202
|
-
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
图库
|
|
209
|
-
图库
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
>
|
|
214
|
-
>
|
|
215
|
-
>
|
|
216
|
-
>
|
|
217
|
-
>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
>
|
|
233
|
-
>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
|
276
|
-
|
|
277
|
-
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
|
398
|
-
|
|
399
|
-
|
|
|
400
|
-
|
|
|
401
|
-
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
### Q: 提示生成失败
|
|
505
|
-
**A:** 检查 baseUrl 是否可访问、apiKey 是否正确、所用模型是否支持图片输入。
|
|
506
|
-
|
|
507
|
-
### Q: API 返回 401
|
|
508
|
-
**A:** 确认 apiKey 已正确填写,并且服务端允许 Bearer Token 鉴权。
|
|
509
|
-
|
|
510
|
-
### Q: API 返回 429 或配额不足
|
|
511
|
-
**A:** 检查账户额度,插件检测到配额不足会自动停止重试。
|
|
512
|
-
|
|
513
|
-
### Q: 启动报 `ReferenceError: Cannot access 'galleryLoaded' before initialization`
|
|
514
|
-
**A:** 这是 **1.0.4 及更早版本**的 bug,1.1.1 已修复,升级即可。
|
|
515
|
-
|
|
516
|
-
原因:图库启动预热 `void loadGallery()` 写在了 `let galleryLoaded = false` **之前**。
|
|
517
|
-
`loadGallery` 是 `async` 函数,函数体开头读 `galleryLoaded` 时变量还在「暂时性死区」,
|
|
518
|
-
于是抛出的 `ReferenceError` 变成了**未处理的 Promise 拒绝**,日志里显示为 `[W] app`:
|
|
519
|
-
|
|
520
|
-
```
|
|
521
|
-
[W] app ReferenceError: Cannot access 'galleryLoaded' before initialization
|
|
522
|
-
at loadGallery (.../koishi-plugin-image-prompt/lib/index.js:1715:7)
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
它的表现是**图库检索静默失效**(后续报「agent 请求失败」「图库里没有合适的图」),
|
|
526
|
-
而不是让机器人起不来 —— 所以容易被当成别的问题排查。修法很简单:把预热调用挪到声明之后。
|
|
527
|
-
|
|
528
|
-
> 本仓库 `tests/apply-smoke.js` 就是专门防这个的:用真实 koishi Context 跑一遍
|
|
529
|
-
> `apply` + `ready`,监听 `unhandledRejection`。跑 `node tests/apply-smoke.js` 即可验证。
|
|
530
|
-
|
|
531
|
-
# 本插件基于[koishi-plugin-lmarena](https://github.com/HydroGest/lmarena)修改
|
|
1
|
+
# koishi-plugin-image-prompt
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/koishi-plugin-image-prompt)
|
|
4
|
+
|
|
5
|
+
🎯 **一键将图片转换为手办风格!**
|
|
6
|
+
|
|
7
|
+
基于 OpenAI 兼容的 Chat Completions 接口,支持多种 AI 绘图模型,让你的图片瞬间变成精美手办。
|
|
8
|
+
|
|
9
|
+
**特色能力**:**Agent 模式**(把「查不查图库 / 要不要追问 / 什么时候开画」全交给模型,像 NeoBot 一样多轮对话)·
|
|
10
|
+
参考图片分组 + 关键词检索 · 用户附加需求融合进提示词 · 提示词回显(QQ 走 markdown 代码块)·
|
|
11
|
+
**指令一触发就回「收到」** · 提示词不再过度加工(绘图模型听得懂中文)· 生成结果自动入库形成闭环 ·
|
|
12
|
+
后台绘图 + 完成推送 · 参考图描述 AI 自动生成 · 429/限流自动退避重试。
|
|
13
|
+
|
|
14
|
+
## ⚙️ 插件设置
|
|
15
|
+
|
|
16
|
+
直接在 Koishi 控制台的插件设置中填写「API 设置」即可:
|
|
17
|
+
|
|
18
|
+
| 配置项 | 说明 | 默认值 |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| API 服务器地址(baseUrl) | OpenAI 兼容的 Chat Completions 接口地址 | `https://api.gptgod.online/v1/chat/completions` |
|
|
21
|
+
| 使用的模型(model) | 生成图片所使用的模型名称 | `gemini-2.5-flash-image` |
|
|
22
|
+
| API 密钥(apiKey) | 你的 API Key(请求会携带 `Authorization: Bearer <key>`) | 空 |
|
|
23
|
+
| 最大重试次数 | 请求失败后的最大重试次数 | 3 |
|
|
24
|
+
| 重试间隔(毫秒) | 每次重试之间的等待时间 | 1000 |
|
|
25
|
+
|
|
26
|
+
建议前往[gptgod](https://gptgod.online/register/n7iydg8nf09ghbikik3jytod)获取你的api key
|
|
27
|
+
|
|
28
|
+
> 注意:请填写支持图片输入(vision / image)的模型,否则无法正常生成图片。
|
|
29
|
+
|
|
30
|
+
## 📖 使用说明
|
|
31
|
+
|
|
32
|
+
配置完成后即可使用内置指令生成图片,例如:
|
|
33
|
+
|
|
34
|
+
- 手办化
|
|
35
|
+
- 手办化2
|
|
36
|
+
- 手办化3
|
|
37
|
+
- coser化
|
|
38
|
+
- mc化
|
|
39
|
+
- 合并图片(自定义指令,允许附带自定义提示词)
|
|
40
|
+
- 修图(自定义指令)
|
|
41
|
+
|
|
42
|
+
## 🤖 Agent 模式(默认开启,推荐)
|
|
43
|
+
|
|
44
|
+
指令一触发,插件就把「用户说了什么 + 指令自带的提示词 + 可用的参考图」全部交给**对话模型**,
|
|
45
|
+
由模型自己决定下一步 —— 这套写法参考 NeoBot 的 agent(`neobot_chat/runtime/agent.py`):
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
指令触发
|
|
49
|
+
↓
|
|
50
|
+
「收到,正在准备...」 ← 立刻回,不让用户干等
|
|
51
|
+
↓
|
|
52
|
+
模型拿到 3 个工具,自己决定怎么走:
|
|
53
|
+
├─ gallery_search(关键词) → 自己想关键词、自己搜图库
|
|
54
|
+
├─ ask_user(问题) → 自己开口问、自己等用户回话
|
|
55
|
+
└─ draw(prompt, references) → 自己写提示词、自己挑参考图、开画
|
|
56
|
+
↓
|
|
57
|
+
模型说最后一句话 → 发给用户
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
也就是说:**参考图选谁、要不要追问、什么时候开画,全部是模型自己决定的**。
|
|
61
|
+
插件不再写死「需求分析 → 关键词召回 → 逐图打分 → 阈值兜底」这套流程,
|
|
62
|
+
也不再自己判断「用户回的是不是确认」。模型想搜几次图库、想和你来回几轮都行,
|
|
63
|
+
直到它认为可以画了为止。
|
|
64
|
+
|
|
65
|
+
| 工具 | 作用 |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `gallery_search` | 按关键词搜参考图库(关键词由模型自己拟,空格分隔多词)。返回每条的 `id`,写进 `draw` 的 `references` |
|
|
68
|
+
| `ask_user` | 把一句话发给用户**并等他的下一条消息**(他发的图片也会一起带回来,会拿到新编号) |
|
|
69
|
+
| `draw` | 真正开画。传最终提示词 + 参考图编号,画好自动发到群里 |
|
|
70
|
+
|
|
71
|
+
### 工作规则(写进提示词,由模型执行)
|
|
72
|
+
|
|
73
|
+
1. **涉及角色时先搜图库**:有立绘就填进 `references`;没有就如实说「图库里没有这个立绘,将按描述创作」,然后正常画。
|
|
74
|
+
2. 用户明说「不用参考 / 随意画 / 自由发挥」→ 跳过搜索,一次都不搜。
|
|
75
|
+
3. **信息不够才开口**,而且一次只问一个最关键的问题(不连珠炮、不顺带聊别的)。
|
|
76
|
+
4. **开画前先问一句**(默认开):把「这次参考哪几张图 + 大致画成什么样」告诉你,你点头它才画。
|
|
77
|
+
5. 画面上要出文字(台词/标题/招牌)→ 原样写进提示词,并说明「必须原样出现,不能变形或自创字形」。
|
|
78
|
+
6. 只填它确认存在的编号,**不许编造 id**(编了会被丢掉并告诉它不存在)。
|
|
79
|
+
|
|
80
|
+
### Agent 配置
|
|
81
|
+
|
|
82
|
+
| 配置项 | 说明 | 默认值 |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| 启用 Agent 模式 | 关掉就退化成「指令提示词 + 用户附加需求直接画」,不查图库也不追问 | 开 |
|
|
85
|
+
| 开画前先问一句 | 让模型把「参考哪几张图 + 大致画面」告诉你,你点头才画 | 开 |
|
|
86
|
+
| 最多来回轮数 | 每轮 = 一次模型请求 + 它要调的工具。防死循环的天花板 | 8 |
|
|
87
|
+
| 一次最多参考几张图 | 模型给多了会被截断到这个数 | 3 |
|
|
88
|
+
| 单次搜索返回条数 | `gallery_search` 一次最多回多少条 | 12 |
|
|
89
|
+
| 询问等待时间(秒) | `ask_user` 等用户回复的秒数,超时会告诉模型「用户没回」 | 120 |
|
|
90
|
+
| 单次请求超时(秒) | — | 120 |
|
|
91
|
+
| 采样温度 | — | 0.3 |
|
|
92
|
+
| 输出长度上限 | **推理模型会把额度耗在思考上**,太小会一个字都生成不出来。0 = 不限制 | 8000 |
|
|
93
|
+
| 记住最近几轮对话 | 同一频道记住最近 N 轮,「再画一张」「换个风格」才能接上;0 = 不记忆(重启即失效) | 6 |
|
|
94
|
+
| 工具调用日志 | 把每一轮的模型输出与工具调用写进日志,排查用 | 关 |
|
|
95
|
+
| agent 专用模型 / 地址 / 密钥 | 留空则复用「AI 模型接口」里的配置 | 留空 |
|
|
96
|
+
| 指令模板 | 只写「有哪些工具 + 什么时候用」,别写死流程。占位符 `{confirmRule}` 等 | 内置模板 |
|
|
97
|
+
|
|
98
|
+
**关于模型选型**:agent 需要模型支持 **function calling(工具调用)**。
|
|
99
|
+
不支持也没关系 —— 插件内置了「一行 JSON」兜底协议:接口拒了 `tools` 参数时会自动改用它,
|
|
100
|
+
模型只要输出 `{"tool":"draw","args":{"prompt":"...","references":["ref1"]}}` 就能照常跑流程。
|
|
101
|
+
|
|
102
|
+
已知能用的:各家 `gpt-4o` / `gpt-4.1` 系、`Qwen` 的 `-Instruct` 新版、`DeepSeek-V3` 及之后
|
|
103
|
+
(带 tool 支持的版本)、`glm-4` 系等。老的小模型(如 `Qwen2.5-7B-Instruct`)可能不支持工具调用,
|
|
104
|
+
这时就走 JSON 兜底协议,效果取决于模型听不听话。
|
|
105
|
+
|
|
106
|
+
### 🖼️ 参考图片组 / 图库
|
|
107
|
+
|
|
108
|
+
参考图以**分组**的方式注册,agent 通过 `gallery_search` 按需搜。
|
|
109
|
+
|
|
110
|
+
#### 1. 注册参考图片组
|
|
111
|
+
|
|
112
|
+
在插件配置 → **参考图片组** 中新增分组:
|
|
113
|
+
|
|
114
|
+
| 字段 | 说明 |
|
|
115
|
+
|---|---|
|
|
116
|
+
| 组名称 | 在指令中通过该名称引用,例如 `角色A` |
|
|
117
|
+
| 是否启用 | 关闭后不再参与搜索 |
|
|
118
|
+
| 图片链接 | 参考图的 URL |
|
|
119
|
+
| 图片描述 | **关键**:agent 就是靠这句描述搜到它的,写得越具体越好(发色发型、服装、动作、画风) |
|
|
120
|
+
|
|
121
|
+
#### 2. 在指令中引用组
|
|
122
|
+
|
|
123
|
+
| 指令配置项 | 说明 |
|
|
124
|
+
|---|---|
|
|
125
|
+
| 引用的参考图片组名称 | 可填多个组名,agent 只能在这些组里搜 |
|
|
126
|
+
| 是否走 agent | `跟随全局 / 走 agent / 不走 agent`,可针对单条指令覆盖 |
|
|
127
|
+
|
|
128
|
+
> 指令留空组名时,是否搜索全部组由「AI 模型接口 → 指令未指定组时允许搜索全部组」决定(默认开启)。
|
|
129
|
+
> 没有配任何参考图片组的指令,agent 依然可以纯文生图(不参考任何图)。
|
|
130
|
+
|
|
131
|
+
#### 3. AI 模型接口
|
|
132
|
+
|
|
133
|
+
| 配置项 | 说明 | 默认值 |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| 对话接口地址 | OpenAI 兼容 Chat Completions,留空复用绘图接口地址 | 空(复用) |
|
|
136
|
+
| 对话接口密钥 | 留空复用绘图 API 密钥 | 空(复用) |
|
|
137
|
+
| 对话模型 | agent 循环、提示词优化、生成描述都用它 | `Qwen/Qwen2.5-7B-Instruct` |
|
|
138
|
+
| 采样温度 / 超时 / 重试次数 / 重试间隔 | 同前,429 会自动指数退避并优先遵循 `Retry-After` | — |
|
|
139
|
+
| 指令未指定组时允许搜索全部组 | — | 开 |
|
|
140
|
+
| 把指令默认图片也纳入可搜索参考图 | — | 关 |
|
|
141
|
+
| 生成描述相关(指令名 / 模型 / 提示词 / 批量上限) | 见下方「自动生成参考图描述」 | — |
|
|
142
|
+
|
|
143
|
+
### 4. 一次完整的交互长什么样
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
你:手办化 白发少女
|
|
147
|
+
|
|
148
|
+
bot:收到,正在准备...
|
|
149
|
+
bot:这次参考 ref1(白发少女 双马尾 水手服),画成桌上的摆件可以吗?
|
|
150
|
+
你:可以
|
|
151
|
+
bot:```
|
|
152
|
+
a white-hair girl figure on a desk, ...
|
|
153
|
+
```
|
|
154
|
+
bot:
|
|
155
|
+
bot:画好啦,按 ref1 的立绘做的~
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- 你回「算了」/ 不回 → 模型自己决定这次不画,**不会白画一张**。
|
|
159
|
+
- 你直接发图 → 图会被登记成 `user1`、`user2`…,模型可以照样填进 `references`。
|
|
160
|
+
- 「收到」那条不会重复发,提示词也只回显一次。
|
|
161
|
+
|
|
162
|
+
### 📝 提示词回显
|
|
163
|
+
|
|
164
|
+
处理时会把**最终交给绘图模型的提示词**一起发出来,方便你确认它到底用了什么。
|
|
165
|
+
用默认的「原话直出」时,你看到的基本就是你发的那句话。
|
|
166
|
+
|
|
167
|
+
| 配置项 | 说明 | 默认 |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| 发送最终提示词 | 关闭则不回显 | 开 |
|
|
170
|
+
| 回显提示词的最大字符数 | 超出截断并标注;**0 = 不截断** | 4000 |
|
|
171
|
+
|
|
172
|
+
- **官方 QQ**(`qq` / `qq-*` / `qqbot`):发 `markdown` **元素**,由适配器走 QQ 的 markdown API,
|
|
173
|
+
客户端渲染成代码块
|
|
174
|
+
- **其它平台**(QQ 频道、OneBot 系、Discord、Telegram、KOOK…):纯文本
|
|
175
|
+
|
|
176
|
+
> **代码块围栏必须独占一行**:适配器是把 markdown 内容直接拼在已有文本后面的,中间不补换行。
|
|
177
|
+
> 所以提示词会**单独作为一条消息**发送,且内容前补一个换行——否则围栏会被前文顶到行中,
|
|
178
|
+
> QQ 不会识别成代码块(提示词按普通 markdown 渲染,末尾那个围栏反而开出一个空代码块)。
|
|
179
|
+
>
|
|
180
|
+
> 回显会**保留提示词的原始换行**(不压成一行),代码块里段落结构才看得清。
|
|
181
|
+
> 内置指令的提示词普遍上千字符(「手办化」就有 1463 字符),默认上限 4000 刚好能完整显示;
|
|
182
|
+
> 自定义指令的提示词如果更长,把它设为 0 不截断,或调大到 20000。
|
|
183
|
+
> QQ 的 markdown 有内容长度上限,太长可能被拒收,那时再调小或关掉回显。
|
|
184
|
+
>
|
|
185
|
+
> **关键点**:光在字符串里写 ``` 是没用的,客户端只会当普通文本原样显示。
|
|
186
|
+
> 必须构造 `h('markdown', content)` 元素,让适配器走专门的 markdown 接口
|
|
187
|
+
> (`koishi-plugin-adapter-qq-crack` 里 `type === 'markdown'` 分支负责这件事)。
|
|
188
|
+
>
|
|
189
|
+
> 平台白名单只认官方 QQ,**`qqguild`(频道)不支持**——它走另一套编码器,
|
|
190
|
+
> md 元素在那里会被当纯文本原样发出去。口径与 kkk 插件的 `supportsMarkdown` 一致。
|
|
191
|
+
|
|
192
|
+
### ♻️ 生成结果入库(闭环)
|
|
193
|
+
|
|
194
|
+
画完的图自动存进图库,下次能被自己检索到并复用——对应 NeoBot 的 Gallery。
|
|
195
|
+
|
|
196
|
+
| 配置项 | 说明 | 默认 |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| 把生成结果自动存入图库 | 总开关 | 关 |
|
|
199
|
+
| 存入哪个参考图片组 | 不存在会自动创建 | 生成结果 |
|
|
200
|
+
| 用什么当描述 | 完整提示词 / 用户附加需求 / 两者拼接 | 完整提示词 |
|
|
201
|
+
| 描述截断长度 | 提示词通常很长 | 120 |
|
|
202
|
+
| 图库容量上限 | 超出淘汰最旧的 | 50 |
|
|
203
|
+
| 图库指令名 | 查看/清空 | 图库 |
|
|
204
|
+
|
|
205
|
+
指令:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
图库 列出入库的图片(最多 20 条)
|
|
209
|
+
图库 角色A 只列名字/描述含「角色A」的
|
|
210
|
+
图库 清空 清空图库
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> **检索到它的前提**:对应指令的「引用的参考图片组名称」里包含这个组名,
|
|
214
|
+
> 或者「指令未指定组时使用全部组」是开启的(默认开)。
|
|
215
|
+
>
|
|
216
|
+
> **为什么不在控制台里显示**:入库走本地文件 `data/image-prompt/gallery.json`,
|
|
217
|
+
> 而不是写回插件配置——写回配置会触发插件**重启**(`scope.update(config, true)` 的行为),
|
|
218
|
+
> 每画一张图重启一次太脏。好处是不重启、重启 Koishi 后也还在。
|
|
219
|
+
|
|
220
|
+
### 💬 随指令发的需求会写进提示词
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
手办化 deepseekQ版 在偷吃白饭被发现的表情
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
这句里的附加需求会**同时**用于两件事:
|
|
227
|
+
|
|
228
|
+
1. 交给 AI 参考(agent 模式下用于决策;该搜什么、要不要问用户、用哪张参考图)
|
|
229
|
+
2. **原样进入绘图提示词**——这样出图才会带上「偷吃白饭被发现的表情」。
|
|
230
|
+
默认不再加工:不扩写、不翻译成英文、不拼接指令自带的那串英文提示词
|
|
231
|
+
|
|
232
|
+
> 之前只有 `custom` 类型的指令才合并用户输入,普通指令(手办化、coser化…)只拿它去选图、
|
|
233
|
+
> 画图时丢掉,所以会出现「图选对了但需求没体现」。现在两者都合并。
|
|
234
|
+
>
|
|
235
|
+
> 另外文本取的是**指令参数**,不是整条消息——否则提示词里会混进指令名(「手办化 xxx」→ 只取 xxx)。
|
|
236
|
+
|
|
237
|
+
### 🪄 提示词融合方式(默认:直接说人话,不多加工)
|
|
238
|
+
|
|
239
|
+
> **现在的绘图模型听得懂中文,也有基本的理解力。** 把用户那句话原样交给它就够了 ——
|
|
240
|
+
> 反过来,把它「优化」成一两百字的英文术语堆砌,各要素互相稀释,出图反而更容易走样。
|
|
241
|
+
> 所以 2.0.3 起默认是**做减法**。
|
|
242
|
+
|
|
243
|
+
| 配置项 | 说明 | 默认 |
|
|
244
|
+
|---|---|---|
|
|
245
|
+
| 附加需求如何并入提示词 | `passthrough` 原话直出 / `merge` 追加 / `rewrite` 融合重写 / `off` 不处理 | **`passthrough`** |
|
|
246
|
+
| 把用户附加需求并入提示词 | 关闭则只用于选图,不改提示词 | 开 |
|
|
247
|
+
| 融合重写用的提示词模板 | 占位符 `{prompt}` 原始提示词、`{userInput}` 用户附加需求 | 内置模板(已改成「宁短勿长」) |
|
|
248
|
+
|
|
249
|
+
- **`passthrough`(原话直出,推荐)**:用户说了话就用**他的原话**,不再拼指令自带的长提示词、
|
|
250
|
+
不扩写、不翻译。用户没说话时才退回指令自带的提示词
|
|
251
|
+
- **`merge`(追加)**:把用户的原话贴在指令自带提示词后面,不做改写
|
|
252
|
+
- **`rewrite`(融合重写)**:让模型把需求写进提示词对应位置 —— **会明显变长**,
|
|
253
|
+
老版本(≤2.0.2)就是默认这个。想要旧行为选它
|
|
254
|
+
- **`off`**:只用指令自身的提示词,忽略用户说的话(agent 模式下仍会把需求交给模型看)
|
|
255
|
+
|
|
256
|
+
`rewrite` 失败时自动退回用户的原话,不会因为优化失败而不出图;失败会在处理消息里提示。
|
|
257
|
+
|
|
258
|
+
> **agent 模式下**(默认开启)这条配置项不影响你的输入是否被保留 ——
|
|
259
|
+
> 用户的话会原封不动地出现在给模型的上下文里(`用户这次说的话:…`),
|
|
260
|
+
> 画图的 prompt 由模型自己组织。2.0.3 起提示词里明确要求它
|
|
261
|
+
> **「短、说人话、保持中文、不要替用户脑补细节」**。
|
|
262
|
+
「(提示词融合失败,已改为追加模式)」,方便排查(多半是模型限流或返回被判空)。
|
|
263
|
+
用的是「AI 模型接口」那套接口/模型(想换更强的模型可以单独改)。
|
|
264
|
+
|
|
265
|
+
> **注意**:agent 模式下,最终提示词是**模型自己在 `draw` 工具里写出来的**,
|
|
266
|
+
> 这里的「融合重写」只在**关掉 agent** 的直连流程里生效。
|
|
267
|
+
|
|
268
|
+
### ⚡ 后台绘图(不阻塞)
|
|
269
|
+
|
|
270
|
+
出图常常要几十秒,同步等待时消息一直转圈。开启后:先回「已开始后台绘图,画好后会通知你」,
|
|
271
|
+
出图在后台跑,完成后**主动推送**结果(带引用回复)。
|
|
272
|
+
|
|
273
|
+
| 配置项 | 说明 | 默认 |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| 后台绘图 | 总开关 | 关 |
|
|
276
|
+
| 同时进行的任务上限 | 超出的排队,逐个执行 | 3 |
|
|
277
|
+
| 排队时提示 | 告知前面还有几个任务 | 开 |
|
|
278
|
+
|
|
279
|
+
失败也会推送失败消息。插件停用时后台任务自动跳过。
|
|
280
|
+
|
|
281
|
+
### ✍️ 自动生成参考图描述(不用再手填)
|
|
282
|
+
|
|
283
|
+
描述是选图和检索的唯一依据,一张张手填很痛苦。用指令让模型自己看图写:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
生成描述 为所有启用组里「描述为空」的图片生成描述(一次最多 8 张)
|
|
287
|
+
生成描述 角色A 只处理名字含「角色A」的组
|
|
288
|
+
生成描述 + 发一张图 只识别这张图并返回描述,方便自己复制
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
生成的描述会**自动写回插件配置**(控制台里能看到),同时把结果发给你。
|
|
292
|
+
|
|
293
|
+
| 配置项 | 说明 | 默认 |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| 自动生成描述的指令名 | 挂在指令根下 | 生成描述 |
|
|
296
|
+
| 生成描述用的模型 | 留空则用选图模型;**必须是支持图片输入的模型** | 空 |
|
|
297
|
+
| 生成描述的提示词 | 要求模型写出便于检索的关键词 | 内置模板 |
|
|
298
|
+
| 一次最多处理多少张 | 避免请求过多被限流 | 8 |
|
|
299
|
+
|
|
300
|
+
> 提示词默认要求模型写出「红发双马尾」「白色水手服」这类**具体词**,而不是「一个女孩」,
|
|
301
|
+
> 这样 agent 搜图才搜得准。默认模型 `Qwen/Qwen2.5-7B-Instruct` 是纯文本模型,
|
|
302
|
+
> 用它生成描述会失败——请换成 VL 模型或单独填写「生成描述用的模型」。
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
### 🔁 限流(429)处理
|
|
307
|
+
|
|
308
|
+
选图模型和绘图模型走的是同一类接口,免费额度下很容易撞上 `429 Too Many Requests`。插件的处理策略:
|
|
309
|
+
|
|
310
|
+
1. 识别 429 / 503,优先按响应头的 `Retry-After` 等待;没有该头则指数退避
|
|
311
|
+
(基础间隔 3 秒 → 6 秒 → 12 秒,上限 30 秒)。
|
|
312
|
+
2. 单次等待超过「单次重试最长等待时间」(默认 20 秒)就不再重试,直接按失败处理,避免用户干等。
|
|
313
|
+
3. 失败后在处理提示里给出人话原因,例如:`AI 选图失败(被限流(429 Too Many Requests)),本次不使用参考图片`。
|
|
314
|
+
|
|
315
|
+
遇到频繁 429 的几种处理方式:
|
|
316
|
+
|
|
317
|
+
- 调大「重试基础间隔」与「请求失败重试次数」,或放宽「单次重试最长等待时间」
|
|
318
|
+
|
|
319
|
+
### 📮 QQ 官方机器人的「被动回复」限制(40034128)
|
|
320
|
+
|
|
321
|
+
报错 `回复消息失败,被动回复时间或者次数超过限制`:QQ 官方机器人里,**引用一条用户消息 = 被动回复**,
|
|
322
|
+
有 **5 分钟时效 + 次数上限**。而一次绘图要发好几条消息(选图中 → 处理中 → 提示词回显 → 结果图),
|
|
323
|
+
每条都带引用必然超限。
|
|
324
|
+
|
|
325
|
+
⚠️ **关键坑:去掉引用元素并不等于变成主动消息。** `koishi-plugin-adapter-qq-crack` 内部是
|
|
326
|
+
`msg_id = session.messageId` —— 只要消息经过 `session.send()`,哪怕不带 `h.quote()`,
|
|
327
|
+
也会被当成被动回复并递增 `msg_seq`,照样受时效/次数限制。**真正的主动消息只能走
|
|
328
|
+
`bot.sendMessage(channelId, content, guildId)`(不经过 session)。**
|
|
329
|
+
|
|
330
|
+
插件现在按下面三条规则处理,不需要你管:
|
|
331
|
+
|
|
332
|
+
1. **同一条用户消息只引用一次**:第一条消息带引用(看起来是"回复你"),后续都是普通消息
|
|
333
|
+
2. **被动回复有次数预算**:同一条消息最多走 3 次被动回复,用满自动改走主动消息
|
|
334
|
+
3. **被动回复被拒时立刻降级**:捕获 40034128,改用 `bot.sendMessage` 发真正的主动消息
|
|
335
|
+
|
|
336
|
+
后台绘图最容易踩这个(出图要几分钟,早过时效了),完成通知同样会自动降级。
|
|
337
|
+
|
|
338
|
+
#### Agent 模式下会发哪几条消息
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
① 「收到,正在准备...」 ← 立刻回,不让用户干等
|
|
342
|
+
② 模型的提问(如有,走 ask_user 工具)
|
|
343
|
+
③ ```
|
|
344
|
+
本次用的提示词(代码块)
|
|
345
|
+
```
|
|
346
|
+
④  ← 自动按真实比例
|
|
347
|
+
⑤ 模型的收尾一句话
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
一次绘图通常是 3~5 条。第 ③ 条是**在开始画图之前**就发出去的(不会让你在绘图期间干等、以为卡住了);
|
|
351
|
+
第 ④ 条是图片出来后再发。被动回复额度用满会自动降级成主动消息(见上一节)。
|
|
352
|
+
|
|
353
|
+
**关于结果图的两个坑:**
|
|
354
|
+
|
|
355
|
+
- **必须带尺寸**:QQ 官方语法是 ``,**不带尺寸手机端 QQ 不渲染**。
|
|
356
|
+
但**写死宽高会把非方形图拉伸变形**——所以插件默认开启「自动尺寸」:下载结果图读文件头
|
|
357
|
+
(PNG/GIF/JPEG/WebP 都支持,不解码整张图),按真实比例等比缩放到「显示宽度上限」(默认 400px)。
|
|
358
|
+
想手动指定就把「自动尺寸」关掉,再填「显示宽度 / 显示高度」(0 表示不限制)。
|
|
359
|
+
- **最好走一次 assets**:绘图接口给的虽然是公网链接,但手机端 QQ 经常拉不到(防盗链/域名)。
|
|
360
|
+
开启后先经 assets 服务(`koishi-plugin-assets-qqbot-part-file` 等)转成平台可访问的地址;
|
|
361
|
+
上传失败会自动用原链接,不会更差。
|
|
362
|
+
- **兜底会按字节发**:发送失败(QQ 报 `[40093007] 富媒体文件下载失败`)时,插件退回去
|
|
363
|
+
**自己把结果图下载下来、按字节交给适配器上传**,而不是把链接再丢给平台去拉。
|
|
364
|
+
这条兜底对「平台服务器拉不到你的图床」这类问题基本是决定性的。
|
|
365
|
+
|
|
366
|
+
| 配置项 | 说明 | 默认 |
|
|
367
|
+
|---|---|---|
|
|
368
|
+
| 收到提示 | 指令一触发就先回一条「收到,正在准备...」 | 开 |
|
|
369
|
+
| 结果图用 markdown | 支持 markdown 的平台用 `` 发结果 | 开 |
|
|
370
|
+
| 结果图经 assets 上传 | 外链手机端常拉不到,转成平台地址 | 开 |
|
|
371
|
+
| 结果图自动尺寸 | 读真实宽高、等比缩放,避免非方形图被拉伸 | 开 |
|
|
372
|
+
| 显示宽度上限 | 自动尺寸时的最大宽度,高度按真实比例算 | 400 |
|
|
373
|
+
| 手动宽 / 高 | 仅在关掉自动尺寸时生效,0 表示不限制 | 0 / 0 |
|
|
374
|
+
|
|
375
|
+
细节:
|
|
376
|
+
- 提示词代码块是**单独一条消息**(围栏必须独占一行,否则 QQ 不认成代码块)
|
|
377
|
+
- **开了后台绘图时,提示词也只发一次**(以前会连同「已开始后台绘图」重复发一遍)
|
|
378
|
+
- 不支持 markdown 的平台(频道、OneBot)自动用纯文本 / 普通图片消息
|
|
379
|
+
|
|
380
|
+
### 🩺 排查「agent 没反应 / 响应里没有文本内容」
|
|
381
|
+
|
|
382
|
+
这个报错的意思不是网络问题,而是**接口返回了 200,但插件从返回里取不出文字**。
|
|
383
|
+
|
|
384
|
+
#### 最常见原因:`max_tokens` 太小,被推理模型吃光
|
|
385
|
+
|
|
386
|
+
用 `deepseek-flash`(DeepSeek-V4.1-Flash)这类**推理模型**实测,附 6 张图选一次图:
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
max_tokens=1000 → finish_reason: length, content: "", reasoning_tokens: 1000 ❌ 全被思考吃掉
|
|
390
|
+
max_tokens=8000 → finish_reason: stop, content: "{...}", reasoning_tokens: 2202 ✅
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
模型光思考就要 1000~4000 token,额度给小了,正文一个字都生成不出来,`content` 就是空的。
|
|
394
|
+
插件现在默认给到 **8000**(agent 单次回复)/ **8000**(提示词优化),
|
|
395
|
+
并且**检测到 `finish_reason=length` 会自动加大额度重试**,不用你手动调。
|
|
396
|
+
|
|
397
|
+
| 配置项 | 说明 | 默认 |
|
|
398
|
+
|---|---|---|
|
|
399
|
+
| agent 输出长度上限 | 太小会报「没有文本内容」 | 8000 |
|
|
400
|
+
| 提示词优化输出长度上限 | 融合/扩写 | 8000 |
|
|
401
|
+
| 截断后最多加大到 | 自动重试的上限 | 32000 |
|
|
402
|
+
|
|
403
|
+
#### 其它已自动兼容的情况
|
|
404
|
+
|
|
405
|
+
| 接口/模型的行为 | 处理方式 |
|
|
406
|
+
|---|---|
|
|
407
|
+
| 推理模型把正文放在 `reasoning_content` | 自动取 |
|
|
408
|
+
| 模型把回答混在 `<think>…</think>` 里 | 自动剥离,只留正式回答 |
|
|
409
|
+
| 输出长度参数只认 `max_completion_tokens`(o1/o3/gpt-5/reasoner) | 自动识别;失败时**重试会自动换另一个参数名** |
|
|
410
|
+
| 响应被 `max_tokens` 截断(`finish_reason=length`) | 明确报「被截断」并**自动加大额度重试**;此时绝不会把 `reasoning_content` 里没想完的思考过程当答案 |
|
|
411
|
+
| 命中安全策略(`content_filter`) | 明确报「被安全策略拦截」 |
|
|
412
|
+
| 中转站把结构塞进 `data` 里 / 返回 Anthropic 风格 `content` 数组 | 自动取 |
|
|
413
|
+
| 中转站无视 `stream` 直接回 SSE 流 | 自动拼接所有 `data:` 块 |
|
|
414
|
+
|
|
415
|
+
还是不行的话,用**诊断指令**(默认 `测试选图`,挂在指令根下)发一次真实请求,
|
|
416
|
+
它会回显接口地址、模型、用的长度参数名、取到的内容,取不到时把**原始返回**打出来:
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
测试选图
|
|
420
|
+
→ 接口:https://...
|
|
421
|
+
模型:deepseek-v4.1-flash
|
|
422
|
+
长度参数:max_tokens
|
|
423
|
+
取不到内容:message.content 为空:{"id":"...","choices":[...]}
|
|
424
|
+
原始返回:...
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
拿到原始返回就能判断是模型名写错、中转站格式另类,还是模型本身不支持工具调用。
|
|
428
|
+
也可以在「AI 模型接口」里手动指定**输出长度参数名**。
|
|
429
|
+
|
|
430
|
+
另外,agent 有问题时把「Agent 配置 → 工具调用日志」打开,
|
|
431
|
+
每一轮的模型输出与工具调用都会写进日志,一眼就能看出是模型没调工具、
|
|
432
|
+
还是调了但参数不对。
|
|
433
|
+
|
|
434
|
+
### 🩺 排查「画不出来 / 接口报错」
|
|
435
|
+
|
|
436
|
+
失败时插件会把**服务端返回的真实原因**原样带出来,先看这一句再决定怎么办:
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
[I] 请求失败(第 3/3 次):Internal Server Error|接口返回:connect ECONNREFUSED 192.168.0.85:20000
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
群里收到的失败消息里同样会带上这句。**这串东西不是乱码**,它通常直接说明问题在哪:
|
|
443
|
+
|
|
444
|
+
| 看到的说法 | 含义 | 怎么办 |
|
|
445
|
+
| --- | --- | --- |
|
|
446
|
+
| `connect ECONNREFUSED <ip>:<端口>` | 中转站的后端节点没起来 / 挂了 | **跟接口提供方无关也不在你这边**,换模型或等它恢复 |
|
|
447
|
+
| `当前模型负载较高` | 该模型现在挤,不是配置问题 | 换个负载均衡点的模型,或稍后再试 |
|
|
448
|
+
| `Model Not Exist` | 模型名写错了 | 核对模型名(大小写也算) |
|
|
449
|
+
| `Invalid API key` | 密钥不对或已过期 | 换密钥 |
|
|
450
|
+
| `insufficient_quota` | 额度没了 | 充值后会立刻恢复,插件不会傻重试 |
|
|
451
|
+
|
|
452
|
+
> 同一个中转站上**所有**绘图模型都报同一个 `ECONNREFUSED` 时,基本可以确定是对方整条链路挂了,
|
|
453
|
+
> 换个模型名也没用,只能等它恢复。判断是否全挂:换 2~3 个不同的绘图模型各试一次,
|
|
454
|
+
> 如果都指向同一个 IP 端口,就是服务端的问题。
|
|
455
|
+
|
|
456
|
+
另外,`429 限流` 和 `5xx 服务端错误` 现在是**指数退避**重试(1s → 2s → 4s…),
|
|
457
|
+
不再用固定间隔连着猛打 —— 对端真的在重启的时候,等久一点反而更容易成功。
|
|
458
|
+
|
|
459
|
+
### ❌ 不会重试的错误
|
|
460
|
+
|
|
461
|
+
`400 / 401 / 403 / 404 / 422` 这类属于永久性错误(参数错、密钥错、地址错、模型不存在),
|
|
462
|
+
重试多少次结果都一样,插件**只请求一次就放弃**,并把服务端返回的具体原因显示出来,例如:
|
|
463
|
+
|
|
464
|
+
- `请求被拒绝(400):Model Not Exist` → 模型名写错了
|
|
465
|
+
- `鉴权失败(401):Invalid API key` → 密钥不对
|
|
466
|
+
- `接口地址不存在(404):Not Found` → baseUrl 写错了
|
|
467
|
+
|
|
468
|
+
只有 `429` 限流、`5xx` 服务端错误、超时/网络错误才会重试。
|
|
469
|
+
- 在「AI 模型接口」里单独填一个接口地址/密钥,与绘图接口分开(不复用额度)
|
|
470
|
+
- 换一个限流更宽松的对话模型(默认 `Qwen/Qwen2.5-7B-Instruct` 是免费模型,容易限流)
|
|
471
|
+
- 给简单指令单独设成「不走 agent」(指令配置 → 是否走 agent),减少模型请求
|
|
472
|
+
|
|
473
|
+
## 🔧 常见问题
|
|
474
|
+
|
|
475
|
+
### Q: 提示生成失败
|
|
476
|
+
**A:** 检查 baseUrl 是否可访问、apiKey 是否正确、所用模型是否支持图片输入。
|
|
477
|
+
|
|
478
|
+
### Q: API 返回 401
|
|
479
|
+
**A:** 确认 apiKey 已正确填写,并且服务端允许 Bearer Token 鉴权。
|
|
480
|
+
|
|
481
|
+
### Q: API 返回 429 或配额不足
|
|
482
|
+
**A:** 检查账户额度,插件检测到配额不足会自动停止重试。
|
|
483
|
+
|
|
484
|
+
### Q: 启动报 `ReferenceError: Cannot access 'galleryLoaded' before initialization`
|
|
485
|
+
**A:** 这是 **1.0.4 及更早版本**的 bug,1.1.1 已修复,升级即可。
|
|
486
|
+
|
|
487
|
+
原因:图库启动预热 `void loadGallery()` 写在了 `let galleryLoaded = false` **之前**。
|
|
488
|
+
`loadGallery` 是 `async` 函数,函数体开头读 `galleryLoaded` 时变量还在「暂时性死区」,
|
|
489
|
+
于是抛出的 `ReferenceError` 变成了**未处理的 Promise 拒绝**,日志里显示为 `[W] app`:
|
|
490
|
+
|
|
491
|
+
```
|
|
492
|
+
[W] app ReferenceError: Cannot access 'galleryLoaded' before initialization
|
|
493
|
+
at loadGallery (.../koishi-plugin-image-prompt/lib/index.js:1715:7)
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
它的表现是**图库检索静默失效**(后续报「agent 请求失败」「图库里没有合适的图」),
|
|
497
|
+
而不是让机器人起不来 —— 所以容易被当成别的问题排查。修法很简单:把预热调用挪到声明之后。
|
|
498
|
+
|
|
499
|
+
> 本仓库 `tests/apply-smoke.js` 就是专门防这个的:用真实 koishi Context 跑一遍
|
|
500
|
+
> `apply` + `ready`,监听 `unhandledRejection`。跑 `node tests/apply-smoke.js` 即可验证。
|
|
501
|
+
|
|
502
|
+
# 本插件基于[koishi-plugin-lmarena](https://github.com/HydroGest/lmarena)修改
|
|
532
503
|
# 部分prompt来自[astrbot_plugin_lmarena](https://github.com/Zhalslar/astrbot_plugin_lmarena)
|