lovart3/docs/smart-auto-implementation-guide.md
Your Name 8763e8d53f feat: 智能图片编辑系统 - 意图分析、提示词优化、模型路由
新增智能自动模式功能:
- smart-analyzer.ts: 智能意图分析器,识别抠图/换背景/增强等8种子意图
- prompt-optimizer.ts: 提示词优化器,将简单输入转为专业提示词
- model-router.ts: 智能模型路由器,根据意图选择最佳模型
- 修改route.ts集成新模块,替换原有关键词匹配逻辑

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-01-31 23:15:11 +08:00

756 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 智能图片编辑 - 实施开发指南
> 版本: 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`
```typescript
/**
* 智能意图分析器
* 使用 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`
```typescript
/**
* 提示词优化器
* 将用户简单输入转换为专业的图片编辑提示词
*/
// 优化结果类型
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`
```typescript
/**
* 智能模型路由器
* 根据用户意图选择最佳模型
*/
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 行),替换为以下代码:
```typescript
// ========== 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天)
1. 创建 `lib/ai/smart-analyzer.ts` - 使用关键词匹配作为主逻辑
2. 创建 `lib/ai/prompt-optimizer.ts` - 实现模板化提示词优化
3. 创建 `lib/ai/model-router.ts` - 实现基于意图的模型路由
4. 修改 `app/(chat)/api/chat/route.ts` - 集成新模块
### Phase 2: 智能升级 (2-3天)
1. 在 `smart-analyzer.ts` 中集成 Qwen3 VL 进行意图分析
2. 测试各种边界情况
3. 优化提示词模板
### Phase 3: 反馈优化 (可选)
1. 添加用户反馈机制
2. 记录用户偏好
3. 持续优化模型路由策略
---
## 六、注意事项
1. **保持向后兼容**:如果智能分析失败,自动回退到关键词匹配
2. **性能考虑**:Qwen3 分析会增加约 1-2 秒延迟,考虑是否需要
3. **错误处理**:所有新模块都需要完善的 try-catch
4. **日志记录**:添加详细日志便于调试
---
## 七、文件结构
```
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 逻辑
```