17 - 图片引用标准与 AI 图库交互¶
状态:已发布(插件 4.28.0 + image-host 1.0.15,2026-10-20)。本文是 CIR v1 标准、实现说明与验收依据;实现状态见 §15。 方案提出时基线:插件 4.27.0(
c8da50b)+ image-host 1.0.14;本次实现:插件 4.28.0 + image-host 1.0.15。 关联:16-图片生命周期与图床方案(图床存储/引用/清理)、04-工具系统、05-命令与配置、08-相关后端项目、09-注意事项与常见问题。 一句话目标:[img:<ref>]成为全插件通用的图片引用标准;AI 能可靠地看图、批量看图、批量处理,并且清楚每张图来自哪个群、是否可信。
0. 背景与目标¶
0.1 调查结论(本次实现要修的现状)¶
| 问题 | 现状 | 本次实现 |
|---|---|---|
| AI 直接看图 | MCP image_search 只返回文本,工具结果里的 [img:<sha>] 不会变成图片;只能靠 image_to_text 让识图模型转述成文字 |
新增 CIR 翻译层 + image_view;image_to_text 接受标准引用 |
| 图床 id 可不可用 | 只有“发送”链路认 [img:<sha>];resolve_special_id / get_image / image_to_text 都不认 |
所有图片入口统一走 resolveRef |
| 工具返回图片的来源 | 新产出/新入库的图片经常没有来源;画廊图来源显示为空 | 工具图片来源 = 工具调用所在的群/会话,永不写“未知”;来源写入元数据;自动标签只对工具产出图片打英文类型标签 |
| 工具返回图片的标签 | 上一版把来源/群/工具/类型打成标签,与元数据重复 | 元数据与标签分离:来源/群/工具/类型只写元数据;自动标签只对工具产出图片打英文类型标签(ai-generated/meme/mcp-image/tool-image),不调识图、不复制元数据 |
| AI 批量看图 | image_view 尚未实现;image_to_text 一次一张 |
image_view 支持 ids[](默认 ≤4);image_to_text 支持 ids[](默认 ≤3) |
| AI 批量处理 | image_keep / image_tag 已支持 ids[],但上限不明确、没有 unkeep |
明确上限(≤50/次);新增 image_unkeep;不提供 AI 删除 |
| 模型取图可达性 | publicUrl 是内网 IP 时云模型取不到;失败后被永久标 urlBroken |
按“模型可达性”自动选 URL/b64;404 才标坏,可恢复 |
| 提示词工程模式 | 工具结果 contentParts 被丢弃,图片看不到 |
PE 模式保留 image parts |
0.2 本次实现的 5 个交付物¶
- CIR v1:
[img:<ref>]通用图片引用标准(含h<sha256>规范形式)。 - ImageRefAdapter 翻译层:工具输出 → 模型上下文、模型/工具入参 → Image、Image → 模型可消费内容。
- 工具图片来源(元数据)与标签分离:工具返回的图片必须有来源(工具调用所在群),来源/群/工具/类型写入元数据;标签只保留类型/内容语义;自动标签只对工具产出图片按产出者打英文类型标签(不调识图),不复制元数据。
- 看图与批量能力:
image_view(批量看)、image_to_text(批量描述)、image_keep/tag/unkeep(批量处理)。 - 可达性与自愈:模型 URL/b64 选择、
urlBroken只对真删除生效、回退链。
1. 决策摘要¶
| # | 决策 | 说明 |
|---|---|---|
| 1 | 通用图片引用标准 CIR v1 | [img:<ref>],ref 支持 h<sha256> / 裸 sha256 / 插件图片 ID / user_avatar: / group_avatar:,可带 :描述 |
| 2 | 翻译层只做“规范化 + 注册 + 解析” | 工具结果里的 [img:<sha>] → [img:h<sha>] 并注册虚拟图;不做自动图片注入 |
| 3 | 工具结果规范化只对“图片引用生产者”生效 | 默认 image-host MCP(按服务器名),或 mcpServers 配置 "imageRefs": true;其它工具文本保持原样,不扩大提示注入面 |
| 4 | 虚拟图只进内存 LRU | 不落 storage、不进 ImageIndex;修掉“识别后把 image_<sha> 写进存储”的问题 |
| 5 | 工具图片来源 = 工具调用上下文 | 平台/群/用户/会话/时间/工具名;没有群时用私聊/会话;任何情况下不写“未知” |
| 6 | 元数据与标签分离 | 来源/群/工具/服务器/类型/信任一律写元数据(不写标签);标签只保留类型/内容语义;自动标签只对工具产出图片按产出者映射英文类型标签(不调识图)、幂等、带上限 |
| 7 | 看图入口 | image_view(多模态直接看)/ image_to_text(文字描述);两者都接受 CIR |
| 8 | image_view 默认注册 |
作为「图片」分类内置工具常驻注册(两个小决策之一) |
| 9 | get_image 对图床引用选 A |
明确报错“无协议端缓存,请用 URL 或 [img:] 发送”,不落本地文件(两个小决策之一) |
| 10 | 批量上限 | 看图 ≤4 张/次;批量描述 ≤3 张/次;keep/tag/unkeep ≤50 个 id/次;search ≤50 条/页;不提供 AI 删除 |
| 11 | 模型可达性 | 公网 publicUrl 用 URL;内网/回环 publicUrl + 云模型改用 b64;本机模型可用 URL |
| 12 | 失败不误标 | 模型下载失败先探 404;真删才 urlBroken;够不到 → b64 重试一次;可恢复 |
| 13 | PE 模式保留 contentParts |
提示词工程模式下工具返回的图片也能被模型看到 |
| 14 | 安全边界不变 | 用户输入仍 stripUserTags;context_edit_replace 仍转义;pub_send 仍净化;媒体队列仍转义显示 |
| 15 | 自动类型标签用英文 | 按产出者确定性映射:ai-generated / meme / mcp-image / tool-image;kebab-case、小写;不调用识图模型;手动内容标签语言不限 |
| 16 | 自动标签不调识图 | 自动类型标签由产出工具确定性映射,零额外模型调用、零额外请求;不根据图片内容猜测标签 |
2. 通用图片引用标准 CIR v1¶
2.1 语法¶
image-tag := "[" "img:" ref (":" description)? "]"
ref := "h" 64HEX // 图床托管图的规范形式(翻译层生成)
| 64HEX // 兼容输入:裸 sha256
| plugin-id // 插件已有图片 ID(旧格式,如 abc123 / AI绘图_xxx)
| "user_avatar:" uid
| "group_avatar:" gid
- 全角括号
[]、全角冒号:兼容(沿用现有解析习惯)。 - 工具返回的
/i/<sha256>绝对地址也作为ref接受(便于模型从搜索结果里复制)。 :描述只用于展示/发送,不参与查找;描述可含冒号,解析取第一个冒号前的 ref。
2.2 规范形式与兼容¶
| 输入 | 规范输出 | 说明 |
|---|---|---|
[img:9f2c…(64hex)] |
[img:h9f2c…] |
工具结果规范化时改写并注册虚拟图 |
[img:h9f2c…] |
原样 | 已是规范形式 |
[img:9f2c…:群友发的猫] |
[img:h9f2c…:群友发的猫] |
保留描述 |
[img:abc123] |
原样 | 插件图片 ID 不变 |
[img:user_avatar:123] |
[img:user_avatar:123] |
头像别名,不变 |
[img:https://…/i/9f2c…] |
[img:h9f2c…] |
工具输出里的绝对地址 |
- 不重写已持久化上下文:旧上下文里的
[img:<sha>]不迁移,靠解析器兼容。 - 只有“工具结果进入上下文”这一处会改写为
h<sha>;用户输入、助手回复、历史消息不改写。
2.3 谁必须遵守¶
- 插件内置工具、MCP 工具(含 image-host 后端):输出图片引用必须用
[img:<ref>];接受图片参数必须接受 CIR 的任意形态。 - 后端 image-host:
image_search输出[img:<sha>](现状不变,由插件规范化);image_keep/image_rename/image_tag接受id/ids[]里的 CIR /h<sha>/ 裸 sha / 插件 ref(见 §9)。
2.4 安全边界¶
- 用户原始文本仍走
stripUserTags,[img:]被转义为字面量,不能借用户输入引用任意图片。 context_edit_replace仍走stripUserTags(防止模型把可发送标签写进持久化上下文)。- 工具结果里的
[img:]是否可被解析,由“来源工具是否声明为图片引用生产者”决定(§3.5)。
3. 翻译层:ImageRefAdapter¶
3.1 位置与职责¶
新增 src/resource/image_ref.ts,是插件内的小模块(不是新服务、不加端口)。只做三件事:
- 工具输出 → 模型:把工具结果里的
[img:<sha>]规范化为[img:h<sha>],并注册虚拟图。 - 模型/工具 → Image:把任意 CIR 形态解析成
Image(插件图/图床图/头像)。 - Image → 模型内容:把引用变成模型可消费的
image_url(URL 或data:image/...;base64)。
[MCP/内置工具] --[img:<sha256>]--> normalizeText --> 上下文 [img:h<sha256>]
[模型] --[img:h<sha>] / 裸 sha / 旧 id--> resolveRef --> Image
[模型] --image_view([img:h<sha>])--> resolveRef --> image_url(多模态)或文字描述(降级)
3.2 接口契约¶
export interface ParsedRef {
kind: 'hosted' | 'plugin' | 'user_avatar' | 'group_avatar';
id: string; // hosted=sha256;plugin=imageId;avatar=uid/gid
description?: string; // 仅用于展示/发送
canonical: string; // [img:h<sha>] / [img:<pluginId>] / [img:avatar:...]
}
export function parseRef(raw: unknown): ParsedRef | null;
export function resolveRef(raw: unknown): Image | null;
export function normalizeText(text: string): { text: string; translated: number };
export async function toModelPart(image: Image, model?: { baseUrl?: string }):
Promise<{ type: 'image_url'; image_url: { url: string } } | null>;
resolveRef 解析顺序:
- 去空白,剥
[img:]/[avatar:]/[group_avatar:]包裹; - 剥
:描述; h+ 64hex / 64hex /{base}/i/<sha>→ hosted;user_avatar:/group_avatar:→ 头像;- 其它 →
Image.get(pluginId); - 失败返回
null。
3.3 四个统一接入点¶
| 边界 | 位置 | 改动 |
|---|---|---|
| 工具结果入上下文 | context.ts addToolCallbackMessage |
若来源工具是图片引用生产者,文本走 normalizeText(见 §3.5) |
| MCP 工具结果 | mcp.ts syncTools → tool.solve |
按服务器 imageRefs 决定是否 normalizeText;保留 contentParts |
| 请求组装 | message.ts resolveImageById / textToMultimodalContent |
改用 resolveRef + getModelSrc |
| 发送与工具入参 | message_segments.ts、context.ts findImage、tool_resolve_id.ts、special_id_params.ts、tool_image.ts、tool_raw.ts、tool_forum.ts、tool_meme.ts |
全部改用 resolveRef,不再各自 Image.get(id.split(':')[0]) |
3.4 虚拟图注册表¶
Image.hostedRefs: Map<string, { img: Image; at: number }>,LRU 上限 256、TTL 1 小时。- 虚拟图:
imageId = 'h' + sha256、hostedId = sha256、hostedUrl = '/i/' + sha256、virtualHosted = true、url = ''。 Image.save对虚拟图直接 return;ImageIndex.touch不调用;不写image_h<sha>存储键。imageToText成功后把description写回虚拟图缓存(仅内存),不落盘。Image.fromHostedId保留为兼容包装,内部走resolveRef。
3.5 工具结果规范化的信任门控¶
- MCP 服务器配置新增可选
"imageRefs": true(标准 mcpServers 扩展字段)。 - 启动器/生成器给 image-host 自动写
"imageRefs": true;旧配置回退按服务器名image-host判定。 - 只有这类服务器的工具结果会做
[img:<sha>] → [img:h<sha>]转换与注册;其它工具文本原样保留。 - 原因:工具结果属于外部数据,不能让任意网页/MCP 文本里的
[img:]自动变成可发送引用(提示注入面)。
3.6 明确不做:不自动把工具结果里的图片全部注入¶
image_search 一次可能返回 20 条;自动把每个 [img:] 变成 pixel 会带来 token/延迟/隐私成本。翻译层只做“引用标签规范化 + 注册”,真正看图由显式 image_view / image_to_text 触发(可审计、可控)。
4. 工具图片:来源元数据与类型标签(新增)¶
4.1 定义与分类¶
“工具返回图片”分四类,处理方式不同:
| 类型 | 例子 | 是否入库 | 来源(元数据) | 自动类型标签 |
|---|---|---|---|---|
| A. 工具新产出 | MCP image 内容块、text_to_image、meme_generator、工具返回 base64/data URL |
是(入图床,异步) | 工具调用所在的群/会话 + tool/server(必填) |
是(按产出工具确定性映射;上传同事务;默认开) |
| B. 工具返回已有图 | image_search、image_view、image_to_text、read_raw、pub_read |
否(已在图床) | 图片自身 ref 来源;另显示“本次调用群” |
否(不重复打标) |
| C. 上下文图片 | 收到消息里的 [img:<pluginId>] |
已在图床(或入库中) | 原 ref 来源;缺失时标“插件抓取(历史数据)” | 否 |
| D. 长期图库图 | WebUI 手动上传 / 收进图库 | 已在图床 | 显示“长期图库(人工上传)”,绝不写“未知” | 否 |
4.2 来源规则:只写元数据,永不写“未知”¶
A 类(新产出) 的来源由工具调用上下文生成,写入 ref 元数据:
interface ToolImageSource {
platform?: string; // QQ / DISCORD / ...
group_id?: string; // 群号;私聊为空
user_id?: string; // 触发者
session_id?: string;
message_id?: string; // 能拿到则填
at: number; // 时间
tool: string; // 工具名
server?: string; // MCP 服务器名
via: 'tool';
}
- 有群:
group_id必填,source显示为「QQ 群<群号>」。 - 私聊:
group_id=''、user_id必填,显示为「QQ 私聊<用户号>」。 - 无 ctx 的命令/定时任务:填
session_id,显示为「会话」。 - 全部为空时兜底
via='tool',显示为「工具调用(会话未记录)」——仍是明确元数据,不出现“未知”。 - 以上来源信息全部是元数据(
ref.source),不生成任何标签。
B 类(已有图) 的来源显示:
- 有 ref 来源:按原来源显示(平台/群/用户/时间)。
origin=manual且无 ref 来源:显示「长期图库(人工上传)」。origin=plugin且无 ref 来源:显示「插件抓取(历史数据)」。- 结果行额外带「本次调用:群<群号>」或「本次调用:私聊」,来自工具调用上下文,仅展示、不写标签。
C/D 类:与 B 相同,来源字段永远有值。
4.3 元数据与标签的边界¶
4.3.1 什么写元数据,什么写标签¶
| 信息 | 存储位置 | 查询方式 | 是否写标签 |
|---|---|---|---|
| 图库/抓取(信任) | blob.origin(manual/plugin) |
scope=gallery/plugin/all |
否 |
| 平台/群/用户/会话/消息/时间 | ref 的来源列 |
platform / group_id 过滤 |
否 |
| 产出工具 / MCP 服务器 | ref.tool / ref.server |
tool / server 过滤 |
否 |
| 格式 / 大小 / 创建时间 / 最后访问 | blob 列 |
排序/展示 | 否 |
| 产出类型(生成图 / 表情包 / MCP 图 / 工具图) | tag 表(自动类型标签) |
tags[] 过滤 |
是(英文类型标签) |
| 用户/AI 内容标签 | tag 表 |
tags[] 过滤 |
是(语言不限) |
规则:来源/群/工具/服务器/时间/文件名等“来源类”信息只写元数据,不写标签。 上一版的 来源: / 群: / 工具: / MCP: / 类型: 标签全部取消。
4.3.2 自动类型标签(确定性映射,不走识图)¶
自动标签只对工具产出的新图片生效,按“谁产出的”直接映射,不调用 image-understanding / 视觉模型,不根据图片内容猜测:
| 产出者 | 自动标签 |
|---|---|
text_to_image / 生图任务 |
ai-generated |
meme_generator |
meme |
MCP image 内容块(任意服务器) |
mcp-image |
| 其它工具返回 base64/data URL、无法识别产出者 | tool-image |
| 收到消息里的图片(插件抓取,非工具产出) | 不打标 |
image_search / image_view / image_to_text / read_raw 等返回的已有图 |
不打标 |
规则:
- 英文小写 kebab-case(
ai-generated/meme/mcp-image/tool-image);不用中文。 - 每图最多 2 个自动类型标签;单标签长度 ≤ 32。
- 幂等:
INSERT OR IGNORE;重复入库不重复写。 - 不写来源/群/用户/工具名/服务器名/时间/文件名/格式/信任等元数据。
- 与手动内容标签共存;用户可在 WebUI 删除。
- 零额外模型调用、零额外网络请求(映射在代码里完成)。
- 配置见 §4.6。
4.3.3 写入时机¶
| 对象 | 时机 | 方式 |
|---|---|---|
| A 类新产出 | 入库同事务 | POST /api/upload 的可选 tags 只放类型标签;来源元数据通过 source / tool / server 字段传 |
| B/C/D 类 | — | 不自动写标签;需要内容标签时由 AI 显式 image_tag 或用户在 WebUI 维护 |
4.4 工具图片入库流程(A 类)¶
工具产出图片字节/URL
→ 创建/补全 Image(sourceMeta = ToolImageSource;producer = text_to_image / meme_generator / mcp)
→ 按 producer 映射出 1–2 个英文类型标签(不调模型)
→ Image.adoptBase64ToHost() / captureToHost()
→ POST /api/upload { base64|url, ref, source, tags }
→ 后端同事务写 blob(origin) + ref(source, tool, server, via) + tag(类型标签)
→ 插件记录 hostedId/hostedUrl(不再保留 base64)
ref表新增tool/server/via列;迁移user_version 3(只追加)。tags只允许类型/内容标签;后端对来源:/群:/工具:/MCP:/类型:前缀或不含语义的元数据式标签直接过滤。- 现有
sourceInfo()只带 session/raw_url;需要补group_id/user_id/platform/tool/server。 - 生图/表情包:在工具提交时把
ToolImageSource与 producer 类型存进MediaTask,落地时按映射写标签,再入库。 - MCP image block:在
normalizeMCPResult时带上工具调用 ctx 与服务器名,入库时写 source +mcp-image标签;不把服务器名/工具名写成标签。
4.5 工具结果文本格式¶
image_search 每行:
<id> | [图库·可信] | 名称 | 标签:ai-generated,cat | 来源: 长期图库(人工上传) | 工具: - | 本次调用: 群<群号> | /i/<id> | [img:<id>]
<id> | [抓取·待验证] | 名称 | 标签:meme | 来源: QQ 群<群号> 用户<用户号> | 工具: image_search | 本次调用: 群<群号> | /i/<id> | [img:<id>]
- 来源/工具/本次调用是元数据,不是标签;标签只显示类型/内容(自动类型标签为英文)。
- 来源字段不允许为空/
-/“未知”;至少是三类明确元数据之一。 本次调用:群<群号>由插件在 MCP 结果后追加(或后端在结果里带,见 §9);仅用于让 AI 知道“这张图是在哪个群被工具拿到的”,不写成标签。
4.6 配置项¶
| 配置 | 分组 | 默认 | 说明 |
|---|---|---|---|
工具产出图片自动类型标签 |
图片 | 开 | A 类新产出图片按产出工具自动打英文类型标签(ai-generated / meme / mcp-image / tool-image) |
自动类型标签每图上限 |
图片 | 2 | 自动类型标签总数上限(1–4) |
自动类型标签是确定性映射,不调用识图/视觉模型、不产生额外请求;失败不影响图片使用;日志 tag
[image-tag]。
5. 看图与批量能力(新增)¶
5.1 image_view(默认注册)¶
{
"name": "image_view",
"description": "直接查看图片内容(把图片交给当前多模态模型)。id 支持标准图片引用 [img:<ref>]、图床托管 ID h<sha256>、裸 sha256、插件图片 ID。支持批量 ids(默认最多 4 张),当前聊天模型不支持视觉时自动降级为文字描述。注意:最终回复里写 [img:<ref>] 是发给用户,不是自己看图;要看图必须调用本工具。",
"parameters": {
"type": "object",
"properties": {
"id": { "type": "string", "description": "单张图片引用" },
"ids": { "type": "array", "items": { "type": "string" }, "maxItems": 4, "description": "批量图片引用(与 id 二选一,最多 4 张)" },
"detail": { "type": "string", "description": "可选:想看图中的什么细节" }
},
"additionalProperties": false
}
}
行为:
- 逐个
resolveRef;失败项在文本里列出,不拖垮整批。 - 若
Model.getChatModel('chat')?.isMultimodal:对每张图toModelPart;成功则返回contentParts(≤4 个 image part)+ 文本摘要;超过单张/总量上限的图跳过并提示。 - 非多模态或取图失败:降级
imageToText(批量上限 3 张),返回文字描述。 - 文本摘要每行只给
[img:<canonical>];来源/标签以image_search结果为准(image_view不额外查后端,避免每次看图多一次请求),不返回大段 base64。
上限(常量,可后续配置化):
| 项 | 默认 | 说明 |
|---|---|---|
IMAGE_VIEW_MAX_IMAGES |
4 | 单次最多看几张 |
IMAGE_VIEW_INLINE_MAX_MB |
4 | 单张内联 base64 上限;超过跳过 |
IMAGE_VIEW_TOTAL_MB |
12 | 单次内联总量上限 |
IMAGE_VIEW_MAX_DESCRIBE |
3 | 非多模态降级时最多描述几张 |
5.2 image_to_text(改造)¶
- 入参:
id?/ids?[](二选一,最多 3 张)、content?(关注点)。 - 接受 CIR 任意形态(含
[img:<ref>]/:描述)。 - 逐张调用识图模型,返回:
- 单张行为与 4.27.0 完全一致;
ids[]是新增能力。 - 失败项明确写“识别失败/未找到”,不静默丢图。
5.3 批量查看¶
- 多模态模型:
image_view(ids=[…≤4])→ 一次拿到 ≤4 张图。 - 非多模态模型:
image_view自动降级image_to_text(≤3 张)或 AI 自己多次image_to_text。 - 先搜后看:
image_search支持limit≤ 50 /offset分页;AI 先筛出候选 id,再image_view(ids)。 - 提示词规则:超过 4 张要分批;不要把 20 张图一次性塞进一次
image_view。
5.4 批量处理¶
| 工具 | 参数 | 上限 | 说明 |
|---|---|---|---|
image_keep |
id? / ids?[] |
50 | 收进长期图库(origin: plugin → manual),幂等 |
image_unkeep |
id? / ids?[] |
50 | 新增:移出长期图库(manual → plugin),可逆;与 WebUI 的「移出图库」一致 |
image_tag |
id? / ids?[] + add?[] / remove?[] |
50 ids / 10 tags | 批量增删标签,幂等 |
image_rename |
id + name |
1 | 单张(批量同名无意义,维持现设计) |
image_search |
limit ≤ 50 |
50/页 | 分页 |
~~image_delete~~ |
— | — | 不做:删除只留给人(WebUI) |
批量规则:
- 单批 > 10 张时,提示词要求 AI 先向用户确认(避免误操作大量图片)。
- 返回必须带
affected、failed、changed_ids;部分失败不整批报错。 - 批量操作前建议先
image_search核对来源/标签;image_keep只对plugin生效,已是manual的幂等跳过。 - 不提供 AI 批量删除/批量重命名/批量移出后清空等危险动作。
5.5 上限汇总¶
| 能力 | 默认上限 | 备注 |
|---|---|---|
image_view 单次张数 |
4 | 超出提示分批 |
image_view 单张内联 |
4 MB | 超出跳过 |
image_view 单次内联总量 |
12 MB | 超出跳过 |
image_to_text 单次张数 |
3 | 每张一次识图调用 |
image_keep/unkeep/tag ids |
50 | 后端 MCP 侧硬限制 |
image_search limit |
50 | 分页 |
| 自动类型标签/图 | 2 | 按产出者映射(ai-generated/meme/mcp-image/tool-image) |
| AI 删除 | 0 | 不提供 |
5.6 提示词工程模式(PE)¶
message.ts 的 PE 分支当前丢弃工具结果 contentParts,导致 image_view 与其它 MCP 图片在 PE 模式下看不到图。改为:
role=tool且有contentParts且当前模型是多模态 → 返回{ role:'user', content: [textPart, ...imageParts] };- 无图片/非多模态 → 保持现有纯文本输出。
- 非 PE 模式路径不变(已支持 contentParts)。
5.7 降级与失败¶
| 场景 | 行为 |
|---|---|
| 引用解析失败 | 文本列出失败项,其余继续 |
| 单张取图失败 | 跳过该张,文本说明原因;不整批失败 |
| 非多模态模型 | 自动降级文字描述 |
| 图片超过内联上限 | 跳过并提示用 image_to_text |
| 图床 404 | 文本“图片已删除”,不重试 |
| 图床不可达 | 文本“图床不可达”,本轮降级,下轮可重试 |
6. 提示词定稿¶
6.1 MCP 后端工具描述¶
image_search
搜索私人图库。
scope=gallery(默认)只搜长期图库:人工上传或确认收藏的图片,来源可信、不会被自动清理,可直接使用。scope=plugin搜插件自动抓取的图片:来源混杂(群聊/私聊/来源可能未记录),未经确认,使用、发送或收藏前必须核对来源、名称与标签;涉及他人隐私或用途不明确时先询问用户。scope=all两者都搜。 结果每行带[图库·可信]/[抓取·待验证]、来源(平台/群/用户/时间)、工具/服务器、本次调用群、类型/内容标签和[img:<id>]。来源/信任/工具/服务器是元数据,用scope/platform/group_id/tool/server过滤;tags表示图片类型/内容(自动类型标签为英文)。[img:<id>]是标准图片引用,可直接写进回复发送,也可传给看图工具。limit≤ 50,可offset分页。
image_keep
把图片收进长期图库(
origin → manual),此后不会被自动清理。只对插件自动抓取的图有意义。请先核对来源与用途,确认适宜后再收藏;单次最多 50 张。参数id或ids[],也接受标准图片引用[img:<ref>]/h<sha>。
image_unkeep
把图片移出长期图库(
manual → plugin),之后重新进入自动淘汰候选。可逆操作;单次最多 50 张。参数id或ids[]。
image_tag
给图片增删内容标签(手动语义标签,语言不限),支持批量
ids[](≤50)与add[]/remove[](每组 ≤10 个)。自动类型标签(ai-generated/meme/mcp-image/tool-image)由系统维护,不要重复添加;不要写来源/群/工具/时间等元数据。幂等;返回真正变化的图片数与未找到项。
image_rename
给单张图片重命名(不支持批量同名)。
image_tags
列出长期图库的标签清单(按使用次数降序,支持关键字过滤与分页)。
6.2 插件系统提示词新增段(仅图床/MCP 启用时注入)¶
## 图片与图库
- 图片统一用 [img:<ref>] 引用(插件图片 ID、图床托管 ID h<sha256>、user_avatar:<ID>、group_avatar:<ID>)。
- 长期图库(origin=manual,image_search 默认 scope=gallery)的图片由人上传或确认收藏,来源可信、不会被自动清理,可直接用于回复/发送/以图生图。
- 插件自动抓取的图(origin=plugin)来源混杂(群聊/私聊/来源可能未记录),未经确认;使用、发送或收藏前必须核对来源、名称与标签;涉及他人隐私或用途不明确时先询问用户,不要擅自传播或收藏。
- 上下文里由用户/群消息带来的图片([img:插件ID])属于插件抓取,转发、外发或收藏前按同样规则处理。
- 工具返回图片的来源/群/工具/服务器是元数据,不是标签;检索时用 scope / group_id / tool / server 过滤来源,不要指望标签里出现群号或工具名。
- 工具产出的图片会自动打英文类型标签(ai-generated / meme / mcp-image / tool-image,按产出者映射,不调识图);标签用于类型/内容检索,不要把来源、群号、工具名、时间写进标签。
- 想把抓取的图升级为可信资产:确认后调用 image_keep(收进长期图库);移出用 image_unkeep。
- 在最终回复里写 [img:<ref>] 是发给用户;要自己查看图片内容,调用 image_view(多模态模型直接看,支持一次 ≤4 张)或 image_to_text(返回文字描述,支持一次 ≤3 张)。
- 批量处理:keep/unkeep/tag 单次 ≤50 张;超过 10 张先向用户确认;不要尝试删除图片(没有删除工具)。
6.3 内置工具描述¶
image_to_text:查看图片内容并返回文字描述;id 支持 CIR / 图床托管 ID / 插件图片 ID;支持ids[](≤3)。image_view:见 §5.1。resolve_special_id(type=image):支持 CIR,返回hosted_id、来源(元数据)、类型/内容标签。get_resource_path:只服务本地资源;图床引用请用image_view/[img:]发送(见 §8.4)。
7. 全量 img 标签覆盖矩阵¶
复核范围:
src/**/*.ts中所有[img:/avatar:/group_avatar:文本命中,以及所有Image.get(...)直接调用。真正需要改动的函数/分支约 20 处;其余属于生产端、展示端或安全边界,保持不动。
7.1 生产端(写入上下文/描述)——不改¶
| 位置 | 行为 | 结论 |
|---|---|---|
image.ts handleImageMessageSegment |
生成 [img:<pluginId>(:描述)] |
不动 |
raw_marker.ts buildImageTruncateMarker |
截断标记带 image_id |
不动;read_raw 用解析器兼容 |
| task_queue.ts、tool_meme.ts、mcp/result.ts | 生图/表情包/MCP 图片结果生成 [img:<pluginId>] |
不动 |
string.ts normalizeRenderTags |
旧 <|img:...|> 归一化 |
不动 |
| snapshot.ts | pub_read 快照保留 [img:] |
不动 |
string.ts stripUserTags |
用户输入 [img:] 转义 |
不动(安全边界) |
tool_context.ts sanitizeText |
上下文编辑替换文本转义 | 不动(安全边界) |
| tool_media_tasks.ts | 队列列表转义 [img:] |
不动 |
7.2 解析/发送端——统一改走 resolveRef¶
| 位置 | 现状 | 改动 |
|---|---|---|
string.ts parseSpecialTokens |
正则兼容 h<sha>:desc |
不改(只验证) |
string.ts transformContentToText |
findImage |
改走 resolveRef |
message_segments.ts textToSegments |
findImage + split(':') |
改走 resolveRef |
message.ts resolveImageById |
只 Image.get |
改走 resolveRef |
message.ts textToMultimodalContent |
已解析 Image | 改走 resolveRef + getModelSrc |
| special_id_params.ts | 只 Image.get |
改走 resolveRef;get_image 按 §8.4 |
| tool_resolve_id.ts | 只 Image.get |
改走 resolveRef,返回 hosted_id |
tool_image.ts image_to_text |
findImage 不剥标签 |
改走 resolveRef;支持 ids[] |
tool_image.ts resolveTtiImage |
已剥标签 | 改走 resolveRef + 模型可用地址 |
| tool_meme.ts | findImage |
改走 resolveRef |
| tool_meme.ts 上游参考图 | img.url \|\| img.path |
改走 getModelSrc,失败明确报错 |
tool_forum.ts extractImagesFromContent |
Image.get |
改走 resolveRef |
tool_forum.ts image_ids |
Image.get |
改走 resolveRef |
tool_raw.ts collectImageRawEntries / readImageById |
Image.get |
改走 resolveRef;虚拟图无原文时提示先识别 |
api.ts imageToText |
Image.get/URL |
改走 resolveRef |
| cmd/sub_cmd/image.ts | findImage |
不改(findImage 内部改) |
| tool_resource_path.ts | 只查本地资源 | 不改;图床引用明确 NOT_FOUND(文档说明) |
| tool_pub.ts | resolveSendMessage + 源会话 context |
不改(解析器改) |
7.3 解析器/发送/模型消费——新增或改造¶
| 位置 | 改动 |
|---|---|
新增 src/resource/image_ref.ts |
CIR 解析、规范化、虚拟图 LRU、resolveRef、toModelPart |
| image.ts | virtualHosted;Image.save/Index 跳过;getModelSrc;imageToText 可达性/回退;markUrlBrokenByUrls hosted-aware |
| image_host.ts | urlForModel(hostedId, modelBaseUrl);lastStatus;probeHosted(复用 b64 出口判断 404/不可达) |
context.ts findImage |
走 resolveRef |
| agent.ts 图片下载失败 | hosted 探测 + b64 重试 + 不误标 |
| mcp.ts | 按 imageRefs 规范化结果文本;保留 contentParts |
| templates.ts | 新增“图片与图库”段(条件注入) |
| 配置层 | mcpServers 增加 imageRefs;图片配置增加 §4.6 两项 |
image.ts getSendFile / ensureBytes |
保持现有语义,仅新增 getModelSrc 调用方 |
7.4 持久化/清理——小幅改动¶
| 位置 | 改动 |
|---|---|
image.ts Image.save |
虚拟图 no-op;不写 image_h<sha> |
| image_index.ts | 虚拟图不 touch |
| image_gc.ts | 不动(索引里只有插件图;虚拟图不进索引) |
validKeysMap |
不新增持久字段(模型内联标记只放内存) |
8. 网络、失败与边界行为¶
8.1 模型可达性¶
新增 Image.getModelSrc(model?: { baseUrl?: string }):
base64 → data:image/...;base64
hosted:
externalBase 为空 → fetchBase64 → data URL
externalBase 公网 → remoteUrl
externalBase 内网/回环:
模型 baseUrl 也是内网/回环 → remoteUrl
否则 → fetchBase64 → data URL
非 hosted URL → 现有逻辑(ensureBytes / 原始 URL)
头像 → qlogo URL
externalBase=image-host.publicUrl(非回环时)或非回环的url。- 模型端点分类:baseUrl 的 host 是字面量私网/回环 → 本机/内网模型;否则视为云模型。
- 协议端发送仍用
getSendFile()/publicUrl,不受getModelSrc影响。 - 可选配置
图床模型取图方式(自动/总是URL/总是base64),默认自动;先不强制实现。
8.2 urlBroken 自愈¶
- 模型报“无法下载图片”时:
- 对 hosted URL:
fetchBase64(id)探测; - 200 → 图片存在,设置本轮/该图
inlineForModel,用 b64 重试一次,不标urlBroken; - HTTP 404 → 真删除,标
urlBroken; - 网络错误/图床不可达 → 不标坏,下一轮再试。
- hosted 图的
urlBroken可恢复:探测 200 且 b64 成功后清除。 markUrlBrokenByUrls只处理非 hosted URL;hosted URL 走新的markHostedDownloadFailures。
8.3 回退链¶
textToMultimodalContent/imageToText不再在“图床取不到字节”时直接留文本。imageToText的urlBroken早退只对“确认已删”生效。
8.4 get_image 对图床引用(决策 A)¶
get_image的file传 hosted 引用([img:h<sha>]/ 裸 sha)时:- 返回
INVALID_FILE,提示:“图床图片没有协议端缓存文件;请直接用 URL 或[img:<ref>]发送;需要字节请用image_view/image_to_text//i/<id>/b64”。 - 不下载、不落本地文件。
- 插件 ID 的
get_image行为保持现状。 resolve_special_id(type=image)对 hosted 引用返回hosted_id、内部 URL、来源(元数据)/类型/内容标签摘要,供 AI 判断。
9. 后端(image-host)改动¶
9.1 MCP 工具¶
| 改动 | 内容 |
|---|---|
image_search |
since 真正实现;多标签 AND;platform/group_id/tool/server 下推 SQL 并修正 total/offset;输出 origin(元数据)+ 来源(不写“未知”)+ 工具/服务器 + 本次调用群 + 类型/内容标签;limit ≤ 50 |
image_keep |
支持 ref(插件 imageId)与 CIR;ids 上限 50;返回 changed_ids / skipped / failed;截断要提示 |
image_unkeep |
新增:manual → plugin,可逆,ids ≤ 50 |
image_tag |
只接受类型/内容标签;自动类型标签仅由系统写入;拒绝 来源:/群:/工具:/MCP:/类型: 等元数据式标签;上报 failed/not_found;affected 按图片数而非行数;add+remove 不重复计;字符串参数按单值处理;上限 50/10 |
image_rename |
id 格式/名称长度校验;回收站图是否允许改名明确(建议否) |
image_tags |
统计类型/内容标签;与 gallery 口径一致;默认只统计长期图库(或显式标注包含两类) |
| 传输 | tools/call 参数错误返回 isError;inputSchema 运行时校验;unknown tool 用 -32602;文档头改成 6 工具(含 unkeep) |
| 文档 | mcp.py docstring、backend.json 描述、docs/16 §5.11 同步 |
9.2 REST / 数据¶
| 接口/表 | 改动 |
|---|---|
POST /api/upload |
增加可选 tags(只允许类型/内容标签);source 增加 tool / server / via;同事务写 blob(origin) + ref(source,tool,server,via) + tag(类型标签) |
ref 表 |
新增 tool TEXT、server TEXT、via TEXT;迁移 PRAGMA user_version = 3(只追加列) |
POST /api/batch |
支持 AI 手动补内容标签(已有 action=tag);单次上限 50 张 |
image_search 输出 |
来源/工具/类型均为元数据且永远有值:有 ref 显示原来源;无 ref 按 origin 显示「长期图库(人工上传)」/「插件抓取(历史数据)」 |
| WebUI | 标签视图显示类型/内容标签;来源/工具/类型作为卡片元数据展示;不新增页面 |
9.3 自动类型标签写入¶
- 只对 A 类新产出:upload 同事务写入
tags,按产出者映射: text_to_image/ 生图任务 →ai-generatedmeme_generator→meme- MCP
image内容块 →mcp-image - 其它工具 base64/data URL →
tool-image - B/C/D 类不自动写标签。
- 后端过滤元数据式标签:以
来源:/群:/工具:/MCP:/类型:开头,或纯群号/工具名/时间/文件名的标签,一律拒绝。 - 不调用识图/视觉模型;零额外模型调用、零额外请求。
10. 安全与“不影响正常行为”¶
10.1 硬约束¶
- 图床未配置时全链路零变化:无 hosted 引用、无 b64 差异、无额外网络请求;提示词段不注入。
- 不重写已持久化上下文:只对新的工具结果做规范化;旧
[img:<sha>]靠解析器兼容。 - 不改变插件图片 ID 语义:生成、解析、发送、清理保持。
- 不改安全边界:用户输入仍转义;
context_edit_replace仍stripUserTags;pub_send仍净化;媒体队列仍转义显示。 - 工具结果规范化只对
imageRefs服务器:其他工具文本原样,不扩大提示注入面。 - 虚拟图不落盘/不进索引:
Image.save/ImageIndex跳过,GC 行为不变。 - 模型 URL/b64 选择只影响“模型/上游”:协议端发送仍用
getSendFile。 - PE 修复只影响带 contentParts 的多模态工具结果:无图片时输出与现在一致。
- 自动类型标签写入失败不阻断主流程:只记日志,图片照常使用(映射在代码内完成,通常不会失败)。
- AI 仍不能删除图片:删除只在 WebUI。
- 新增
image_view会让工具清单多一项(预期增量,属于本次实现的一部分);已有工具的名称、描述与行为不变。 - 标签不与元数据重复:来源/群/工具/服务器/类型/信任只写元数据;标签只做类型/内容语义(自动类型标签英文,手动标签语言不限)。
- 自动类型标签零模型调用:只按产出者确定性映射,不调用识图/视觉模型,不根据图片内容猜测。
10.2 回归清单¶
| # | 场景 | 期望 |
|---|---|---|
| 1 | 未配图床 | 既有单测全过;无额外 fetch |
| 2 | 插件图片 ID(发送/识图/read_raw/resolve_special_id/get_image) | 与 4.27.0 一致 |
| 3 | 用户输入 [img:...] |
仍被转义,不可发送 |
| 4 | context_edit_replace 写入 [img:sha] |
仍被转义 |
| 5 | pub_send 非 QQ |
仍剥标签 |
| 6 | media_tasks 列表 |
仍不显示可解析标签 |
| 7 | 旧 <|img:...|> 上下文 |
仍归一化并可发送 |
| 8 | 图床公网 publicUrl |
仍用 URL,不额外取 b64 |
| 9 | 图床回环 + 无 publicUrl |
仍用 b64 |
| 10 | 云模型 + 内网 publicUrl |
改用 b64,不产生 urlBroken |
| 11 | 图床删图 404 | 标坏一次,之后不再请求 |
| 12 | 图床宕机 | 不标坏,恢复后可用 |
| 13 | PE 模式 + MCP 图片 | 能看到图;无图时输出一致 |
| 14 | 工具图片入库 | 有 source 元数据、无元数据式标签、自动类型标签为英文(ai-generated/meme/mcp-image/tool-image)、无“未知” |
| 15 | image_view 批量 4 张 |
返回 ≤4 个 image part;超限提示 |
| 16 | image_tag/keep/unkeep 批量 |
部分失败不整批失败;affected 准确 |
| 17 | 标签内容 | 不出现群号/工具名/来源前缀;自动类型标签为英文 kebab-case;不调用识图模型 |
11. 逐文件改动清单¶
11.1 插件¶
| 文件 | 改动 |
|---|---|
src/resource/image_ref.ts |
新增:CIR 解析、规范化、虚拟图 LRU、resolveRef、toModelPart |
| image.ts | virtualHosted;save/index 跳过;getModelSrc;imageToText 可达性/回退;markUrlBrokenByUrls hosted-aware;fromHostedId 走 LRU |
| image_host.ts | urlForModel;lastStatus;probeHosted;uploadByUrl/uploadBase64 支持 tags |
| context.ts | findImage 走 resolveRef;工具结果规范化入口 |
| message.ts | 多模态解析走 resolveRef;getModelSrc;PE 模式保留 contentParts |
| string.ts | transformContentToText 走 resolveRef(解析器不改) |
| message_segments.ts | textToSegments 走 resolveRef |
| special_id_params.ts | 走 resolveRef;get_image 决策 A |
| tool_resolve_id.ts | 走 resolveRef;返回 hosted_id |
| tool_image.ts | image_to_text 支持 CIR/ids[];新增 image_view;TTI 参考图走 getModelSrc |
| tool_meme.ts | image_ids 走 resolveRef;上游参考图走 getModelSrc;入库 source 元数据 + 类型标签(meme) |
| tool_forum.ts | 两处 Image.get → resolveRef;image_ids 支持 CIR |
| tool_raw.ts | 两处 Image.get → resolveRef |
| api.ts | imageToText 走 resolveRef |
| mcp.ts | 按 imageRefs 规范化;返回图类型标签(mcp-image/tool-image)与调用上下文元数据 |
| mcp/result.ts | MCP image block 入库(source 元数据 + mcp-image 类型标签) |
| agent.ts | 图片下载失败 hosted-aware;handleMessages 传 model |
| templates.ts | “图片与图库”提示词段 |
| media/task_queue.ts | 生图落库带 source 元数据 + 类型标签(ai-generated) |
| 配置层 | imageRefs;§4.6 两项;get_image/批量相关常量 |
scripts/unit-test-image-host.ts、scripts/unit-test-entry.ts |
新增 §12 用例 |
11.2 后端(aiplugin4-backends-shop/backends/image-host/)¶
| 文件 | 改动 |
|---|---|
mcp.py |
6 工具(新增 unkeep)、CIR/ref 入参、信任/来源/调用群、since/多标签/SQL 过滤、tag 计数、keep 报告、isError、参数校验、文档头 |
store.py |
搜索 total/SQL、tag 计数、回收站一致性、resolve_refs、ref tool/server/via、类型/内容标签入库 |
imagehost.py |
/api/upload 接收 tags(类型/内容)/source.tool/server/via;过滤元数据式标签;错误码 |
backend.json |
描述改 6 工具 |
tests/ |
补 keep/unkeep/rename/tag/search/MCP/CIR/自动类型标签用例 |
11.3 文档 / 生成器 / 启动器¶
- 本文(17);
docs/README.md导航;docs-site收录与 nav。 docs/16增加“AI 引用/看图/工具图片”交叉引用。docs/04工具表增加image_view;docs/05配置表增加 §4.6 两项;docs/16MCP 工具表增加image_unkeep并更新为 6 工具。aiplugin4-configMCP 默认给 image-host 加"imageRefs": true。- 启动器复制 MCP 配置时给 image-host 写
imageRefs。
12. 测试¶
12.1 插件单测¶
parseRef矩阵:[img:sha]、h<sha>、[img:sha:desc]、全角、/i/<sha>、插件 ID、头像、非法。normalizeText:sha → h;插件 ID 不动;非imageRefs工具不调用。- 虚拟图:重复解析复用;不写 storage、不进 index;LRU 淘汰。
- 解析器覆盖:
findImage、resolveImageById、textToSegments、resolve_special_id、get_image、image_to_text、image_ids、read_raw、agent API。 image_view:多模态 contentPart(1/4 张)、非多模态描述、回环 b64、404、超限。image_to_text:单张旧行为不变;ids[]批量与失败项。textToMultimodalContent用户消息含[img:h<sha>]。- PE 模式:tool contentParts → user image part。
- 可达性:公网/内网/回环 × 模型公网/本机 四种组合。
- 降级:hosted 200 → 不标坏 + b64 重试;404 → 标坏;网络失败 → 不标坏;恢复。
- 工具图片:A 类入库带 source 元数据 + 英文类型标签(ai-generated/meme/mcp-image/tool-image);B 类不自动写标签;标签不含元数据;来源文本无“未知”。
- 标签校验:自动类型标签为英文 kebab-case;拒绝元数据式前缀与纯群号;自动路径不调用识图模型。
- 批量:keep/unkeep/tag 的 50 上限、部分失败、affected。
- 安全:用户输入/context_edit/pub_send/media 列表不变。
- 非图床路径 golden:与 4.27.0 输出一致。
12.2 后端单测¶
- 自动类型标签(producer 映射、无元数据)入库幂等/上限;ref
tool/server/via;image_search来源永不空;since;多标签;平台/群/tool 分页;tag failed/affected;keep/unkeep;CIR/ref 入参;isError。 - 回归:上传/去重/引用计数/cap/manual 保护/回收站/变更日志。
12.3 集成¶
- 真图床:工具返回图片入库 → 来源=当前群(元数据)、标签为
ai-generated→image_search可见 →image_view(ids=[…])一次看 4 张 → 回复[img:h<sha>]发送。 - 长期图库图
image_search(scope=gallery)→ 来源显示「长期图库(人工上传)」→image_keep幂等。 - 删除图床图片 → 插件对账标坏;不重复请求。
- 图床停掉 → 发送/识图降级不报错。
- 同一张图两条 ref:keep 一条不影响另一条。
12.4 验收标准¶
- 既有单测 + 新增测试全绿。
grep复核:不存在未走resolveRef的图片解析入口。- 未配图床实例逐场景对比无差异。
- 工具返回图片结果里不再出现“未知/空来源”。
image_view批量与image_keep/tag/unkeep上限生效。
13. 分期¶
| 阶段 | 内容 | 依赖 |
|---|---|---|
| A | CIR + resolveRef + 虚拟图 + 全量解析点接入 |
无 |
| B | 工具图片入库/来源元数据/英文类型标签(producer 映射,不调识图) | A |
| C | image_view / image_to_text 批量 + PE contentParts 修复 |
A |
| D | 可达性 + urlBroken 自愈 + 回退链 |
A |
| E | 后端 MCP 6 工具/搜索/tag/keep/unkeep/CIR | B |
| F | 提示词、配置、文档、生成器/启动器同步 | B/C/E |
| G | 全量测试与回归 | 全部 |
14. 未决与后续¶
图床模型取图方式是否需要暴露为用户配置(自动/总是URL/总是base64)?默认自动;可后置。image_tags是否只统计长期图库,还是显式分成两组(gallery/plugin)?建议先统一为 gallery 口径并标注。- 自动类型标签的映射表是否覆盖全部产出工具(目前 4 类);新增产出工具时需同步扩展映射。
- 是否给“收到消息图片”也打
chat-image类型标签?当前不打,避免与插件抓取元数据重复。 - 是否给
image_search增加id精确查询(便于验证单张图来源/标签)?可作为 P2。 - 本文与
16的分工:16 管存储/引用/清理;17 管 AI 引用、看图、工具图来源元数据/英文类型标签、批量交互。
15. 实现状态(4.28.0 / image-host 1.0.15)¶
| 项 | 状态 |
|---|---|
CIR v1 解析/规范化 + Image.resolveRef + 虚拟图内存 LRU(不落 storage/索引) |
✅ |
工具结果规范化(仅 imageRefs / image-host MCP);其它工具文本不动 |
✅ |
image_view(默认注册,id/ids[]≤4,多模态 contentParts,非多模态/失败降级描述,内联 4MB/张、12MB/次) |
✅ |
image_to_text(id/ids[]≤3,CIR,逐张失败可报告) |
✅ |
get_image 对图床引用明确报错(决策 A) |
✅ |
resolve_special_id(type=image) 返回 hosted_id / hosted_url |
✅ |
| 工具产出来源元数据(source/tool/server/via;生成图/表情包/MCP image block) | ✅ |
工具产出图片英文类型标签(ai-generated / meme / mcp-image / tool-image,确定性映射、不调识图) |
✅ |
模型可达性(内网 publicUrl + 云模型走 b64)与 urlBroken 404/够不到区分、b64 重试 |
✅ |
| PE 模式保留工具结果 image contentParts | ✅ |
| image-host:ref tool/server/via、upload tags/source、MCP 6 工具(search/keep/unkeep/rename/tag/tags)、搜索 SQL 过滤/total/since/多标签、tag 计数与元数据标签拒绝 | ✅ |
启动器「复制 MCP 配置」/ 生成器为 image-host 写 imageRefs: true |
✅ |
| 文档/提示词/工具描述同步 | ✅ |
已知差异/后续(不影响本次实现验收):
image_view超过 4 张直接返回“请分批”,不静默截断。- 只有工具产出的图片自动打类型标签;
image_search等返回的已有图不自动改标签(避免读放大/污染图库)。 image_tags默认 gallery 口径;REST/api/tags默认全部来源以兼容 WebUI。- REST
/api/batch仍保留 500 ids 上限(50 上限在 MCP 工具侧),WebUI 不受影响。 get_resource_path仍只服务本地资源;图床引用请用image_view/image_to_text/[img:]发送。- 后端 57 个 Python 单测 + 插件 483 个单测通过;另用临时 image-host 1.0.15 服务跑过 upload(tags/source) → MCP 6 工具 → search/keep/unkeep/tag/rename 契约 E2E(未做浏览器视觉 E2E)。