智能图片编辑 - 实施开发指南
版本: v1.0
日期: 2025-01-31
目标: 在聊天对话框中实现智能图片编辑功能
一、核心流程
用户在对话框中发送 [图片 + 文字]
│
▼
┌──────────────────────────────────────────────────────────────┐
│ POST /api/chat │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. 提取用户消息 │ │
│ │ - 图片 URL (from message.parts where type='file') │ │
│ │ - 文字内容 (from message.parts where type='text') │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2. 智能意图分析 (如果 modelId === 'auto') │ │
│ │ - 调用 Qwen3 VL 分析用户意图 │ │
│ │ - 返回: intent, subIntent, confidence │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3. 提示词优化 (仅图片编辑类意图) │ │
│ │ - 根据子意图选择模板 │ │
│ │ - 填充用户参数,生成专业提示词 │ │
│ │ - 添加负面提示词 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 4. 模型路由 │ │
│ │ - 根据意图选择最佳模型 │ │
│ │ - 图片编辑 → alibaba-image │ │
│ │ - 视觉理解 → alibaba (Qwen3 VL) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 5. 调用对应模型生成 │ │
│ │ - 使用优化后的提示词 │ │
│ │ - 传入用户图片 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 6. 返回结果到对话框 │ │
│ │ - 编辑后的图片 (Markdown格式) │ │
│ │ - 保存到数据库 │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
二、需要修改/创建的文件
2.1 新建文件
| 文件路径 |
作用 |
lib/ai/smart-analyzer.ts |
智能意图分析器 |
lib/ai/prompt-optimizer.ts |
提示词优化器 |
lib/ai/model-router.ts |
智能模型路由器 |
2.2 修改文件
| 文件路径 |
修改内容 |
app/(chat)/api/chat/route.ts |
Auto Mode 逻辑替换 |
三、详细代码实现
3.1 创建 lib/ai/smart-analyzer.ts
/**
* 智能意图分析器
* 使用 Qwen3 VL 分析用户输入,识别图片编辑意图
*/
import { generateText } from "ai";
import { getLanguageModelById } from "./dynamic-provider";
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
// 分析结果类型
export interface AnalysisResult {
intent: "image_edit" | "vision" | "image_gen" | "video_gen" | "chat";
subIntent?: string;
confidence: number;
optimizedPrompt?: string;
negativePrompt?: string;
suggestedModel?: string;
needsClarification?: boolean;
clarifyingQuestions?: string[];
}
// 系统提示词 - 针对图片编辑场景优化
const ANALYZER_SYSTEM_PROMPT = `你是一个专业的图片编辑意图分析专家。请分析用户的请求,判断其意图类型。
## 意图分类(按优先级)
### 1. image_edit - 图片编辑(最高优先级,需要用户上传了图片)
子意图:
- remove_background: 抠图、去背景、透明背景、去除背景
- replace_background: 换背景、改背景、白底、场景替换、背景换成
- enhance: 变清晰、高清、锐化、降噪、提升质量、修复
- extend: 扩展、拓展、延伸、outpainting、扩图
- inpaint: 去除XX、消除、擦掉、修改XX部分、局部修改、P掉
- style_transfer: 风格化、卡通化、动漫风、油画风、改风格
- resize: 缩放、放大、缩小、调整尺寸、裁剪
- color_adjust: 调色、调整颜色、亮度、对比度、饱和度
### 2. vision - 图片理解(需要用户上传了图片)
触发词:看、识别、分析、描述、这是什么、有什么
### 3. image_gen - 图片生成(不需要上传图片)
触发词:画、绘制、生成图片、创建、设计
### 4. video_gen - 视频生成
触发词:视频、动画、动起来
### 5. chat - 普通对话(默认)
## 输出格式(严格JSON)
{
"intent": "image_edit",
"subIntent": "replace_background",
"confidence": 0.95,
"optimizedPrompt": "优化后的提示词",
"negativePrompt": "需要避免的内容",
"needsClarification": false,
"clarifyingQuestions": []
}
## 特殊规则
1. 如果用户上传了图片且有编辑类关键词 → image_edit
2. 如果用户上传了图片但意图不明确 → needsClarification: true,并提供澄清问题
3. 如果用户要求编辑但没上传图片 → needsClarification: true,提示"请上传图片"`;
/**
* 分析用户意图
*/
export async function analyzeIntent(params: {
text: string;
hasImage: boolean;
imageUrls?: string[];
}): Promise<AnalysisResult> {
const { text, hasImage, imageUrls } = params;
// 获取千问3 VL 模型
const allModels = await getEnabledAiModelsWithProvider();
const qwenModel = allModels.find(
(m) => m.provider.type === "alibaba" && m.model.supportsVision
);
// 如果没有可用的分析模型,使用回退逻辑
if (!qwenModel) {
console.log("[Smart Analyzer] No Qwen3 VL model found, using fallback");
return fallbackKeywordAnalysis(text, hasImage);
}
try {
const model = await getLanguageModelById(qwenModel.model.id);
if (!model) {
return fallbackKeywordAnalysis(text, hasImage);
}
// 构建用户消息
const userMessage = hasImage
? `用户上传了图片,请求内容:"${text}"`
: `用户请求(无图片):"${text}"`;
console.log("[Smart Analyzer] Analyzing with Qwen3 VL:", userMessage);
// 调用模型分析
const { text: responseText } = await generateText({
model,
system: ANALYZER_SYSTEM_PROMPT,
prompt: userMessage,
temperature: 0.1, // 低温度保证稳定输出
maxTokens: 500,
});
// 解析JSON响应
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const result = JSON.parse(jsonMatch[0]) as AnalysisResult;
console.log("[Smart Analyzer] Analysis result:", result);
return result;
}
} catch (error) {
console.error("[Smart Analyzer] Error:", error);
}
// 出错时使用回退逻辑
return fallbackKeywordAnalysis(text, hasImage);
}
/**
* 回退方案:关键词匹配
*/
function fallbackKeywordAnalysis(
text: string,
hasImage: boolean
): AnalysisResult {
const lowerText = text.toLowerCase();
// 图片编辑关键词检测
if (hasImage) {
// 抠图/去背景
if (/抠图|去背景|透明背景|去背|扣图/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "remove_background",
confidence: 0.9,
};
}
// 换背景
if (/换背景|白底|改背景|背景换成|纯色背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "replace_background",
confidence: 0.9,
};
}
// 图片增强
if (/变清晰|高清|锐化|降噪|提升质量|修复/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "enhance",
confidence: 0.9,
};
}
// 图像拓展
if (/扩展|拓展|延伸|扩图/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "extend",
confidence: 0.9,
};
}
// 局部修改
if (/去除|消除|擦掉|P掉|修改.*部分/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "inpaint",
confidence: 0.9,
};
}
// 风格迁移
if (/风格|卡通化|动漫风|油画风/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "style_transfer",
confidence: 0.9,
};
}
// 视觉理解
if (/看|识别|分析|描述|这是什么|有什么/.test(lowerText)) {
return { intent: "vision", confidence: 0.8 };
}
// 有图但意图不明确
return {
intent: "image_edit",
confidence: 0.5,
needsClarification: true,
clarifyingQuestions: [
"您想对这张图片做什么处理?(抠图/换背景/变清晰/其他)",
],
};
}
// 无图情况
if (/画|绘制|生成图|创建.*图/.test(lowerText)) {
return { intent: "image_gen", confidence: 0.8 };
}
if (/视频|动画|动起来/.test(lowerText)) {
return { intent: "video_gen", confidence: 0.8 };
}
// 默认对话
return { intent: "chat", confidence: 0.7 };
}
export { fallbackKeywordAnalysis };
3.2 创建 lib/ai/prompt-optimizer.ts
/**
* 提示词优化器
* 将用户简单输入转换为专业的图片编辑提示词
*/
// 优化结果类型
export interface OptimizeResult {
originalPrompt: string;
optimizedPrompt: string;
negativePrompt: string;
}
// 图片编辑子意图的提示词模板
const EDIT_TEMPLATES: Record<
string,
{
template: string;
negative: string;
extractors: Record<string, RegExp>;
}
> = {
remove_background: {
template:
"去除图片背景,保留主体完整,输出透明背景PNG格式,边缘处理平滑自然,保留细节(如发丝、毛发)",
negative: "残留背景,毛边,边缘模糊,主体不完整,锯齿",
extractors: {},
},
replace_background: {
template:
"将图片背景替换为{background},保持主体完整清晰,光影自然协调,边缘过渡平滑,保留主体阴影",
negative: "残留原背景,边缘不自然,光影不协调,透视错误,主体变形",
extractors: {
background: /(?:换成|改成|替换为|变成|换为)(.+?)(?:背景|底|$)/,
},
},
enhance: {
template:
"提升图片整体清晰度和质量,保持自然色彩不失真,去除噪点,增强细节,适度锐化",
negative: "过度锐化,色彩失真,噪点增加,伪影,画质下降",
extractors: {},
},
extend: {
template:
"向{direction}方向扩展图片{amount},保持原有风格和色调一致,光影过渡自然,无明显接缝",
negative: "风格不一致,明显接缝,透视错误,内容突变",
extractors: {
direction: /向?(上|下|左|右|四周)/,
amount: /(\d+%?)/,
},
},
inpaint: {
template:
"去除/修改图片中的{target},用周围环境自然填充,保持整体风格一致,无修复痕迹",
negative: "明显修复痕迹,风格不一致,内容错误,边缘不自然",
extractors: {
target: /(?:去除|消除|擦掉|删除|P掉)(.+?)(?:,|。|$)/,
},
},
style_transfer: {
template:
"将图片转换为{style}风格,保持主体可识别性,色彩风格协调,整体效果自然",
negative: "主体变形,特征丢失,风格不统一,色彩异常",
extractors: {
style: /(?:转换为|变成|改成)(.+?)(?:风格|$)/,
},
},
resize: {
template: "调整图片尺寸为{size},保持画质清晰,比例协调",
negative: "画质损失,比例失调,模糊",
extractors: {
size: /(\d+[x×]\d+|\d+%)/,
},
},
color_adjust: {
template: "调整图片{adjustment},保持自然效果,色彩协调",
negative: "色彩失真,过度调整,不自然",
extractors: {
adjustment: /(?:调整|增加|减少|提高|降低)(.+?)(?:,|。|$)/,
},
},
};
/**
* 优化提示词
*/
export function optimizePrompt(params: {
originalPrompt: string;
intent: string;
subIntent?: string;
}): OptimizeResult {
const { originalPrompt, intent, subIntent } = params;
// 只对图片编辑类意图进行优化
if (intent !== "image_edit" || !subIntent) {
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印",
};
}
const template = EDIT_TEMPLATES[subIntent];
if (!template) {
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印",
};
}
// 使用模板生成优化后的提示词
let optimizedPrompt = template.template;
// 从用户输入中提取参数并填充模板
for (const [key, regex] of Object.entries(template.extractors)) {
const match = originalPrompt.match(regex);
const value = match ? match[1].trim() : getDefaultValue(key);
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, value);
}
// 附加用户原始意图
optimizedPrompt = `${optimizedPrompt}。\n\n用户原始要求:${originalPrompt}`;
console.log("[Prompt Optimizer] Optimized:", {
original: originalPrompt,
optimized: optimizedPrompt,
negative: template.negative,
});
return {
originalPrompt,
optimizedPrompt,
negativePrompt: template.negative,
};
}
/**
* 获取参数默认值
*/
function getDefaultValue(key: string): string {
const defaults: Record<string, string> = {
background: "纯白色",
direction: "四周",
amount: "50%",
target: "指定区域",
style: "卡通",
size: "原尺寸",
adjustment: "颜色",
};
return defaults[key] || "默认";
}
3.3 创建 lib/ai/model-router.ts
/**
* 智能模型路由器
* 根据用户意图选择最佳模型
*/
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
// 路由结果类型
export interface RouteResult {
id: string;
displayName: string;
providerType: string;
reason: string;
}
// 意图到模型的映射配置
const INTENT_MODEL_MAP: Record<
string,
{
providerTypes: string[];
requireVision?: boolean;
requireImageGen?: boolean;
}
> = {
// 图片编辑:优先 alibaba-image(灵魂4.5)
image_edit: {
providerTypes: ["alibaba-image", "gemini"],
requireVision: true,
requireImageGen: true,
},
// 视觉理解:优先千问3 VL(成本低效果好)
vision: {
providerTypes: ["alibaba", "gemini"],
requireVision: true,
},
// 图片生成
image_gen: {
providerTypes: ["alibaba-image", "gemini", "volcano-vision"],
requireImageGen: true,
},
// 视频生成
video_gen: {
providerTypes: ["volcano-video", "qianwen-video"],
},
// 普通对话
chat: {
providerTypes: ["alibaba", "openai"],
},
};
/**
* 路由到最佳模型
*/
export async function routeToModel(params: {
intent: string;
subIntent?: string;
hasImage: boolean;
}): Promise<RouteResult> {
const { intent, subIntent, hasImage } = params;
console.log("[Model Router] Routing for intent:", intent, subIntent);
// 获取所有可用模型
const allModels = await getEnabledAiModelsWithProvider();
// 获取意图对应的配置
const config = INTENT_MODEL_MAP[intent] || INTENT_MODEL_MAP["chat"];
// 按优先级查找匹配的模型
for (const providerType of config.providerTypes) {
const candidates = allModels.filter((m) => {
// 匹配 provider 类型
if (m.provider.type !== providerType) return false;
// 检查能力要求
if (config.requireVision && !m.model.supportsVision) return false;
if (config.requireImageGen && !m.model.supportsImageGen) return false;
// 排除子模型
if (m.model.isSubModel) return false;
// 必须启用
if (!m.model.isEnabled) return false;
return true;
});
if (candidates.length > 0) {
// 优先选择默认模型
const defaultModel = candidates.find((c) => c.model.isDefault);
const selected = defaultModel || candidates[0];
const result: RouteResult = {
id: selected.model.id,
displayName: selected.model.displayName,
providerType: selected.provider.type,
reason: `${intent}${subIntent ? `/${subIntent}` : ""} → ${selected.model.displayName}`,
};
console.log("[Model Router] Selected:", result);
return result;
}
}
// 兜底:返回任意可用模型
const fallback =
allModels.find((m) => !m.model.isSubModel && m.model.isEnabled) ||
allModels[0];
console.log("[Model Router] Using fallback model:", fallback.model.displayName);
return {
id: fallback.model.id,
displayName: fallback.model.displayName,
providerType: fallback.provider.type,
reason: "fallback",
};
}
3.4 修改 app/(chat)/api/chat/route.ts
在现有的 Auto Mode 逻辑位置(约第 334-422 行),替换为以下代码:
// ========== Smart Auto Mode Logic ==========
if (finalModelId === "auto") {
console.log("[Smart Auto Mode] Starting intelligent analysis...");
// 1. 提取用户消息内容
const lastUserMessage = message;
const textContent = lastUserMessage.parts
.filter((p) => p.type === "text")
.map((p) => (p as { type: "text"; text: string }).text)
.join(" ");
const hasImage = lastUserMessage.parts.some(
(p) => p.type === "file" || p.type === "image" || p.type === "image_url"
);
const imageUrls = lastUserMessage.parts
.filter((p): p is { type: "file"; url: string } => p.type === "file")
.map((p) => p.url);
// 2. 调用智能分析器
const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
const analysisResult = await analyzeIntent({
text: textContent,
hasImage,
imageUrls,
});
console.log("[Smart Auto Mode] Analysis result:", analysisResult);
// 3. 如果需要澄清,返回澄清问题(可选功能)
if (analysisResult.needsClarification && analysisResult.clarifyingQuestions) {
console.log("[Smart Auto Mode] Needs clarification, but proceeding with best guess...");
// 暂时不中断流程,继续使用最佳猜测
}
// 4. 如果是图片编辑类意图,优化提示词
if (analysisResult.intent === "image_edit" && analysisResult.subIntent) {
const { optimizePrompt } = await import("@/lib/ai/prompt-optimizer");
const optimizedResult = optimizePrompt({
originalPrompt: textContent,
intent: analysisResult.intent,
subIntent: analysisResult.subIntent,
});
console.log("[Smart Auto Mode] Prompt optimized");
// 替换消息中的文本为优化后的提示词
message.parts = message.parts.map((part) => {
if (part.type === "text") {
return {
...part,
text: optimizedResult.optimizedPrompt,
};
}
return part;
});
// 如果模型支持负面提示词,可以在 imageParams 中传递
// requestBody.imageParams = {
// ...requestBody.imageParams,
// negativePrompt: optimizedResult.negativePrompt,
// };
}
// 5. 路由到最佳模型
const { routeToModel } = await import("@/lib/ai/model-router");
const routeResult = await routeToModel({
intent: analysisResult.intent,
subIntent: analysisResult.subIntent,
hasImage,
});
finalModelId = routeResult.id;
console.log(`[Smart Auto Mode] ✅ Routed to: ${routeResult.displayName} (${routeResult.reason})`);
}
// ========== End Smart Auto Mode Logic ==========
四、测试场景
4.1 图片编辑场景测试
| 用户输入 |
预期意图 |
预期模型 |
| [图片] + "帮我把背景换成白色" |
replace_background |
alibaba-image |
| [图片] + "抠图" |
remove_background |
alibaba-image |
| [图片] + "变清晰一点" |
enhance |
alibaba-image |
| [图片] + "把右边的人P掉" |
inpaint |
alibaba-image |
| [图片] + "转成卡通风格" |
style_transfer |
alibaba-image |
4.2 非编辑场景测试
| 用户输入 |
预期意图 |
预期模型 |
| [图片] + "这是什么?" |
vision |
alibaba (Qwen3 VL) |
| "画一个可爱的猫" |
image_gen |
alibaba-image |
| "你好" |
chat |
alibaba (Qwen3 VL) |
五、开发步骤
Phase 1: 基础实现 (1-2天)
- 创建
lib/ai/smart-analyzer.ts - 使用关键词匹配作为主逻辑
- 创建
lib/ai/prompt-optimizer.ts - 实现模板化提示词优化
- 创建
lib/ai/model-router.ts - 实现基于意图的模型路由
- 修改
app/(chat)/api/chat/route.ts - 集成新模块
Phase 2: 智能升级 (2-3天)
- 在
smart-analyzer.ts 中集成 Qwen3 VL 进行意图分析
- 测试各种边界情况
- 优化提示词模板
Phase 3: 反馈优化 (可选)
- 添加用户反馈机制
- 记录用户偏好
- 持续优化模型路由策略
六、注意事项
- 保持向后兼容:如果智能分析失败,自动回退到关键词匹配
- 性能考虑:Qwen3 分析会增加约 1-2 秒延迟,考虑是否需要
- 错误处理:所有新模块都需要完善的 try-catch
- 日志记录:添加详细日志便于调试
七、文件结构
lib/
└── ai/
├── smart-analyzer.ts # 智能意图分析器
├── prompt-optimizer.ts # 提示词优化器
├── model-router.ts # 智能模型路由器
├── dynamic-provider.ts # 现有模型提供器
└── providers/ # 现有模型提供商
├── alibaba-image.ts
├── gemini-image.ts
└── ...
app/
└── (chat)/
└── api/
└── chat/
└── route.ts # 修改 Auto Mode 逻辑