GPU_GUARD_MONOREPO/docs/superpowers/specs/2026-05-02-image-generation-tools-design.md

483 lines
18 KiB
Markdown
Raw Normal View History

2026-05-20 21:39:12 +08:00
# 文生图与图生图工具设计
> 日期2026-05-02
> 状态:待实施
> 范围:后端工具层、图片 Provider 层、前端工具渲染、Prompt Builder
## 1. 背景与目标
系统已在模型渠道中配置了火山引擎和 MiniMax 的图片生成模型。需要在 Agent 对话中提供文生图和图生图能力,主要面向电商场景(产品主图、详情图、文章配图),并支持配置专用电商套图 Agent 一次性生成成套图片。
### 目标
- 新增 `text_to_image``image_to_image` 两个独立工具
- 建立可扩展的图片生成 Provider 层,当前支持火山引擎和 MiniMax未来可扩展其他渠道
- 扩展 `ToolResultContent` 支持多图返回
- 前端 tool-card 支持单图/多图渲染
- 生成图片转存本地,解决 Provider 临时 URL 过期问题
- Prompt Builder 根据可用工具动态生成附件提示语
### 不做
- 不改造 LLM Provider 层(图片生成走独立工具,不走 chat completions
- 不新增附件上传能力(现有机制已满足图生图的参考图传递)
- 不做图片编辑器 UI生成结果在 tool-card 内渲染和预览)
## 2. 架构总览
```
packages/backend/src/modules/netaclaw/
├── image_providers/ # 新增:图片生成 Provider 层
│ ├── types.ts # 统一接口、凭证、错误类型、工厂函数
│ ├── ark.ts # 火山引擎OpenAI SDK images.generate
│ └── minimax.ts # MiniMax自有 REST API
├── tools/
│ ├── common.ts # 修改:新增 images 类型
│ ├── catalog.ts # 修改:注册两个新工具
│ └── builtin/
│ ├── text_to_image.ts # 新增:文生图工具
│ └── image_to_image.ts # 新增:图生图工具
├── service/
│ ├── tool_resolver.ts # 修改:注入凭证和 provider
│ └── image_storage.ts # 新增:图片转存本地服务
└── runtime/
└── prompt_builder.ts # 修改:附件提示语扩展
packages/frontend/src/modules/agent/
├── tools/renderer-registry.ts # 修改rawResult 新增 images 类型
└── components/tool-card.vue # 修改:单图/多图渲染
```
## 3. Provider 层
### 3.1 统一接口
```typescript
// image_providers/types.ts
export interface ImageProviderCredentials {
baseUrl: string;
apiKey: string;
supplier: string;
modelId: string;
promptHint: string | null;
extra?: ToolGovernanceExtra | null;
}
export interface TextToImageParams {
prompt: string;
width?: number;
height?: number;
aspectRatio?: string;
n?: number;
responseFormat?: 'url' | 'base64';
watermark?: boolean;
seed?: number;
extra?: Record<string, unknown>;
}
export interface ImageToImageParams extends TextToImageParams {
referenceImage: string;
strength?: number;
}
export interface ImageGenerationResult {
images: { url?: string; base64?: string; width?: number; height?: number }[];
model: string;
provider: string;
}
export interface ImageGenerationProvider {
readonly id: string;
textToImage(params: TextToImageParams, creds: ImageProviderCredentials): Promise<ImageGenerationResult>;
imageToImage(params: ImageToImageParams, creds: ImageProviderCredentials): Promise<ImageGenerationResult>;
}
export class ImageGenerationError extends Error {
constructor(
message: string,
public readonly code: 'content_safety' | 'rate_limit' | 'insufficient_balance' |
'invalid_params' | 'timeout' | 'network' | 'unknown',
public readonly retryable: boolean,
) {
super(message);
}
}
```
### 3.2 Provider 路由
supplier + baseUrl 联合路由,解决火山引擎 supplier 可能配为 "OpenAI" 的问题:
```typescript
export function getImageProvider(supplier: string, baseUrl: string): ImageGenerationProvider | null {
const s = supplier.toLowerCase();
if (s === 'minimax') return providers.get('minimax')!;
if (s === 'ark' || s === 'volcengine') return providers.get('ark')!;
if (s === 'openai') {
if (baseUrl.includes('volces.com') || baseUrl.includes('volcengine')) return providers.get('ark')!;
if (baseUrl.includes('minimax')) return providers.get('minimax')!;
}
return null;
}
```
### 3.3 火山引擎实现 (ark.ts)
- 使用 OpenAI SDK `client.images.generate()`
- 尺寸通过 `size` 字段传递(如 `"1024x1024"``"2K"`
- 图生图通过 `extra_body.image` 传参考图
- 特有参数watermark 等)通过 `extra_body` 透传
- 60 秒超时保护
### 3.4 MiniMax 实现 (minimax.ts)
- 使用自有 REST API `POST {baseUrl}/v1/image_generation`
- 尺寸通过 `aspect_ratio``width + height` 传递
- 图生图通过 `subject_reference` 字段传参考图
- 特有参数:`style`(画风)、`prompt_optimizer`prompt 优化)通过 `extra` 透传
- 响应从 `data.image_urls[]` 归一化到统一结构
- Bearer token 认证
- 60 秒超时保护
### 3.5 扩展新渠道
新增 Provider 只需:
1.`image_providers/` 下新建文件,实现 `ImageGenerationProvider` 接口
2. 在工厂函数 `getImageProvider` 中注册路由规则
## 4. 工具层
### 4.1 text_to_image
```typescript
// tools/builtin/text_to_image.ts
const Params = Type.Object({
prompt: Type.String({ description: '图片描述,尽量详细具体' }),
aspectRatio: Type.Optional(Type.String({
description: '宽高比。可选: 1:1, 16:9, 4:3, 3:2, 2:3, 3:4, 9:16',
})),
width: Type.Optional(Type.Integer({ description: '精确宽度(像素),优先级低于 aspectRatio' })),
height: Type.Optional(Type.Integer({ description: '精确高度(像素)' })),
n: Type.Optional(Type.Integer({ description: '生成数量,默认 1最大 9', minimum: 1, maximum: 9 })),
watermark: Type.Optional(Type.Boolean({ description: '是否添加水印' })),
seed: Type.Optional(Type.Integer({ description: '随机种子,相同 seed 可复现相近结果' })),
extra: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
description: 'Provider 特有参数,如 MiniMax 的 style、prompt_optimizer',
})),
});
registerSchema({
name: 'text_to_image',
toolset: 'vision',
description: '根据文字描述生成图片,支持指定尺寸、数量、风格等参数。',
capability: 'multimodal',
visibility: 'tool',
isCore: false,
canDisable: true,
supportsPromptHint: true,
requiresModel: true,
});
```
工具描述会拼接 `promptHint`,管理员可在后台配置行业特定的默认提示词。
### 4.2 image_to_image
```typescript
// tools/builtin/image_to_image.ts
const Params = Type.Object({
prompt: Type.String({ description: '对参考图的修改描述' }),
referenceImage: Type.String({ description: '参考图片 URL从用户上传附件获取' }),
strength: Type.Optional(Type.Number({
description: '参考图影响强度 0-1越大越接近原图', minimum: 0, maximum: 1,
})),
aspectRatio: Type.Optional(Type.String({ description: '宽高比' })),
width: Type.Optional(Type.Integer({ description: '精确宽度(像素)' })),
height: Type.Optional(Type.Integer({ description: '精确高度(像素)' })),
n: Type.Optional(Type.Integer({ description: '生成数量,默认 1最大 9', minimum: 1, maximum: 9 })),
watermark: Type.Optional(Type.Boolean({ description: '是否添加水印' })),
seed: Type.Optional(Type.Integer({ description: '随机种子' })),
extra: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
description: 'Provider 特有参数',
})),
});
registerSchema({
name: 'image_to_image',
toolset: 'vision',
description: '基于参考图片生成新图片支持风格迁移、内容编辑等。传入参考图URL和修改描述。',
capability: 'multimodal',
visibility: 'tool',
isCore: false,
canDisable: true,
supportsPromptHint: true,
requiresModel: true,
});
```
### 4.3 tool_resolver 集成
两个工具在 tool_resolver 中的注入逻辑与 `image_recognize` 对称:
1. 检查 `filteredNames` 是否包含工具名
2.`toolRegistry.getToolModelConfig()` 获取模型渠道配置
3.`modelChannelService.resolveForAgent()` 解析凭证
4. 通过 `getImageProvider(supplier, baseUrl)` 获取 provider 实例
5. 创建工具实例,注入 creds 和 provider
6. 未配置时写入 `disabledReasons`
两个工具可以绑定不同的模型渠道(如文生图用火山引擎,图生图用 MiniMax
## 5. 多图返回
### 5.1 后端类型扩展
```typescript
// tools/common.ts
export interface ImageItem {
url: string;
mimeType?: string;
width?: number;
height?: number;
seed?: number;
}
export type ToolResultContent =
| { type: 'text'; text: string }
| { type: 'json'; data: unknown }
| { type: 'image'; url: string; mimeType?: string; text?: string;
width?: number; height?: number; bytes?: number;
originalWidth?: number; originalHeight?: number;
originalBytes?: number; resized?: boolean; }
| { type: 'images'; images: ImageItem[]; text?: string };
export function imagesResult(images: ImageItem[], text?: string): ToolResultContent {
return { type: 'images', images, text };
}
```
### 5.2 toolResultToText 扩展
```typescript
if (value.type === 'images') {
const lines = value.images.map((img, i) =>
`[图${i + 1}] ${img.url}${img.width && img.height ? ` (${img.width}x${img.height})` : ''}`
);
const header = value.text || `已生成 ${value.images.length} 张图片`;
return `${header}\n${lines.join('\n')}`;
}
```
### 5.3 返回策略
- 单图n=1返回 `type: 'image'`,向后兼容
- 多图n>1返回 `type: 'images'`,前端网格渲染
## 6. 图片转存
### 6.1 问题
MiniMax URL 有效期 24 小时,火山引擎类似。历史会话中图片会失效。
### 6.2 方案
新增 `service/image_storage.ts`,工具 execute 完成后立即将临时 URL 下载并转存到本地存储:
```typescript
export class ImageStorageService {
async persist(tempUrl: string, metadata?: { toolName: string }): Promise<string> {
const response = await fetch(tempUrl);
const buffer = Buffer.from(await response.arrayBuffer());
const ext = this.detectExtension(response.headers.get('content-type'));
const filename = `${Date.now()}-${randomUUID().slice(0, 8)}${ext}`;
// 复用现有文件存储基础设施写入本地
return await this.fileService.saveBuffer(buffer, filename);
}
}
```
工具内部在 provider 返回后、构造 ToolResultContent 前执行转存session tree 中存储的是永久本地 URL。
## 7. 前端渲染
### 7.1 renderer-registry 扩展
`ToolRenderSource.rawResult` 新增 `images` 类型:
```typescript
rawResult?: {
type: 'text' | 'json' | 'image' | 'images';
// 现有字段...
images?: { url: string; mimeType?: string; width?: number; height?: number; seed?: number }[];
};
```
### 7.2 message-item.vue 渲染
当前 `message-item.vue` 已有 `rawResult.type === 'image'` 的单图渲染(`<img>` 标签)。需要:
- 将单图渲染升级为 `el-image`,支持点击预览大图
- 新增 `rawResult.type === 'images'` 分支CSS Grid 网格布局,`el-image` 预览列表联动
- 其他类型保持原有 `<pre>` 文本渲染
多图网格样式:`grid-template-columns: repeat(auto-fill, minmax(140px, 1fr))`,自适应列数。
## 8. Prompt Builder 扩展
### 8.1 改动
`buildLLMMessages` 新增 `toolNames` 参数,附件提示语根据 Agent 实际可用工具动态生成:
-`image_recognize` → 提示"如需分析图片内容,请使用 image_recognize 工具"
-`image_to_image` → 提示"如需基于图片生成新图片,请使用 image_to_image 工具,将图片 URL 作为 referenceImage 参数"
- 两者都有 → 两条提示都输出
避免提到 Agent 没有的工具。
## 9. 错误处理
Provider 层统一抛出 `ImageGenerationError`,包含错误码和是否可重试标记:
| 错误码 | 含义 | 可重试 | Agent 可见信息 |
|--------|------|--------|--------------|
| content_safety | 内容安全拦截 | 否 | "提示词触发内容安全策略,请调整描述" |
| rate_limit | 限流 | 是 | "当前请求过多,请稍后重试" |
| insufficient_balance | 余额不足 | 否 | "模型渠道余额不足" |
| invalid_params | 参数错误 | 否 | 具体参数错误信息 |
| timeout | 超时60s | 是 | "生成超时,可尝试降低图片尺寸" |
| network | 网络错误 | 是 | "网络连接失败" |
工具层捕获后返回结构化错误文本Agent 可据此决策(换 prompt 重试或告知用户)。
## 10. 工具参数控制权
### 10.1 问题
图片生成工具的参数n、aspectRatio、watermark、width/height 等)存在三个来源:
| 来源 | 设置者 | 例子 |
|------|--------|------|
| 工具管理页 `extra` | 管理员 | 默认 n=1、watermark=true |
| Agent 系统 prompt | 管理员 | "电商主图用 1:1" |
| Agent 运行时 tool_use | Agent响应用户 | `{ n: 4, aspectRatio: "16:9" }` |
如果管理员在工具管理页设置了 n=1但用户说"生成 4 张"Agent 传了 n=4应该听谁的
### 10.2 设计原则Agent 决策优先,管理员设默认值
参数分为两类:
**默认值参数Agent 可覆盖)**`n``aspectRatio``width``height``watermark``seed``responseFormat`
管理员在工具管理页的 `extra` 字段中配置默认值。Agent 不传时用默认值Agent 传了则以 Agent 为准。这些参数在工具编辑页可查看可编辑,标注"默认值Agent 可覆盖"。
**约束参数Agent 不可突破)**`maxN``maxWidth``maxHeight`
管理员设置硬上限,工具 execute 内部做 clamp。防止 Agent 被用户诱导生成过多或过大图片导致成本失控。这些参数在工具编辑页可查看可编辑,标注"硬上限"。
### 10.3 extra 字段结构
扩展 `netaclaw_tool.extra`,图片工具新增:
```typescript
// ToolGovernanceExtra 扩展
export type ToolGovernanceExtra = {
allowInSubagent?: boolean;
workerRoutingStrategy?: ToolWorkerRoutingStrategy;
// 图片工具新增
imageDefaults?: {
n?: number;
aspectRatio?: string;
width?: number;
height?: number;
watermark?: boolean;
responseFormat?: 'url' | 'base64';
};
imageConstraints?: {
maxN?: number; // 默认 9
maxWidth?: number; // 默认 2048
maxHeight?: number; // 默认 2048
};
};
```
### 10.4 工具 execute 内部合并逻辑
```typescript
async execute(_id, params) {
const defaults = creds.extra?.imageDefaults ?? {};
const constraints = creds.extra?.imageConstraints ?? {};
const merged = {
prompt: params.prompt,
n: Math.min(params.n ?? defaults.n ?? 1, constraints.maxN ?? 9),
aspectRatio: params.aspectRatio ?? defaults.aspectRatio,
width: clamp(params.width ?? defaults.width, constraints.maxWidth ?? 2048),
height: clamp(params.height ?? defaults.height, constraints.maxHeight ?? 2048),
watermark: params.watermark ?? defaults.watermark ?? false,
// ...
};
const result = await provider.textToImage(merged, creds);
// ...
}
```
### 10.5 前端工具编辑页
工具编辑抽屉中,当工具名为 `text_to_image``image_to_image` 时,在模型配置区域下方新增"图片生成配置"区块:
```
┌─ 图片生成配置 ──────────────────────────────┐
│ │
│ 默认值Agent 可覆盖) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 数量: 1 │ │ 比例: 1:1│ │ 水印: ☑ │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ 硬上限 │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │最大数量:9│ │最大宽:2048│ │最大高:2048 │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ ⓘ 默认值在 Agent 未指定时生效Agent 可根据 │
│ 用户指令覆盖。硬上限不可突破。 │
└──────────────────────────────────────────────┘
```
## 11. 专用电商套图 Agent
通过管理后台 Agent 编辑页配置:
- **系统 Prompt**:电商视觉设计领域知识(平台尺寸规范、构图原则、套图工作流)
- **工具集**`text_to_image` + `image_to_image` + `image_recognize` + `todo`
- **maxToolRounds**30套图需要多轮工具调用
- **promptHint**:各工具在后台配置行业特定的默认提示词
- **imageDefaults**:工具管理页配置电商常用默认值(如 aspectRatio: "1:1"、watermark: false
- **imageConstraints**:设置 maxN 防止成本失控
典型流程:用户描述产品 → Agent 规划套图方案 → 逐张生成 → 如有参考图则用图生图 → 汇总输出。
## 12. 完整改动清单
| 层 | 文件 | 改动类型 |
|----|------|---------|
| Provider | `image_providers/types.ts` | 新增 |
| Provider | `image_providers/ark.ts` | 新增 |
| Provider | `image_providers/minimax.ts` | 新增 |
| 工具 | `tools/common.ts` | 修改 |
| 工具 | `tools/builtin/text_to_image.ts` | 新增 |
| 工具 | `tools/builtin/image_to_image.ts` | 新增 |
| 注册 | `tools/catalog.ts` | 修改 |
| 治理 | `tools/manifest.ts` | 修改ToolGovernanceExtra 扩展) |
| 解析 | `service/tool_resolver.ts` | 修改 |
| 存储 | `service/image_storage.ts` | 新增 |
| Prompt | `runtime/prompt_builder.ts` | 修改 |
| 前端 | `tools/renderer-registry.ts` | 修改 |
| 前端 | `components/message-item.vue` | 修改(图片渲染升级 + 多图支持) |
| 前端 | `views/tools.vue` | 修改(图片生成配置区块) |